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