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