Be explicit if the binary was built without IPV6 support.
[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\n");
987 #ifdef HAVE_INET6
988 printf("\t--ipv6\n"
989 "\t\tListen on IPv6 address.\n\n");
990 #else
991 printf("\t(This binary was built without IPv6 support: -DNO_IPV6)\n\n");
992 #endif
993 }
994
995 /* Returns 1 if string is a number, 0 otherwise. Set num to NULL if
996 * disinterested in value.
997 */
998 static int str_to_num(const char *str, long long *num) {
999 char *endptr;
1000 long long n;
1001
1002 errno = 0;
1003 n = strtoll(str, &endptr, 10);
1004 if (*endptr != '\0')
1005 return 0;
1006 if (n == LLONG_MIN && errno == ERANGE)
1007 return 0;
1008 if (n == LLONG_MAX && errno == ERANGE)
1009 return 0;
1010 if (num != NULL)
1011 *num = n;
1012 return 1;
1013 }
1014
1015 /* Returns a valid number or dies. */
1016 static long long xstr_to_num(const char *str) {
1017 long long ret;
1018
1019 if (!str_to_num(str, &ret)) {
1020 errx(1, "number \"%s\" is invalid", str);
1021 }
1022 return ret;
1023 }
1024
1025 static void parse_commandline(const int argc, char *argv[]) {
1026 int i;
1027 size_t len;
1028
1029 if ((argc < 2) || (argc == 2 && strcmp(argv[1], "--help") == 0)) {
1030 usage(argv[0]); /* no wwwroot given */
1031 exit(EXIT_SUCCESS);
1032 }
1033
1034 if (getuid() == 0)
1035 bindport = 80;
1036
1037 wwwroot = xstrdup(argv[1]);
1038 /* Strip ending slash. */
1039 len = strlen(wwwroot);
1040 if (len > 0)
1041 if (wwwroot[len - 1] == '/')
1042 wwwroot[len - 1] = '\0';
1043
1044 /* walk through the remainder of the arguments (if any) */
1045 for (i = 2; i < argc; i++) {
1046 if (strcmp(argv[i], "--port") == 0) {
1047 if (++i >= argc)
1048 errx(1, "missing number after --port");
1049 bindport = (uint16_t)xstr_to_num(argv[i]);
1050 }
1051 else if (strcmp(argv[i], "--addr") == 0) {
1052 if (++i >= argc)
1053 errx(1, "missing ip after --addr");
1054 bindaddr = argv[i];
1055 }
1056 else if (strcmp(argv[i], "--maxconn") == 0) {
1057 if (++i >= argc)
1058 errx(1, "missing number after --maxconn");
1059 max_connections = (int)xstr_to_num(argv[i]);
1060 }
1061 else if (strcmp(argv[i], "--log") == 0) {
1062 if (++i >= argc)
1063 errx(1, "missing filename after --log");
1064 logfile_name = argv[i];
1065 }
1066 else if (strcmp(argv[i], "--chroot") == 0) {
1067 want_chroot = 1;
1068 }
1069 else if (strcmp(argv[i], "--daemon") == 0) {
1070 want_daemon = 1;
1071 }
1072 else if (strcmp(argv[i], "--index") == 0) {
1073 if (++i >= argc)
1074 errx(1, "missing filename after --index");
1075 index_name = argv[i];
1076 }
1077 else if (strcmp(argv[i], "--no-listing") == 0) {
1078 no_listing = 1;
1079 }
1080 else if (strcmp(argv[i], "--mimetypes") == 0) {
1081 if (++i >= argc)
1082 errx(1, "missing filename after --mimetypes");
1083 parse_extension_map_file(argv[i]);
1084 }
1085 else if (strcmp(argv[i], "--default-mimetype") == 0) {
1086 if (++i >= argc)
1087 errx(1, "missing string after --default-mimetype");
1088 default_mimetype = argv[i];
1089 }
1090 else if (strcmp(argv[i], "--uid") == 0) {
1091 struct passwd *p;
1092 if (++i >= argc)
1093 errx(1, "missing uid after --uid");
1094 p = getpwnam(argv[i]);
1095 if (!p) {
1096 p = getpwuid((uid_t)xstr_to_num(argv[i]));
1097 }
1098 if (!p)
1099 errx(1, "no such uid: `%s'", argv[i]);
1100 drop_uid = p->pw_uid;
1101 }
1102 else if (strcmp(argv[i], "--gid") == 0) {
1103 struct group *g;
1104 if (++i >= argc)
1105 errx(1, "missing gid after --gid");
1106 g = getgrnam(argv[i]);
1107 if (!g) {
1108 g = getgrgid((gid_t)xstr_to_num(argv[i]));
1109 }
1110 if (!g) {
1111 errx(1, "no such gid: `%s'", argv[i]);
1112 }
1113 drop_gid = g->gr_gid;
1114 }
1115 else if (strcmp(argv[i], "--pidfile") == 0) {
1116 if (++i >= argc)
1117 errx(1, "missing filename after --pidfile");
1118 pidfile_name = argv[i];
1119 }
1120 else if (strcmp(argv[i], "--no-keepalive") == 0) {
1121 want_keepalive = 0;
1122 }
1123 else if (strcmp(argv[i], "--accf") == 0) {
1124 want_accf = 1;
1125 }
1126 else if (strcmp(argv[i], "--forward") == 0) {
1127 const char *host, *url;
1128 if (++i >= argc)
1129 errx(1, "missing host after --forward");
1130 host = argv[i];
1131 if (++i >= argc)
1132 errx(1, "missing url after --forward");
1133 url = argv[i];
1134 add_forward_mapping(host, url);
1135 }
1136 else if (strcmp(argv[i], "--forward-all") == 0) {
1137 if (++i >= argc)
1138 errx(1, "missing url after --forward-all");
1139 forward_all_url = argv[i];
1140 }
1141 else if (strcmp(argv[i], "--no-server-id") == 0) {
1142 want_server_id = 0;
1143 }
1144 #ifdef HAVE_INET6
1145 else if (strcmp(argv[i], "--ipv6") == 0) {
1146 inet6 = 1;
1147 }
1148 #endif
1149 else
1150 errx(1, "unknown argument `%s'", argv[i]);
1151 }
1152 }
1153
1154 /* Allocate and initialize an empty connection. */
1155 static struct connection *new_connection(void) {
1156 struct connection *conn = xmalloc(sizeof(struct connection));
1157
1158 conn->socket = -1;
1159 memset(&conn->client, 0, sizeof(conn->client));
1160 conn->last_active = now;
1161 conn->request = NULL;
1162 conn->request_length = 0;
1163 conn->method = NULL;
1164 conn->url = NULL;
1165 conn->referer = NULL;
1166 conn->user_agent = NULL;
1167 conn->range_begin = 0;
1168 conn->range_end = 0;
1169 conn->range_begin_given = 0;
1170 conn->range_end_given = 0;
1171 conn->header = NULL;
1172 conn->header_length = 0;
1173 conn->header_sent = 0;
1174 conn->header_dont_free = 0;
1175 conn->header_only = 0;
1176 conn->http_code = 0;
1177 conn->conn_close = 1;
1178 conn->reply = NULL;
1179 conn->reply_dont_free = 0;
1180 conn->reply_fd = -1;
1181 conn->reply_start = 0;
1182 conn->reply_length = 0;
1183 conn->reply_sent = 0;
1184 conn->total_sent = 0;
1185
1186 /* Make it harmless so it gets garbage-collected if it should, for some
1187 * reason, fail to be correctly filled out.
1188 */
1189 conn->state = DONE;
1190
1191 return conn;
1192 }
1193
1194 /* Accept a connection from sockin and add it to the connection queue. */
1195 static void accept_connection(void) {
1196 struct sockaddr_in addrin;
1197 #ifdef HAVE_INET6
1198 struct sockaddr_in6 addrin6;
1199 #endif
1200 socklen_t sin_size;
1201 struct connection *conn;
1202
1203 /* allocate and initialise struct connection */
1204 conn = new_connection();
1205
1206 #ifdef HAVE_INET6
1207 if (inet6) {
1208 sin_size = sizeof(addrin6);
1209 memset(&addrin6, 0, sin_size);
1210 conn->socket = accept(sockin, (struct sockaddr *)&addrin6, &sin_size);
1211 } else
1212 #endif
1213 {
1214 sin_size = sizeof(addrin);
1215 memset(&addrin, 0, sin_size);
1216 conn->socket = accept(sockin, (struct sockaddr *)&addrin, &sin_size);
1217 }
1218
1219 if (conn->socket == -1)
1220 err(1, "accept()");
1221
1222 nonblock_socket(conn->socket);
1223
1224 conn->state = RECV_REQUEST;
1225
1226 #ifdef HAVE_INET6
1227 if (inet6) {
1228 conn->client = addrin6.sin6_addr;
1229 } else
1230 #endif
1231 {
1232 *(in_addr_t *)&conn->client = addrin.sin_addr.s_addr;
1233 }
1234 LIST_INSERT_HEAD(&connlist, conn, entries);
1235
1236 if (debug)
1237 printf("accepted connection from %s:%u\n",
1238 inet_ntoa(addrin.sin_addr), ntohs(addrin.sin_port));
1239
1240 /* Try to read straight away rather than going through another iteration
1241 * of the select() loop.
1242 */
1243 poll_recv_request(conn);
1244 }
1245
1246 /* Should this character be logencoded?
1247 */
1248 static int needs_logencoding(const unsigned char c) {
1249 return ((c <= 0x1F) || (c >= 0x7F) || (c == '"'));
1250 }
1251
1252 /* Encode string for logging.
1253 */
1254 static void logencode(const char *src, char *dest) {
1255 static const char hex[] = "0123456789ABCDEF";
1256 int i, j;
1257
1258 for (i = j = 0; src[i] != '\0'; i++) {
1259 if (needs_logencoding((unsigned char)src[i])) {
1260 dest[j++] = '%';
1261 dest[j++] = hex[(src[i] >> 4) & 0xF];
1262 dest[j++] = hex[ src[i] & 0xF];
1263 }
1264 else
1265 dest[j++] = src[i];
1266 }
1267 dest[j] = '\0';
1268 }
1269
1270 /* Add a connection's details to the logfile. */
1271 static void log_connection(const struct connection *conn) {
1272 char *safe_method, *safe_url, *safe_referer, *safe_user_agent;
1273
1274 if (logfile == NULL)
1275 return;
1276 if (conn->http_code == 0)
1277 return; /* invalid - died in request */
1278 if (conn->method == NULL)
1279 return; /* invalid - didn't parse - maybe too long */
1280
1281 #define make_safe(x) \
1282 if (conn->x) { \
1283 safe_##x = xmalloc(strlen(conn->x)*3 + 1); \
1284 logencode(conn->x, safe_##x); \
1285 } else { \
1286 safe_##x = NULL; \
1287 }
1288
1289 make_safe(method);
1290 make_safe(url);
1291 make_safe(referer);
1292 make_safe(user_agent);
1293
1294 #define use_safe(x) safe_##x ? safe_##x : ""
1295
1296 fprintf(logfile, "%lu %s \"%s %s\" %d %llu \"%s\" \"%s\"\n",
1297 (unsigned long int)now,
1298 get_address_text(&conn->client),
1299 use_safe(method),
1300 use_safe(url),
1301 conn->http_code,
1302 llu(conn->total_sent),
1303 use_safe(referer),
1304 use_safe(user_agent)
1305 );
1306 fflush(logfile);
1307
1308 #define free_safe(x) if (safe_##x) free(safe_##x);
1309
1310 free_safe(method);
1311 free_safe(url);
1312 free_safe(referer);
1313 free_safe(user_agent);
1314
1315 #undef make_safe
1316 #undef use_safe
1317 #undef free_safe
1318 }
1319
1320 /* Log a connection, then cleanly deallocate its internals. */
1321 static void free_connection(struct connection *conn) {
1322 if (debug) printf("free_connection(%d)\n", conn->socket);
1323 log_connection(conn);
1324 if (conn->socket != -1) xclose(conn->socket);
1325 if (conn->request != NULL) free(conn->request);
1326 if (conn->method != NULL) free(conn->method);
1327 if (conn->url != NULL) free(conn->url);
1328 if (conn->referer != NULL) free(conn->referer);
1329 if (conn->user_agent != NULL) free(conn->user_agent);
1330 if (conn->header != NULL && !conn->header_dont_free) free(conn->header);
1331 if (conn->reply != NULL && !conn->reply_dont_free) free(conn->reply);
1332 if (conn->reply_fd != -1) xclose(conn->reply_fd);
1333 }
1334
1335 /* Recycle a finished connection for HTTP/1.1 Keep-Alive. */
1336 static void recycle_connection(struct connection *conn) {
1337 int socket_tmp = conn->socket;
1338 if (debug)
1339 printf("recycle_connection(%d)\n", socket_tmp);
1340 conn->socket = -1; /* so free_connection() doesn't close it */
1341 free_connection(conn);
1342 conn->socket = socket_tmp;
1343
1344 /* don't reset conn->client */
1345 conn->request = NULL;
1346 conn->request_length = 0;
1347 conn->method = NULL;
1348 conn->url = NULL;
1349 conn->referer = NULL;
1350 conn->user_agent = NULL;
1351 conn->range_begin = 0;
1352 conn->range_end = 0;
1353 conn->range_begin_given = 0;
1354 conn->range_end_given = 0;
1355 conn->header = NULL;
1356 conn->header_length = 0;
1357 conn->header_sent = 0;
1358 conn->header_dont_free = 0;
1359 conn->header_only = 0;
1360 conn->http_code = 0;
1361 conn->conn_close = 1;
1362 conn->reply = NULL;
1363 conn->reply_dont_free = 0;
1364 conn->reply_fd = -1;
1365 conn->reply_start = 0;
1366 conn->reply_length = 0;
1367 conn->reply_sent = 0;
1368 conn->total_sent = 0;
1369
1370 conn->state = RECV_REQUEST; /* ready for another */
1371 }
1372
1373 /* Uppercasify all characters in a string of given length. */
1374 static void strntoupper(char *str, const size_t length) {
1375 size_t i;
1376
1377 for (i = 0; i < length; i++)
1378 str[i] = (char)toupper(str[i]);
1379 }
1380
1381 /* If a connection has been idle for more than idletime seconds, it will be
1382 * marked as DONE and killed off in httpd_poll()
1383 */
1384 static void poll_check_timeout(struct connection *conn) {
1385 if (idletime > 0) { /* optimised away by compiler */
1386 if (now - conn->last_active >= idletime) {
1387 if (debug)
1388 printf("poll_check_timeout(%d) caused closure\n",
1389 conn->socket);
1390 conn->conn_close = 1;
1391 conn->state = DONE;
1392 }
1393 }
1394 }
1395
1396 /* Format [when] as an RFC1123 date, stored in the specified buffer. The same
1397 * buffer is returned for convenience.
1398 */
1399 #define DATE_LEN 30 /* strlen("Fri, 28 Feb 2003 00:02:08 GMT")+1 */
1400 static char *rfc1123_date(char *dest, const time_t when) {
1401 time_t when_copy = when;
1402 if (strftime(dest, DATE_LEN,
1403 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&when_copy)) == 0)
1404 errx(1, "strftime() failed [%s]", dest);
1405 return dest;
1406 }
1407
1408 /* Decode URL by converting %XX (where XX are hexadecimal digits) to the
1409 * character it represents. Don't forget to free the return value.
1410 */
1411 static char *urldecode(const char *url) {
1412 size_t i, pos, len = strlen(url);
1413 char *out = xmalloc(len+1);
1414
1415 for (i = 0, pos = 0; i < len; i++) {
1416 if ((url[i] == '%') && (i+2 < len) &&
1417 isxdigit(url[i+1]) && isxdigit(url[i+2])) {
1418 /* decode %XX */
1419 #define HEX_TO_DIGIT(hex) ( \
1420 ((hex) >= 'A' && (hex) <= 'F') ? ((hex)-'A'+10): \
1421 ((hex) >= 'a' && (hex) <= 'f') ? ((hex)-'a'+10): \
1422 ((hex)-'0') )
1423
1424 out[pos++] = HEX_TO_DIGIT(url[i+1]) * 16 +
1425 HEX_TO_DIGIT(url[i+2]);
1426 i += 2;
1427 #undef HEX_TO_DIGIT
1428 } else {
1429 /* straight copy */
1430 out[pos++] = url[i];
1431 }
1432 }
1433 out[pos] = '\0';
1434 return out;
1435 }
1436
1437 /* Returns Connection or Keep-Alive header, depending on conn_close. */
1438 static const char *keep_alive(const struct connection *conn)
1439 {
1440 return (conn->conn_close ? "Connection: close\r\n" : keep_alive_field);
1441 }
1442
1443 /* "Generated by " + pkgname + " on " + date + "\n"
1444 * 1234567890123 1234 2 ('\n' and '\0')
1445 */
1446 static char _generated_on_buf[13 + sizeof(pkgname) - 1 + 4 + DATE_LEN + 2];
1447 static const char *generated_on(const char date[DATE_LEN]) {
1448 if (!want_server_id)
1449 return "";
1450 snprintf(_generated_on_buf, sizeof(_generated_on_buf),
1451 "Generated by %s on %s\n",
1452 pkgname, date);
1453 return _generated_on_buf;
1454 }
1455
1456 /* A default reply for any (erroneous) occasion. */
1457 static void default_reply(struct connection *conn,
1458 const int errcode, const char *errname, const char *format, ...)
1459 __printflike(4, 5);
1460 static void default_reply(struct connection *conn,
1461 const int errcode, const char *errname, const char *format, ...) {
1462 char *reason, date[DATE_LEN];
1463 va_list va;
1464
1465 va_start(va, format);
1466 xvasprintf(&reason, format, va);
1467 va_end(va);
1468
1469 /* Only really need to calculate the date once. */
1470 rfc1123_date(date, now);
1471
1472 conn->reply_length = xasprintf(&(conn->reply),
1473 "<html><head><title>%d %s</title></head><body>\n"
1474 "<h1>%s</h1>\n" /* errname */
1475 "%s\n" /* reason */
1476 "<hr>\n"
1477 "%s" /* generated on */
1478 "</body></html>\n",
1479 errcode, errname, errname, reason, generated_on(date));
1480 free(reason);
1481
1482 conn->header_length = xasprintf(&(conn->header),
1483 "HTTP/1.1 %d %s\r\n"
1484 "Date: %s\r\n"
1485 "%s" /* server */
1486 "Accept-Ranges: bytes\r\n"
1487 "%s" /* keep-alive */
1488 "Content-Length: %llu\r\n"
1489 "Content-Type: text/html; charset=UTF-8\r\n"
1490 "\r\n",
1491 errcode, errname, date, server_hdr, keep_alive(conn),
1492 llu(conn->reply_length));
1493
1494 conn->reply_type = REPLY_GENERATED;
1495 conn->http_code = errcode;
1496 }
1497
1498 static void redirect(struct connection *conn, const char *format, ...)
1499 __printflike(2, 3);
1500 static void redirect(struct connection *conn, const char *format, ...) {
1501 char *where, date[DATE_LEN];
1502 va_list va;
1503
1504 va_start(va, format);
1505 xvasprintf(&where, format, va);
1506 va_end(va);
1507
1508 /* Only really need to calculate the date once. */
1509 rfc1123_date(date, now);
1510
1511 conn->reply_length = xasprintf(&(conn->reply),
1512 "<html><head><title>301 Moved Permanently</title></head><body>\n"
1513 "<h1>Moved Permanently</h1>\n"
1514 "Moved to: <a href=\"%s\">%s</a>\n" /* where x 2 */
1515 "<hr>\n"
1516 "%s" /* generated on */
1517 "</body></html>\n",
1518 where, where, generated_on(date));
1519
1520 conn->header_length = xasprintf(&(conn->header),
1521 "HTTP/1.1 301 Moved Permanently\r\n"
1522 "Date: %s\r\n"
1523 "%s" /* server */
1524 /* "Accept-Ranges: bytes\r\n" - not relevant here */
1525 "Location: %s\r\n"
1526 "%s" /* keep-alive */
1527 "Content-Length: %llu\r\n"
1528 "Content-Type: text/html; charset=UTF-8\r\n"
1529 "\r\n",
1530 date, server_hdr, where, keep_alive(conn), llu(conn->reply_length));
1531
1532 free(where);
1533 conn->reply_type = REPLY_GENERATED;
1534 conn->http_code = 301;
1535 }
1536
1537 /* Parses a single HTTP request field. Returns string from end of [field] to
1538 * first \r, \n or end of request string. Returns NULL if [field] can't be
1539 * matched.
1540 *
1541 * You need to remember to deallocate the result.
1542 * example: parse_field(conn, "Referer: ");
1543 */
1544 static char *parse_field(const struct connection *conn, const char *field) {
1545 size_t bound1, bound2;
1546 char *pos;
1547
1548 /* find start */
1549 pos = strstr(conn->request, field);
1550 if (pos == NULL)
1551 return NULL;
1552 assert(pos >= conn->request);
1553 bound1 = (size_t)(pos - conn->request) + strlen(field);
1554
1555 /* find end */
1556 for (bound2 = bound1;
1557 ((bound2 < conn->request_length) &&
1558 (conn->request[bound2] != '\r') &&
1559 (conn->request[bound2] != '\n'));
1560 bound2++)
1561 ;
1562
1563 /* copy to buffer */
1564 return split_string(conn->request, bound1, bound2);
1565 }
1566
1567 /* Parse a Range: field into range_begin and range_end. Only handles the
1568 * first range if a list is given. Sets range_{begin,end}_given to 1 if
1569 * either part of the range is given.
1570 */
1571 static void parse_range_field(struct connection *conn) {
1572 char *range;
1573
1574 range = parse_field(conn, "Range: bytes=");
1575 if (range == NULL)
1576 return;
1577
1578 do {
1579 size_t bound1, bound2, len;
1580 len = strlen(range);
1581
1582 /* parse number up to hyphen */
1583 bound1 = 0;
1584 for (bound2=0;
1585 isdigit((int)range[bound2]) && (bound2 < len);
1586 bound2++)
1587 ;
1588
1589 if ((bound2 == len) || (range[bound2] != '-'))
1590 break; /* there must be a hyphen here */
1591
1592 if (bound1 != bound2) {
1593 conn->range_begin_given = 1;
1594 conn->range_begin = (off_t)strtoll(range+bound1, NULL, 10);
1595 }
1596
1597 /* parse number after hyphen */
1598 bound2++;
1599 for (bound1=bound2;
1600 isdigit((int)range[bound2]) && (bound2 < len);
1601 bound2++)
1602 ;
1603
1604 if ((bound2 != len) && (range[bound2] != ','))
1605 break; /* must be end of string or a list to be valid */
1606
1607 if (bound1 != bound2) {
1608 conn->range_end_given = 1;
1609 conn->range_end = (off_t)strtoll(range+bound1, NULL, 10);
1610 }
1611 } while(0);
1612 free(range);
1613 }
1614
1615 /* Parse an HTTP request like "GET / HTTP/1.1" to get the method (GET), the
1616 * url (/), the referer (if given) and the user-agent (if given). Remember to
1617 * deallocate all these buffers. The method will be returned in uppercase.
1618 */
1619 static int parse_request(struct connection *conn) {
1620 size_t bound1, bound2;
1621 char *tmp;
1622 assert(conn->request_length == strlen(conn->request));
1623
1624 /* parse method */
1625 for (bound1 = 0;
1626 (bound1 < conn->request_length) &&
1627 (conn->request[bound1] != ' ');
1628 bound1++)
1629 ;
1630
1631 conn->method = split_string(conn->request, 0, bound1);
1632 strntoupper(conn->method, bound1);
1633
1634 /* parse url */
1635 for (;
1636 (bound1 < conn->request_length) &&
1637 (conn->request[bound1] == ' ');
1638 bound1++)
1639 ;
1640
1641 if (bound1 == conn->request_length)
1642 return 0; /* fail */
1643
1644 for (bound2 = bound1 + 1;
1645 (bound2 < conn->request_length) &&
1646 (conn->request[bound2] != ' ') &&
1647 (conn->request[bound2] != '\r') &&
1648 (conn->request[bound2] != '\n');
1649 bound2++)
1650 ;
1651
1652 conn->url = split_string(conn->request, bound1, bound2);
1653
1654 /* parse protocol to determine conn_close */
1655 if (conn->request[bound2] == ' ') {
1656 char *proto;
1657 for (bound1 = bound2;
1658 (bound1 < conn->request_length) &&
1659 (conn->request[bound1] == ' ');
1660 bound1++)
1661 ;
1662
1663 for (bound2 = bound1 + 1;
1664 (bound2 < conn->request_length) &&
1665 (conn->request[bound2] != ' ') &&
1666 (conn->request[bound2] != '\r');
1667 bound2++)
1668 ;
1669
1670 proto = split_string(conn->request, bound1, bound2);
1671 if (strcasecmp(proto, "HTTP/1.1") == 0)
1672 conn->conn_close = 0;
1673 free(proto);
1674 }
1675
1676 /* parse connection field */
1677 tmp = parse_field(conn, "Connection: ");
1678 if (tmp != NULL) {
1679 if (strcasecmp(tmp, "close") == 0)
1680 conn->conn_close = 1;
1681 else if (strcasecmp(tmp, "keep-alive") == 0)
1682 conn->conn_close = 0;
1683 free(tmp);
1684 }
1685
1686 /* cmdline flag can be used to deny keep-alive */
1687 if (!want_keepalive)
1688 conn->conn_close = 1;
1689
1690 /* parse important fields */
1691 conn->referer = parse_field(conn, "Referer: ");
1692 conn->user_agent = parse_field(conn, "User-Agent: ");
1693 parse_range_field(conn);
1694 return 1;
1695 }
1696
1697 static int file_exists(const char *path) {
1698 struct stat filestat;
1699 if ((stat(path, &filestat) == -1) && (errno == ENOENT))
1700 return 0;
1701 else
1702 return 1;
1703 }
1704
1705 struct dlent {
1706 char *name;
1707 int is_dir;
1708 off_t size;
1709 };
1710
1711 static int dlent_cmp(const void *a, const void *b) {
1712 return strcmp((*((const struct dlent * const *)a))->name,
1713 (*((const struct dlent * const *)b))->name);
1714 }
1715
1716 /* Make sorted list of files in a directory. Returns number of entries, or -1
1717 * if error occurs.
1718 */
1719 static ssize_t make_sorted_dirlist(const char *path, struct dlent ***output) {
1720 DIR *dir;
1721 struct dirent *ent;
1722 size_t entries = 0;
1723 size_t pool = 128;
1724 char *currname;
1725 struct dlent **list = NULL;
1726
1727 dir = opendir(path);
1728 if (dir == NULL)
1729 return -1;
1730
1731 currname = xmalloc(strlen(path) + MAXNAMLEN + 1);
1732 list = xmalloc(sizeof(struct dlent*) * pool);
1733
1734 /* construct list */
1735 while ((ent = readdir(dir)) != NULL) {
1736 struct stat s;
1737
1738 if ((ent->d_name[0] == '.') && (ent->d_name[1] == '\0'))
1739 continue; /* skip "." */
1740 assert(strlen(ent->d_name) <= MAXNAMLEN);
1741 sprintf(currname, "%s%s", path, ent->d_name);
1742 if (stat(currname, &s) == -1)
1743 continue; /* skip un-stat-able files */
1744 if (entries == pool) {
1745 pool *= 2;
1746 list = xrealloc(list, sizeof(struct dlent*) * pool);
1747 }
1748 list[entries] = xmalloc(sizeof(struct dlent));
1749 list[entries]->name = xstrdup(ent->d_name);
1750 list[entries]->is_dir = S_ISDIR(s.st_mode);
1751 list[entries]->size = s.st_size;
1752 entries++;
1753 }
1754 closedir(dir);
1755 free(currname);
1756 qsort(list, entries, sizeof(struct dlent*), dlent_cmp);
1757 *output = list;
1758 return (ssize_t)entries;
1759 }
1760
1761 /* Cleanly deallocate a sorted list of directory files. */
1762 static void cleanup_sorted_dirlist(struct dlent **list, const ssize_t size) {
1763 ssize_t i;
1764
1765 for (i = 0; i < size; i++) {
1766 free(list[i]->name);
1767 free(list[i]);
1768 }
1769 }
1770
1771 /* Is this an unreserved character according to
1772 * https://tools.ietf.org/html/rfc3986#section-2.3
1773 */
1774 static int is_unreserved(const unsigned char c) {
1775 if (c >= 'a' && c <= 'z') return 1;
1776 if (c >= 'A' && c <= 'Z') return 1;
1777 if (c >= '0' && c <= '9') return 1;
1778 switch (c) {
1779 case '-':
1780 case '.':
1781 case '_':
1782 case '~':
1783 return 1;
1784 }
1785 return 0;
1786 }
1787
1788 /* Encode string to be an RFC3986-compliant URL part.
1789 * Contributed by nf.
1790 */
1791 static void urlencode(const char *src, char *dest) {
1792 static const char hex[] = "0123456789ABCDEF";
1793 int i, j;
1794
1795 for (i = j = 0; src[i] != '\0'; i++) {
1796 if (!is_unreserved((unsigned char)src[i])) {
1797 dest[j++] = '%';
1798 dest[j++] = hex[(src[i] >> 4) & 0xF];
1799 dest[j++] = hex[ src[i] & 0xF];
1800 }
1801 else
1802 dest[j++] = src[i];
1803 }
1804 dest[j] = '\0';
1805 }
1806
1807 static void generate_dir_listing(struct connection *conn, const char *path) {
1808 char date[DATE_LEN], *spaces;
1809 struct dlent **list;
1810 ssize_t listsize;
1811 size_t maxlen = 2; /* There has to be ".." */
1812 int i;
1813 struct apbuf *listing;
1814
1815 listsize = make_sorted_dirlist(path, &list);
1816 if (listsize == -1) {
1817 default_reply(conn, 500, "Internal Server Error",
1818 "Couldn't list directory: %s", strerror(errno));
1819 return;
1820 }
1821
1822 for (i=0; i<listsize; i++) {
1823 size_t tmp = strlen(list[i]->name);
1824 if (maxlen < tmp)
1825 maxlen = tmp;
1826 }
1827
1828 listing = make_apbuf();
1829 append(listing, "<html>\n<head>\n <title>");
1830 append(listing, conn->url);
1831 append(listing, "</title>\n</head>\n<body>\n<h1>");
1832 append(listing, conn->url);
1833 append(listing, "</h1>\n<tt><pre>\n");
1834
1835 spaces = xmalloc(maxlen);
1836 memset(spaces, ' ', maxlen);
1837
1838 for (i=0; i<listsize; i++) {
1839 /* If a filename is made up of entirely unsafe chars,
1840 * the url would be three times its original length.
1841 */
1842 char safe_url[MAXNAMLEN*3 + 1];
1843
1844 urlencode(list[i]->name, safe_url);
1845
1846 append(listing, "<a href=\"");
1847 append(listing, safe_url);
1848 append(listing, "\">");
1849 append(listing, list[i]->name);
1850 append(listing, "</a>");
1851
1852 if (list[i]->is_dir)
1853 append(listing, "/\n");
1854 else {
1855 appendl(listing, spaces, maxlen-strlen(list[i]->name));
1856 appendf(listing, "%10llu\n", llu(list[i]->size));
1857 }
1858 }
1859
1860 cleanup_sorted_dirlist(list, listsize);
1861 free(list);
1862 free(spaces);
1863
1864 append(listing,
1865 "</pre></tt>\n"
1866 "<hr>\n");
1867
1868 rfc1123_date(date, now);
1869 append(listing, generated_on(date));
1870 append(listing, "</body>\n</html>\n");
1871
1872 conn->reply = listing->str;
1873 conn->reply_length = (off_t)listing->length;
1874 free(listing); /* don't free inside of listing */
1875
1876 conn->header_length = xasprintf(&(conn->header),
1877 "HTTP/1.1 200 OK\r\n"
1878 "Date: %s\r\n"
1879 "%s" /* server */
1880 "Accept-Ranges: bytes\r\n"
1881 "%s" /* keep-alive */
1882 "Content-Length: %llu\r\n"
1883 "Content-Type: text/html; charset=UTF-8\r\n"
1884 "\r\n",
1885 date, server_hdr, keep_alive(conn), llu(conn->reply_length));
1886
1887 conn->reply_type = REPLY_GENERATED;
1888 conn->http_code = 200;
1889 }
1890
1891 /* Process a GET/HEAD request. */
1892 static void process_get(struct connection *conn) {
1893 char *decoded_url, *target, *if_mod_since;
1894 char date[DATE_LEN], lastmod[DATE_LEN];
1895 const char *mimetype = NULL;
1896 const char *forward_to = NULL;
1897 struct stat filestat;
1898
1899 /* work out path of file being requested */
1900 decoded_url = urldecode(conn->url);
1901
1902 /* make sure it's safe */
1903 if (make_safe_url(decoded_url) == NULL) {
1904 default_reply(conn, 400, "Bad Request",
1905 "You requested an invalid URL: %s", conn->url);
1906 free(decoded_url);
1907 return;
1908 }
1909
1910 /* test the host against web forward options */
1911 if (forward_map) {
1912 char *host = parse_field(conn, "Host: ");
1913 if (host) {
1914 size_t i;
1915 if (debug)
1916 printf("host=\"%s\"\n", host);
1917 for (i = 0; i < forward_map_size; i++) {
1918 if (strcasecmp(forward_map[i].host, host) == 0) {
1919 forward_to = forward_map[i].target_url;
1920 break;
1921 }
1922 }
1923 free(host);
1924 }
1925 }
1926 if (!forward_to) {
1927 forward_to = forward_all_url;
1928 }
1929 if (forward_to) {
1930 redirect(conn, "%s%s", forward_to, decoded_url);
1931 free(decoded_url);
1932 return;
1933 }
1934
1935 /* does it end in a slash? serve up url/index_name */
1936 if (decoded_url[strlen(decoded_url)-1] == '/') {
1937 xasprintf(&target, "%s%s%s", wwwroot, decoded_url, index_name);
1938 if (!file_exists(target)) {
1939 free(target);
1940 if (no_listing) {
1941 free(decoded_url);
1942 /* Return 404 instead of 403 to make --no-listing
1943 * indistinguishable from the directory not existing.
1944 * i.e.: Don't leak information.
1945 */
1946 default_reply(conn, 404, "Not Found",
1947 "The URL you requested (%s) was not found.", conn->url);
1948 return;
1949 }
1950 xasprintf(&target, "%s%s", wwwroot, decoded_url);
1951 generate_dir_listing(conn, target);
1952 free(target);
1953 free(decoded_url);
1954 return;
1955 }
1956 mimetype = url_content_type(index_name);
1957 }
1958 else {
1959 /* points to a file */
1960 xasprintf(&target, "%s%s", wwwroot, decoded_url);
1961 mimetype = url_content_type(decoded_url);
1962 }
1963 free(decoded_url);
1964 if (debug)
1965 printf("url=\"%s\", target=\"%s\", content-type=\"%s\"\n",
1966 conn->url, target, mimetype);
1967
1968 /* open file */
1969 conn->reply_fd = open(target, O_RDONLY | O_NONBLOCK);
1970 free(target);
1971
1972 if (conn->reply_fd == -1) {
1973 /* open() failed */
1974 if (errno == EACCES)
1975 default_reply(conn, 403, "Forbidden",
1976 "You don't have permission to access (%s).", conn->url);
1977 else if (errno == ENOENT)
1978 default_reply(conn, 404, "Not Found",
1979 "The URL you requested (%s) was not found.", conn->url);
1980 else
1981 default_reply(conn, 500, "Internal Server Error",
1982 "The URL you requested (%s) cannot be returned: %s.",
1983 conn->url, strerror(errno));
1984
1985 return;
1986 }
1987
1988 /* stat the file */
1989 if (fstat(conn->reply_fd, &filestat) == -1) {
1990 default_reply(conn, 500, "Internal Server Error",
1991 "fstat() failed: %s.", strerror(errno));
1992 return;
1993 }
1994
1995 /* make sure it's a regular file */
1996 if (S_ISDIR(filestat.st_mode)) {
1997 redirect(conn, "%s/", conn->url);
1998 return;
1999 }
2000 else if (!S_ISREG(filestat.st_mode)) {
2001 default_reply(conn, 403, "Forbidden", "Not a regular file.");
2002 return;
2003 }
2004
2005 conn->reply_type = REPLY_FROMFILE;
2006 rfc1123_date(lastmod, filestat.st_mtime);
2007
2008 /* check for If-Modified-Since, may not have to send */
2009 if_mod_since = parse_field(conn, "If-Modified-Since: ");
2010 if ((if_mod_since != NULL) &&
2011 (strcmp(if_mod_since, lastmod) == 0)) {
2012 if (debug)
2013 printf("not modified since %s\n", if_mod_since);
2014 conn->http_code = 304;
2015 conn->header_length = xasprintf(&(conn->header),
2016 "HTTP/1.1 304 Not Modified\r\n"
2017 "Date: %s\r\n"
2018 "%s" /* server */
2019 "Accept-Ranges: bytes\r\n"
2020 "%s" /* keep-alive */
2021 "\r\n",
2022 rfc1123_date(date, now), server_hdr, keep_alive(conn));
2023 conn->reply_length = 0;
2024 conn->reply_type = REPLY_GENERATED;
2025 conn->header_only = 1;
2026
2027 free(if_mod_since);
2028 return;
2029 }
2030 free(if_mod_since);
2031
2032 if (conn->range_begin_given || conn->range_end_given) {
2033 off_t from, to;
2034
2035 if (conn->range_begin_given && conn->range_end_given) {
2036 /* 100-200 */
2037 from = conn->range_begin;
2038 to = conn->range_end;
2039
2040 /* clamp end to filestat.st_size-1 */
2041 if (to > (filestat.st_size - 1))
2042 to = filestat.st_size - 1;
2043 }
2044 else if (conn->range_begin_given && !conn->range_end_given) {
2045 /* 100- :: yields 100 to end */
2046 from = conn->range_begin;
2047 to = filestat.st_size - 1;
2048 }
2049 else if (!conn->range_begin_given && conn->range_end_given) {
2050 /* -200 :: yields last 200 */
2051 to = filestat.st_size - 1;
2052 from = to - conn->range_end + 1;
2053
2054 /* clamp start */
2055 if (from < 0)
2056 from = 0;
2057 }
2058 else
2059 errx(1, "internal error - from/to mismatch");
2060
2061 if (from >= filestat.st_size) {
2062 default_reply(conn, 416, "Requested Range Not Satisfiable",
2063 "You requested a range outside of the file.");
2064 return;
2065 }
2066
2067 if (to < from) {
2068 default_reply(conn, 416, "Requested Range Not Satisfiable",
2069 "You requested a backward range.");
2070 return;
2071 }
2072
2073 conn->reply_start = from;
2074 conn->reply_length = to - from + 1;
2075
2076 conn->header_length = xasprintf(&(conn->header),
2077 "HTTP/1.1 206 Partial Content\r\n"
2078 "Date: %s\r\n"
2079 "%s" /* server */
2080 "Accept-Ranges: bytes\r\n"
2081 "%s" /* keep-alive */
2082 "Content-Length: %llu\r\n"
2083 "Content-Range: bytes %llu-%llu/%llu\r\n"
2084 "Content-Type: %s\r\n"
2085 "Last-Modified: %s\r\n"
2086 "\r\n"
2087 ,
2088 rfc1123_date(date, now), server_hdr, keep_alive(conn),
2089 llu(conn->reply_length), llu(from), llu(to),
2090 llu(filestat.st_size), mimetype, lastmod
2091 );
2092 conn->http_code = 206;
2093 if (debug)
2094 printf("sending %llu-%llu/%llu\n",
2095 llu(from), llu(to), llu(filestat.st_size));
2096 }
2097 else {
2098 /* no range stuff */
2099 conn->reply_length = filestat.st_size;
2100 conn->header_length = xasprintf(&(conn->header),
2101 "HTTP/1.1 200 OK\r\n"
2102 "Date: %s\r\n"
2103 "%s" /* server */
2104 "Accept-Ranges: bytes\r\n"
2105 "%s" /* keep-alive */
2106 "Content-Length: %llu\r\n"
2107 "Content-Type: %s\r\n"
2108 "Last-Modified: %s\r\n"
2109 "\r\n"
2110 ,
2111 rfc1123_date(date, now), server_hdr, keep_alive(conn),
2112 llu(conn->reply_length), mimetype, lastmod
2113 );
2114 conn->http_code = 200;
2115 }
2116 }
2117
2118 /* Process a request: build the header and reply, advance state. */
2119 static void process_request(struct connection *conn) {
2120 num_requests++;
2121 if (!parse_request(conn)) {
2122 default_reply(conn, 400, "Bad Request",
2123 "You sent a request that the server couldn't understand.");
2124 }
2125 else if (strcmp(conn->method, "GET") == 0) {
2126 process_get(conn);
2127 }
2128 else if (strcmp(conn->method, "HEAD") == 0) {
2129 process_get(conn);
2130 conn->header_only = 1;
2131 }
2132 else if ((strcmp(conn->method, "OPTIONS") == 0) ||
2133 (strcmp(conn->method, "POST") == 0) ||
2134 (strcmp(conn->method, "PUT") == 0) ||
2135 (strcmp(conn->method, "DELETE") == 0) ||
2136 (strcmp(conn->method, "TRACE") == 0) ||
2137 (strcmp(conn->method, "CONNECT") == 0)) {
2138 default_reply(conn, 501, "Not Implemented",
2139 "The method you specified (%s) is not implemented.",
2140 conn->method);
2141 }
2142 else {
2143 default_reply(conn, 400, "Bad Request",
2144 "%s is not a valid HTTP/1.1 method.", conn->method);
2145 }
2146
2147 /* advance state */
2148 conn->state = SEND_HEADER;
2149
2150 /* request not needed anymore */
2151 free(conn->request);
2152 conn->request = NULL; /* important: don't free it again later */
2153 }
2154
2155 /* Receiving request. */
2156 static void poll_recv_request(struct connection *conn) {
2157 char buf[1<<15];
2158 ssize_t recvd;
2159
2160 assert(conn->state == RECV_REQUEST);
2161 recvd = recv(conn->socket, buf, sizeof(buf), 0);
2162 if (debug)
2163 printf("poll_recv_request(%d) got %d bytes\n",
2164 conn->socket, (int)recvd);
2165 if (recvd < 1) {
2166 if (recvd == -1) {
2167 if (errno == EAGAIN) {
2168 if (debug) printf("poll_recv_request would have blocked\n");
2169 return;
2170 }
2171 if (debug) printf("recv(%d) error: %s\n",
2172 conn->socket, strerror(errno));
2173 }
2174 conn->conn_close = 1;
2175 conn->state = DONE;
2176 return;
2177 }
2178 conn->last_active = now;
2179
2180 /* append to conn->request */
2181 assert(recvd > 0);
2182 conn->request = xrealloc(
2183 conn->request, conn->request_length + (size_t)recvd + 1);
2184 memcpy(conn->request+conn->request_length, buf, (size_t)recvd);
2185 conn->request_length += (size_t)recvd;
2186 conn->request[conn->request_length] = 0;
2187 total_in += (size_t)recvd;
2188
2189 /* process request if we have all of it */
2190 if ((conn->request_length > 2) &&
2191 (memcmp(conn->request+conn->request_length-2, "\n\n", 2) == 0))
2192 process_request(conn);
2193 else if ((conn->request_length > 4) &&
2194 (memcmp(conn->request+conn->request_length-4, "\r\n\r\n", 4) == 0))
2195 process_request(conn);
2196
2197 /* die if it's too large */
2198 if (conn->request_length > MAX_REQUEST_LENGTH) {
2199 default_reply(conn, 413, "Request Entity Too Large",
2200 "Your request was dropped because it was too long.");
2201 conn->state = SEND_HEADER;
2202 }
2203
2204 /* if we've moved on to the next state, try to send right away, instead of
2205 * going through another iteration of the select() loop.
2206 */
2207 if (conn->state == SEND_HEADER)
2208 poll_send_header(conn);
2209 }
2210
2211 /* Sending header. Assumes conn->header is not NULL. */
2212 static void poll_send_header(struct connection *conn) {
2213 ssize_t sent;
2214
2215 assert(conn->state == SEND_HEADER);
2216 assert(conn->header_length == strlen(conn->header));
2217
2218 sent = send(conn->socket,
2219 conn->header + conn->header_sent,
2220 conn->header_length - conn->header_sent,
2221 0);
2222 conn->last_active = now;
2223 if (debug)
2224 printf("poll_send_header(%d) sent %d bytes\n",
2225 conn->socket, (int)sent);
2226
2227 /* handle any errors (-1) or closure (0) in send() */
2228 if (sent < 1) {
2229 if ((sent == -1) && (errno == EAGAIN)) {
2230 if (debug) printf("poll_send_header would have blocked\n");
2231 return;
2232 }
2233 if (debug && (sent == -1))
2234 printf("send(%d) error: %s\n", conn->socket, strerror(errno));
2235 conn->conn_close = 1;
2236 conn->state = DONE;
2237 return;
2238 }
2239 assert(sent > 0);
2240 conn->header_sent += (size_t)sent;
2241 conn->total_sent += (size_t)sent;
2242 total_out += (size_t)sent;
2243
2244 /* check if we're done sending header */
2245 if (conn->header_sent == conn->header_length) {
2246 if (conn->header_only)
2247 conn->state = DONE;
2248 else {
2249 conn->state = SEND_REPLY;
2250 /* go straight on to body, don't go through another iteration of
2251 * the select() loop.
2252 */
2253 poll_send_reply(conn);
2254 }
2255 }
2256 }
2257
2258 /* Send chunk on socket <s> from FILE *fp, starting at <ofs> and of size
2259 * <size>. Use sendfile() if possible since it's zero-copy on some platforms.
2260 * Returns the number of bytes sent, 0 on closure, -1 if send() failed, -2 if
2261 * read error.
2262 */
2263 static ssize_t send_from_file(const int s, const int fd,
2264 off_t ofs, size_t size) {
2265 #ifdef __FreeBSD__
2266 off_t sent;
2267 int ret = sendfile(fd, s, ofs, size, NULL, &sent, 0);
2268
2269 /* It is possible for sendfile to send zero bytes due to a blocking
2270 * condition. Handle this correctly.
2271 */
2272 if (ret == -1)
2273 if (errno == EAGAIN)
2274 if (sent == 0)
2275 return -1;
2276 else
2277 return sent;
2278 else
2279 return -1;
2280 else
2281 return size;
2282 #else
2283 #if defined(__linux) || defined(__sun__)
2284 /* Limit truly ridiculous (LARGEFILE) requests. */
2285 if (size > 1<<20)
2286 size = 1<<20;
2287 return sendfile(s, fd, &ofs, size);
2288 #else
2289 /* Fake sendfile() with read(). */
2290 # ifndef min
2291 # define min(a,b) ( ((a)<(b)) ? (a) : (b) )
2292 # endif
2293 char buf[1<<15];
2294 size_t amount = min(sizeof(buf), size);
2295 ssize_t numread;
2296
2297 if (lseek(fd, ofs, SEEK_SET) == -1)
2298 err(1, "fseek(%d)", (int)ofs);
2299 numread = read(fd, buf, amount);
2300 if (numread == 0) {
2301 fprintf(stderr, "premature eof on fd %d\n", fd);
2302 return -1;
2303 }
2304 else if (numread == -1) {
2305 fprintf(stderr, "error reading on fd %d: %s", fd, strerror(errno));
2306 return -1;
2307 }
2308 else if ((size_t)numread != amount) {
2309 fprintf(stderr, "read %zd bytes, expecting %zu bytes on fd %d\n",
2310 numread, amount, fd);
2311 return -1;
2312 }
2313 else
2314 return send(s, buf, amount, 0);
2315 #endif
2316 #endif
2317 }
2318
2319 /* Sending reply. */
2320 static void poll_send_reply(struct connection *conn)
2321 {
2322 ssize_t sent;
2323
2324 assert(conn->state == SEND_REPLY);
2325 assert(!conn->header_only);
2326 if (conn->reply_type == REPLY_GENERATED) {
2327 assert(conn->reply_length >= conn->reply_sent);
2328 sent = send(conn->socket,
2329 conn->reply + conn->reply_start + conn->reply_sent,
2330 (size_t)(conn->reply_length - conn->reply_sent), 0);
2331 }
2332 else {
2333 errno = 0;
2334 assert(conn->reply_length >= conn->reply_sent);
2335 sent = send_from_file(conn->socket, conn->reply_fd,
2336 conn->reply_start + conn->reply_sent,
2337 (size_t)(conn->reply_length - conn->reply_sent));
2338 if (debug && (sent < 1))
2339 printf("send_from_file returned %lld (errno=%d %s)\n",
2340 (long long)sent, errno, strerror(errno));
2341 }
2342 conn->last_active = now;
2343 if (debug)
2344 printf("poll_send_reply(%d) sent %d: %lld+[%lld-%lld] of %lld\n",
2345 conn->socket, (int)sent, llu(conn->reply_start),
2346 llu(conn->reply_sent), llu(conn->reply_sent + sent - 1),
2347 llu(conn->reply_length));
2348
2349 /* handle any errors (-1) or closure (0) in send() */
2350 if (sent < 1) {
2351 if (sent == -1) {
2352 if (errno == EAGAIN) {
2353 if (debug)
2354 printf("poll_send_reply would have blocked\n");
2355 return;
2356 }
2357 if (debug)
2358 printf("send(%d) error: %s\n", conn->socket, strerror(errno));
2359 }
2360 else if (sent == 0) {
2361 if (debug)
2362 printf("send(%d) closure\n", conn->socket);
2363 }
2364 conn->conn_close = 1;
2365 conn->state = DONE;
2366 return;
2367 }
2368 conn->reply_sent += sent;
2369 conn->total_sent += (size_t)sent;
2370 total_out += (size_t)sent;
2371
2372 /* check if we're done sending */
2373 if (conn->reply_sent == conn->reply_length)
2374 conn->state = DONE;
2375 }
2376
2377 /* Main loop of the httpd - a select() and then delegation to accept
2378 * connections, handle receiving of requests, and sending of replies.
2379 */
2380 static void httpd_poll(void) {
2381 fd_set recv_set, send_set;
2382 int max_fd, select_ret;
2383 struct connection *conn, *next;
2384 int bother_with_timeout = 0;
2385 struct timeval timeout;
2386
2387 timeout.tv_sec = idletime;
2388 timeout.tv_usec = 0;
2389
2390 FD_ZERO(&recv_set);
2391 FD_ZERO(&send_set);
2392 max_fd = 0;
2393
2394 /* set recv/send fd_sets */
2395 #define MAX_FD_SET(sock, fdset) { FD_SET(sock,fdset); \
2396 max_fd = (max_fd<sock) ? sock : max_fd; }
2397 MAX_FD_SET(sockin, &recv_set);
2398
2399 LIST_FOREACH_SAFE(conn, &connlist, entries, next) {
2400 poll_check_timeout(conn);
2401 switch (conn->state) {
2402 case DONE:
2403 /* do nothing */
2404 break;
2405
2406 case RECV_REQUEST:
2407 MAX_FD_SET(conn->socket, &recv_set);
2408 bother_with_timeout = 1;
2409 break;
2410
2411 case SEND_HEADER:
2412 case SEND_REPLY:
2413 MAX_FD_SET(conn->socket, &send_set);
2414 bother_with_timeout = 1;
2415 break;
2416 }
2417 }
2418 #undef MAX_FD_SET
2419
2420 /* -select- */
2421 select_ret = select(max_fd + 1, &recv_set, &send_set, NULL,
2422 (bother_with_timeout) ? &timeout : NULL);
2423 if (select_ret == 0) {
2424 if (!bother_with_timeout)
2425 errx(1, "select() timed out");
2426 else
2427 return;
2428 }
2429 if (select_ret == -1) {
2430 if (errno == EINTR)
2431 return; /* interrupted by signal */
2432 else
2433 err(1, "select() failed");
2434 }
2435
2436 /* update time */
2437 now = time(NULL);
2438
2439 /* poll connections that select() says need attention */
2440 if (FD_ISSET(sockin, &recv_set))
2441 accept_connection();
2442
2443 LIST_FOREACH_SAFE(conn, &connlist, entries, next) {
2444 switch (conn->state) {
2445 case RECV_REQUEST:
2446 if (FD_ISSET(conn->socket, &recv_set)) poll_recv_request(conn);
2447 break;
2448
2449 case SEND_HEADER:
2450 if (FD_ISSET(conn->socket, &send_set)) poll_send_header(conn);
2451 break;
2452
2453 case SEND_REPLY:
2454 if (FD_ISSET(conn->socket, &send_set)) poll_send_reply(conn);
2455 break;
2456
2457 case DONE:
2458 /* (handled later; ignore for now as it's a valid state) */
2459 break;
2460 }
2461
2462 if (conn->state == DONE) {
2463 /* clean out finished connection */
2464 if (conn->conn_close) {
2465 LIST_REMOVE(conn, entries);
2466 free_connection(conn);
2467 free(conn);
2468 } else {
2469 recycle_connection(conn);
2470 /* and go right back to recv_request without going through
2471 * select() again.
2472 */
2473 poll_recv_request(conn);
2474 }
2475 }
2476 }
2477 }
2478
2479 /* Daemonize helpers. */
2480 #define PATH_DEVNULL "/dev/null"
2481 static int lifeline[2] = { -1, -1 };
2482 static int fd_null = -1;
2483
2484 static void daemonize_start(void) {
2485 pid_t f;
2486
2487 if (pipe(lifeline) == -1)
2488 err(1, "pipe(lifeline)");
2489
2490 fd_null = open(PATH_DEVNULL, O_RDWR, 0);
2491 if (fd_null == -1)
2492 err(1, "open(" PATH_DEVNULL ")");
2493
2494 f = fork();
2495 if (f == -1)
2496 err(1, "fork");
2497 else if (f != 0) {
2498 /* parent: wait for child */
2499 char tmp[1];
2500 int status;
2501 pid_t w;
2502
2503 if (close(lifeline[1]) == -1)
2504 warn("close lifeline in parent");
2505 if (read(lifeline[0], tmp, sizeof(tmp)) == -1)
2506 warn("read lifeline in parent");
2507 w = waitpid(f, &status, WNOHANG);
2508 if (w == -1)
2509 err(1, "waitpid");
2510 else if (w == 0)
2511 /* child is running happily */
2512 exit(EXIT_SUCCESS);
2513 else
2514 /* child init failed, pass on its exit status */
2515 exit(WEXITSTATUS(status));
2516 }
2517 /* else we are the child: continue initializing */
2518 }
2519
2520 static void daemonize_finish(void) {
2521 if (fd_null == -1)
2522 return; /* didn't daemonize_start() so we're not daemonizing */
2523
2524 if (setsid() == -1)
2525 err(1, "setsid");
2526 if (close(lifeline[0]) == -1)
2527 warn("close read end of lifeline in child");
2528 if (close(lifeline[1]) == -1)
2529 warn("couldn't cut the lifeline");
2530
2531 /* close all our std fds */
2532 if (dup2(fd_null, STDIN_FILENO) == -1)
2533 warn("dup2(stdin)");
2534 if (dup2(fd_null, STDOUT_FILENO) == -1)
2535 warn("dup2(stdout)");
2536 if (dup2(fd_null, STDERR_FILENO) == -1)
2537 warn("dup2(stderr)");
2538 if (fd_null > 2)
2539 close(fd_null);
2540 }
2541
2542 /* [->] pidfile helpers, based on FreeBSD src/lib/libutil/pidfile.c,v 1.3
2543 * Original was copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
2544 */
2545 static int pidfile_fd = -1;
2546 #define PIDFILE_MODE 0600
2547
2548 static void pidfile_remove(void) {
2549 if (unlink(pidfile_name) == -1)
2550 err(1, "unlink(pidfile) failed");
2551 /* if (flock(pidfile_fd, LOCK_UN) == -1)
2552 err(1, "unlock(pidfile) failed"); */
2553 xclose(pidfile_fd);
2554 pidfile_fd = -1;
2555 }
2556
2557 static int pidfile_read(void) {
2558 char buf[16];
2559 int fd, i;
2560 long long pid;
2561
2562 fd = open(pidfile_name, O_RDONLY);
2563 if (fd == -1)
2564 err(1, " after create failed");
2565
2566 i = (int)read(fd, buf, sizeof(buf) - 1);
2567 if (i == -1)
2568 err(1, "read from pidfile failed");
2569 xclose(fd);
2570 buf[i] = '\0';
2571
2572 if (!str_to_num(buf, &pid)) {
2573 err(1, "invalid pidfile contents: \"%s\"", buf);
2574 }
2575 return (int)pid;
2576 }
2577
2578 static void pidfile_create(void) {
2579 int error, fd;
2580 char pidstr[16];
2581
2582 /* Open the PID file and obtain exclusive lock. */
2583 fd = open(pidfile_name,
2584 O_WRONLY | O_CREAT | O_EXLOCK | O_TRUNC | O_NONBLOCK, PIDFILE_MODE);
2585 if (fd == -1) {
2586 if ((errno == EWOULDBLOCK) || (errno == EEXIST))
2587 errx(1, "daemon already running with PID %d", pidfile_read());
2588 else
2589 err(1, "can't create pidfile %s", pidfile_name);
2590 }
2591 pidfile_fd = fd;
2592
2593 if (ftruncate(fd, 0) == -1) {
2594 error = errno;
2595 pidfile_remove();
2596 errno = error;
2597 err(1, "ftruncate() failed");
2598 }
2599
2600 snprintf(pidstr, sizeof(pidstr), "%d", (int)getpid());
2601 if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
2602 error = errno;
2603 pidfile_remove();
2604 errno = error;
2605 err(1, "pwrite() failed");
2606 }
2607 }
2608 /* [<-] end of pidfile helpers. */
2609
2610 /* Close all sockets and FILEs and exit. */
2611 static void stop_running(int sig unused) {
2612 running = 0;
2613 }
2614
2615 /* Execution starts here. */
2616 int main(int argc, char **argv) {
2617 printf("%s, %s.\n", pkgname, copyright);
2618 parse_default_extension_map();
2619 parse_commandline(argc, argv);
2620 /* parse_commandline() might override parts of the extension map by
2621 * parsing a user-specified file.
2622 */
2623 sort_mime_map();
2624 xasprintf(&keep_alive_field, "Keep-Alive: timeout=%d\r\n", idletime);
2625 if (want_server_id)
2626 xasprintf(&server_hdr, "Server: %s\r\n", pkgname);
2627 else
2628 server_hdr = xstrdup("");
2629 init_sockin();
2630
2631 /* open logfile */
2632 if (logfile_name == NULL)
2633 logfile = stdout;
2634 else {
2635 logfile = fopen(logfile_name, "ab");
2636 if (logfile == NULL)
2637 err(1, "opening logfile: fopen(\"%s\")", logfile_name);
2638 }
2639
2640 if (want_daemon)
2641 daemonize_start();
2642
2643 /* signals */
2644 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
2645 err(1, "signal(ignore SIGPIPE)");
2646 if (signal(SIGINT, stop_running) == SIG_ERR)
2647 err(1, "signal(SIGINT)");
2648 if (signal(SIGTERM, stop_running) == SIG_ERR)
2649 err(1, "signal(SIGTERM)");
2650
2651 /* security */
2652 if (want_chroot) {
2653 tzset(); /* read /etc/localtime before we chroot */
2654 if (chdir(wwwroot) == -1)
2655 err(1, "chdir(%s)", wwwroot);
2656 if (chroot(wwwroot) == -1)
2657 err(1, "chroot(%s)", wwwroot);
2658 printf("chrooted to `%s'\n", wwwroot);
2659 wwwroot[0] = '\0'; /* empty string */
2660 }
2661 if (drop_gid != INVALID_GID) {
2662 gid_t list[1];
2663 list[0] = drop_gid;
2664 if (setgroups(1, list) == -1)
2665 err(1, "setgroups([%d])", (int)drop_gid);
2666 if (setgid(drop_gid) == -1)
2667 err(1, "setgid(%d)", (int)drop_gid);
2668 printf("set gid to %d\n", (int)drop_gid);
2669 }
2670 if (drop_uid != INVALID_UID) {
2671 if (setuid(drop_uid) == -1)
2672 err(1, "setuid(%d)", (int)drop_uid);
2673 printf("set uid to %d\n", (int)drop_uid);
2674 }
2675
2676 /* create pidfile */
2677 if (pidfile_name) pidfile_create();
2678
2679 if (want_daemon) daemonize_finish();
2680
2681 /* main loop */
2682 while (running) httpd_poll();
2683
2684 /* clean exit */
2685 xclose(sockin);
2686 if (logfile != NULL) fclose(logfile);
2687 if (pidfile_name) pidfile_remove();
2688
2689 /* close and free connections */
2690 {
2691 struct connection *conn, *next;
2692
2693 LIST_FOREACH_SAFE(conn, &connlist, entries, next) {
2694 LIST_REMOVE(conn, entries);
2695 free_connection(conn);
2696 free(conn);
2697 }
2698 }
2699
2700 /* free the mallocs */
2701 {
2702 size_t i;
2703 for (i=0; i<mime_map_size; i++) {
2704 free(mime_map[i].extension);
2705 free(mime_map[i].mimetype);
2706 }
2707 free(mime_map);
2708 if (forward_map)
2709 free(forward_map);
2710 free(keep_alive_field);
2711 free(wwwroot);
2712 free(server_hdr);
2713 }
2714
2715 /* usage stats */
2716 {
2717 struct rusage r;
2718
2719 getrusage(RUSAGE_SELF, &r);
2720 printf("CPU time used: %u.%02u user, %u.%02u system\n",
2721 (unsigned int)r.ru_utime.tv_sec,
2722 (unsigned int)(r.ru_utime.tv_usec/10000),
2723 (unsigned int)r.ru_stime.tv_sec,
2724 (unsigned int)(r.ru_stime.tv_usec/10000)
2725 );
2726 printf("Requests: %llu\n", llu(num_requests));
2727 printf("Bytes: %llu in, %llu out\n", llu(total_in), llu(total_out));
2728 }
2729
2730 return 0;
2731 }
2732
2733 /* vim:set tabstop=4 shiftwidth=4 expandtab tw=78: */