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