Return to http_server.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / contrib / libpdel / http |
1.1 misho 1: 2: /* 3: * Copyright (c) 2001-2002 Packet Design, LLC. 4: * All rights reserved. 5: * 6: * Subject to the following obligations and disclaimer of warranty, 7: * use and redistribution of this software, in source or object code 8: * forms, with or without modifications are expressly permitted by 9: * Packet Design; provided, however, that: 10: * 11: * (i) Any and all reproductions of the source or object code 12: * must include the copyright notice above and the following 13: * disclaimer of warranties; and 14: * (ii) No rights are granted, in any manner or form, to use 15: * Packet Design trademarks, including the mark "PACKET DESIGN" 16: * on advertising, endorsements, or otherwise except as such 17: * appears in the above copyright notice or in the software. 18: * 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF 36: * THE POSSIBILITY OF SUCH DAMAGE. 37: * 38: * Author: Archie Cobbs <archie@freebsd.org> 39: */ 40: 41: #include <sys/types.h> 42: #include <sys/param.h> 43: #include <sys/socket.h> 44: #include <sys/syslog.h> 45: #include <sys/queue.h> 46: 47: #include <stdlib.h> 48: #include <stdarg.h> 49: #include <unistd.h> 50: #include <errno.h> 51: #include <assert.h> 52: #include <unistd.h> 53: #include <string.h> 54: #include <fcntl.h> 55: #include <ctype.h> 56: #include <limits.h> 57: #include <regex.h> 58: #include <pthread.h> 59: #include <netdb.h> 60: 61: #include <netinet/in_systm.h> 62: #include <netinet/in.h> 63: #include <arpa/inet.h> 64: 65: #include <openssl/ssl.h> 66: #include <openssl/err.h> 67: 68: #include "structs/structs.h" 69: #include "structs/type/array.h" 70: 71: #include "io/ssl_fp.h" 72: #include "http/http_defs.h" 73: #include "http/http_server.h" 74: #include "http/http_internal.h" 75: #include "http/http_servlet.h" 76: #include "util/pevent.h" 77: #include "util/ghash.h" 78: #include "util/typed_mem.h" 79: 80: /* 81: * Embedded HTTP[S] web server. 82: */ 83: 84: #define MAX_CONNECTIONS 1024 85: #define HTTP_SERVER_TIMEOUT 90 86: 87: /* HTTP server */ 88: struct http_server { 89: struct pevent_ctx *ctx; /* event context */ 90: struct pevent *conn_event; /* new connection event */ 91: int sock; /* accept(2) socket */ 92: SSL_CTX *ssl; /* ssl context, if doing ssl */ 93: char *pkey_pw; /* ssl private key password */ 94: char *server_name; /* server name */ 95: struct ghash *vhosts; /* virtual hosts */ 96: http_proxy_t *proxy_handler; /* proxy handler */ 97: void *proxy_arg; /* proxy handler cookie */ 98: LIST_HEAD(,http_connection) 99: conn_list; /* active connections */ 100: int max_conn; /* max number of connections */ 101: int num_conn; /* number of connections */ 102: http_logger_t *logger; /* error logging routine */ 103: pthread_mutex_t mutex; /* mutex */ 104: u_char stopping; /* server being stopped */ 105: #if PDEL_DEBUG 106: int mutex_count; /* mutex count */ 107: #endif 108: }; 109: 110: /* Virtual host */ 111: struct http_virthost { 112: struct http_server *server; /* back pointer to server */ 113: char *host; /* virtual hostname */ 114: LIST_HEAD(,http_servlet_hook) 115: servlets; /* registered servlets */ 116: }; 117: 118: /* What a registered servlet looks like */ 119: struct http_servlet_hook { 120: struct http_servlet *servlet; /* servlet */ 121: struct http_virthost *vhost; /* back pointer to vhost */ 122: #if PDEL_DEBUG 123: char *spat; /* string pattern */ 124: #endif 125: regex_t pat; /* regex pattern */ 126: int order; /* processing order */ 127: pthread_rwlock_t rwlock; /* servlet lock */ 128: LIST_ENTRY(http_servlet_hook) 129: next; /* next in vhost list */ 130: }; 131: 132: /* 133: * Internal functions 134: */ 135: static void *http_server_connection_main(void *arg); 136: static void http_server_connection_cleanup(void *arg); 137: static void http_server_dispatch(struct http_request *req, 138: struct http_response *resp); 139: static int http_server_ssl_pem_password_cb(char *buf, int size, 140: int rwflag, void *udata); 141: 142: static pevent_handler_t http_server_accept; 143: 144: static ghash_equal_t http_server_virthost_equal; 145: static ghash_hash_t http_server_virthost_hash; 146: 147: static ssl_logger_t http_server_ssl_logger; 148: 149: /********************************************************************* 150: SERVER START/STOP ROUTINES 151: *********************************************************************/ 152: 153: /* 154: * Create and start a new server. The server runs in a separate thread. 155: */ 156: struct http_server * 157: http_server_start(struct pevent_ctx *ctx, struct in_addr ip, 158: u_int16_t port, const struct http_server_ssl *ssl, 159: const char *server_name, http_logger_t *logger) 160: { 161: static const int one = 1; 162: struct http_server *serv; 163: struct sockaddr_in sin; 164: int got_mutex = 0; 165: 166: /* Initialize new server structure */ 167: if ((serv = MALLOC("http_server", sizeof(*serv))) == NULL) { 168: (*logger)(LOG_ERR, "%s: %s", "realloc", strerror(errno)); 169: return (NULL); 170: } 171: memset(serv, 0, sizeof(*serv)); 172: LIST_INIT(&serv->conn_list); 173: serv->ctx = ctx; 174: serv->logger = logger; 175: serv->sock = -1; 176: serv->max_conn = MAX_CONNECTIONS; /* XXX make configurable */ 177: 178: /* Copy server name */ 179: if ((serv->server_name 180: = STRDUP("http_server.server_name", server_name)) == NULL) { 181: (*logger)(LOG_ERR, "%s: %s", "strdup", strerror(errno)); 182: goto fail; 183: } 184: 185: /* Create virtual host hash table */ 186: if ((serv->vhosts = ghash_create(serv, 0, 0, "http_server.vhosts", 187: http_server_virthost_hash, http_server_virthost_equal, NULL, 188: NULL)) == NULL) { 189: (*logger)(LOG_ERR, "%s: %s", "strdup", strerror(errno)); 190: goto fail; 191: } 192: 193: /* Initialize ssl */ 194: if (ssl != NULL) { 195: 196: /* Initialize SSL stuff */ 197: _http_ssl_init(); 198: 199: /* Initialize SSL context for this server */ 200: if ((serv->ssl = SSL_CTX_new(SSLv2_server_method())) == NULL) { 201: ssl_log(http_server_ssl_logger, serv); 202: goto fail; 203: } 204: 205: /* Set callback for getting private key file password */ 206: SSL_CTX_set_default_passwd_cb(serv->ssl, 207: http_server_ssl_pem_password_cb); 208: SSL_CTX_set_default_passwd_cb_userdata(serv->ssl, serv); 209: if (serv->pkey_pw != NULL 210: && (serv->pkey_pw = STRDUP("http_server.pkey_pw", 211: ssl->pkey_password)) == NULL) { 212: (*serv->logger)(LOG_ERR, "%s: %s", 213: "strdup", strerror(errno)); 214: goto fail; 215: } 216: 217: /* Read in certificate and private key files */ 218: if (SSL_CTX_use_certificate_file(serv->ssl, 219: ssl->cert_path, SSL_FILETYPE_PEM) <= 0) { 220: ssl_log(http_server_ssl_logger, serv); 221: goto fail; 222: } 223: if (SSL_CTX_use_PrivateKey_file(serv->ssl, 224: ssl->pkey_path, SSL_FILETYPE_PEM) <= 0) { 225: ssl_log(http_server_ssl_logger, serv); 226: goto fail; 227: } 228: 229: /* Verify that certificate actually signs the public key */ 230: if (!SSL_CTX_check_private_key(serv->ssl)) { 231: (*serv->logger)(LOG_ERR, 232: "certificate %s does not match private key %s", 233: ssl->cert_path, ssl->pkey_path); 234: goto fail; 235: } 236: } 237: 238: /* Create socket */ 239: if ((serv->sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { 240: (*serv->logger)(LOG_ERR, "%s: %s", "socket", strerror(errno)); 241: goto fail; 242: } 243: (void)fcntl(serv->sock, F_SETFD, 1); 244: if (setsockopt(serv->sock, SOL_SOCKET, 245: SO_REUSEADDR, (char *)&one, sizeof(one)) == -1) { 246: (*serv->logger)(LOG_ERR, 247: "%s: %s", "setsockopt", strerror(errno)); 248: goto fail; 249: } 250: memset(&sin, 0, sizeof(sin)); 251: #if !defined(__linux__) && !defined(__sun__) 252: sin.sin_len = sizeof(sin); 253: #endif 254: sin.sin_family = AF_INET; 255: sin.sin_port = htons(port); 256: sin.sin_addr = ip; 257: if (bind(serv->sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) { 258: (*serv->logger)(LOG_ERR, "%s: %s", "bind", strerror(errno)); 259: goto fail; 260: } 261: if (listen(serv->sock, 1024) == -1) { 262: (*serv->logger)(LOG_ERR, "%s: %s", "listen", strerror(errno)); 263: goto fail; 264: } 265: 266: /* Initialize mutex */ 267: if ((errno = pthread_mutex_init(&serv->mutex, NULL)) != 0) { 268: (*serv->logger)(LOG_ERR, "%s: %s", 269: "pthread_mutex_init", strerror(errno)); 270: goto fail; 271: } 272: got_mutex = 1; 273: 274: /* Start accepting connections */ 275: if (pevent_register(serv->ctx, &serv->conn_event, PEVENT_RECURRING, 276: &serv->mutex, http_server_accept, serv, PEVENT_READ, serv->sock) 277: == -1) { 278: (*serv->logger)(LOG_ERR, "%s: %s", 279: "pevent_register", strerror(errno)); 280: goto fail; 281: } 282: DBG(HTTP, "server %p started", serv); 283: 284: /* Done */ 285: return (serv); 286: 287: fail: 288: /* Cleanup after failure */ 289: if (got_mutex) 290: pthread_mutex_destroy(&serv->mutex); 291: if (serv->pkey_pw != NULL) { 292: memset(serv->pkey_pw, 0, strlen(serv->pkey_pw)); 293: FREE("http_server.pkey_pw", serv->pkey_pw); 294: } 295: if (serv->sock != -1) 296: (void)close(serv->sock); 297: if (serv->ssl != NULL) 298: SSL_CTX_free(serv->ssl); 299: ghash_destroy(&serv->vhosts); 300: FREE("http_server.server_name", serv->server_name); 301: FREE("http_server", serv); 302: return (NULL); 303: } 304: 305: /* 306: * Stop HTTP server. 307: */ 308: void 309: http_server_stop(struct http_server **sp) 310: { 311: struct http_server *const serv = *sp; 312: struct http_connection *conn; 313: 314: /* Already stopped? */ 315: if (serv == NULL) 316: return; 317: *sp = NULL; 318: 319: /* Set 'stopping' flag to prevent new servlet registrations */ 320: if (serv->stopping) 321: return; 322: serv->stopping = 1; 323: DBG(HTTP, "stopping server %p", serv); 324: 325: /* Acquire mutex */ 326: MUTEX_LOCK(&serv->mutex, serv->mutex_count); 327: 328: /* Stop accepting new connections */ 329: pevent_unregister(&serv->conn_event); 330: 331: /* 332: * Destroy all registered servlets. Because we must unlock the 333: * server to do this, don't rely on iteration. Instead, start at 334: * the beginning each time. 335: */ 336: while (ghash_size(serv->vhosts) > 0) { 337: struct http_servlet_hook *hook; 338: struct http_servlet *servlet; 339: struct http_virthost *vhost; 340: struct ghash_walk walk; 341: 342: /* Get the first virtual host */ 343: ghash_walk_init(serv->vhosts, &walk); 344: vhost = ghash_walk_next(serv->vhosts, &walk); 345: assert(vhost != NULL); 346: 347: /* Get the first servlet in this virtual host */ 348: assert(!LIST_EMPTY(&vhost->servlets)); 349: hook = LIST_FIRST(&vhost->servlets); 350: servlet = hook->servlet; 351: 352: /* Unlock server and nuke the servlet */ 353: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 354: http_server_destroy_servlet(&servlet); 355: MUTEX_LOCK(&serv->mutex, serv->mutex_count); 356: } 357: 358: /* Kill any remaining connections */ 359: while (!LIST_EMPTY(&serv->conn_list)) { 360: 361: /* Kill active connections; they will clean up themselves */ 362: LIST_FOREACH(conn, &serv->conn_list, next) { 363: if (conn->started && conn->tid != 0) { 364: DBG(HTTP, "canceling conn %p (thread %p)", 365: conn, conn->tid); 366: assert(conn->tid != pthread_self()); 367: pthread_cancel(conn->tid); 368: conn->tid = 0; /* don't cancel twice */ 369: } 370: } 371: 372: /* Wait for outstanding connections to complete */ 373: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 374: usleep(100000); 375: MUTEX_LOCK(&serv->mutex, serv->mutex_count); 376: } 377: 378: /* Free SSL context */ 379: if (serv->ssl != NULL) 380: SSL_CTX_free(serv->ssl); 381: 382: /* Close listen socket */ 383: (void)close(serv->sock); 384: 385: /* Free strings */ 386: if (serv->pkey_pw != NULL) { 387: memset(serv->pkey_pw, 0, strlen(serv->pkey_pw)); 388: FREE("http_server.pkey_pw", serv->pkey_pw); 389: } 390: FREE("http_server.server_name", serv->server_name); 391: 392: /* Free virtual hosts hash table */ 393: assert(ghash_size(serv->vhosts) == 0); 394: ghash_destroy(&serv->vhosts); 395: 396: /* Free server structure itself */ 397: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 398: pthread_mutex_destroy(&serv->mutex); 399: DBG(HTTP, "freeing server %p", serv); 400: FREE("http_server", serv); 401: } 402: 403: /********************************************************************* 404: SERVLET REGISTRATION 405: *********************************************************************/ 406: 407: /* 408: * Register a servlet 409: */ 410: int 411: http_server_register_servlet(struct http_server *serv, 412: struct http_servlet *servlet, const char *vhost, 413: const char *urlpat, int order) 414: { 415: struct http_servlet_hook *hook; 416: struct http_virthost vhost_key; 417: int got_rwlock = 0; 418: int got_regex = 0; 419: char ebuf[128]; 420: int r; 421: 422: /* Sanity */ 423: if (servlet == NULL) { 424: errno = EINVAL; 425: return (-1); 426: } 427: if (servlet->hook != NULL) { 428: errno = EALREADY; 429: return (-1); 430: } 431: if (serv->stopping) { 432: errno = ESRCH; 433: return (-1); 434: } 435: if (vhost == NULL) 436: vhost = ""; 437: 438: /* Create new servlet hook */ 439: if ((hook = MALLOC("http_servlet_hook", sizeof(*hook))) == NULL) { 440: (*serv->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno)); 441: return (-1); 442: } 443: memset(hook, 0, sizeof(*hook)); 444: hook->servlet = servlet; 445: hook->order = order; 446: #if PDEL_DEBUG 447: if ((hook->spat = STRDUP("http_servlet_hook.spat", urlpat)) == NULL) { 448: (*serv->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno)); 449: goto fail; 450: } 451: #endif 452: 453: /* Compile URL regular expression */ 454: if ((r = regcomp(&hook->pat, urlpat, REG_EXTENDED | REG_NOSUB)) != 0) { 455: regerror(r, &hook->pat, ebuf, sizeof(ebuf)); 456: (*serv->logger)(LOG_ERR, 457: "invalid URL pattern \"%s\": %s", urlpat, ebuf); 458: goto fail; 459: } 460: got_regex = 1; 461: 462: /* Initialize read/write lock */ 463: if ((errno = pthread_rwlock_init(&hook->rwlock, NULL)) != 0) { 464: (*serv->logger)(LOG_ERR, "%s: %s", 465: "pthread_rwlock_init", strerror(errno)); 466: goto fail; 467: } 468: got_rwlock = 1; 469: 470: /* Lock server */ 471: MUTEX_LOCK(&serv->mutex, serv->mutex_count); 472: 473: /* Find virtual host; create a new one if necessary */ 474: vhost_key.host = (char *)vhost; 475: if ((hook->vhost = ghash_get(serv->vhosts, &vhost_key)) == NULL) { 476: 477: /* Create a new virtual host */ 478: if ((hook->vhost = MALLOC("http_virthost", 479: sizeof(*hook->vhost))) == NULL) { 480: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 481: (*serv->logger)(LOG_ERR, "%s: %s", 482: "malloc", strerror(errno)); 483: goto fail; 484: } 485: memset(hook->vhost, 0, sizeof(*hook->vhost)); 486: if ((hook->vhost->host 487: = STRDUP("http_virthost.host", vhost)) == NULL) { 488: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 489: (*serv->logger)(LOG_ERR, "%s: %s", 490: "malloc", strerror(errno)); 491: goto fail; 492: } 493: LIST_INIT(&hook->vhost->servlets); 494: 495: /* Add virtual host to server's list */ 496: if ((r = ghash_put(serv->vhosts, hook->vhost)) == -1) { 497: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 498: goto fail; 499: } 500: assert(r == 0); 501: hook->vhost->server = serv; 502: } 503: 504: /* Register servlet with virtual host */ 505: LIST_INSERT_HEAD(&hook->vhost->servlets, hook, next); 506: servlet->hook = hook; 507: 508: /* Unlock server */ 509: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 510: 511: /* Done */ 512: return (0); 513: 514: fail: 515: /* Clean up after failure */ 516: if (hook->vhost != NULL) { 517: FREE("http_virthost.host", hook->vhost->host); 518: FREE("http_virthost", hook->vhost); 519: } 520: if (got_rwlock) 521: pthread_rwlock_destroy(&hook->rwlock); 522: if (got_regex) 523: regfree(&hook->pat); 524: #if PDEL_DEBUG 525: FREE("http_servlet_hook.spat", hook->spat); 526: #endif 527: FREE("http_servlet_hook", hook); 528: return (-1); 529: } 530: 531: /* 532: * Destroy a servlet, unregistering it if necessary. 533: * 534: * If it's the last servlet in the virtual host, remove the virtual host too. 535: */ 536: void 537: http_server_destroy_servlet(struct http_servlet **servletp) 538: { 539: struct http_servlet *const servlet = *servletp; 540: struct http_servlet_hook *hook; 541: struct http_virthost *vhost; 542: struct http_server *serv; 543: int r; 544: 545: /* Sanity */ 546: if (servlet == NULL) 547: return; 548: *servletp = NULL; 549: hook = servlet->hook; 550: 551: /* If servlet is not registered, just destroy it */ 552: if (hook == NULL) 553: goto done; 554: vhost = hook->vhost; 555: serv = vhost->server; 556: 557: /* Lock server */ 558: MUTEX_LOCK(&serv->mutex, serv->mutex_count); 559: 560: /* Unregister servlet from its virtual host */ 561: LIST_REMOVE(hook, next); 562: hook->vhost = NULL; /* for good measure */ 563: 564: /* Remove the virtual host if it has no more servlets */ 565: if (LIST_EMPTY(&vhost->servlets)) { 566: r = ghash_remove(serv->vhosts, vhost); 567: assert(r == 1); 568: vhost->server = NULL; /* for good measure */ 569: FREE("http_virthost.host", vhost->host); 570: FREE("http_virthost", vhost); 571: } 572: 573: /* Unlock server */ 574: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 575: 576: /* Wait for any threads running this servlet to finish */ 577: r = pthread_rwlock_wrlock(&hook->rwlock); 578: assert(r == 0); 579: r = pthread_rwlock_unlock(&hook->rwlock); 580: assert(r == 0); 581: 582: /* Destroy servlet hook */ 583: regfree(&hook->pat); 584: pthread_rwlock_destroy(&hook->rwlock); 585: #if PDEL_DEBUG 586: FREE("http_servlet_hook.spat", hook->spat); 587: #endif 588: FREE("http_servlet_hook", hook); 589: servlet->hook = NULL; /* for good measure */ 590: 591: done: 592: /* Destroy servlet itself */ 593: (*servlet->destroy)(servlet); 594: } 595: 596: /* 597: * Set proxy servlet 598: */ 599: extern void 600: http_server_set_proxy_handler(struct http_server *serv, 601: http_proxy_t *handler, void *arg) 602: { 603: MUTEX_LOCK(&serv->mutex, serv->mutex_count); 604: serv->proxy_handler = handler; 605: serv->proxy_arg = arg; 606: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 607: } 608: 609: /********************************************************************* 610: SERVER MAIN THREAD 611: *********************************************************************/ 612: 613: /* 614: * Accept a new connection. 615: * 616: * The mutex will be locked when this is called. 617: */ 618: static void 619: http_server_accept(void *arg) 620: { 621: struct http_server *const serv = arg; 622: struct http_connection *conn; 623: struct sockaddr_in sin; 624: socklen_t slen = sizeof(sin); 625: int sock; 626: 627: /* Accept next connection */ 628: if ((sock = accept(serv->sock, (struct sockaddr *)&sin, &slen)) == -1) { 629: if (errno != ECONNABORTED && errno != ENOTCONN) { 630: (*serv->logger)(LOG_ERR, "%s: %s", 631: "accept", strerror(errno)); 632: } 633: return; 634: } 635: (void)fcntl(sock, F_SETFD, 1); 636: 637: /* Get new connection object */ 638: if ((conn = _http_connection_create(NULL, sock, 1, sin.sin_addr, 639: ntohs(sin.sin_port), serv->ssl, serv->logger, 640: HTTP_SERVER_TIMEOUT)) == NULL) { 641: (*serv->logger)(LOG_ERR, "%s: %s", 642: "_http_connection_create", strerror(errno)); 643: (void)close(sock); 644: return; 645: } 646: conn->owner = serv; 647: 648: /* Add to server's list of active connections */ 649: LIST_INSERT_HEAD(&serv->conn_list, conn, next); 650: serv->num_conn++; 651: 652: /* Spawn a new thread to handle request */ 653: if ((errno = pthread_create(&conn->tid, NULL, 654: http_server_connection_main, conn)) != 0) { 655: (*serv->logger)(LOG_ERR, "%s: %s", 656: "pthread_create", strerror(errno)); 657: conn->tid = 0; 658: LIST_REMOVE(conn, next); 659: serv->num_conn--; 660: _http_connection_free(&conn); 661: } 662: 663: /* Detach thread */ 664: pthread_detach(conn->tid); 665: DBG(HTTP, "spawning %p for connection %p from %s:%u", 666: conn->tid, conn, inet_ntoa(conn->remote_ip), conn->remote_port); 667: 668: /* If maximum number of connections reached, stop accepting new ones */ 669: if (serv->num_conn >= serv->max_conn) 670: pevent_unregister(&serv->conn_event); 671: } 672: 673: /********************************************************************* 674: SERVER CONNECTION MAIN THREAD 675: *********************************************************************/ 676: 677: /* 678: * HTTP connection thread main routine. 679: */ 680: static void * 681: http_server_connection_main(void *arg) 682: { 683: struct http_connection *const conn = arg; 684: struct http_server *const serv = conn->owner; 685: 686: /* Add shutdown cleanup hook */ 687: pthread_cleanup_push(http_server_connection_cleanup, conn); 688: conn->started = 1; /* avoids pthread_cancel() race */ 689: DBG(HTTP, "connection %p started", conn); 690: 691: /* Read requests as long as connection is kept alive */ 692: conn->keep_alive = 1; 693: while (1) { 694: struct http_request *const req = conn->req; 695: struct http_response *const resp = conn->resp; 696: const char *hval; 697: char dbuf[64]; 698: struct tm tm; 699: time_t now; 700: 701: /* Read in request */ 702: if (_http_request_read(conn) == -1) { 703: if (errno == ENOTCONN) /* remote side disconnected */ 704: break; 705: conn->keep_alive = 0; 706: goto send_response; 707: } 708: 709: /* Set default response headers */ 710: now = time(NULL); 711: strftime(dbuf, sizeof(dbuf), 712: HTTP_TIME_FMT_RFC1123, gmtime_r(&now, &tm)); 713: if (http_response_set_header(resp, 0, 714: HDR_REPLY_VERSION, HTTP_PROTO_1_1) == -1 715: || http_response_set_header(resp, 0, HDR_REPLY_STATUS, 716: "%d", HTTP_STATUS_OK) == -1 717: || http_response_set_header(resp, 0, HDR_REPLY_REASON, 718: "%s", http_response_status_msg(HTTP_STATUS_OK)) == -1 719: || http_response_set_header(resp, 0, HTTP_HEADER_SERVER, 720: "%s", serv->server_name) == -1 721: || http_response_set_header(resp, 0, HTTP_HEADER_DATE, 722: "%s", dbuf) == -1 723: || http_response_set_header(resp, 0, 724: HTTP_HEADER_LAST_MODIFIED, "%s", dbuf) == -1) { 725: conn->keep_alive = 0; 726: goto send_response; 727: } 728: 729: /* Turn off keep-alive if client doesn't want it */ 730: if (!_http_head_want_keepalive(req->msg->head)) 731: conn->keep_alive = 0; 732: 733: /* Handle request */ 734: http_server_dispatch(req, resp); 735: 736: /* Set Connection: header if not already set */ 737: if (((hval = http_request_get_method(req)) == NULL 738: || strcmp(hval, HTTP_METHOD_CONNECT) != 0) 739: && http_response_get_header(resp, 740: _http_message_connection_header(resp->msg)) == NULL) { 741: http_response_set_header(resp, 0, 742: _http_message_connection_header(resp->msg), 743: conn->keep_alive ? "Keep-Alive" : "Close"); 744: } 745: 746: /* Slurp up any remaining entity data if keep-alive */ 747: if (conn->keep_alive && req != NULL && !feof(req->msg->input)) { 748: static char buf[1024]; 749: 750: while (fgets(buf, sizeof(buf), req->msg->input) != NULL) 751: ; 752: } 753: 754: send_response: 755: /* Send back headers (if not already sent) */ 756: http_response_send_headers(resp, 0); 757: 758: /* Send back body (if it was buffered) */ 759: _http_message_send_body(resp->msg); 760: 761: /* Determine if we can still keep this connection alive */ 762: if (!resp->msg->no_body 763: && (http_response_get_header(resp, 764: HTTP_HEADER_CONTENT_LENGTH) == NULL 765: || ferror(conn->fp) 766: || feof(conn->fp) 767: || !_http_head_want_keepalive(resp->msg->head))) 768: conn->keep_alive = 0; 769: 770: /* Close connection unless keeping it alive */ 771: if (!conn->keep_alive) 772: break; 773: 774: /* Reset request & response for next time */ 775: _http_request_free(&conn->req); 776: _http_response_free(&conn->resp); 777: if (_http_request_new(conn) == -1 778: || _http_response_new(conn) == -1) 779: break; 780: } 781: 782: /* Done with this connection */ 783: DBG(HTTP, "done with connection %p", conn); 784: pthread_cleanup_pop(1); 785: return (NULL); 786: } 787: 788: /* 789: * Cleanup when shutting down an HTTP server connection. 790: */ 791: static void 792: http_server_connection_cleanup(void *arg) 793: { 794: struct http_connection *conn = arg; 795: struct http_server *const serv = conn->owner; 796: 797: /* Lock server */ 798: DBG(HTTP, "connection %p cleaning up", conn); 799: MUTEX_LOCK(&serv->mutex, serv->mutex_count); 800: 801: /* Restart accepting new connections if needed */ 802: if (serv->conn_event == NULL && !serv->stopping) { 803: if (pevent_register(serv->ctx, &serv->conn_event, 804: PEVENT_RECURRING, &serv->mutex, http_server_accept, 805: serv, PEVENT_READ, serv->sock) == -1) { 806: (*serv->logger)(LOG_ERR, "%s: %s", 807: "pevent_register", strerror(errno)); 808: } 809: } 810: 811: /* Remove this connection from the list of connections */ 812: LIST_REMOVE(conn, next); 813: serv->num_conn--; 814: 815: /* Unlock server */ 816: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 817: 818: /* Free connection */ 819: _http_connection_free(&conn); 820: } 821: 822: /* 823: * Dispatch a request 824: */ 825: static void 826: http_server_dispatch(struct http_request *req, struct http_response *resp) 827: { 828: struct http_connection *conn = req->msg->conn; 829: struct http_server *const serv = conn->owner; 830: const char *url = http_request_get_path(req); 831: struct http_virthost vhost_key; 832: char buf[MAXHOSTNAMELEN]; 833: const char *hval; 834: int order; 835: int done; 836: 837: /* Special handling for proxy requests */ 838: if (conn->proxy) { 839: http_proxy_t *proxy_handler; 840: void *proxy_arg; 841: 842: /* Get proxy handler from server */ 843: MUTEX_LOCK(&serv->mutex, serv->mutex_count); 844: proxy_handler = serv->proxy_handler; 845: proxy_arg = serv->proxy_arg; 846: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 847: 848: /* Handle request */ 849: if (proxy_handler == NULL) { 850: http_response_send_error(resp, 851: (strcmp(http_request_get_method(req), 852: HTTP_METHOD_CONNECT) == 0) ? 853: HTTP_STATUS_METHOD_NOT_ALLOWED : 854: HTTP_STATUS_NOT_FOUND, NULL); 855: return; 856: } 857: (*proxy_handler)(proxy_arg, req, resp); 858: return; 859: } 860: 861: /* Extract the desired virtual host from the request */ 862: if ((hval = http_request_get_header(req, HTTP_HEADER_HOST)) != NULL) { 863: char *s; 864: 865: strlcpy(buf, hval, sizeof(buf)); 866: if ((s = strchr(buf, ':')) != NULL) /* trim port */ 867: *s = '\0'; 868: } else 869: *buf = '\0'; /* fall back to default vhost */ 870: vhost_key.host = buf; 871: 872: /* Lock server */ 873: MUTEX_LOCK(&serv->mutex, serv->mutex_count); 874: 875: /* Choose and fix desired virtual host before running any servlets */ 876: if (ghash_get(serv->vhosts, &vhost_key) == NULL) 877: *buf = '\0'; /* fall back to default vhost */ 878: 879: /* Unlock server */ 880: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 881: 882: /* Execute matching vhost servlets, in order, until there is output */ 883: for (done = 0, order = INT_MIN; !done; ) { 884: struct http_servlet_hook *best = NULL; 885: struct http_servlet_hook *hook; 886: struct http_virthost *vhost; 887: int r; 888: 889: /* Lock server */ 890: MUTEX_LOCK(&serv->mutex, serv->mutex_count); 891: 892: /* Find virtual host (do this each time because we unlock) */ 893: if ((vhost = ghash_get(serv->vhosts, &vhost_key)) == NULL) { 894: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 895: break; 896: } 897: 898: /* Find lowest order virtual host servlet that matches */ 899: LIST_FOREACH(hook, &vhost->servlets, next) { 900: 901: /* Skip if we've already tried it */ 902: if (hook->order <= order) 903: continue; 904: 905: /* Compare URL path, choosing best match as we go */ 906: if ((r = regexec(&hook->pat, url, 0, NULL, 0)) == 0) { 907: if (best == NULL || hook->order < best->order) 908: best = hook; 909: continue; 910: } 911: 912: /* If it didn't match, try the next servlet */ 913: if (r == REG_NOMATCH) 914: continue; 915: 916: /* We got some weird error from regexec() */ 917: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 918: regerror(r, &hook->pat, buf, sizeof(buf)); 919: (*serv->logger)(LOG_ERR, "%s: %s", "regexec", buf); 920: http_response_send_error(resp, 921: HTTP_STATUS_INTERNAL_SERVER_ERROR, 922: "regexec: %s", buf); 923: return; 924: } 925: 926: /* If no matching servlet was found, we're done */ 927: if ((hook = best) == NULL) { 928: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 929: break; 930: } 931: 932: /* Update lowest order for next iteration */ 933: order = hook->order; 934: 935: /* Lock servlet to prevent it from going away */ 936: r = pthread_rwlock_rdlock(&hook->rwlock); 937: assert(r == 0); 938: 939: /* Add cleanup hook that unlocks servlet */ 940: pthread_cleanup_push((void (*)(void *))pthread_rwlock_unlock, 941: &hook->rwlock); 942: 943: /* Unlock server */ 944: MUTEX_UNLOCK(&serv->mutex, serv->mutex_count); 945: 946: /* Execute servlet */ 947: done = (*hook->servlet->run)(hook->servlet, req, resp); 948: 949: /* Unlock servlet */ 950: pthread_cleanup_pop(1); 951: 952: /* If servlet returned an error, bail out */ 953: if (done == -1) { 954: http_response_send_errno_error(resp); 955: break; 956: } 957: } 958: 959: /* No matching servlet found? */ 960: if (!done) 961: http_response_send_error(resp, HTTP_STATUS_NOT_FOUND, NULL); 962: } 963: 964: /********************************************************************* 965: MISC ROUTINES 966: *********************************************************************/ 967: 968: /* 969: * SSL callback to get the password for encrypted private key files. 970: */ 971: static int 972: http_server_ssl_pem_password_cb(char *buf, int size, int rwflag, void *udata) 973: { 974: struct http_server *const serv = udata; 975: 976: if (serv->pkey_pw == NULL) { 977: (*serv->logger)(LOG_ERR, 978: "SSL private key is encrypted but no key was supplied"); 979: return (-1); 980: } 981: strlcpy(buf, serv->pkey_pw, size); 982: return (strlen(buf)); 983: } 984: 985: /* 986: * SSL callback for logging. 987: */ 988: static void 989: http_server_ssl_logger(void *arg, int sev, const char *fmt, ...) 990: { 991: struct http_server *const serv = arg; 992: va_list args; 993: char *s; 994: 995: /* Prepend "startup" message to error message */ 996: va_start(args, fmt); 997: VASPRINTF(TYPED_MEM_TEMP, &s, fmt, args); 998: va_end(args); 999: if (s == NULL) 1000: return; 1001: (*serv->logger)(sev, "%s: %s", "startup error", s); 1002: FREE(TYPED_MEM_TEMP, s); 1003: } 1004: 1005: /* 1006: * Virtual host hashing routines 1007: */ 1008: static int 1009: http_server_virthost_equal(struct ghash *g, 1010: const void *item1, const void *item2) 1011: { 1012: const struct http_virthost *const vhost1 = item1; 1013: const struct http_virthost *const vhost2 = item2; 1014: 1015: return (strcasecmp(vhost1->host, vhost2->host) == 0); 1016: } 1017: 1018: u_int32_t 1019: http_server_virthost_hash(struct ghash *g, const void *item) 1020: { 1021: const struct http_virthost *const vhost = item; 1022: u_int32_t hash; 1023: const char *s; 1024: 1025: for (hash = 0, s = vhost->host; *s != '\0'; s++) 1026: hash = (hash * 31) + (u_char)tolower(*s); 1027: return (hash); 1028: } 1029: 1030: