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