Annotation of embedaddon/mpd/src/contrib/libpdel/http/http_server.c, revision 1.1.1.3
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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>