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