Fix handling of files with question mark in the name.
[darkhttpd] / darkhttpd.c
1 /* darkhttpd - a simple, single-threaded, static content webserver.
2 * https://unix4lyfe.org/darkhttpd/
3 * Copyright (c) 2003-2018 Emil Mikulic <emikulic@gmail.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 static const char
21 pkgname[] = "darkhttpd/1.12.from.git",
22 copyright[] = "copyright (c) 2003-2018 Emil Mikulic";
23
24 /* Possible build options: -DDEBUG -DNO_IPV6 */
25
26 #ifndef NO_IPV6
27 # define HAVE_INET6
28 #endif
29
30 #ifndef DEBUG
31 # define NDEBUG
32 static const int debug = 0;
33 #else
34 static const int debug = 1;
35 #endif
36
37 #ifdef __linux
38 # define _GNU_SOURCE /* for strsignal() and vasprintf() */
39 # define _FILE_OFFSET_BITS 64 /* stat() files bigger than 2GB */
40 # include <sys/sendfile.h>
41 #endif
42
43 #ifdef __sun__
44 # include <sys/sendfile.h>
45 #endif
46
47 #include <sys/time.h>
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <sys/stat.h>
51 #include <sys/resource.h>
52 #include <sys/wait.h>
53 #include <sys/param.h>
54 #include <netinet/in.h>
55 #include <netinet/tcp.h>
56 #include <arpa/inet.h>
57 #include <assert.h>
58 #include <ctype.h>
59 #include <dirent.h>
60 #include <errno.h>
61 #include <fcntl.h>
62 #include <grp.h>
63 #include <limits.h>
64 #include <pwd.h>
65 #include <signal.h>
66 #include <stdarg.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <time.h>
71 #include <unistd.h>
72
73 #if defined(__has_feature)
74 # if __has_feature(memory_sanitizer)
75 # include <sanitizer/msan_interface.h>
76 # endif
77 #endif
78
79 #ifdef __sun__
80 # ifndef INADDR_NONE
81 # define INADDR_NONE -1
82 # endif
83 #endif
84
85 #ifndef MAXNAMLEN
86 # ifdef NAME_MAX
87 # define MAXNAMLEN NAME_MAX
88 # else
89 # define MAXNAMLEN 255
90 # endif
91 #endif
92
93 #if defined(O_EXCL) && !defined(O_EXLOCK)
94 # define O_EXLOCK O_EXCL
95 #endif
96
97 #ifndef __printflike
98 # ifdef __GNUC__
99 /* [->] borrowed from FreeBSD's src/sys/sys/cdefs.h,v 1.102.2.2.2.1 */
100 # define __printflike(fmtarg, firstvararg) \
101 __attribute__((__format__(__printf__, fmtarg, firstvararg)))
102 /* [<-] */
103 # else
104 # define __printflike(fmtarg, firstvararg)
105 # endif
106 #endif
107
108 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
109 # define unused __attribute__((__unused__))
110 #else
111 # define unused
112 #endif
113
114 /* [->] borrowed from FreeBSD's src/sys/sys/systm.h,v 1.276.2.7.4.1 */
115 #ifndef CTASSERT /* Allow lint to override */
116 # define CTASSERT(x) _CTASSERT(x, __LINE__)
117 # define _CTASSERT(x, y) __CTASSERT(x, y)
118 # define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1]
119 #endif
120 /* [<-] */
121
122 CTASSERT(sizeof(unsigned long long) >= sizeof(off_t));
123 #define llu(x) ((unsigned long long)(x))
124
125 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux)
126 # include <err.h>
127 #else
128 /* err - prints "error: format: strerror(errno)" to stderr and exit()s with
129 * the given code.
130 */
131 static void err(const int code, const char *format, ...) __printflike(2, 3);
132 static void err(const int code, const char *format, ...) {
133 va_list va;
134
135 va_start(va, format);
136 fprintf(stderr, "error: ");
137 vfprintf(stderr, format, va);
138 fprintf(stderr, ": %s\n", strerror(errno));
139 va_end(va);
140 exit(code);
141 }
142
143 /* errx - err() without the strerror */
144 static void errx(const int code, const char *format, ...) __printflike(2, 3);
145 static void errx(const int code, const char *format, ...) {
146 va_list va;
147
148 va_start(va, format);
149 fprintf(stderr, "error: ");
150 vfprintf(stderr, format, va);
151 fprintf(stderr, "\n");
152 va_end(va);
153 exit(code);
154 }
155
156 /* warn - err() without the exit */
157 static void warn(const char *format, ...) __printflike(1, 2);
158 static void warn(const char *format, ...) {
159 va_list va;
160
161 va_start(va, format);
162 fprintf(stderr, "warning: ");
163 vfprintf(stderr, format, va);
164 fprintf(stderr, ": %s\n", strerror(errno));
165 va_end(va);
166 }
167 #endif
168
169 /* [->] LIST_* macros taken from FreeBSD's src/sys/sys/queue.h,v 1.56
170 * Copyright (c) 1991, 1993
171 * The Regents of the University of California. All rights reserved.
172 *
173 * Under a BSD license.
174 */
175 #define LIST_HEAD(name, type) \
176 struct name { \
177 struct type *lh_first; /* first element */ \
178 }
179
180 #define LIST_HEAD_INITIALIZER(head) \
181 { NULL }
182
183 #define LIST_ENTRY(type) \
184 struct { \
185 struct type *le_next; /* next element */ \
186 struct type **le_prev; /* address of previous next element */ \
187 }
188
189 #define LIST_FIRST(head) ((head)->lh_first)
190
191 #define LIST_FOREACH_SAFE(var, head, field, tvar) \
192 for ((var) = LIST_FIRST((head)); \
193 (var) && ((tvar) = LIST_NEXT((var), field), 1); \
194 (var) = (tvar))
195
196 #define LIST_INSERT_HEAD(head, elm, field) do { \
197 if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
198 LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
199 LIST_FIRST((head)) = (elm); \
200 (elm)->field.le_prev = &LIST_FIRST((head)); \
201 } while (0)
202
203 #define LIST_NEXT(elm, field) ((elm)->field.le_next)
204
205 #define LIST_REMOVE(elm, field) do { \
206 if (LIST_NEXT((elm), field) != NULL) \
207 LIST_NEXT((elm), field)->field.le_prev = \
208 (elm)->field.le_prev; \
209 *(elm)->field.le_prev = LIST_NEXT((elm), field); \
210 } while (0)
211 /* [<-] */
212
213 static LIST_HEAD(conn_list_head, connection) connlist =
214 LIST_HEAD_INITIALIZER(conn_list_head);
215
216 struct connection {
217 LIST_ENTRY(connection) entries;
218
219 int socket;
220 #ifdef HAVE_INET6
221 struct in6_addr client;
222 #else
223 in_addr_t client;
224 #endif
225 time_t last_active;
226 enum {
227 RECV_REQUEST, /* receiving request */
228 SEND_HEADER, /* sending generated header */
229 SEND_REPLY, /* sending reply */
230 DONE /* connection closed, need to remove from queue */
231 } state;
232
233 /* char request[request_length+1] is null-terminated */
234 char *request;
235 size_t request_length;
236
237 /* request fields */
238 char *method, *url, *referer, *user_agent;
239 off_t range_begin, range_end;
240 off_t range_begin_given, range_end_given;
241
242 char *header;
243 size_t header_length, header_sent;
244 int header_dont_free, header_only, http_code, conn_close;
245
246 enum { REPLY_GENERATED, REPLY_FROMFILE } reply_type;
247 char *reply;
248 int reply_dont_free;
249 int reply_fd;
250 off_t reply_start, reply_length, reply_sent,
251 total_sent; /* header + body = total, for logging */
252 };
253
254 struct forward_mapping {
255 const char *host, *target_url; /* These point at argv. */
256 };
257
258 static struct forward_mapping *forward_map = NULL;
259 static size_t forward_map_size = 0;
260 static const char *forward_all_url = NULL;
261
262 struct mime_mapping {
263 char *extension, *mimetype;
264 };
265
266 static struct mime_mapping *mime_map = NULL;
267 static size_t mime_map_size = 0;
268 static size_t longest_ext = 0;
269
270 /* If a connection is idle for timeout_secs or more, it gets closed and
271 * removed from the connlist.
272 */
273 static int timeout_secs = 30;
274 static char *keep_alive_field = NULL;
275
276 /* Time is cached in the event loop to avoid making an excessive number of
277 * gettimeofday() calls.
278 */
279 static time_t now;
280
281 /* To prevent a malformed request from eating up too much memory, die once the
282 * request exceeds this many bytes:
283 */
284 #define MAX_REQUEST_LENGTH 4000
285
286 /* Defaults can be overridden on the command-line */
287 static const char *bindaddr;
288 static uint16_t bindport = 8080; /* or 80 if running as root */
289 static int max_connections = -1; /* kern.ipc.somaxconn */
290 static const char *index_name = "index.html";
291 static int no_listing = 0;
292
293 static int sockin = -1; /* socket to accept connections from */
294 #ifdef HAVE_INET6
295 static int inet6 = 0; /* whether the socket uses inet6 */
296 #endif
297 static char *wwwroot = NULL; /* a path name */
298 static char *logfile_name = NULL; /* NULL = no logging */
299 static FILE *logfile = NULL;
300 static char *pidfile_name = NULL; /* NULL = no pidfile */
301 static int want_chroot = 0, want_daemon = 0, want_accf = 0,
302 want_keepalive = 1, want_server_id = 1;
303 static char *server_hdr = NULL;
304 static uint64_t num_requests = 0, total_in = 0, total_out = 0;
305 static int accepting = 1; /* set to 0 to stop accept()ing */
306
307 static volatile int running = 1; /* signal handler sets this to false */
308
309 #define INVALID_UID ((uid_t) -1)
310 #define INVALID_GID ((gid_t) -1)
311
312 static uid_t drop_uid = INVALID_UID;
313 static gid_t drop_gid = INVALID_GID;
314
315 /* Default mimetype mappings - make sure this array is NULL terminated. */
316 static const char *default_extension_map[] = {
317 "application/ogg" " ogg",
318 "application/pdf" " pdf",
319 "application/wasm" " wasm",
320 "application/xml" " xsl xml",
321 "application/xml-dtd" " dtd",
322 "application/xslt+xml" " xslt",
323 "application/zip" " zip",
324 "audio/mpeg" " mp2 mp3 mpga",
325 "image/gif" " gif",
326 "image/jpeg" " jpeg jpe jpg",
327 "image/png" " png",
328 "text/css" " css",
329 "text/html" " html htm",
330 "text/javascript" " js",
331 "text/plain" " txt asc",
332 "video/mpeg" " mpeg mpe mpg",
333 "video/quicktime" " qt mov",
334 "video/x-msvideo" " avi",
335 NULL
336 };
337
338 static const char octet_stream[] = "application/octet-stream";
339 static const char *default_mimetype = octet_stream;
340
341 /* Prototypes. */
342 static void poll_recv_request(struct connection *conn);
343 static void poll_send_header(struct connection *conn);
344 static void poll_send_reply(struct connection *conn);
345
346 /* close() that dies on error. */
347 static void xclose(const int fd) {
348 if (close(fd) == -1)
349 err(1, "close()");
350 }
351
352 /* malloc that dies if it can't allocate. */
353 static void *xmalloc(const size_t size) {
354 void *ptr = malloc(size);
355 if (ptr == NULL)
356 errx(1, "can't allocate %zu bytes", size);
357 return ptr;
358 }
359
360 /* realloc() that dies if it can't reallocate. */
361 static void *xrealloc(void *original, const size_t size) {
362 void *ptr = realloc(original, size);
363 if (ptr == NULL)
364 errx(1, "can't reallocate %zu bytes", size);
365 return ptr;
366 }
367
368 /* strdup() that dies if it can't allocate.
369 * Implement this ourselves since regular strdup() isn't C89.
370 */
371 static char *xstrdup(const char *src) {
372 size_t len = strlen(src) + 1;
373 char *dest = xmalloc(len);
374 memcpy(dest, src, len);
375 return dest;
376 }
377
378 #ifdef __sun /* unimpressed by Solaris */
379 static int vasprintf(char **strp, const char *fmt, va_list ap) {
380 char tmp;
381 int result = vsnprintf(&tmp, 1, fmt, ap);
382 *strp = xmalloc(result+1);
383 result = vsnprintf(*strp, result+1, fmt, ap);
384 return result;
385 }
386 #endif
387
388 /* vasprintf() that dies if it fails. */
389 static unsigned int xvasprintf(char **ret, const char *format, va_list ap)
390 __printflike(2,0);
391 static unsigned int xvasprintf(char **ret, const char *format, va_list ap) {
392 int len = vasprintf(ret, format, ap);
393 if (ret == NULL || len == -1)
394 errx(1, "out of memory in vasprintf()");
395 return (unsigned int)len;
396 }
397
398 /* asprintf() that dies if it fails. */
399 static unsigned int xasprintf(char **ret, const char *format, ...)
400 __printflike(2,3);
401 static unsigned int xasprintf(char **ret, const char *format, ...) {
402 va_list va;
403 unsigned int len;
404
405 va_start(va, format);
406 len = xvasprintf(ret, format, va);
407 va_end(va);
408 return len;
409 }
410
411 /* Append buffer code. A somewhat efficient string buffer with pool-based
412 * reallocation.
413 */
414 #ifndef APBUF_INIT
415 # define APBUF_INIT 4096
416 #endif
417 #define APBUF_GROW APBUF_INIT
418 struct apbuf {
419 size_t length, pool;
420 char *str;
421 };
422
423 static struct apbuf *make_apbuf(void) {
424 struct apbuf *buf = xmalloc(sizeof(struct apbuf));
425 buf->length = 0;
426 buf->pool = APBUF_INIT;
427 buf->str = xmalloc(buf->pool);
428 return buf;
429 }
430
431 /* Append s (of length len) to buf. */
432 static void appendl(struct apbuf *buf, const char *s, const size_t len) {
433 size_t need = buf->length + len;
434 if (buf->pool < need) {
435 /* pool has dried up */
436 while (buf->pool < need)
437 buf->pool += APBUF_GROW;
438 buf->str = xrealloc(buf->str, buf->pool);
439 }
440 memcpy(buf->str + buf->length, s, len);
441 buf->length += len;
442 }
443
444 #ifdef __GNUC__
445 #define append(buf, s) appendl(buf, s, \
446 (__builtin_constant_p(s) ? sizeof(s)-1 : strlen(s)) )
447 #else
448 static void append(struct apbuf *buf, const char *s) {
449 appendl(buf, s, strlen(s));
450 }
451 #endif
452
453 static void appendf(struct apbuf *buf, const char *format, ...)
454 __printflike(2, 3);
455 static void appendf(struct apbuf *buf, const char *format, ...) {
456 char *tmp;
457 va_list va;
458 size_t len;
459
460 va_start(va, format);
461 len = xvasprintf(&tmp, format, va);
462 va_end(va);
463 appendl(buf, tmp, len);
464 free(tmp);
465 }
466
467 /* Make the specified socket non-blocking. */
468 static void nonblock_socket(const int sock) {
469 int flags = fcntl(sock, F_GETFL);
470
471 if (flags == -1)
472 err(1, "fcntl(F_GETFL)");
473 flags |= O_NONBLOCK;
474 if (fcntl(sock, F_SETFL, flags) == -1)
475 err(1, "fcntl() to set O_NONBLOCK");
476 }
477
478 /* Split string out of src with range [left:right-1] */
479 static char *split_string(const char *src,
480 const size_t left, const size_t right) {
481 char *dest;
482 assert(left <= right);
483 assert(left < strlen(src)); /* [left means must be smaller */
484 assert(right <= strlen(src)); /* right) means can be equal or smaller */
485
486 dest = xmalloc(right - left + 1);
487 memcpy(dest, src+left, right-left);
488 dest[right-left] = '\0';
489 return dest;
490 }
491
492 /* Resolve /./ and /../ in a URL, in-place.
493 * Returns NULL if the URL is invalid/unsafe, or the original buffer if
494 * successful.
495 */
496 static char *make_safe_url(char *const url) {
497 char *src = url, *dst;
498 #define ends(c) ((c) == '/' || (c) == '\0')
499
500 /* URLs not starting with a slash are illegal. */
501 if (*src != '/')
502 return NULL;
503
504 /* Fast case: skip until first double-slash or dot-dir. */
505 for ( ; *src; ++src) {
506 if (*src == '/') {
507 if (src[1] == '/')
508 break;
509 else if (src[1] == '.') {
510 if (ends(src[2]))
511 break;
512 else if (src[2] == '.' && ends(src[3]))
513 break;
514 }
515 }
516 }
517
518 /* Copy to dst, while collapsing multi-slashes and handling dot-dirs. */
519 dst = src;
520 while (*src) {
521 if (*src != '/')
522 *dst++ = *src++;
523 else if (*++src == '/')
524 ;
525 else if (*src != '.')
526 *dst++ = '/';
527 else if (ends(src[1]))
528 /* Ignore single-dot component. */
529 ++src;
530 else if (src[1] == '.' && ends(src[2])) {
531 /* Double-dot component. */
532 src += 2;
533 if (dst == url)
534 return NULL; /* Illegal URL */
535 else
536 /* Backtrack to previous slash. */
537 while (*--dst != '/' && dst > url);
538 }
539 else
540 *dst++ = '/';
541 }
542
543 if (dst == url)
544 ++dst;
545 *dst = '\0';
546 return url;
547 #undef ends
548 }
549
550 static void add_forward_mapping(const char * const host,
551 const char * const target_url) {
552 forward_map_size++;
553 forward_map = xrealloc(forward_map,
554 sizeof(*forward_map) * forward_map_size);
555 forward_map[forward_map_size - 1].host = host;
556 forward_map[forward_map_size - 1].target_url = target_url;
557 }
558
559 /* Associates an extension with a mimetype in the mime_map. Entries are in
560 * unsorted order. Makes copies of extension and mimetype strings.
561 */
562 static void add_mime_mapping(const char *extension, const char *mimetype) {
563 size_t i;
564 assert(strlen(extension) > 0);
565 assert(strlen(mimetype) > 0);
566
567 /* update longest_ext */
568 i = strlen(extension);
569 if (i > longest_ext)
570 longest_ext = i;
571
572 /* look through list and replace an existing entry if possible */
573 for (i = 0; i < mime_map_size; i++)
574 if (strcmp(mime_map[i].extension, extension) == 0) {
575 free(mime_map[i].mimetype);
576 mime_map[i].mimetype = xstrdup(mimetype);
577 return;
578 }
579
580 /* no replacement - add a new entry */
581 mime_map_size++;
582 mime_map = xrealloc(mime_map,
583 sizeof(struct mime_mapping) * mime_map_size);
584 mime_map[mime_map_size - 1].extension = xstrdup(extension);
585 mime_map[mime_map_size - 1].mimetype = xstrdup(mimetype);
586 }
587
588 /* qsort() the mime_map. The map must be sorted before it can be
589 * binary-searched.
590 */
591 static int mime_mapping_cmp(const void *a, const void *b) {
592 return strcmp(((const struct mime_mapping *)a)->extension,
593 ((const struct mime_mapping *)b)->extension);
594 }
595
596 static void sort_mime_map(void) {
597 qsort(mime_map, mime_map_size, sizeof(struct mime_mapping),
598 mime_mapping_cmp);
599 }
600
601 /* Parses a mime.types line and adds the parsed data to the mime_map. */
602 static void parse_mimetype_line(const char *line) {
603 unsigned int pad, bound1, lbound, rbound;
604
605 /* parse mimetype */
606 for (pad=0; (line[pad] == ' ') || (line[pad] == '\t'); pad++)
607 ;
608 if (line[pad] == '\0' || /* empty line */
609 line[pad] == '#') /* comment */
610 return;
611
612 for (bound1=pad+1;
613 (line[bound1] != ' ') &&
614 (line[bound1] != '\t');
615 bound1++) {
616 if (line[bound1] == '\0')
617 return; /* malformed line */
618 }
619
620 lbound = bound1;
621 for (;;) {
622 char *mimetype, *extension;
623
624 /* find beginning of extension */
625 for (; (line[lbound] == ' ') || (line[lbound] == '\t'); lbound++)
626 ;
627 if (line[lbound] == '\0')
628 return; /* end of line */
629
630 /* find end of extension */
631 for (rbound = lbound;
632 line[rbound] != ' ' &&
633 line[rbound] != '\t' &&
634 line[rbound] != '\0';
635 rbound++)
636 ;
637
638 mimetype = split_string(line, pad, bound1);
639 extension = split_string(line, lbound, rbound);
640 add_mime_mapping(extension, mimetype);
641 free(mimetype);
642 free(extension);
643
644 if (line[rbound] == '\0')
645 return; /* end of line */
646 else
647 lbound = rbound + 1;
648 }
649 }
650
651 /* Adds contents of default_extension_map[] to mime_map list. The array must
652 * be NULL terminated.
653 */
654 static void parse_default_extension_map(void) {
655 size_t i;
656
657 for (i = 0; default_extension_map[i] != NULL; i++)
658 parse_mimetype_line(default_extension_map[i]);
659 }
660
661 /* read a line from fp, return its contents in a dynamically allocated buffer,
662 * not including the line ending.
663 *
664 * Handles CR, CRLF and LF line endings, as well as NOEOL correctly. If
665 * already at EOF, returns NULL. Will err() or errx() in case of
666 * unexpected file error or running out of memory.
667 */
668 static char *read_line(FILE *fp) {
669 char *buf;
670 long startpos, endpos;
671 size_t linelen, numread;
672 int c;
673
674 startpos = ftell(fp);
675 if (startpos == -1)
676 err(1, "ftell()");
677
678 /* find end of line (or file) */
679 linelen = 0;
680 for (;;) {
681 c = fgetc(fp);
682 if ((c == EOF) || (c == (int)'\n') || (c == (int)'\r'))
683 break;
684 linelen++;
685 }
686
687 /* return NULL on EOF (and empty line) */
688 if (linelen == 0 && c == EOF)
689 return NULL;
690
691 endpos = ftell(fp);
692 if (endpos == -1)
693 err(1, "ftell()");
694
695 /* skip CRLF */
696 if ((c == (int)'\r') && (fgetc(fp) == (int)'\n'))
697 endpos++;
698
699 buf = xmalloc(linelen + 1);
700
701 /* rewind file to where the line stared and load the line */
702 if (fseek(fp, startpos, SEEK_SET) == -1)
703 err(1, "fseek()");
704 numread = fread(buf, 1, linelen, fp);
705 if (numread != linelen)
706 errx(1, "fread() %zu bytes, expecting %zu bytes", numread, linelen);
707
708 /* terminate buffer */
709 buf[linelen] = 0;
710
711 /* advance file pointer over the endline */
712 if (fseek(fp, endpos, SEEK_SET) == -1)
713 err(1, "fseek()");
714
715 return buf;
716 }
717
718 /* ---------------------------------------------------------------------------
719 * Adds contents of specified file to mime_map list.
720 */
721 static void parse_extension_map_file(const char *filename) {
722 char *buf;
723 FILE *fp = fopen(filename, "rb");
724
725 if (fp == NULL)
726 err(1, "fopen(\"%s\")", filename);
727 while ((buf = read_line(fp)) != NULL) {
728 parse_mimetype_line(buf);
729 free(buf);
730 }
731 fclose(fp);
732 }
733
734 /* Uses the mime_map to determine a Content-Type: for a requested URL. This
735 * bsearch()es mime_map, so make sure it's sorted first.
736 */
737 static int mime_mapping_cmp_str(const void *a, const void *b) {
738 return strcmp((const char *)a,
739 ((const struct mime_mapping *)b)->extension);
740 }
741
742 static const char *url_content_type(const char *url) {
743 int period, urllen = (int)strlen(url);
744
745 for (period = urllen - 1;
746 (period > 0) && (url[period] != '.') &&
747 (urllen - period - 1 <= (int)longest_ext);
748 period--)
749 ;
750
751 if ((period >= 0) && (url[period] == '.')) {
752 struct mime_mapping *result =
753 bsearch((url + period + 1), mime_map, mime_map_size,
754 sizeof(struct mime_mapping), mime_mapping_cmp_str);
755 if (result != NULL) {
756 assert(strcmp(url + period + 1, result->extension) == 0);
757 return result->mimetype;
758 }
759 }
760 /* else no period found in the string */
761 return default_mimetype;
762 }
763
764 static const char *get_address_text(const void *addr) {
765 #ifdef HAVE_INET6
766 if (inet6) {
767 static char text_addr[INET6_ADDRSTRLEN];
768 inet_ntop(AF_INET6, (const struct in6_addr *)addr, text_addr,
769 INET6_ADDRSTRLEN);
770 return text_addr;
771 } else
772 #endif
773 {
774 return inet_ntoa(*(const struct in_addr *)addr);
775 }
776 }
777
778 /* Initialize the sockin global. This is the socket that we accept
779 * connections from.
780 */
781 static void init_sockin(void) {
782 struct sockaddr_in addrin;
783 #ifdef HAVE_INET6
784 struct sockaddr_in6 addrin6;
785 #endif
786 socklen_t addrin_len;
787 int sockopt;
788
789 #ifdef HAVE_INET6
790 if (inet6) {
791 memset(&addrin6, 0, sizeof(addrin6));
792 if (inet_pton(AF_INET6, bindaddr ? bindaddr : "::",
793 &addrin6.sin6_addr) == -1) {
794 errx(1, "malformed --addr argument");
795 }
796 sockin = socket(PF_INET6, SOCK_STREAM, 0);
797 } else
798 #endif
799 {
800 memset(&addrin, 0, sizeof(addrin));
801 addrin.sin_addr.s_addr = bindaddr ? inet_addr(bindaddr) : INADDR_ANY;
802 if (addrin.sin_addr.s_addr == (in_addr_t)INADDR_NONE)
803 errx(1, "malformed --addr argument");
804 sockin = socket(PF_INET, SOCK_STREAM, 0);
805 }
806
807 if (sockin == -1)
808 err(1, "socket()");
809
810 /* reuse address */
811 sockopt = 1;
812 if (setsockopt(sockin, SOL_SOCKET, SO_REUSEADDR,
813 &sockopt, sizeof(sockopt)) == -1)
814 err(1, "setsockopt(SO_REUSEADDR)");
815
816 #if 0
817 /* disable Nagle since we buffer everything ourselves */
818 sockopt = 1;
819 if (setsockopt(sockin, IPPROTO_TCP, TCP_NODELAY,
820 &sockopt, sizeof(sockopt)) == -1)
821 err(1, "setsockopt(TCP_NODELAY)");
822 #endif
823
824 #ifdef TORTURE
825 /* torture: cripple the kernel-side send buffer so we can only squeeze out
826 * one byte at a time (this is for debugging)
827 */
828 sockopt = 1;
829 if (setsockopt(sockin, SOL_SOCKET, SO_SNDBUF,
830 &sockopt, sizeof(sockopt)) == -1)
831 err(1, "setsockopt(SO_SNDBUF)");
832 #endif
833
834 /* bind socket */
835 #ifdef HAVE_INET6
836 if (inet6) {
837 addrin6.sin6_family = AF_INET6;
838 addrin6.sin6_port = htons(bindport);
839 if (bind(sockin, (struct sockaddr *)&addrin6,
840 sizeof(struct sockaddr_in6)) == -1)
841 err(1, "bind(port %u)", bindport);
842
843 addrin_len = sizeof(addrin6);
844 if (getsockname(sockin, (struct sockaddr *)&addrin6, &addrin_len) == -1)
845 err(1, "getsockname()");
846 printf("listening on: http://[%s]:%u/\n",
847 get_address_text(&addrin6.sin6_addr), bindport);
848 } else
849 #endif
850 {
851 addrin.sin_family = (u_char)PF_INET;
852 addrin.sin_port = htons(bindport);
853 if (bind(sockin, (struct sockaddr *)&addrin,
854 sizeof(struct sockaddr_in)) == -1)
855 err(1, "bind(port %u)", bindport);
856 addrin_len = sizeof(addrin);
857 if (getsockname(sockin, (struct sockaddr *)&addrin, &addrin_len) == -1)
858 err(1, "getsockname()");
859 printf("listening on: http://%s:%u/\n",
860 get_address_text(&addrin.sin_addr), bindport);
861 }
862
863 /* listen on socket */
864 if (listen(sockin, max_connections) == -1)
865 err(1, "listen()");
866
867 /* enable acceptfilter (this is only available on FreeBSD) */
868 if (want_accf) {
869 #if defined(__FreeBSD__)
870 struct accept_filter_arg filt = {"httpready", ""};
871 if (setsockopt(sockin, SOL_SOCKET, SO_ACCEPTFILTER,
872 &filt, sizeof(filt)) == -1)
873 fprintf(stderr, "cannot enable acceptfilter: %s\n",
874 strerror(errno));
875 else
876 printf("enabled acceptfilter\n");
877 #else
878 printf("this platform doesn't support acceptfilter\n");
879 #endif
880 }
881 }
882
883 static void usage(const char *argv0) {
884 printf("usage:\t%s /path/to/wwwroot [flags]\n\n", argv0);
885 printf("flags:\t--port number (default: %u, or 80 if running as root)\n"
886 "\t\tSpecifies which port to listen on for connections.\n"
887 "\t\tPass 0 to let the system choose any free port for you.\n\n", bindport);
888 printf("\t--addr ip (default: all)\n"
889 "\t\tIf multiple interfaces are present, specifies\n"
890 "\t\twhich one to bind the listening port to.\n\n");
891 printf("\t--maxconn number (default: system maximum)\n"
892 "\t\tSpecifies how many concurrent connections to accept.\n\n");
893 printf("\t--log filename (default: stdout)\n"
894 "\t\tSpecifies which file to append the request log to.\n\n");
895 printf("\t--chroot (default: don't chroot)\n"
896 "\t\tLocks server into wwwroot directory for added security.\n\n");
897 printf("\t--daemon (default: don't daemonize)\n"
898 "\t\tDetach from the controlling terminal and run in the background.\n\n");
899 printf("\t--index filename (default: %s)\n"
900 "\t\tDefault file to serve when a directory is requested.\n\n",
901 index_name);
902 printf("\t--no-listing\n"
903 "\t\tDo not serve listing if directory is requested.\n\n");
904 printf("\t--mimetypes filename (optional)\n"
905 "\t\tParses specified file for extension-MIME associations.\n\n");
906 printf("\t--default-mimetype string (optional, default: %s)\n"
907 "\t\tFiles with unknown extensions are served as this mimetype.\n\n",
908 octet_stream);
909 printf("\t--uid uid/uname, --gid gid/gname (default: don't privdrop)\n"
910 "\t\tDrops privileges to given uid:gid after initialization.\n\n");
911 printf("\t--pidfile filename (default: no pidfile)\n"
912 "\t\tWrite PID to the specified file. Note that if you are\n"
913 "\t\tusing --chroot, then the pidfile must be relative to,\n"
914 "\t\tand inside the wwwroot.\n\n");
915 printf("\t--no-keepalive\n"
916 "\t\tDisables HTTP Keep-Alive functionality.\n\n");
917 #ifdef __FreeBSD__
918 printf("\t--accf (default: don't use acceptfilter)\n"
919 "\t\tUse acceptfilter. Needs the accf_http module loaded.\n\n");
920 #endif
921 printf("\t--forward host url (default: don't forward)\n"
922 "\t\tWeb forward (301 redirect).\n"
923 "\t\tRequests to the host are redirected to the corresponding url.\n"
924 "\t\tThe option may be specified multiple times, in which case\n"
925 "\t\tthe host is matched in order of appearance.\n\n");
926 printf("\t--forward-all url (default: don't forward)\n"
927 "\t\tWeb forward (301 redirect).\n"
928 "\t\tAll requests are redirected to the corresponding url.\n\n");
929 printf("\t--no-server-id\n"
930 "\t\tDon't identify the server type in headers\n"
931 "\t\tor directory listings.\n\n");
932 printf("\t--timeout secs (default: %d)\n"
933 "\t\tIf a connection is idle for more than this many seconds,\n"
934 "\t\tit will be closed. Set to zero to disable timeouts.\n\n",
935 timeout_secs);
936 #ifdef HAVE_INET6
937 printf("\t--ipv6\n"
938 "\t\tListen on IPv6 address.\n\n");
939 #else
940 printf("\t(This binary was built without IPv6 support: -DNO_IPV6)\n\n");
941 #endif
942 }
943
944 /* Returns 1 if string is a number, 0 otherwise. Set num to NULL if
945 * disinterested in value.
946 */
947 static int str_to_num(const char *str, long long *num) {
948 char *endptr;
949 long long n;
950
951 errno = 0;
952 n = strtoll(str, &endptr, 10);
953 if (*endptr != '\0')
954 return 0;
955 if (n == LLONG_MIN && errno == ERANGE)
956 return 0;
957 if (n == LLONG_MAX && errno == ERANGE)
958 return 0;
959 if (num != NULL)
960 *num = n;
961 return 1;
962 }
963
964 /* Returns a valid number or dies. */
965 static long long xstr_to_num(const char *str) {
966 long long ret;
967
968 if (!str_to_num(str, &ret)) {
969 errx(1, "number \"%s\" is invalid", str);
970 }
971 return ret;
972 }
973
974 static void parse_commandline(const int argc, char *argv[]) {
975 int i;
976 size_t len;
977
978 if ((argc < 2) || (argc == 2 && strcmp(argv[1], "--help") == 0)) {
979 usage(argv[0]); /* no wwwroot given */
980 exit(EXIT_SUCCESS);
981 }
982
983 if (getuid() == 0)
984 bindport = 80;
985
986 wwwroot = xstrdup(argv[1]);
987 /* Strip ending slash. */
988 len = strlen(wwwroot);
989 if (len > 0)
990 if (wwwroot[len - 1] == '/')
991 wwwroot[len - 1] = '\0';
992
993 /* walk through the remainder of the arguments (if any) */
994 for (i = 2; i < argc; i++) {
995 if (strcmp(argv[i], "--port") == 0) {
996 if (++i >= argc)
997 errx(1, "missing number after --port");
998 bindport = (uint16_t)xstr_to_num(argv[i]);
999 }
1000 else if (strcmp(argv[i], "--addr") == 0) {
1001 if (++i >= argc)
1002 errx(1, "missing ip after --addr");
1003 bindaddr = argv[i];
1004 }
1005 else if (strcmp(argv[i], "--maxconn") == 0) {
1006 if (++i >= argc)
1007 errx(1, "missing number after --maxconn");
1008 max_connections = (int)xstr_to_num(argv[i]);
1009 }
1010 else if (strcmp(argv[i], "--log") == 0) {
1011 if (++i >= argc)
1012 errx(1, "missing filename after --log");
1013 logfile_name = argv[i];
1014 }
1015 else if (strcmp(argv[i], "--chroot") == 0) {
1016 want_chroot = 1;
1017 }
1018 else if (strcmp(argv[i], "--daemon") == 0) {
1019 want_daemon = 1;
1020 }
1021 else if (strcmp(argv[i], "--index") == 0) {
1022 if (++i >= argc)
1023 errx(1, "missing filename after --index");
1024 index_name = argv[i];
1025 }
1026 else if (strcmp(argv[i], "--no-listing") == 0) {
1027 no_listing = 1;
1028 }
1029 else if (strcmp(argv[i], "--mimetypes") == 0) {
1030 if (++i >= argc)
1031 errx(1, "missing filename after --mimetypes");
1032 parse_extension_map_file(argv[i]);
1033 }
1034 else if (strcmp(argv[i], "--default-mimetype") == 0) {
1035 if (++i >= argc)
1036 errx(1, "missing string after --default-mimetype");
1037 default_mimetype = argv[i];
1038 }
1039 else if (strcmp(argv[i], "--uid") == 0) {
1040 struct passwd *p;
1041 if (++i >= argc)
1042 errx(1, "missing uid after --uid");
1043 p = getpwnam(argv[i]);
1044 if (!p) {
1045 p = getpwuid((uid_t)xstr_to_num(argv[i]));
1046 }
1047 if (!p)
1048 errx(1, "no such uid: `%s'", argv[i]);
1049 drop_uid = p->pw_uid;
1050 }
1051 else if (strcmp(argv[i], "--gid") == 0) {
1052 struct group *g;
1053 if (++i >= argc)
1054 errx(1, "missing gid after --gid");
1055 g = getgrnam(argv[i]);
1056 if (!g) {
1057 g = getgrgid((gid_t)xstr_to_num(argv[i]));
1058 }
1059 if (!g) {
1060 errx(1, "no such gid: `%s'", argv[i]);
1061 }
1062 drop_gid = g->gr_gid;
1063 }
1064 else if (strcmp(argv[i], "--pidfile") == 0) {
1065 if (++i >= argc)
1066 errx(1, "missing filename after --pidfile");
1067 pidfile_name = argv[i];
1068 }
1069 else if (strcmp(argv[i], "--no-keepalive") == 0) {
1070 want_keepalive = 0;
1071 }
1072 else if (strcmp(argv[i], "--accf") == 0) {
1073 want_accf = 1;
1074 }
1075 else if (strcmp(argv[i], "--forward") == 0) {
1076 const char *host, *url;
1077 if (++i >= argc)
1078 errx(1, "missing host after --forward");
1079 host = argv[i];
1080 if (++i >= argc)
1081 errx(1, "missing url after --forward");
1082 url = argv[i];
1083 add_forward_mapping(host, url);
1084 }
1085 else if (strcmp(argv[i], "--forward-all") == 0) {
1086 if (++i >= argc)
1087 errx(1, "missing url after --forward-all");
1088 forward_all_url = argv[i];
1089 }
1090 else if (strcmp(argv[i], "--no-server-id") == 0) {
1091 want_server_id = 0;
1092 }
1093 else if (strcmp(argv[i], "--timeout") == 0) {
1094 if (++i >= argc)
1095 errx(1, "missing number after --timeout");
1096 timeout_secs = (int)xstr_to_num(argv[i]);
1097 }
1098 #ifdef HAVE_INET6
1099 else if (strcmp(argv[i], "--ipv6") == 0) {
1100 inet6 = 1;
1101 }
1102 #endif
1103 else
1104 errx(1, "unknown argument `%s'", argv[i]);
1105 }
1106 }
1107
1108 /* Allocate and initialize an empty connection. */
1109 static struct connection *new_connection(void) {
1110 struct connection *conn = xmalloc(sizeof(struct connection));
1111
1112 conn->socket = -1;
1113 memset(&conn->client, 0, sizeof(conn->client));
1114 conn->last_active = now;
1115 conn->request = NULL;
1116 conn->request_length = 0;
1117 conn->method = NULL;
1118 conn->url = NULL;
1119 conn->referer = NULL;
1120 conn->user_agent = NULL;
1121 conn->range_begin = 0;
1122 conn->range_end = 0;
1123 conn->range_begin_given = 0;
1124 conn->range_end_given = 0;
1125 conn->header = NULL;
1126 conn->header_length = 0;
1127 conn->header_sent = 0;
1128 conn->header_dont_free = 0;
1129 conn->header_only = 0;
1130 conn->http_code = 0;
1131 conn->conn_close = 1;
1132 conn->reply = NULL;
1133 conn->reply_dont_free = 0;
1134 conn->reply_fd = -1;
1135 conn->reply_start = 0;
1136 conn->reply_length = 0;
1137 conn->reply_sent = 0;
1138 conn->total_sent = 0;
1139
1140 /* Make it harmless so it gets garbage-collected if it should, for some
1141 * reason, fail to be correctly filled out.
1142 */
1143 conn->state = DONE;
1144
1145 return conn;
1146 }
1147
1148 /* Accept a connection from sockin and add it to the connection queue. */
1149 static void accept_connection(void) {
1150 struct sockaddr_in addrin;
1151 #ifdef HAVE_INET6
1152 struct sockaddr_in6 addrin6;
1153 #endif
1154 socklen_t sin_size;
1155 struct connection *conn;
1156 int fd;
1157
1158 #ifdef HAVE_INET6
1159 if (inet6) {
1160 sin_size = sizeof(addrin6);
1161 memset(&addrin6, 0, sin_size);
1162 fd = accept(sockin, (struct sockaddr *)&addrin6, &sin_size);
1163 } else
1164 #endif
1165 {
1166 sin_size = sizeof(addrin);
1167 memset(&addrin, 0, sin_size);
1168 fd = accept(sockin, (struct sockaddr *)&addrin, &sin_size);
1169 }
1170
1171 if (fd == -1) {
1172 /* Failed to accept, but try to keep serving existing connections. */
1173 if (errno == EMFILE || errno == ENFILE) accepting = 0;
1174 warn("accept()");
1175 return;
1176 }
1177
1178 /* Allocate and initialize struct connection. */
1179 conn = new_connection();
1180 conn->socket = fd;
1181 nonblock_socket(conn->socket);
1182 conn->state = RECV_REQUEST;
1183
1184 #ifdef HAVE_INET6
1185 if (inet6) {
1186 conn->client = addrin6.sin6_addr;
1187 } else
1188 #endif
1189 {
1190 *(in_addr_t *)&conn->client = addrin.sin_addr.s_addr;
1191 }
1192 LIST_INSERT_HEAD(&connlist, conn, entries);
1193
1194 if (debug)
1195 printf("accepted connection from %s:%u (fd %d)\n",
1196 inet_ntoa(addrin.sin_addr),
1197 ntohs(addrin.sin_port),
1198 conn->socket);
1199
1200 /* Try to read straight away rather than going through another iteration
1201 * of the select() loop.
1202 */
1203 poll_recv_request(conn);
1204 }
1205
1206 /* Should this character be logencoded?
1207 */
1208 static int needs_logencoding(const unsigned char c) {
1209 return ((c <= 0x1F) || (c >= 0x7F) || (c == '"'));
1210 }
1211
1212 /* Encode string for logging.
1213 */
1214 static void logencode(const char *src, char *dest) {
1215 static const char hex[] = "0123456789ABCDEF";
1216 int i, j;
1217
1218 for (i = j = 0; src[i] != '\0'; i++) {
1219 if (needs_logencoding((unsigned char)src[i])) {
1220 dest[j++] = '%';
1221 dest[j++] = hex[(src[i] >> 4) & 0xF];
1222 dest[j++] = hex[ src[i] & 0xF];
1223 }
1224 else
1225 dest[j++] = src[i];
1226 }
1227 dest[j] = '\0';
1228 }
1229
1230 /* Add a connection's details to the logfile. */
1231 static void log_connection(const struct connection *conn) {
1232 char *safe_method, *safe_url, *safe_referer, *safe_user_agent;
1233
1234 if (logfile == NULL)
1235 return;
1236 if (conn->http_code == 0)
1237 return; /* invalid - died in request */
1238 if (conn->method == NULL)
1239 return; /* invalid - didn't parse - maybe too long */
1240
1241 #define make_safe(x) do { \
1242 if (conn->x) { \
1243 safe_##x = xmalloc(strlen(conn->x)*3 + 1); \
1244 logencode(conn->x, safe_##x); \
1245 } else { \
1246 safe_##x = NULL; \
1247 } \
1248 } while(0)
1249
1250 make_safe(method);
1251 make_safe(url);
1252 make_safe(referer);
1253 make_safe(user_agent);
1254
1255 #define use_safe(x) safe_##x ? safe_##x : ""
1256
1257 fprintf(logfile, "%lu %s \"%s %s\" %d %llu \"%s\" \"%s\"\n",
1258 (unsigned long int)now,
1259 get_address_text(&conn->client),
1260 use_safe(method),
1261 use_safe(url),
1262 conn->http_code,
1263 llu(conn->total_sent),
1264 use_safe(referer),
1265 use_safe(user_agent)
1266 );
1267 fflush(logfile);
1268
1269 #define free_safe(x) if (safe_##x) free(safe_##x)
1270
1271 free_safe(method);
1272 free_safe(url);
1273 free_safe(referer);
1274 free_safe(user_agent);
1275
1276 #undef make_safe
1277 #undef use_safe
1278 #undef free_safe
1279 }
1280
1281 /* Log a connection, then cleanly deallocate its internals. */
1282 static void free_connection(struct connection *conn) {
1283 if (debug) printf("free_connection(%d)\n", conn->socket);
1284 log_connection(conn);
1285 if (conn->socket != -1) xclose(conn->socket);
1286 if (conn->request != NULL) free(conn->request);
1287 if (conn->method != NULL) free(conn->method);
1288 if (conn->url != NULL) free(conn->url);
1289 if (conn->referer != NULL) free(conn->referer);
1290 if (conn->user_agent != NULL) free(conn->user_agent);
1291 if (conn->header != NULL && !conn->header_dont_free) free(conn->header);
1292 if (conn->reply != NULL && !conn->reply_dont_free) free(conn->reply);
1293 if (conn->reply_fd != -1) xclose(conn->reply_fd);
1294 /* If we ran out of sockets, try to resume accepting. */
1295 accepting = 1;
1296 }
1297
1298 /* Recycle a finished connection for HTTP/1.1 Keep-Alive. */
1299 static void recycle_connection(struct connection *conn) {
1300 int socket_tmp = conn->socket;
1301 if (debug)
1302 printf("recycle_connection(%d)\n", socket_tmp);
1303 conn->socket = -1; /* so free_connection() doesn't close it */
1304 free_connection(conn);
1305 conn->socket = socket_tmp;
1306
1307 /* don't reset conn->client */
1308 conn->request = NULL;
1309 conn->request_length = 0;
1310 conn->method = NULL;
1311 conn->url = NULL;
1312 conn->referer = NULL;
1313 conn->user_agent = NULL;
1314 conn->range_begin = 0;
1315 conn->range_end = 0;
1316 conn->range_begin_given = 0;
1317 conn->range_end_given = 0;
1318 conn->header = NULL;
1319 conn->header_length = 0;
1320 conn->header_sent = 0;
1321 conn->header_dont_free = 0;
1322 conn->header_only = 0;
1323 conn->http_code = 0;
1324 conn->conn_close = 1;
1325 conn->reply = NULL;
1326 conn->reply_dont_free = 0;
1327 conn->reply_fd = -1;
1328 conn->reply_start = 0;
1329 conn->reply_length = 0;
1330 conn->reply_sent = 0;
1331 conn->total_sent = 0;
1332
1333 conn->state = RECV_REQUEST; /* ready for another */
1334 }
1335
1336 /* Uppercasify all characters in a string of given length. */
1337 static void strntoupper(char *str, const size_t length) {
1338 size_t i;
1339
1340 for (i = 0; i < length; i++)
1341 str[i] = (char)toupper(str[i]);
1342 }
1343
1344 /* If a connection has been idle for more than timeout_secs, it will be
1345 * marked as DONE and killed off in httpd_poll().
1346 */
1347 static void poll_check_timeout(struct connection *conn) {
1348 if (timeout_secs > 0) {
1349 if (now - conn->last_active >= timeout_secs) {
1350 if (debug)
1351 printf("poll_check_timeout(%d) closing connection\n",
1352 conn->socket);
1353 conn->conn_close = 1;
1354 conn->state = DONE;
1355 }
1356 }
1357 }
1358
1359 /* Format [when] as an RFC1123 date, stored in the specified buffer. The same
1360 * buffer is returned for convenience.
1361 */
1362 #define DATE_LEN 30 /* strlen("Fri, 28 Feb 2003 00:02:08 GMT")+1 */
1363 static char *rfc1123_date(char *dest, const time_t when) {
1364 time_t when_copy = when;
1365 if (strftime(dest, DATE_LEN,
1366 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&when_copy)) == 0)
1367 errx(1, "strftime() failed [%s]", dest);
1368 return dest;
1369 }
1370
1371 /* Decode URL by converting %XX (where XX are hexadecimal digits) to the
1372 * character it represents. Don't forget to free the return value.
1373 */
1374 static char *urldecode(const char *url) {
1375 size_t i, pos, len = strlen(url);
1376 char *out = xmalloc(len+1);
1377
1378 for (i = 0, pos = 0; i < len; i++) {
1379 if ((url[i] == '%') && (i+2 < len) &&
1380 isxdigit(url[i+1]) && isxdigit(url[i+2])) {
1381 /* decode %XX */
1382 #define HEX_TO_DIGIT(hex) ( \
1383 ((hex) >= 'A' && (hex) <= 'F') ? ((hex)-'A'+10): \
1384 ((hex) >= 'a' && (hex) <= 'f') ? ((hex)-'a'+10): \
1385 ((hex)-'0') )
1386
1387 out[pos++] = HEX_TO_DIGIT(url[i+1]) * 16 +
1388 HEX_TO_DIGIT(url[i+2]);
1389 i += 2;
1390 #undef HEX_TO_DIGIT
1391 } else {
1392 /* straight copy */
1393 out[pos++] = url[i];
1394 }
1395 }
1396 out[pos] = '\0';
1397 return out;
1398 }
1399
1400 /* Returns Connection or Keep-Alive header, depending on conn_close. */
1401 static const char *keep_alive(const struct connection *conn)
1402 {
1403 return (conn->conn_close ? "Connection: close\r\n" : keep_alive_field);
1404 }
1405
1406 /* "Generated by " + pkgname + " on " + date + "\n"
1407 * 1234567890123 1234 2 ('\n' and '\0')
1408 */
1409 static char _generated_on_buf[13 + sizeof(pkgname) - 1 + 4 + DATE_LEN + 2];
1410 static const char *generated_on(const char date[DATE_LEN]) {
1411 if (!want_server_id)
1412 return "";
1413 snprintf(_generated_on_buf, sizeof(_generated_on_buf),
1414 "Generated by %s on %s\n",
1415 pkgname, date);
1416 return _generated_on_buf;
1417 }
1418
1419 /* A default reply for any (erroneous) occasion. */
1420 static void default_reply(struct connection *conn,
1421 const int errcode, const char *errname, const char *format, ...)
1422 __printflike(4, 5);
1423 static void default_reply(struct connection *conn,
1424 const int errcode, const char *errname, const char *format, ...) {
1425 char *reason, date[DATE_LEN];
1426 va_list va;
1427
1428 va_start(va, format);
1429 xvasprintf(&reason, format, va);
1430 va_end(va);
1431
1432 /* Only really need to calculate the date once. */
1433 rfc1123_date(date, now);
1434
1435 conn->reply_length = xasprintf(&(conn->reply),
1436 "<html><head><title>%d %s</title></head><body>\n"
1437 "<h1>%s</h1>\n" /* errname */
1438 "%s\n" /* reason */
1439 "<hr>\n"
1440 "%s" /* generated on */
1441 "</body></html>\n",
1442 errcode, errname, errname, reason, generated_on(date));
1443 free(reason);
1444
1445 conn->header_length = xasprintf(&(conn->header),
1446 "HTTP/1.1 %d %s\r\n"
1447 "Date: %s\r\n"
1448 "%s" /* server */
1449 "Accept-Ranges: bytes\r\n"
1450 "%s" /* keep-alive */
1451 "Content-Length: %llu\r\n"
1452 "Content-Type: text/html; charset=UTF-8\r\n"
1453 "\r\n",
1454 errcode, errname, date, server_hdr, keep_alive(conn),
1455 llu(conn->reply_length));
1456
1457 conn->reply_type = REPLY_GENERATED;
1458 conn->http_code = errcode;
1459 }
1460
1461 static void redirect(struct connection *conn, const char *format, ...)
1462 __printflike(2, 3);
1463 static void redirect(struct connection *conn, const char *format, ...) {
1464 char *where, date[DATE_LEN];
1465 va_list va;
1466
1467 va_start(va, format);
1468 xvasprintf(&where, format, va);
1469 va_end(va);
1470
1471 /* Only really need to calculate the date once. */
1472 rfc1123_date(date, now);
1473
1474 conn->reply_length = xasprintf(&(conn->reply),
1475 "<html><head><title>301 Moved Permanently</title></head><body>\n"
1476 "<h1>Moved Permanently</h1>\n"
1477 "Moved to: <a href=\"%s\">%s</a>\n" /* where x 2 */
1478 "<hr>\n"
1479 "%s" /* generated on */
1480 "</body></html>\n",
1481 where, where, generated_on(date));
1482
1483 conn->header_length = xasprintf(&(conn->header),
1484 "HTTP/1.1 301 Moved Permanently\r\n"
1485 "Date: %s\r\n"
1486 "%s" /* server */
1487 /* "Accept-Ranges: bytes\r\n" - not relevant here */
1488 "Location: %s\r\n"
1489 "%s" /* keep-alive */
1490 "Content-Length: %llu\r\n"
1491 "Content-Type: text/html; charset=UTF-8\r\n"
1492 "\r\n",
1493 date, server_hdr, where, keep_alive(conn), llu(conn->reply_length));
1494
1495 free(where);
1496 conn->reply_type = REPLY_GENERATED;
1497 conn->http_code = 301;
1498 }
1499
1500 /* Parses a single HTTP request field. Returns string from end of [field] to
1501 * first \r, \n or end of request string. Returns NULL if [field] can't be
1502 * matched.
1503 *
1504 * You need to remember to deallocate the result.
1505 * example: parse_field(conn, "Referer: ");
1506 */
1507 static char *parse_field(const struct connection *conn, const char *field) {
1508 size_t bound1, bound2;
1509 char *pos;
1510
1511 /* find start */
1512 pos = strstr(conn->request, field);
1513 if (pos == NULL)
1514 return NULL;
1515 assert(pos >= conn->request);
1516 bound1 = (size_t)(pos - conn->request) + strlen(field);
1517
1518 /* find end */
1519 for (bound2 = bound1;
1520 ((bound2 < conn->request_length) &&
1521 (conn->request[bound2] != '\r') &&
1522 (conn->request[bound2] != '\n'));
1523 bound2++)
1524 ;
1525
1526 /* copy to buffer */
1527 return split_string(conn->request, bound1, bound2);
1528 }
1529
1530 /* Parse a Range: field into range_begin and range_end. Only handles the
1531 * first range if a list is given. Sets range_{begin,end}_given to 1 if
1532 * either part of the range is given.
1533 */
1534 static void parse_range_field(struct connection *conn) {
1535 char *range;
1536
1537 range = parse_field(conn, "Range: bytes=");
1538 if (range == NULL)
1539 return;
1540
1541 do {
1542 size_t bound1, bound2, len;
1543 len = strlen(range);
1544
1545 /* parse number up to hyphen */
1546 bound1 = 0;
1547 for (bound2=0;
1548 (bound2 < len) && isdigit((int)range[bound2]);
1549 bound2++)
1550 ;
1551
1552 if ((bound2 == len) || (range[bound2] != '-'))
1553 break; /* there must be a hyphen here */
1554
1555 if (bound1 != bound2) {
1556 conn->range_begin_given = 1;
1557 conn->range_begin = (off_t)strtoll(range+bound1, NULL, 10);
1558 }
1559
1560 /* parse number after hyphen */
1561 bound2++;
1562 for (bound1=bound2;
1563 (bound2 < len) && isdigit((int)range[bound2]);
1564 bound2++)
1565 ;
1566
1567 if ((bound2 != len) && (range[bound2] != ','))
1568 break; /* must be end of string or a list to be valid */
1569
1570 if (bound1 != bound2) {
1571 conn->range_end_given = 1;
1572 conn->range_end = (off_t)strtoll(range+bound1, NULL, 10);
1573 }
1574 } while(0);
1575 free(range);
1576 }
1577
1578 /* Parse an HTTP request like "GET / HTTP/1.1" to get the method (GET), the
1579 * url (/), the referer (if given) and the user-agent (if given). Remember to
1580 * deallocate all these buffers. The method will be returned in uppercase.
1581 */
1582 static int parse_request(struct connection *conn) {
1583 size_t bound1, bound2;
1584 char *tmp;
1585 assert(conn->request_length == strlen(conn->request));
1586
1587 /* parse method */
1588 for (bound1 = 0;
1589 (bound1 < conn->request_length) &&
1590 (conn->request[bound1] != ' ');
1591 bound1++)
1592 ;
1593
1594 conn->method = split_string(conn->request, 0, bound1);
1595 strntoupper(conn->method, bound1);
1596
1597 /* parse url */
1598 for (;
1599 (bound1 < conn->request_length) &&
1600 (conn->request[bound1] == ' ');
1601 bound1++)
1602 ;
1603
1604 if (bound1 == conn->request_length)
1605 return 0; /* fail */
1606
1607 for (bound2 = bound1 + 1;
1608 (bound2 < conn->request_length) &&
1609 (conn->request[bound2] != ' ') &&
1610 (conn->request[bound2] != '\r') &&
1611 (conn->request[bound2] != '\n');
1612 bound2++)
1613 ;
1614
1615 conn->url = split_string(conn->request, bound1, bound2);
1616
1617 /* parse protocol to determine conn_close */
1618 if (conn->request[bound2] == ' ') {
1619 char *proto;
1620 for (bound1 = bound2;
1621 (bound1 < conn->request_length) &&
1622 (conn->request[bound1] == ' ');
1623 bound1++)
1624 ;
1625
1626 for (bound2 = bound1 + 1;
1627 (bound2 < conn->request_length) &&
1628 (conn->request[bound2] != ' ') &&
1629 (conn->request[bound2] != '\r');
1630 bound2++)
1631 ;
1632
1633 proto = split_string(conn->request, bound1, bound2);
1634 if (strcasecmp(proto, "HTTP/1.1") == 0)
1635 conn->conn_close = 0;
1636 free(proto);
1637 }
1638
1639 /* parse connection field */
1640 tmp = parse_field(conn, "Connection: ");
1641 if (tmp != NULL) {
1642 if (strcasecmp(tmp, "close") == 0)
1643 conn->conn_close = 1;
1644 else if (strcasecmp(tmp, "keep-alive") == 0)
1645 conn->conn_close = 0;
1646 free(tmp);
1647 }
1648
1649 /* cmdline flag can be used to deny keep-alive */
1650 if (!want_keepalive)
1651 conn->conn_close = 1;
1652
1653 /* parse important fields */
1654 conn->referer = parse_field(conn, "Referer: ");
1655 conn->user_agent = parse_field(conn, "User-Agent: ");
1656 parse_range_field(conn);
1657 return 1;
1658 }
1659
1660 static int file_exists(const char *path) {
1661 struct stat filestat;
1662 if ((stat(path, &filestat) == -1) && (errno == ENOENT))
1663 return 0;
1664 else
1665 return 1;
1666 }
1667
1668 struct dlent {
1669 char *name;
1670 int is_dir;
1671 off_t size;
1672 };
1673
1674 static int dlent_cmp(const void *a, const void *b) {
1675 return strcmp((*((const struct dlent * const *)a))->name,
1676 (*((const struct dlent * const *)b))->name);
1677 }
1678
1679 /* Make sorted list of files in a directory. Returns number of entries, or -1
1680 * if error occurs.
1681 */
1682 static ssize_t make_sorted_dirlist(const char *path, struct dlent ***output) {
1683 DIR *dir;
1684 struct dirent *ent;
1685 size_t entries = 0;
1686 size_t pool = 128;
1687 char *currname;
1688 struct dlent **list = NULL;
1689
1690 dir = opendir(path);
1691 if (dir == NULL)
1692 return -1;
1693
1694 currname = xmalloc(strlen(path) + MAXNAMLEN + 1);
1695 list = xmalloc(sizeof(struct dlent*) * pool);
1696
1697 /* construct list */
1698 while ((ent = readdir(dir)) != NULL) {
1699 struct stat s;
1700
1701 if ((ent->d_name[0] == '.') && (ent->d_name[1] == '\0'))
1702 continue; /* skip "." */
1703 assert(strlen(ent->d_name) <= MAXNAMLEN);
1704 sprintf(currname, "%s%s", path, ent->d_name);
1705 if (stat(currname, &s) == -1)
1706 continue; /* skip un-stat-able files */
1707 if (entries == pool) {
1708 pool *= 2;
1709 list = xrealloc(list, sizeof(struct dlent*) * pool);
1710 }
1711 list[entries] = xmalloc(sizeof(struct dlent));
1712 list[entries]->name = xstrdup(ent->d_name);
1713 list[entries]->is_dir = S_ISDIR(s.st_mode);
1714 list[entries]->size = s.st_size;
1715 entries++;
1716 }
1717 closedir(dir);
1718 free(currname);
1719 qsort(list, entries, sizeof(struct dlent*), dlent_cmp);
1720 *output = list;
1721 return (ssize_t)entries;
1722 }
1723
1724 /* Cleanly deallocate a sorted list of directory files. */
1725 static void cleanup_sorted_dirlist(struct dlent **list, const ssize_t size) {
1726 ssize_t i;
1727
1728 for (i = 0; i < size; i++) {
1729 free(list[i]->name);
1730 free(list[i]);
1731 }
1732 }
1733
1734 /* Is this an unreserved character according to
1735 * https://tools.ietf.org/html/rfc3986#section-2.3
1736 */
1737 static int is_unreserved(const unsigned char c) {
1738 if (c >= 'a' && c <= 'z') return 1;
1739 if (c >= 'A' && c <= 'Z') return 1;
1740 if (c >= '0' && c <= '9') return 1;
1741 switch (c) {
1742 case '-':
1743 case '.':
1744 case '_':
1745 case '~':
1746 return 1;
1747 }
1748 return 0;
1749 }
1750
1751 /* Encode string to be an RFC3986-compliant URL part.
1752 * Contributed by nf.
1753 */
1754 static void urlencode(const char *src, char *dest) {
1755 static const char hex[] = "0123456789ABCDEF";
1756 int i, j;
1757
1758 for (i = j = 0; src[i] != '\0'; i++) {
1759 if (!is_unreserved((unsigned char)src[i])) {
1760 dest[j++] = '%';
1761 dest[j++] = hex[(src[i] >> 4) & 0xF];
1762 dest[j++] = hex[ src[i] & 0xF];
1763 }
1764 else
1765 dest[j++] = src[i];
1766 }
1767 dest[j] = '\0';
1768 }
1769
1770 static void generate_dir_listing(struct connection *conn, const char *path) {
1771 char date[DATE_LEN], *spaces;
1772 struct dlent **list;
1773 ssize_t listsize;
1774 size_t maxlen = 2; /* There has to be ".." */
1775 int i;
1776 struct apbuf *listing;
1777
1778 listsize = make_sorted_dirlist(path, &list);
1779 if (listsize == -1) {
1780 default_reply(conn, 500, "Internal Server Error",
1781 "Couldn't list directory: %s", strerror(errno));
1782 return;
1783 }
1784
1785 for (i=0; i<listsize; i++) {
1786 size_t tmp = strlen(list[i]->name);
1787 if (maxlen < tmp)
1788 maxlen = tmp;
1789 }
1790
1791 listing = make_apbuf();
1792 append(listing, "<html>\n<head>\n <title>");
1793 append(listing, conn->url);
1794 append(listing, "</title>\n</head>\n<body>\n<h1>");
1795 append(listing, conn->url);
1796 append(listing, "</h1>\n<tt><pre>\n");
1797
1798 spaces = xmalloc(maxlen);
1799 memset(spaces, ' ', maxlen);
1800
1801 for (i=0; i<listsize; i++) {
1802 /* If a filename is made up of entirely unsafe chars,
1803 * the url would be three times its original length.
1804 */
1805 char safe_url[MAXNAMLEN*3 + 1];
1806
1807 urlencode(list[i]->name, safe_url);
1808
1809 append(listing, "<a href=\"");
1810 append(listing, safe_url);
1811 append(listing, "\">");
1812 append(listing, list[i]->name);
1813 append(listing, "</a>");
1814
1815 if (list[i]->is_dir)
1816 append(listing, "/\n");
1817 else {
1818 appendl(listing, spaces, maxlen-strlen(list[i]->name));
1819 appendf(listing, "%10llu\n", llu(list[i]->size));
1820 }
1821 }
1822
1823 cleanup_sorted_dirlist(list, listsize);
1824 free(list);
1825 free(spaces);
1826
1827 append(listing,
1828 "</pre></tt>\n"
1829 "<hr>\n");
1830
1831 rfc1123_date(date, now);
1832 append(listing, generated_on(date));
1833 append(listing, "</body>\n</html>\n");
1834
1835 conn->reply = listing->str;
1836 conn->reply_length = (off_t)listing->length;
1837 free(listing); /* don't free inside of listing */
1838
1839 conn->header_length = xasprintf(&(conn->header),
1840 "HTTP/1.1 200 OK\r\n"
1841 "Date: %s\r\n"
1842 "%s" /* server */
1843 "Accept-Ranges: bytes\r\n"
1844 "%s" /* keep-alive */
1845 "Content-Length: %llu\r\n"
1846 "Content-Type: text/html; charset=UTF-8\r\n"
1847 "\r\n",
1848 date, server_hdr, keep_alive(conn), llu(conn->reply_length));
1849
1850 conn->reply_type = REPLY_GENERATED;
1851 conn->http_code = 200;
1852 }
1853
1854 /* Process a GET/HEAD request. */
1855 static void process_get(struct connection *conn) {
1856 char *decoded_url, *end, *target, *if_mod_since;
1857 char date[DATE_LEN], lastmod[DATE_LEN];
1858 const char *mimetype = NULL;
1859 const char *forward_to = NULL;
1860 struct stat filestat;
1861
1862 /* strip out query params */
1863 if (end = strchr(conn->url, '?'))
1864 *end = '\0';
1865
1866 /* work out path of file being requested */
1867 decoded_url = urldecode(conn->url);
1868
1869 /* make sure it's safe */
1870 if (make_safe_url(decoded_url) == NULL) {
1871 default_reply(conn, 400, "Bad Request",
1872 "You requested an invalid URL: %s", conn->url);
1873 free(decoded_url);
1874 return;
1875 }
1876
1877 /* test the host against web forward options */
1878 if (forward_map) {
1879 char *host = parse_field(conn, "Host: ");
1880 if (host) {
1881 size_t i;
1882 if (debug)
1883 printf("host=\"%s\"\n", host);
1884 for (i = 0; i < forward_map_size; i++) {
1885 if (strcasecmp(forward_map[i].host, host) == 0) {
1886 forward_to = forward_map[i].target_url;
1887 break;
1888 }
1889 }
1890 free(host);
1891 }
1892 }
1893 if (!forward_to) {
1894 forward_to = forward_all_url;
1895 }
1896 if (forward_to) {
1897 redirect(conn, "%s%s", forward_to, decoded_url);
1898 free(decoded_url);
1899 return;
1900 }
1901
1902 /* does it end in a slash? serve up url/index_name */
1903 if (decoded_url[strlen(decoded_url)-1] == '/') {
1904 xasprintf(&target, "%s%s%s", wwwroot, decoded_url, index_name);
1905 if (!file_exists(target)) {
1906 free(target);
1907 if (no_listing) {
1908 free(decoded_url);
1909 /* Return 404 instead of 403 to make --no-listing
1910 * indistinguishable from the directory not existing.
1911 * i.e.: Don't leak information.
1912 */
1913 default_reply(conn, 404, "Not Found",
1914 "The URL you requested (%s) was not found.", conn->url);
1915 return;
1916 }
1917 xasprintf(&target, "%s%s", wwwroot, decoded_url);
1918 generate_dir_listing(conn, target);
1919 free(target);
1920 free(decoded_url);
1921 return;
1922 }
1923 mimetype = url_content_type(index_name);
1924 }
1925 else {
1926 /* points to a file */
1927 xasprintf(&target, "%s%s", wwwroot, decoded_url);
1928 mimetype = url_content_type(decoded_url);
1929 }
1930 free(decoded_url);
1931 if (debug)
1932 printf("url=\"%s\", target=\"%s\", content-type=\"%s\"\n",
1933 conn->url, target, mimetype);
1934
1935 /* open file */
1936 conn->reply_fd = open(target, O_RDONLY | O_NONBLOCK);
1937 free(target);
1938
1939 if (conn->reply_fd == -1) {
1940 /* open() failed */
1941 if (errno == EACCES)
1942 default_reply(conn, 403, "Forbidden",
1943 "You don't have permission to access (%s).", conn->url);
1944 else if (errno == ENOENT)
1945 default_reply(conn, 404, "Not Found",
1946 "The URL you requested (%s) was not found.", conn->url);
1947 else
1948 default_reply(conn, 500, "Internal Server Error",
1949 "The URL you requested (%s) cannot be returned: %s.",
1950 conn->url, strerror(errno));
1951
1952 return;
1953 }
1954
1955 /* stat the file */
1956 if (fstat(conn->reply_fd, &filestat) == -1) {
1957 default_reply(conn, 500, "Internal Server Error",
1958 "fstat() failed: %s.", strerror(errno));
1959 return;
1960 }
1961
1962 /* make sure it's a regular file */
1963 if (S_ISDIR(filestat.st_mode)) {
1964 redirect(conn, "%s/", conn->url);
1965 return;
1966 }
1967 else if (!S_ISREG(filestat.st_mode)) {
1968 default_reply(conn, 403, "Forbidden", "Not a regular file.");
1969 return;
1970 }
1971
1972 conn->reply_type = REPLY_FROMFILE;
1973 rfc1123_date(lastmod, filestat.st_mtime);
1974
1975 /* check for If-Modified-Since, may not have to send */
1976 if_mod_since = parse_field(conn, "If-Modified-Since: ");
1977 if ((if_mod_since != NULL) &&
1978 (strcmp(if_mod_since, lastmod) == 0)) {
1979 if (debug)
1980 printf("not modified since %s\n", if_mod_since);
1981 conn->http_code = 304;
1982 conn->header_length = xasprintf(&(conn->header),
1983 "HTTP/1.1 304 Not Modified\r\n"
1984 "Date: %s\r\n"
1985 "%s" /* server */
1986 "Accept-Ranges: bytes\r\n"
1987 "%s" /* keep-alive */
1988 "\r\n",
1989 rfc1123_date(date, now), server_hdr, keep_alive(conn));
1990 conn->reply_length = 0;
1991 conn->reply_type = REPLY_GENERATED;
1992 conn->header_only = 1;
1993
1994 free(if_mod_since);
1995 return;
1996 }
1997 free(if_mod_since);
1998
1999 if (conn->range_begin_given || conn->range_end_given) {
2000 off_t from, to;
2001
2002 if (conn->range_begin_given && conn->range_end_given) {
2003 /* 100-200 */
2004 from = conn->range_begin;
2005 to = conn->range_end;
2006
2007 /* clamp end to filestat.st_size-1 */
2008 if (to > (filestat.st_size - 1))
2009 to = filestat.st_size - 1;
2010 }
2011 else if (conn->range_begin_given && !conn->range_end_given) {
2012 /* 100- :: yields 100 to end */
2013 from = conn->range_begin;
2014 to = filestat.st_size - 1;
2015 }
2016 else if (!conn->range_begin_given && conn->range_end_given) {
2017 /* -200 :: yields last 200 */
2018 to = filestat.st_size - 1;
2019 from = to - conn->range_end + 1;
2020
2021 /* clamp start */
2022 if (from < 0)
2023 from = 0;
2024 }
2025 else
2026 errx(1, "internal error - from/to mismatch");
2027
2028 if (from >= filestat.st_size) {
2029 default_reply(conn, 416, "Requested Range Not Satisfiable",
2030 "You requested a range outside of the file.");
2031 return;
2032 }
2033
2034 if (to < from) {
2035 default_reply(conn, 416, "Requested Range Not Satisfiable",
2036 "You requested a backward range.");
2037 return;
2038 }
2039
2040 conn->reply_start = from;
2041 conn->reply_length = to - from + 1;
2042
2043 conn->header_length = xasprintf(&(conn->header),
2044 "HTTP/1.1 206 Partial Content\r\n"
2045 "Date: %s\r\n"
2046 "%s" /* server */
2047 "Accept-Ranges: bytes\r\n"
2048 "%s" /* keep-alive */
2049 "Content-Length: %llu\r\n"
2050 "Content-Range: bytes %llu-%llu/%llu\r\n"
2051 "Content-Type: %s\r\n"
2052 "Last-Modified: %s\r\n"
2053 "\r\n"
2054 ,
2055 rfc1123_date(date, now), server_hdr, keep_alive(conn),
2056 llu(conn->reply_length), llu(from), llu(to),
2057 llu(filestat.st_size), mimetype, lastmod
2058 );
2059 conn->http_code = 206;
2060 if (debug)
2061 printf("sending %llu-%llu/%llu\n",
2062 llu(from), llu(to), llu(filestat.st_size));
2063 }
2064 else {
2065 /* no range stuff */
2066 conn->reply_length = filestat.st_size;
2067 conn->header_length = xasprintf(&(conn->header),
2068 "HTTP/1.1 200 OK\r\n"
2069 "Date: %s\r\n"
2070 "%s" /* server */
2071 "Accept-Ranges: bytes\r\n"
2072 "%s" /* keep-alive */
2073 "Content-Length: %llu\r\n"
2074 "Content-Type: %s\r\n"
2075 "Last-Modified: %s\r\n"
2076 "\r\n"
2077 ,
2078 rfc1123_date(date, now), server_hdr, keep_alive(conn),
2079 llu(conn->reply_length), mimetype, lastmod
2080 );
2081 conn->http_code = 200;
2082 }
2083 }
2084
2085 /* Process a request: build the header and reply, advance state. */
2086 static void process_request(struct connection *conn) {
2087 num_requests++;
2088 if (!parse_request(conn)) {
2089 default_reply(conn, 400, "Bad Request",
2090 "You sent a request that the server couldn't understand.");
2091 }
2092 else if (strcmp(conn->method, "GET") == 0) {
2093 process_get(conn);
2094 }
2095 else if (strcmp(conn->method, "HEAD") == 0) {
2096 process_get(conn);
2097 conn->header_only = 1;
2098 }
2099 else if ((strcmp(conn->method, "OPTIONS") == 0) ||
2100 (strcmp(conn->method, "POST") == 0) ||
2101 (strcmp(conn->method, "PUT") == 0) ||
2102 (strcmp(conn->method, "DELETE") == 0) ||
2103 (strcmp(conn->method, "TRACE") == 0) ||
2104 (strcmp(conn->method, "CONNECT") == 0)) {
2105 default_reply(conn, 501, "Not Implemented",
2106 "The method you specified (%s) is not implemented.",
2107 conn->method);
2108 }
2109 else {
2110 default_reply(conn, 400, "Bad Request",
2111 "%s is not a valid HTTP/1.1 method.", conn->method);
2112 }
2113
2114 /* advance state */
2115 conn->state = SEND_HEADER;
2116
2117 /* request not needed anymore */
2118 free(conn->request);
2119 conn->request = NULL; /* important: don't free it again later */
2120 }
2121
2122 /* Receiving request. */
2123 static void poll_recv_request(struct connection *conn) {
2124 char buf[1<<15];
2125 ssize_t recvd;
2126
2127 assert(conn->state == RECV_REQUEST);
2128 recvd = recv(conn->socket, buf, sizeof(buf), 0);
2129 if (debug)
2130 printf("poll_recv_request(%d) got %d bytes\n",
2131 conn->socket, (int)recvd);
2132 if (recvd < 1) {
2133 if (recvd == -1) {
2134 if (errno == EAGAIN) {
2135 if (debug) printf("poll_recv_request would have blocked\n");
2136 return;
2137 }
2138 if (debug) printf("recv(%d) error: %s\n",
2139 conn->socket, strerror(errno));
2140 }
2141 conn->conn_close = 1;
2142 conn->state = DONE;
2143 return;
2144 }
2145 conn->last_active = now;
2146
2147 /* append to conn->request */
2148 assert(recvd > 0);
2149 conn->request = xrealloc(
2150 conn->request, conn->request_length + (size_t)recvd + 1);
2151 memcpy(conn->request+conn->request_length, buf, (size_t)recvd);
2152 conn->request_length += (size_t)recvd;
2153 conn->request[conn->request_length] = 0;
2154 total_in += (size_t)recvd;
2155
2156 /* process request if we have all of it */
2157 if ((conn->request_length > 2) &&
2158 (memcmp(conn->request+conn->request_length-2, "\n\n", 2) == 0))
2159 process_request(conn);
2160 else if ((conn->request_length > 4) &&
2161 (memcmp(conn->request+conn->request_length-4, "\r\n\r\n", 4) == 0))
2162 process_request(conn);
2163
2164 /* die if it's too large */
2165 if (conn->request_length > MAX_REQUEST_LENGTH) {
2166 default_reply(conn, 413, "Request Entity Too Large",
2167 "Your request was dropped because it was too long.");
2168 conn->state = SEND_HEADER;
2169 }
2170
2171 /* if we've moved on to the next state, try to send right away, instead of
2172 * going through another iteration of the select() loop.
2173 */
2174 if (conn->state == SEND_HEADER)
2175 poll_send_header(conn);
2176 }
2177
2178 /* Sending header. Assumes conn->header is not NULL. */
2179 static void poll_send_header(struct connection *conn) {
2180 ssize_t sent;
2181
2182 assert(conn->state == SEND_HEADER);
2183 assert(conn->header_length == strlen(conn->header));
2184
2185 sent = send(conn->socket,
2186 conn->header + conn->header_sent,
2187 conn->header_length - conn->header_sent,
2188 0);
2189 conn->last_active = now;
2190 if (debug)
2191 printf("poll_send_header(%d) sent %d bytes\n",
2192 conn->socket, (int)sent);
2193
2194 /* handle any errors (-1) or closure (0) in send() */
2195 if (sent < 1) {
2196 if ((sent == -1) && (errno == EAGAIN)) {
2197 if (debug) printf("poll_send_header would have blocked\n");
2198 return;
2199 }
2200 if (debug && (sent == -1))
2201 printf("send(%d) error: %s\n", conn->socket, strerror(errno));
2202 conn->conn_close = 1;
2203 conn->state = DONE;
2204 return;
2205 }
2206 assert(sent > 0);
2207 conn->header_sent += (size_t)sent;
2208 conn->total_sent += (size_t)sent;
2209 total_out += (size_t)sent;
2210
2211 /* check if we're done sending header */
2212 if (conn->header_sent == conn->header_length) {
2213 if (conn->header_only)
2214 conn->state = DONE;
2215 else {
2216 conn->state = SEND_REPLY;
2217 /* go straight on to body, don't go through another iteration of
2218 * the select() loop.
2219 */
2220 poll_send_reply(conn);
2221 }
2222 }
2223 }
2224
2225 /* Send chunk on socket <s> from FILE *fp, starting at <ofs> and of size
2226 * <size>. Use sendfile() if possible since it's zero-copy on some platforms.
2227 * Returns the number of bytes sent, 0 on closure, -1 if send() failed, -2 if
2228 * read error.
2229 */
2230 static ssize_t send_from_file(const int s, const int fd,
2231 off_t ofs, size_t size) {
2232 #ifdef __FreeBSD__
2233 off_t sent;
2234 int ret = sendfile(fd, s, ofs, size, NULL, &sent, 0);
2235
2236 /* It is possible for sendfile to send zero bytes due to a blocking
2237 * condition. Handle this correctly.
2238 */
2239 if (ret == -1)
2240 if (errno == EAGAIN)
2241 if (sent == 0)
2242 return -1;
2243 else
2244 return sent;
2245 else
2246 return -1;
2247 else
2248 return size;
2249 #else
2250 #if defined(__linux) || defined(__sun__)
2251 /* Limit truly ridiculous (LARGEFILE) requests. */
2252 if (size > 1<<20)
2253 size = 1<<20;
2254 return sendfile(s, fd, &ofs, size);
2255 #else
2256 /* Fake sendfile() with read(). */
2257 # ifndef min
2258 # define min(a,b) ( ((a)<(b)) ? (a) : (b) )
2259 # endif
2260 char buf[1<<15];
2261 size_t amount = min(sizeof(buf), size);
2262 ssize_t numread;
2263
2264 if (lseek(fd, ofs, SEEK_SET) == -1)
2265 err(1, "fseek(%d)", (int)ofs);
2266 numread = read(fd, buf, amount);
2267 if (numread == 0) {
2268 fprintf(stderr, "premature eof on fd %d\n", fd);
2269 return -1;
2270 }
2271 else if (numread == -1) {
2272 fprintf(stderr, "error reading on fd %d: %s", fd, strerror(errno));
2273 return -1;
2274 }
2275 else if ((size_t)numread != amount) {
2276 fprintf(stderr, "read %zd bytes, expecting %zu bytes on fd %d\n",
2277 numread, amount, fd);
2278 return -1;
2279 }
2280 else
2281 return send(s, buf, amount, 0);
2282 #endif
2283 #endif
2284 }
2285
2286 /* Sending reply. */
2287 static void poll_send_reply(struct connection *conn)
2288 {
2289 ssize_t sent;
2290
2291 assert(conn->state == SEND_REPLY);
2292 assert(!conn->header_only);
2293 if (conn->reply_type == REPLY_GENERATED) {
2294 assert(conn->reply_length >= conn->reply_sent);
2295 sent = send(conn->socket,
2296 conn->reply + conn->reply_start + conn->reply_sent,
2297 (size_t)(conn->reply_length - conn->reply_sent), 0);
2298 }
2299 else {
2300 errno = 0;
2301 assert(conn->reply_length >= conn->reply_sent);
2302 sent = send_from_file(conn->socket, conn->reply_fd,
2303 conn->reply_start + conn->reply_sent,
2304 (size_t)(conn->reply_length - conn->reply_sent));
2305 if (debug && (sent < 1))
2306 printf("send_from_file returned %lld (errno=%d %s)\n",
2307 (long long)sent, errno, strerror(errno));
2308 }
2309 conn->last_active = now;
2310 if (debug)
2311 printf("poll_send_reply(%d) sent %d: %llu+[%llu-%llu] of %llu\n",
2312 conn->socket, (int)sent, llu(conn->reply_start),
2313 llu(conn->reply_sent), llu(conn->reply_sent + sent - 1),
2314 llu(conn->reply_length));
2315
2316 /* handle any errors (-1) or closure (0) in send() */
2317 if (sent < 1) {
2318 if (sent == -1) {
2319 if (errno == EAGAIN) {
2320 if (debug)
2321 printf("poll_send_reply would have blocked\n");
2322 return;
2323 }
2324 if (debug)
2325 printf("send(%d) error: %s\n", conn->socket, strerror(errno));
2326 }
2327 else if (sent == 0) {
2328 if (debug)
2329 printf("send(%d) closure\n", conn->socket);
2330 }
2331 conn->conn_close = 1;
2332 conn->state = DONE;
2333 return;
2334 }
2335 conn->reply_sent += sent;
2336 conn->total_sent += (size_t)sent;
2337 total_out += (size_t)sent;
2338
2339 /* check if we're done sending */
2340 if (conn->reply_sent == conn->reply_length)
2341 conn->state = DONE;
2342 }
2343
2344 /* Main loop of the httpd - a select() and then delegation to accept
2345 * connections, handle receiving of requests, and sending of replies.
2346 */
2347 static void httpd_poll(void) {
2348 fd_set recv_set, send_set;
2349 int max_fd, select_ret;
2350 struct connection *conn, *next;
2351 int bother_with_timeout = 0;
2352 struct timeval timeout, t0, t1;
2353
2354 timeout.tv_sec = timeout_secs;
2355 timeout.tv_usec = 0;
2356
2357 FD_ZERO(&recv_set);
2358 FD_ZERO(&send_set);
2359 max_fd = 0;
2360
2361 /* set recv/send fd_sets */
2362 #define MAX_FD_SET(sock, fdset) do { FD_SET(sock,fdset); \
2363 max_fd = (max_fd<sock) ? sock : max_fd; } \
2364 while (0)
2365 if (accepting) MAX_FD_SET(sockin, &recv_set);
2366
2367 LIST_FOREACH_SAFE(conn, &connlist, entries, next) {
2368 switch (conn->state) {
2369 case DONE:
2370 /* do nothing */
2371 break;
2372
2373 case RECV_REQUEST:
2374 MAX_FD_SET(conn->socket, &recv_set);
2375 bother_with_timeout = 1;
2376 break;
2377
2378 case SEND_HEADER:
2379 case SEND_REPLY:
2380 MAX_FD_SET(conn->socket, &send_set);
2381 bother_with_timeout = 1;
2382 break;
2383 }
2384 }
2385 #undef MAX_FD_SET
2386
2387 #if defined(__has_feature)
2388 # if __has_feature(memory_sanitizer)
2389 __msan_unpoison(&recv_set, sizeof(recv_set));
2390 __msan_unpoison(&send_set, sizeof(send_set));
2391 # endif
2392 #endif
2393
2394 /* -select- */
2395 if (debug) {
2396 printf("select() with max_fd %d timeout %d\n",
2397 max_fd, bother_with_timeout ? (int)timeout.tv_sec : 0);
2398 gettimeofday(&t0, NULL);
2399 }
2400 select_ret = select(max_fd + 1, &recv_set, &send_set, NULL,
2401 (bother_with_timeout) ? &timeout : NULL);
2402 if (select_ret == 0) {
2403 if (!bother_with_timeout)
2404 errx(1, "select() timed out");
2405 }
2406 if (select_ret == -1) {
2407 if (errno == EINTR)
2408 return; /* interrupted by signal */
2409 else
2410 err(1, "select() failed");
2411 }
2412 if (debug) {
2413 long long sec, usec;
2414 gettimeofday(&t1, NULL);
2415 sec = t1.tv_sec - t0.tv_sec;
2416 usec = t1.tv_usec - t0.tv_usec;
2417 if (usec < 0) {
2418 usec += 1000000;
2419 sec--;
2420 }
2421 printf("select() returned %d after %lld.%06lld secs\n",
2422 select_ret, sec, usec);
2423 }
2424
2425 /* update time */
2426 now = time(NULL);
2427
2428 /* poll connections that select() says need attention */
2429 if (FD_ISSET(sockin, &recv_set))
2430 accept_connection();
2431
2432 LIST_FOREACH_SAFE(conn, &connlist, entries, next) {
2433 poll_check_timeout(conn);
2434 switch (conn->state) {
2435 case RECV_REQUEST:
2436 if (FD_ISSET(conn->socket, &recv_set)) poll_recv_request(conn);
2437 break;
2438
2439 case SEND_HEADER:
2440 if (FD_ISSET(conn->socket, &send_set)) poll_send_header(conn);
2441 break;
2442
2443 case SEND_REPLY:
2444 if (FD_ISSET(conn->socket, &send_set)) poll_send_reply(conn);
2445 break;
2446
2447 case DONE:
2448 /* (handled later; ignore for now as it's a valid state) */
2449 break;
2450 }
2451
2452 /* Handling SEND_REPLY could have set the state to done. */
2453 if (conn->state == DONE) {
2454 /* clean out finished connection */
2455 if (conn->conn_close) {
2456 LIST_REMOVE(conn, entries);
2457 free_connection(conn);
2458 free(conn);
2459 } else {
2460 recycle_connection(conn);
2461 /* and go right back to recv_request without going through
2462 * select() again.
2463 */
2464 poll_recv_request(conn);
2465 }
2466 }
2467 }
2468 }
2469
2470 /* Daemonize helpers. */
2471 #define PATH_DEVNULL "/dev/null"
2472 static int lifeline[2] = { -1, -1 };
2473 static int fd_null = -1;
2474
2475 static void daemonize_start(void) {
2476 pid_t f;
2477
2478 if (pipe(lifeline) == -1)
2479 err(1, "pipe(lifeline)");
2480
2481 fd_null = open(PATH_DEVNULL, O_RDWR, 0);
2482 if (fd_null == -1)
2483 err(1, "open(" PATH_DEVNULL ")");
2484
2485 f = fork();
2486 if (f == -1)
2487 err(1, "fork");
2488 else if (f != 0) {
2489 /* parent: wait for child */
2490 char tmp[1];
2491 int status;
2492 pid_t w;
2493
2494 if (close(lifeline[1]) == -1)
2495 warn("close lifeline in parent");
2496 if (read(lifeline[0], tmp, sizeof(tmp)) == -1)
2497 warn("read lifeline in parent");
2498 w = waitpid(f, &status, WNOHANG);
2499 if (w == -1)
2500 err(1, "waitpid");
2501 else if (w == 0)
2502 /* child is running happily */
2503 exit(EXIT_SUCCESS);
2504 else
2505 /* child init failed, pass on its exit status */
2506 exit(WEXITSTATUS(status));
2507 }
2508 /* else we are the child: continue initializing */
2509 }
2510
2511 static void daemonize_finish(void) {
2512 if (fd_null == -1)
2513 return; /* didn't daemonize_start() so we're not daemonizing */
2514
2515 if (setsid() == -1)
2516 err(1, "setsid");
2517 if (close(lifeline[0]) == -1)
2518 warn("close read end of lifeline in child");
2519 if (close(lifeline[1]) == -1)
2520 warn("couldn't cut the lifeline");
2521
2522 /* close all our std fds */
2523 if (dup2(fd_null, STDIN_FILENO) == -1)
2524 warn("dup2(stdin)");
2525 if (dup2(fd_null, STDOUT_FILENO) == -1)
2526 warn("dup2(stdout)");
2527 if (dup2(fd_null, STDERR_FILENO) == -1)
2528 warn("dup2(stderr)");
2529 if (fd_null > 2)
2530 close(fd_null);
2531 }
2532
2533 /* [->] pidfile helpers, based on FreeBSD src/lib/libutil/pidfile.c,v 1.3
2534 * Original was copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
2535 */
2536 static int pidfile_fd = -1;
2537 #define PIDFILE_MODE 0600
2538
2539 static void pidfile_remove(void) {
2540 if (unlink(pidfile_name) == -1)
2541 err(1, "unlink(pidfile) failed");
2542 /* if (flock(pidfile_fd, LOCK_UN) == -1)
2543 err(1, "unlock(pidfile) failed"); */
2544 xclose(pidfile_fd);
2545 pidfile_fd = -1;
2546 }
2547
2548 static int pidfile_read(void) {
2549 char buf[16];
2550 int fd, i;
2551 long long pid;
2552
2553 fd = open(pidfile_name, O_RDONLY);
2554 if (fd == -1)
2555 err(1, " after create failed");
2556
2557 i = (int)read(fd, buf, sizeof(buf) - 1);
2558 if (i == -1)
2559 err(1, "read from pidfile failed");
2560 xclose(fd);
2561 buf[i] = '\0';
2562
2563 if (!str_to_num(buf, &pid)) {
2564 err(1, "invalid pidfile contents: \"%s\"", buf);
2565 }
2566 return (int)pid;
2567 }
2568
2569 static void pidfile_create(void) {
2570 int error, fd;
2571 char pidstr[16];
2572
2573 /* Open the PID file and obtain exclusive lock. */
2574 fd = open(pidfile_name,
2575 O_WRONLY | O_CREAT | O_EXLOCK | O_TRUNC | O_NONBLOCK, PIDFILE_MODE);
2576 if (fd == -1) {
2577 if ((errno == EWOULDBLOCK) || (errno == EEXIST))
2578 errx(1, "daemon already running with PID %d", pidfile_read());
2579 else
2580 err(1, "can't create pidfile %s", pidfile_name);
2581 }
2582 pidfile_fd = fd;
2583
2584 if (ftruncate(fd, 0) == -1) {
2585 error = errno;
2586 pidfile_remove();
2587 errno = error;
2588 err(1, "ftruncate() failed");
2589 }
2590
2591 snprintf(pidstr, sizeof(pidstr), "%d", (int)getpid());
2592 if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
2593 error = errno;
2594 pidfile_remove();
2595 errno = error;
2596 err(1, "pwrite() failed");
2597 }
2598 }
2599 /* [<-] end of pidfile helpers. */
2600
2601 /* Close all sockets and FILEs and exit. */
2602 static void stop_running(int sig unused) {
2603 running = 0;
2604 }
2605
2606 /* Execution starts here. */
2607 int main(int argc, char **argv) {
2608 printf("%s, %s.\n", pkgname, copyright);
2609 parse_default_extension_map();
2610 parse_commandline(argc, argv);
2611 /* parse_commandline() might override parts of the extension map by
2612 * parsing a user-specified file.
2613 */
2614 sort_mime_map();
2615 xasprintf(&keep_alive_field, "Keep-Alive: timeout=%d\r\n", timeout_secs);
2616 if (want_server_id)
2617 xasprintf(&server_hdr, "Server: %s\r\n", pkgname);
2618 else
2619 server_hdr = xstrdup("");
2620 init_sockin();
2621
2622 /* open logfile */
2623 if (logfile_name == NULL)
2624 logfile = stdout;
2625 else {
2626 logfile = fopen(logfile_name, "ab");
2627 if (logfile == NULL)
2628 err(1, "opening logfile: fopen(\"%s\")", logfile_name);
2629 }
2630
2631 if (want_daemon)
2632 daemonize_start();
2633
2634 /* signals */
2635 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
2636 err(1, "signal(ignore SIGPIPE)");
2637 if (signal(SIGINT, stop_running) == SIG_ERR)
2638 err(1, "signal(SIGINT)");
2639 if (signal(SIGTERM, stop_running) == SIG_ERR)
2640 err(1, "signal(SIGTERM)");
2641
2642 /* security */
2643 if (want_chroot) {
2644 tzset(); /* read /etc/localtime before we chroot */
2645 if (chdir(wwwroot) == -1)
2646 err(1, "chdir(%s)", wwwroot);
2647 if (chroot(wwwroot) == -1)
2648 err(1, "chroot(%s)", wwwroot);
2649 printf("chrooted to `%s'\n", wwwroot);
2650 wwwroot[0] = '\0'; /* empty string */
2651 }
2652 if (drop_gid != INVALID_GID) {
2653 gid_t list[1];
2654 list[0] = drop_gid;
2655 if (setgroups(1, list) == -1)
2656 err(1, "setgroups([%d])", (int)drop_gid);
2657 if (setgid(drop_gid) == -1)
2658 err(1, "setgid(%d)", (int)drop_gid);
2659 printf("set gid to %d\n", (int)drop_gid);
2660 }
2661 if (drop_uid != INVALID_UID) {
2662 if (setuid(drop_uid) == -1)
2663 err(1, "setuid(%d)", (int)drop_uid);
2664 printf("set uid to %d\n", (int)drop_uid);
2665 }
2666
2667 /* create pidfile */
2668 if (pidfile_name) pidfile_create();
2669
2670 if (want_daemon) daemonize_finish();
2671
2672 /* main loop */
2673 while (running) httpd_poll();
2674
2675 /* clean exit */
2676 xclose(sockin);
2677 if (logfile != NULL) fclose(logfile);
2678 if (pidfile_name) pidfile_remove();
2679
2680 /* close and free connections */
2681 {
2682 struct connection *conn, *next;
2683
2684 LIST_FOREACH_SAFE(conn, &connlist, entries, next) {
2685 LIST_REMOVE(conn, entries);
2686 free_connection(conn);
2687 free(conn);
2688 }
2689 }
2690
2691 /* free the mallocs */
2692 {
2693 size_t i;
2694 for (i=0; i<mime_map_size; i++) {
2695 free(mime_map[i].extension);
2696 free(mime_map[i].mimetype);
2697 }
2698 free(mime_map);
2699 if (forward_map)
2700 free(forward_map);
2701 free(keep_alive_field);
2702 free(wwwroot);
2703 free(server_hdr);
2704 }
2705
2706 /* usage stats */
2707 {
2708 struct rusage r;
2709
2710 getrusage(RUSAGE_SELF, &r);
2711 printf("CPU time used: %u.%02u user, %u.%02u system\n",
2712 (unsigned int)r.ru_utime.tv_sec,
2713 (unsigned int)(r.ru_utime.tv_usec/10000),
2714 (unsigned int)r.ru_stime.tv_sec,
2715 (unsigned int)(r.ru_stime.tv_usec/10000)
2716 );
2717 printf("Requests: %llu\n", llu(num_requests));
2718 printf("Bytes: %llu in, %llu out\n", llu(total_in), llu(total_out));
2719 }
2720
2721 return 0;
2722 }
2723
2724 /* vim:set ts=4 sw=4 sts=4 expandtab tw=78: */