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