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