Annotation of embedaddon/mpd/src/contrib/libpdel/http/http_server.c, revision 1.1.1.2
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 */
1.1.1.2 ! misho 200: if ((serv->ssl = SSL_CTX_new(SSLv23_server_method())) == NULL) {
1.1 misho 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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>