2 * copyright (c) 2003-2008 Emil Mikulic.
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
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.
20 pkgname
[] = "darkhttpd/1.7",
21 copyright
[] = "copyright (c) 2003-2008 Emil Mikulic",
26 static const int debug
= 0;
28 static const int debug
= 1;
32 #define _GNU_SOURCE /* for strsignal() and vasprintf() */
33 #include <sys/sendfile.h>
37 #include <sys/sendfile.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
43 #include <sys/resource.h>
45 #include <sys/param.h>
46 #include <netinet/in.h>
47 #include <netinet/tcp.h>
48 #include <arpa/inet.h>
65 #define min(a,b) ( ((a)<(b)) ? (a) : (b) )
69 #define INADDR_NONE -1
72 #if defined(O_EXCL) && !defined(O_EXLOCK)
73 #define O_EXLOCK O_EXCL
76 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux)
79 /* err - prints "error: format: strerror(errno)" to stderr and exit()s with
83 err(const int code
, const char *format
, ...)
88 fprintf(stderr
, "error: ");
89 vfprintf(stderr
, format
, va
);
90 fprintf(stderr
, ": %s\n", strerror(errno
));
95 /* errx - err without the strerror */
97 errx(const int code
, const char *format
, ...)
101 va_start(va
, format
);
102 fprintf(stderr
, "error: ");
103 vfprintf(stderr
, format
, va
);
104 fprintf(stderr
, "\n");
109 /* warn - err without the exit */
111 warn(const char *format
, ...)
115 va_start(va
, format
);
116 fprintf(stderr
, "warning: ");
117 vfprintf(stderr
, format
, va
);
118 fprintf(stderr
, ": %s\n", strerror(errno
));
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.
128 * Under a BSD license.
130 #define LIST_HEAD(name, type) \
132 struct type *lh_first; /* first element */ \
135 #define LIST_HEAD_INITIALIZER(head) \
138 #define LIST_ENTRY(type) \
140 struct type *le_next; /* next element */ \
141 struct type **le_prev; /* address of previous next element */ \
144 #define LIST_FIRST(head) ((head)->lh_first)
146 #define LIST_FOREACH(var, head, field) \
147 for ((var) = LIST_FIRST((head)); \
149 (var) = LIST_NEXT((var), field))
151 #define LIST_FOREACH_SAFE(var, head, field, tvar) \
152 for ((var) = LIST_FIRST((head)); \
153 (var) && ((tvar) = LIST_NEXT((var), field), 1); \
156 #define LIST_INIT(head) do { \
157 LIST_FIRST((head)) = NULL; \
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)); \
167 #define LIST_NEXT(elm, field) ((elm)->field.le_next)
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); \
175 /* ------------------------------------------------------------------------ */
179 LIST_HEAD(conn_list_head
, connection
) connlist
=
180 LIST_HEAD_INITIALIZER(conn_list_head
);
184 LIST_ENTRY(connection
) entries
;
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 */
196 /* char request[request_length+1] is null-terminated */
198 size_t request_length
;
201 char *method
, *uri
, *referer
, *user_agent
;
202 size_t range_begin
, range_end
;
203 int range_begin_given
, range_end_given
;
206 size_t header_length
, header_sent
;
207 int header_dont_free
, header_only
, http_code
, conn_close
;
209 enum { REPLY_GENERATED
, REPLY_FROMFILE
} reply_type
;
213 size_t reply_start
, reply_length
, reply_sent
;
215 unsigned int total_sent
; /* header + body = total, for logging */
222 char *extension
, *mimetype
;
225 struct mime_mapping
*mime_map
= NULL
;
226 size_t mime_map_size
= 0;
227 size_t longest_ext
= 0;
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
235 static int idletime
= 60;
236 static char *keep_alive_field
= NULL
;
238 /* Time is cached in the event loop to avoid making an excessive number of
239 * gettimeofday() calls.
243 /* To prevent a malformed request from eating up too much memory, die once the
244 * request exceeds this many bytes:
246 #define MAX_REQUEST_LENGTH 4000
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";
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;
265 static int running
= 1; /* signal handler sets this to false */
267 #define INVALID_UID ((uid_t) -1)
268 #define INVALID_GID ((gid_t) -1)
270 static uid_t drop_uid
= INVALID_UID
;
271 static gid_t drop_gid
= INVALID_GID
;
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",
283 "image/jpeg" " jpeg jpe jpg",
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",
295 static const char default_mimetype
[] = "application/octet-stream";
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)
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
);
310 /* ---------------------------------------------------------------------------
311 * close that dies on error.
313 static void xclose(const int fd
)
315 if (close(fd
) == -1) err(1, "close()");
320 /* ---------------------------------------------------------------------------
321 * malloc that errx()s if it can't allocate.
323 static void *xmalloc(const size_t size
)
325 void *ptr
= malloc(size
);
326 if (ptr
== NULL
) errx(1, "can't allocate %u bytes", size
);
332 /* ---------------------------------------------------------------------------
333 * realloc() that errx()s if it can't allocate.
335 static void *xrealloc(void *original
, const size_t size
)
337 void *ptr
= realloc(original
, size
);
338 if (ptr
== NULL
) errx(1, "can't reallocate %u bytes", size
);
344 /* ---------------------------------------------------------------------------
345 * strdup() that errx()s if it can't allocate. Do this by hand since strdup()
348 static char *xstrdup(const char *src
)
350 size_t len
= strlen(src
) + 1;
351 char *dest
= xmalloc(len
);
352 memcpy(dest
, src
, len
);
358 #ifdef __sun /* unimpressed by Solaris */
359 static int vasprintf(char **strp
, const char *fmt
, va_list ap
)
362 int result
= vsnprintf(&tmp
, 1, fmt
, ap
);
363 *strp
= xmalloc(result
+1);
364 result
= vsnprintf(*strp
, result
+1, fmt
, ap
);
371 /* ---------------------------------------------------------------------------
372 * vasprintf() that errx()s if it fails.
374 static unsigned int xvasprintf(char **ret
, const char *format
, va_list ap
)
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
;
383 /* ---------------------------------------------------------------------------
384 * asprintf() that errx()s if it fails.
386 static unsigned int xasprintf(char **ret
, const char *format
, ...)
391 va_start(va
, format
);
392 len
= xvasprintf(ret
, format
, va
);
399 /* ---------------------------------------------------------------------------
400 * Append buffer code. A somewhat efficient string buffer with pool-based
403 #define APBUF_INIT 4096
404 #define APBUF_GROW APBUF_INIT
413 static struct apbuf
*make_apbuf(void)
415 struct apbuf
*buf
= xmalloc(sizeof(struct apbuf
));
417 buf
->pool
= APBUF_INIT
;
418 buf
->str
= xmalloc(buf
->pool
);
424 static void appendl(struct apbuf
*buf
, const char *s
, const size_t len
)
426 if (buf
->pool
< buf
->length
+ len
)
428 /* pool has dried up */
429 while (buf
->pool
< buf
->length
+ len
) buf
->pool
+= APBUF_GROW
;
430 buf
->str
= xrealloc(buf
->str
, buf
->pool
);
433 memcpy(buf
->str
+ buf
->length
, s
, len
);
440 #define append(buf, s) appendl(buf, s, \
441 (__builtin_constant_p(s) ? sizeof(s)-1 : strlen(s)) )
443 static void append(struct apbuf
*buf
, const char *s
)
445 appendl(buf
, s
, strlen(s
));
451 static void appendf(struct apbuf
*buf
, const char *format
, ...)
457 va_start(va
, format
);
458 len
= xvasprintf(&tmp
, format
, va
);
461 appendl(buf
, tmp
, len
);
467 /* ---------------------------------------------------------------------------
468 * Make the specified socket non-blocking.
471 nonblock_socket(const int sock
)
473 int flags
= fcntl(sock
, F_GETFL
, NULL
);
476 err(1, "fcntl(F_GETFL)");
478 if (fcntl(sock
, F_SETFL
, flags
) == -1)
479 err(1, "fcntl() to set O_NONBLOCK");
484 /* ---------------------------------------------------------------------------
485 * Split string out of src with range [left:right-1]
487 static char *split_string(const char *src
,
488 const size_t left
, const size_t right
)
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 */
495 dest
= xmalloc(right
- left
+ 1);
496 memcpy(dest
, src
+left
, right
-left
);
497 dest
[right
-left
] = '\0';
503 /* ---------------------------------------------------------------------------
504 * Consolidate slashes in-place by shifting parts of the string over repeated
507 static void consolidate_slashes(char *s
)
509 size_t left
= 0, right
= 0;
514 while (s
[right
] != '\0')
518 if (s
[right
] == '/') right
++;
522 s
[left
++] = s
[right
++];
527 if (s
[right
] == '/') saw_slash
++;
528 s
[left
++] = s
[right
++];
536 /* ---------------------------------------------------------------------------
537 * Resolve /./ and /../ in a URI, in-place. Returns NULL if the URI is
538 * invalid/unsafe, or the original buffer if successful.
540 static char *make_safe_uri(char *uri
)
546 unsigned int num_slashes
, num_chunks
;
547 size_t urilen
, i
, j
, pos
;
551 if (uri
[0] != '/') return NULL
;
552 consolidate_slashes(uri
);
553 urilen
= strlen(uri
);
555 ends_in_slash
= (uri
[urilen
-1] == '/');
559 /* count the slashes */
560 for (i
=0, num_slashes
=0; i
<urilen
; i
++)
561 if (uri
[i
] == '/') num_slashes
++;
563 /* make an array for the URI elements */
564 chunks
= xmalloc(sizeof(*chunks
) * num_slashes
);
566 /* split by slashes and build chunks array */
568 for (i
=1; i
<urilen
;) {
569 /* look for the next slash */
570 for (j
=i
; j
<urilen
&& uri
[j
] != '/'; j
++)
573 /* process uri[i,j) */
574 if ((j
== i
+1) && (uri
[i
] == '.'))
576 else if ((j
== i
+2) && (uri
[i
] == '.') && (uri
[i
+1] == '.')) {
578 if (num_chunks
== 0) {
579 /* unsafe string so free chunks */
585 chunks
[num_chunks
].start
= uri
+i
;
586 chunks
[num_chunks
].len
= j
-i
;
590 i
= j
+ 1; /* uri[j] is a slash - move along one */
593 /* reassemble in-place */
595 for (i
=0; i
<num_chunks
; i
++) {
596 assert(pos
<= urilen
);
599 assert(pos
+ chunks
[i
].len
<= urilen
);
600 assert(uri
+ pos
<= chunks
[i
].start
);
602 if (uri
+pos
< chunks
[i
].start
)
603 memmove(uri
+pos
, chunks
[i
].start
, chunks
[i
].len
);
604 pos
+= chunks
[i
].len
;
608 if ((num_chunks
== 0) || ends_in_slash
) uri
[pos
++] = '/';
609 assert(pos
<= urilen
);
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.
620 static void add_mime_mapping(const char *extension
, const char *mimetype
)
623 assert(strlen(extension
) > 0);
624 assert(strlen(mimetype
) > 0);
626 /* update longest_ext */
627 i
= strlen(extension
);
628 if (i
> longest_ext
) longest_ext
= i
;
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)
634 free(mime_map
[i
].mimetype
);
635 mime_map
[i
].mimetype
= xstrdup(mimetype
);
639 /* no replacement - add a new entry */
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
);
649 /* ---------------------------------------------------------------------------
650 * qsort() the mime_map. The map must be sorted before it can be searched
653 static int mime_mapping_cmp(const void *a
, const void *b
)
655 return strcmp( ((const struct mime_mapping
*)a
)->extension
,
656 ((const struct mime_mapping
*)b
)->extension
);
659 static void sort_mime_map(void)
661 qsort(mime_map
, mime_map_size
, sizeof(struct mime_mapping
),
667 /* ---------------------------------------------------------------------------
668 * Parses a mime.types line and adds the parsed data to the mime_map.
670 static void parse_mimetype_line(const char *line
)
672 unsigned int pad
, bound1
, lbound
, rbound
;
675 for (pad
=0; line
[pad
] == ' ' || line
[pad
] == '\t'; pad
++);
676 if (line
[pad
] == '\0' || /* empty line */
677 line
[pad
] == '#') /* comment */
681 line
[bound1
] != ' ' &&
682 line
[bound1
] != '\t';
685 if (line
[bound1
] == '\0') return; /* malformed line */
691 char *mimetype
, *extension
;
693 /* find beginning of extension */
694 for (; line
[lbound
] == ' ' || line
[lbound
] == '\t'; lbound
++);
695 if (line
[lbound
] == '\0') return; /* end of line */
697 /* find end of extension */
698 for (rbound
= lbound
;
699 line
[rbound
] != ' ' &&
700 line
[rbound
] != '\t' &&
701 line
[rbound
] != '\0';
704 mimetype
= split_string(line
, pad
, bound1
);
705 extension
= split_string(line
, lbound
, rbound
);
706 add_mime_mapping(extension
, mimetype
);
710 if (line
[rbound
] == '\0') return; /* end of line */
711 else lbound
= rbound
+ 1;
717 /* ---------------------------------------------------------------------------
718 * Adds contents of default_extension_map[] to mime_map list. The array must
719 * be NULL terminated.
721 static void parse_default_extension_map(void)
725 for (i
=0; default_extension_map
[i
] != NULL
; i
++)
726 parse_mimetype_line(default_extension_map
[i
]);
731 /* ---------------------------------------------------------------------------
732 * read_line - read a line from [fp], return its contents in a
733 * dynamically allocated buffer, not including the line ending.
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.
739 static char *read_line(FILE *fp
)
742 long startpos
, endpos
;
743 size_t linelen
, numread
;
746 startpos
= ftell(fp
);
747 if (startpos
== -1) err(1, "ftell()");
749 /* find end of line (or file) */
754 if (c
== EOF
|| c
== (int)'\n' || c
== (int)'\r') break;
758 /* return NULL on EOF (and empty line) */
759 if (linelen
== 0 && c
== EOF
) return NULL
;
762 if (endpos
== -1) err(1, "ftell()");
765 if (c
== (int)'\r' && fgetc(fp
) == (int)'\n') endpos
++;
767 buf
= (char*)xmalloc(linelen
+ 1);
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
);
775 /* terminate buffer */
778 /* advance file pointer over the endline */
779 if (fseek(fp
, endpos
, SEEK_SET
) == -1) err(1, "fseek()");
786 /* ---------------------------------------------------------------------------
787 * Removes the ending newline in a string, if there is one.
789 static void chomp(char *str
)
791 size_t len
= strlen(str
);
792 if (len
== 0) return;
793 if (str
[len
-1] == '\n') str
[len
-1] = '\0';
798 /* ---------------------------------------------------------------------------
799 * Adds contents of specified file to mime_map list.
801 static void parse_extension_map_file(const char *filename
)
804 FILE *fp
= fopen(filename
, "rb");
805 if (fp
== NULL
) err(1, "fopen(\"%s\")", filename
);
807 while ( (buf
= read_line(fp
)) != NULL
)
810 parse_mimetype_line(buf
);
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.
823 static int mime_mapping_cmp_str(const void *a
, const void *b
)
827 ((const struct mime_mapping
*)b
)->extension
831 static const char *uri_content_type(const char *uri
)
833 size_t period
, urilen
= strlen(uri
);
835 for (period
=urilen
-1;
837 uri
[period
] != '.' &&
838 (urilen
-period
-1) <= longest_ext
;
842 if (uri
[period
] == '.')
844 struct mime_mapping
*result
=
845 bsearch((uri
+period
+1), mime_map
, mime_map_size
,
846 sizeof(struct mime_mapping
), mime_mapping_cmp_str
);
850 assert(strcmp(uri
+period
+1, result
->extension
) == 0);
851 return result
->mimetype
;
854 /* else no period found in the string */
855 return default_mimetype
;
860 /* ---------------------------------------------------------------------------
861 * Initialize the sockin global. This is the socket that we accept
864 static void init_sockin(void)
866 struct sockaddr_in addrin
;
869 /* create incoming socket */
870 sockin
= socket(PF_INET
, SOCK_STREAM
, 0);
871 if (sockin
== -1) err(1, "socket()");
875 if (setsockopt(sockin
, SOL_SOCKET
, SO_REUSEADDR
,
876 &sockopt
, sizeof(sockopt
)) == -1)
877 err(1, "setsockopt(SO_REUSEADDR)");
880 /* disable Nagle since we buffer everything ourselves */
882 if (setsockopt(sockin
, IPPROTO_TCP
, TCP_NODELAY
,
883 &sockopt
, sizeof(sockopt
)) == -1)
884 err(1, "setsockopt(TCP_NODELAY)");
888 /* torture: cripple the kernel-side send buffer so we can only squeeze out
889 * one byte at a time (this is for debugging)
892 if (setsockopt(sockin
, SOL_SOCKET
, SO_SNDBUF
,
893 &sockopt
, sizeof(sockopt
)) == -1)
894 err(1, "setsockopt(SO_SNDBUF)");
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
);
906 printf("listening on %s:%u\n", inet_ntoa(addrin
.sin_addr
), bindport
);
908 /* listen on socket */
909 if (listen(sockin
, max_connections
) == -1)
912 /* enable acceptfilter (this is only available on FreeBSD) */
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",
922 printf("enabled acceptfilter\n");
924 printf("this platform doesn't support acceptfilter\n");
931 /* ---------------------------------------------------------------------------
932 * Prints a usage statement.
934 static void usage(void)
937 "usage: darkhttpd /path/to/wwwroot [options]\n\n"
940 "\t--port number (default: %u)\n" /* bindport */
941 "\t\tSpecifies which port to listen on for connections.\n"
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"
949 "\t--maxconn number (default: system maximum)\n"
950 "\t\tSpecifies how many concurrent connections to accept.\n"
953 "\t--log filename (default: no logging)\n"
954 "\t\tSpecifies which file to append the request log to.\n"
957 "\t--chroot (default: don't chroot)\n"
958 "\t\tLocks server into wwwroot directory for added security.\n"
961 "\t--daemon (default: don't daemonize)\n"
962 "\t\tDetach from the controlling terminal and run in the background.\n"
965 "\t--index filename (default: %s)\n" /* index_name */
966 "\t\tDefault file to serve when a directory is requested.\n"
969 "\t--mimetypes filename (optional)\n"
970 "\t\tParses specified file for extension-MIME associations.\n"
973 "\t--uid uid/uname, --gid gid/gname (default: don't privdrop)\n"
974 "\t\tDrops privileges to given uid:gid after initialization.\n"
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"
984 "\t--accf (default: don't use acceptfilter)\n"
985 "\t\tUse acceptfilter. Needs the accf_http module loaded.\n"
992 /* ---------------------------------------------------------------------------
993 * Returns 1 if string is a number, 0 otherwise. Set num to NULL if
994 * disinterested in value.
996 static int str_to_num(const char *str
, int *num
)
999 long l
= strtol(str
, &endptr
, 10);
1000 if (*endptr
!= '\0') return 0;
1002 if (num
!= NULL
) *num
= (int)l
;
1008 /* ---------------------------------------------------------------------------
1009 * Parses commandline options.
1011 static void parse_commandline(const int argc
, char *argv
[])
1015 if ((argc
< 2) || (argc
== 2 && strcmp(argv
[1], "--help") == 0))
1017 usage(); /* no wwwroot given */
1020 if (strcmp(argv
[1], "--version") == 0)
1032 wwwroot
= xstrdup(argv
[1]);
1033 /* Strip ending slash. */
1034 if (wwwroot
[strlen(wwwroot
)-1] == '/') wwwroot
[strlen(wwwroot
)-1] = '\0';
1036 /* walk through the remainder of the arguments (if any) */
1037 for (i
=2; i
<argc
; i
++)
1039 if (strcmp(argv
[i
], "--port") == 0)
1041 if (++i
>= argc
) errx(1, "missing number after --port");
1042 bindport
= (unsigned short)atoi(argv
[i
]);
1044 else if (strcmp(argv
[i
], "--addr") == 0)
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");
1051 else if (strcmp(argv
[i
], "--maxconn") == 0)
1053 if (++i
>= argc
) errx(1, "missing number after --maxconn");
1054 max_connections
= atoi(argv
[i
]);
1056 else if (strcmp(argv
[i
], "--log") == 0)
1058 if (++i
>= argc
) errx(1, "missing filename after --log");
1059 logfile_name
= argv
[i
];
1061 else if (strcmp(argv
[i
], "--chroot") == 0)
1065 else if (strcmp(argv
[i
], "--daemon") == 0)
1069 else if (strcmp(argv
[i
], "--index") == 0)
1071 if (++i
>= argc
) errx(1, "missing filename after --index");
1072 index_name
= argv
[i
];
1074 else if (strcmp(argv
[i
], "--mimetypes") == 0)
1076 if (++i
>= argc
) errx(1, "missing filename after --mimetypes");
1077 parse_extension_map_file(argv
[i
]);
1079 else if (strcmp(argv
[i
], "--uid") == 0)
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
);
1088 if (p
== NULL
) errx(1, "no such uid: `%s'", argv
[i
]);
1089 drop_uid
= p
->pw_uid
;
1091 else if (strcmp(argv
[i
], "--gid") == 0)
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
);
1100 if (g
== NULL
) errx(1, "no such gid: `%s'", argv
[i
]);
1101 drop_gid
= g
->gr_gid
;
1103 else if (strcmp(argv
[i
], "--pidfile") == 0)
1106 errx(1, "missing filename after --pidfile");
1107 pidfile_name
= argv
[i
];
1109 else if (strcmp(argv
[i
], "--accf") == 0)
1114 errx(1, "unknown argument `%s'", argv
[i
]);
1120 /* ---------------------------------------------------------------------------
1121 * Allocate and initialize an empty connection.
1123 static struct connection
*new_connection(void)
1125 struct connection
*conn
= xmalloc(sizeof(struct connection
));
1128 conn
->client
= INADDR_ANY
;
1129 conn
->last_active
= now
;
1130 conn
->request
= NULL
;
1131 conn
->request_length
= 0;
1132 conn
->method
= 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;
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;
1155 /* Make it harmless so it gets garbage-collected if it should, for some
1156 * reason, fail to be correctly filled out.
1165 /* ---------------------------------------------------------------------------
1166 * Accept a connection from sockin and add it to the connection queue.
1168 static void accept_connection(void)
1170 struct sockaddr_in addrin
;
1172 struct connection
*conn
;
1174 /* allocate and initialise struct connection */
1175 conn
= new_connection();
1177 sin_size
= sizeof(addrin
);
1178 memset(&addrin
, 0, sin_size
);
1179 conn
->socket
= accept(sockin
, (struct sockaddr
*)&addrin
,
1181 if (conn
->socket
== -1) err(1, "accept()");
1183 nonblock_socket(conn
->socket
);
1185 conn
->state
= RECV_REQUEST
;
1186 conn
->client
= addrin
.sin_addr
.s_addr
;
1187 LIST_INSERT_HEAD(&connlist
, conn
, entries
);
1189 if (debug
) printf("accepted connection from %s:%u\n",
1190 inet_ntoa(addrin
.sin_addr
),
1191 ntohs(addrin
.sin_port
) );
1193 /* try to read straight away rather than going through another iteration
1194 * of the select() loop.
1196 poll_recv_request(conn
);
1201 static void log_connection(const struct connection
*conn
);
1203 /* ---------------------------------------------------------------------------
1204 * Log a connection, then cleanly deallocate its internals.
1206 static void free_connection(struct connection
*conn
)
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
)
1218 if (conn
->reply
!= NULL
&& !conn
->reply_dont_free
) free(conn
->reply
);
1219 if (conn
->reply_fd
!= -1) xclose(conn
->reply_fd
);
1224 /* ---------------------------------------------------------------------------
1225 * Recycle a finished connection for HTTP/1.1 Keep-Alive.
1227 static void recycle_connection(struct connection
*conn
)
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
;
1235 /* don't reset conn->client */
1236 conn
->request
= NULL
;
1237 conn
->request_length
= 0;
1238 conn
->method
= 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;
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;
1261 conn
->state
= RECV_REQUEST
; /* ready for another */
1266 /* ---------------------------------------------------------------------------
1267 * Uppercasify all characters in a string of given length.
1269 static void strntoupper(char *str
, const size_t length
)
1272 for (i
=0; i
<length
; i
++)
1273 str
[i
] = toupper(str
[i
]);
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()
1282 static void poll_check_timeout(struct connection
*conn
)
1284 if (idletime
> 0) /* optimised away by compiler */
1286 if (now
- conn
->last_active
>= idletime
)
1288 if (debug
) printf("poll_check_timeout(%d) caused closure\n",
1290 conn
->conn_close
= 1;
1298 /* ---------------------------------------------------------------------------
1299 * Format [when] as an RFC1123 date, stored in the specified buffer. The same
1300 * buffer is returned for convenience.
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
)
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
);
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.
1318 static char *urldecode(const char *url
)
1320 size_t i
, len
= strlen(url
);
1321 char *out
= xmalloc(len
+1);
1324 for (i
=0, pos
=0; i
<len
; i
++)
1326 if (url
[i
] == '%' && i
+2 < len
&&
1327 isxdigit(url
[i
+1]) && isxdigit(url
[i
+2]))
1330 #define HEX_TO_DIGIT(hex) ( \
1331 ((hex) >= 'A' && (hex) <= 'F') ? ((hex)-'A'+10): \
1332 ((hex) >= 'a' && (hex) <= 'f') ? ((hex)-'a'+10): \
1335 out
[pos
++] = HEX_TO_DIGIT(url
[i
+1]) * 16 +
1336 HEX_TO_DIGIT(url
[i
+2]);
1344 out
[pos
++] = url
[i
];
1353 /* ---------------------------------------------------------------------------
1354 * A default reply for any (erroneous) occasion.
1356 static void default_reply(struct connection
*conn
,
1357 const int errcode
, const char *errname
, const char *format
, ...)
1359 char *reason
, date
[DATE_LEN
];
1362 va_start(va
, format
);
1363 xvasprintf(&reason
, format
, va
);
1366 /* Only really need to calculate the date once. */
1367 rfc1123_date(date
, now
);
1369 conn
->reply_length
= xasprintf(&(conn
->reply
),
1370 "<html><head><title>%d %s</title></head><body>\n"
1371 "<h1>%s</h1>\n" /* errname */
1374 "Generated by %s on %s\n"
1376 errcode
, errname
, errname
, reason
, pkgname
, date
);
1379 conn
->header_length
= xasprintf(&(conn
->header
),
1380 "HTTP/1.1 %d %s\r\n"
1383 "%s" /* keep-alive */
1384 "Content-Length: %d\r\n"
1385 "Content-Type: text/html\r\n"
1387 errcode
, errname
, date
, pkgname
, keep_alive(conn
),
1388 conn
->reply_length
);
1390 conn
->reply_type
= REPLY_GENERATED
;
1391 conn
->http_code
= errcode
;
1396 /* ---------------------------------------------------------------------------
1399 static void redirect(struct connection
*conn
, const char *format
, ...)
1401 char *where
, date
[DATE_LEN
];
1404 va_start(va
, format
);
1405 xvasprintf(&where
, format
, va
);
1408 /* Only really need to calculate the date once. */
1409 rfc1123_date(date
, now
);
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 */
1416 "Generated by %s on %s\n"
1418 where
, where
, pkgname
, date
);
1420 conn
->header_length
= xasprintf(&(conn
->header
),
1421 "HTTP/1.1 301 Moved Permanently\r\n"
1425 "%s" /* keep-alive */
1426 "Content-Length: %d\r\n"
1427 "Content-Type: text/html\r\n"
1429 date
, pkgname
, where
, keep_alive(conn
), conn
->reply_length
);
1432 conn
->reply_type
= REPLY_GENERATED
;
1433 conn
->http_code
= 301;
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
1443 * You need to remember to deallocate the result.
1444 * example: parse_field(conn, "Referer: ");
1446 static char *parse_field(const struct connection
*conn
, const char *field
)
1448 size_t bound1
, bound2
;
1452 pos
= strstr(conn
->request
, field
);
1453 if (pos
== NULL
) return NULL
;
1454 bound1
= pos
- conn
->request
+ strlen(field
);
1457 for (bound2
= bound1
;
1458 conn
->request
[bound2
] != '\r' &&
1459 bound2
< conn
->request_length
; bound2
++)
1462 /* copy to buffer */
1463 return split_string(conn
->request
, bound1
, bound2
);
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.
1473 static void parse_range_field(struct connection
*conn
)
1475 size_t bound1
, bound2
, len
;
1478 range
= parse_field(conn
, "Range: bytes=");
1479 if (range
== NULL
) return;
1480 len
= strlen(range
);
1482 do /* break handling */
1484 /* parse number up to hyphen */
1487 isdigit( (int)range
[bound2
] ) && bound2
< len
;
1491 if (bound2
== len
|| range
[bound2
] != '-')
1492 break; /* there must be a hyphen here */
1494 if (bound1
!= bound2
)
1496 conn
->range_begin_given
= 1;
1497 conn
->range_begin
= (size_t)strtol(range
+bound1
, NULL
, 10);
1501 /* parse number after hyphen */
1504 isdigit( (int)range
[bound2
] ) && bound2
< len
;
1508 if (bound2
!= len
&& range
[bound2
] != ',')
1509 break; /* must be end of string or a list to be valid */
1511 if (bound1
!= bound2
)
1513 conn
->range_end_given
= 1;
1514 conn
->range_end
= (size_t)strtol(range
+bound1
, NULL
, 10);
1517 while(0); /* break handling */
1520 /* sanity check: begin <= end */
1521 if (conn
->range_begin_given
&& conn
->range_end_given
&&
1522 (conn
->range_begin
> conn
->range_end
))
1524 conn
->range_begin_given
= conn
->range_end_given
= 0;
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.
1535 static int parse_request(struct connection
*conn
)
1537 size_t bound1
, bound2
;
1539 assert(conn
->request_length
== strlen(conn
->request
));
1542 for (bound1
= 0; bound1
< conn
->request_length
&&
1543 conn
->request
[bound1
] != ' '; bound1
++)
1546 conn
->method
= split_string(conn
->request
, 0, bound1
);
1547 strntoupper(conn
->method
, bound1
);
1550 for (; bound1
< conn
->request_length
&&
1551 conn
->request
[bound1
] == ' '; bound1
++)
1554 if (bound1
== conn
->request_length
) return 0; /* fail */
1556 for (bound2
=bound1
+1; bound2
< conn
->request_length
&&
1557 conn
->request
[bound2
] != ' ' &&
1558 conn
->request
[bound2
] != '\r'; bound2
++)
1561 conn
->uri
= split_string(conn
->request
, bound1
, bound2
);
1563 /* parse protocol to determine conn_close */
1564 if (conn
->request
[bound2
] == ' ')
1567 for (bound1
= bound2
; bound1
< conn
->request_length
&&
1568 conn
->request
[bound1
] == ' '; bound1
++)
1571 for (bound2
=bound1
+1; bound2
< conn
->request_length
&&
1572 conn
->request
[bound2
] != ' ' &&
1573 conn
->request
[bound2
] != '\r'; bound2
++)
1576 proto
= split_string(conn
->request
, bound1
, bound2
);
1577 if (strcasecmp(proto
, "HTTP/1.1") == 0) conn
->conn_close
= 0;
1581 /* parse connection field */
1582 tmp
= parse_field(conn
, "Connection: ");
1585 if (strcasecmp(tmp
, "close") == 0) conn
->conn_close
= 1;
1586 else if (strcasecmp(tmp
, "keep-alive") == 0) conn
->conn_close
= 0;
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
);
1599 /* ---------------------------------------------------------------------------
1600 * Check if a file exists.
1602 static int file_exists(const char *path
)
1604 struct stat filestat
;
1605 if ((stat(path
, &filestat
) == -1) && (errno
= ENOENT
))
1613 /* ---------------------------------------------------------------------------
1614 * Make sorted list of files in a directory. Returns number of entries, or -1
1624 static int dlent_cmp(const void *a
, const void *b
)
1626 return strcmp( (*((const struct dlent
* const *)a
))->name
,
1627 (*((const struct dlent
* const *)b
))->name
);
1630 static ssize_t
make_sorted_dirlist(const char *path
, struct dlent
***output
)
1634 size_t entries
= 0, pool
= 0;
1635 #define POOL_INCR 100
1637 struct dlent
**list
= NULL
;
1639 dir
= opendir(path
);
1640 if (dir
== NULL
) return -1;
1642 currname
= xmalloc(strlen(path
) + MAXNAMLEN
+ 1);
1644 /* construct list */
1645 while ((ent
= readdir(dir
)) != NULL
)
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 */
1656 if (entries
== pool
)
1659 list
= xrealloc(list
, sizeof(struct dlent
*) * pool
);
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
;
1669 (void)closedir(dir
); /* can't error out if opendir() succeeded */
1672 qsort(list
, entries
, sizeof(struct dlent
*), dlent_cmp
);
1673 *output
= xrealloc(list
, sizeof(struct dlent
*) * entries
);
1680 /* ---------------------------------------------------------------------------
1681 * Cleanly deallocate a sorted list of directory files.
1683 static void cleanup_sorted_dirlist(struct dlent
**list
, const ssize_t size
)
1686 for (i
=0; i
<size
; i
++)
1688 free(list
[i
]->name
);
1693 /* ---------------------------------------------------------------------------
1694 * Should this character be urlencoded (according to rfc1738)
1696 static int needs_urlencoding(unsigned char c
)
1699 const static char bad
[] = "<>\"%{}|^~[]`\\;:/?@#=&";
1701 for (i
=0; i
<sizeof(bad
)-1; i
++)
1705 /* Non-US-ASCII characters */
1706 if ((c
<= 0x1F) || (c
>= 0x80) || (c
== 0x7F))
1712 /* ---------------------------------------------------------------------------
1713 * Encode filename to be an rfc1738-compliant URL part
1715 static void urlencode_filename(unsigned char *name
, unsigned char *safe_url
)
1717 const static char hex
[] = "0123456789ABCDEF";
1720 for (i
= j
= 0; name
[i
] != '\0'; i
++)
1722 if (needs_urlencoding(name
[i
]))
1724 safe_url
[j
++] = '%';
1725 safe_url
[j
++] = hex
[(name
[i
] >> 4) & 0xF];
1726 safe_url
[j
++] = hex
[ name
[i
] & 0xF];
1729 safe_url
[j
++] = name
[i
];
1735 /* ---------------------------------------------------------------------------
1736 * Generate directory listing.
1738 static void generate_dir_listing(struct connection
*conn
, const char *path
)
1740 char date
[DATE_LEN
], *spaces
;
1741 struct dlent
**list
;
1745 struct apbuf
*listing
= make_apbuf();
1747 listsize
= make_sorted_dirlist(path
, &list
);
1750 default_reply(conn
, 500, "Internal Server Error",
1751 "Couldn't list directory: %s", strerror(errno
));
1755 for (i
=0; i
<listsize
; i
++)
1757 size_t tmp
= strlen(list
[i
]->name
);
1758 if (maxlen
< tmp
) maxlen
= tmp
;
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");
1767 spaces
= xmalloc(maxlen
);
1768 memset(spaces
, ' ', maxlen
);
1770 for (i
=0; i
<listsize
; i
++)
1772 /* If a filename is made up of entirely unsafe chars,
1773 * the url would be three times its original length.
1775 char safe_url
[MAXNAMLEN
*3 + 1];
1777 urlencode_filename(list
[i
]->name
, safe_url
);
1779 append(listing
, "<a href=\"");
1780 append(listing
, safe_url
);
1781 append(listing
, "\">");
1782 append(listing
, list
[i
]->name
);
1783 append(listing
, "</a>");
1785 if (list
[i
]->is_dir
)
1786 append(listing
, "/\n");
1789 appendl(listing
, spaces
, maxlen
-strlen(list
[i
]->name
));
1790 appendf(listing
, "%10d\n", list
[i
]->size
);
1794 cleanup_sorted_dirlist(list
, listsize
);
1798 rfc1123_date(date
, now
);
1803 append(listing
, pkgname
);
1804 append(listing
, " on ");
1805 append(listing
, date
);
1806 append(listing
, "\n</body>\n</html>\n");
1808 conn
->reply
= listing
->str
;
1809 conn
->reply_length
= listing
->length
;
1810 free(listing
); /* don't free inside of listing */
1812 conn
->header_length
= xasprintf(&(conn
->header
),
1813 "HTTP/1.1 200 OK\r\n"
1816 "%s" /* keep-alive */
1817 "Content-Length: %u\r\n"
1818 "Content-Type: text/html\r\n"
1820 date
, pkgname
, keep_alive(conn
), conn
->reply_length
);
1822 conn
->reply_type
= REPLY_GENERATED
;
1823 conn
->http_code
= 200;
1828 /* ---------------------------------------------------------------------------
1829 * Process a GET/HEAD request
1831 static void process_get(struct connection
*conn
)
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
;
1838 /* work out path of file being requested */
1839 decoded_url
= urldecode(conn
->uri
);
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
);
1849 /* does it end in a slash? serve up url/index_name */
1850 if (decoded_url
[strlen(decoded_url
)-1] == '/')
1852 xasprintf(&target
, "%s%s%s", wwwroot
, decoded_url
, index_name
);
1853 if (!file_exists(target
))
1856 xasprintf(&target
, "%s%s", wwwroot
, decoded_url
);
1857 generate_dir_listing(conn
, target
);
1862 mimetype
= uri_content_type(index_name
);
1864 else /* points to a file */
1866 xasprintf(&target
, "%s%s", wwwroot
, decoded_url
);
1867 mimetype
= uri_content_type(decoded_url
);
1870 if (debug
) printf("uri=%s, target=%s, content-type=%s\n",
1871 conn
->uri
, target
, mimetype
);
1874 conn
->reply_fd
= open(target
, O_RDONLY
| O_NONBLOCK
);
1877 if (conn
->reply_fd
== -1)
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
);
1887 default_reply(conn
, 500, "Internal Server Error",
1888 "The URI you requested (%s) cannot be returned: %s.",
1889 conn
->uri
, strerror(errno
));
1895 if (fstat(conn
->reply_fd
, &filestat
) == -1)
1897 default_reply(conn
, 500, "Internal Server Error",
1898 "fstat() failed: %s.", strerror(errno
));
1902 /* make sure it's a regular file */
1903 if (S_ISDIR(filestat
.st_mode
))
1905 redirect(conn
, "%s/", conn
->uri
);
1908 else if (!S_ISREG(filestat
.st_mode
))
1910 default_reply(conn
, 403, "Forbidden", "Not a regular file.");
1914 conn
->reply_type
= REPLY_FROMFILE
;
1915 (void) rfc1123_date(lastmod
, filestat
.st_mtime
);
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)
1922 if (debug
) printf("not modified since %s\n", if_mod_since
);
1923 default_reply(conn
, 304, "Not Modified", "");
1924 conn
->header_only
= 1;
1930 if (conn
->range_begin_given
|| conn
->range_end_given
)
1934 if (conn
->range_begin_given
&& conn
->range_end_given
)
1937 from
= conn
->range_begin
;
1938 to
= conn
->range_end
;
1940 /* clamp [to] to filestat.st_size-1 */
1941 if (to
> (size_t)(filestat
.st_size
-1))
1942 to
= filestat
.st_size
-1;
1944 else if (conn
->range_begin_given
&& !conn
->range_end_given
)
1946 /* 100- :: yields 100 to end */
1947 from
= conn
->range_begin
;
1948 to
= filestat
.st_size
-1;
1950 else if (!conn
->range_begin_given
&& conn
->range_end_given
)
1952 /* -200 :: yields last 200 */
1953 to
= filestat
.st_size
-1;
1954 from
= to
- conn
->range_end
+ 1;
1956 /* check for wrapping */
1957 if (from
> to
) from
= 0;
1959 else errx(1, "internal error - from/to mismatch");
1961 conn
->reply_start
= from
;
1962 conn
->reply_length
= to
- from
+ 1;
1964 conn
->header_length
= xasprintf(&(conn
->header
),
1965 "HTTP/1.1 206 Partial Content\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"
1975 rfc1123_date(date
, now
), pkgname
, keep_alive(conn
),
1976 conn
->reply_length
, from
, to
, filestat
.st_size
,
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
);
1984 else /* no range stuff */
1986 conn
->reply_length
= filestat
.st_size
;
1988 conn
->header_length
= xasprintf(&(conn
->header
),
1989 "HTTP/1.1 200 OK\r\n"
1992 "%s" /* keep-alive */
1993 "Content-Length: %d\r\n"
1994 "Content-Type: %s\r\n"
1995 "Last-Modified: %s\r\n"
1998 rfc1123_date(date
, now
), pkgname
, keep_alive(conn
),
1999 conn
->reply_length
, mimetype
, lastmod
2001 conn
->http_code
= 200;
2007 /* ---------------------------------------------------------------------------
2008 * Process a request: build the header and reply, advance state.
2010 static void process_request(struct connection
*conn
)
2013 if (!parse_request(conn
))
2015 default_reply(conn
, 400, "Bad Request",
2016 "You sent a request that the server couldn't understand.");
2018 else if (strcmp(conn
->method
, "GET") == 0)
2022 else if (strcmp(conn
->method
, "HEAD") == 0)
2025 conn
->header_only
= 1;
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)
2034 default_reply(conn
, 501, "Not Implemented",
2035 "The method you specified (%s) is not implemented.",
2040 default_reply(conn
, 400, "Bad Request",
2041 "%s is not a valid HTTP/1.1 method.", conn
->method
);
2045 conn
->state
= SEND_HEADER
;
2047 /* request not needed anymore */
2048 free(conn
->request
);
2049 conn
->request
= NULL
; /* important: don't free it again later */
2054 /* ---------------------------------------------------------------------------
2055 * Receiving request.
2057 static void poll_recv_request(struct connection
*conn
)
2059 #define BUFSIZE 65536
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
);
2070 if (errno
== EAGAIN
) {
2071 if (debug
) printf("poll_recv_request would have blocked\n");
2074 if (debug
) printf("recv(%d) error: %s\n",
2075 conn
->socket
, strerror(errno
));
2077 conn
->conn_close
= 1;
2081 conn
->last_active
= now
;
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;
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
);
2099 /* die if it's too long */
2100 if (conn
->request_length
> MAX_REQUEST_LENGTH
)
2102 default_reply(conn
, 413, "Request Entity Too Large",
2103 "Your request was dropped because it was too long.");
2104 conn
->state
= SEND_HEADER
;
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.
2110 if (conn
->state
== SEND_HEADER
)
2111 poll_send_header(conn
);
2116 /* ---------------------------------------------------------------------------
2117 * Sending header. Assumes conn->header is not NULL.
2119 static void poll_send_header(struct connection
*conn
)
2123 assert(conn
->state
== SEND_HEADER
);
2124 assert(conn
->header_length
== strlen(conn
->header
));
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
);
2132 /* handle any errors (-1) or closure (0) in send() */
2135 if ((sent
== -1) && (errno
== EAGAIN
)) {
2136 if (debug
) printf("poll_send_header would have blocked\n");
2139 if (debug
&& (sent
== -1))
2140 printf("send(%d) error: %s\n", conn
->socket
, strerror(errno
));
2141 conn
->conn_close
= 1;
2145 conn
->header_sent
+= sent
;
2146 conn
->total_sent
+= sent
;
2149 /* check if we're done sending header */
2150 if (conn
->header_sent
== conn
->header_length
)
2152 if (conn
->header_only
)
2155 conn
->state
= SEND_REPLY
;
2156 /* go straight on to body, don't go through another iteration of
2157 * the select() loop.
2159 poll_send_reply(conn
);
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
2172 static ssize_t
send_from_file(const int s
, const int fd
,
2173 off_t ofs
, const size_t size
)
2177 int ret
= sendfile(fd
, s
, ofs
, size
, NULL
, &sent
, 0);
2179 /* It is possible for sendfile to send zero bytes due to a blocking
2180 * condition. Handle this correctly.
2183 if (errno
== EAGAIN
)
2193 #if defined(__linux) || defined(__sun__)
2194 return sendfile(s
, fd
, &ofs
, size
);
2196 #define BUFSIZE 20000
2198 size_t amount
= min((size_t)BUFSIZE
, size
);
2202 if (lseek(fd
, ofs
, SEEK_SET
) == -1) err(1, "fseek(%d)", (int)ofs
);
2203 numread
= read(fd
, buf
, amount
);
2206 fprintf(stderr
, "premature eof on fd %d\n", fd
);
2209 else if (numread
== -1)
2211 fprintf(stderr
, "error reading on fd %d: %s", fd
, strerror(errno
));
2214 else if ((size_t)numread
!= amount
)
2216 fprintf(stderr
, "read %d bytes, expecting %u bytes on fd %d\n",
2217 numread
, amount
, fd
);
2221 return send(s
, buf
, amount
, 0);
2228 /* ---------------------------------------------------------------------------
2231 static void poll_send_reply(struct connection
*conn
)
2235 assert(conn
->state
== SEND_REPLY
);
2236 assert(!conn
->header_only
);
2237 if (conn
->reply_type
== REPLY_GENERATED
)
2239 sent
= send(conn
->socket
,
2240 conn
->reply
+ conn
->reply_start
+ conn
->reply_sent
,
2241 conn
->reply_length
- conn
->reply_sent
, 0);
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
);
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
);
2256 /* handle any errors (-1) or closure (0) in send() */
2261 if (errno
== EAGAIN
) {
2262 if (debug
) printf("poll_send_reply would have blocked\n");
2265 if (debug
) printf("send(%d) error: %s\n",
2266 conn
->socket
, strerror(errno
));
2270 if (debug
) printf("send(%d) closure\n", conn
->socket
);
2272 conn
->conn_close
= 1;
2276 conn
->reply_sent
+= (unsigned int)sent
;
2277 conn
->total_sent
+= (unsigned int)sent
;
2280 /* check if we're done sending */
2281 if (conn
->reply_sent
== conn
->reply_length
) conn
->state
= DONE
;
2286 /* ---------------------------------------------------------------------------
2287 * Add a connection's details to the logfile.
2289 static void log_connection(const struct connection
*conn
)
2291 struct in_addr inaddr
;
2293 if (logfile
== NULL
)
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 */
2300 /* Separated by tabs:
2301 * time client_ip method uri http_code bytes_sent "referer" "user-agent"
2304 inaddr
.s_addr
= conn
->client
;
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
2318 /* ---------------------------------------------------------------------------
2319 * Main loop of the httpd - a select() and then delegation to accept
2320 * connections, handle receiving of requests, and sending of replies.
2322 static void httpd_poll(void)
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
;
2330 timeout
.tv_sec
= idletime
;
2331 timeout
.tv_usec
= 0;
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; }
2341 MAX_FD_SET(sockin
, &recv_set
);
2343 LIST_FOREACH_SAFE(conn
, &connlist
, entries
, next
)
2345 poll_check_timeout(conn
);
2346 switch (conn
->state
)
2353 MAX_FD_SET(conn
->socket
, &recv_set
);
2354 bother_with_timeout
= 1;
2359 MAX_FD_SET(conn
->socket
, &send_set
);
2360 bother_with_timeout
= 1;
2363 default: errx(1, "invalid state");
2369 select_ret
= select(max_fd
+ 1, &recv_set
, &send_set
, NULL
,
2370 (bother_with_timeout
) ? &timeout
: NULL
);
2371 if (select_ret
== 0)
2373 if (!bother_with_timeout
)
2374 errx(1, "select() timed out");
2378 if (select_ret
== -1) {
2380 return; /* interrupted by signal */
2382 err(1, "select() failed");
2388 /* poll connections that select() says need attention */
2389 if (FD_ISSET(sockin
, &recv_set
)) accept_connection();
2391 LIST_FOREACH_SAFE(conn
, &connlist
, entries
, next
)
2393 switch (conn
->state
)
2396 if (FD_ISSET(conn
->socket
, &recv_set
)) poll_recv_request(conn
);
2400 if (FD_ISSET(conn
->socket
, &send_set
)) poll_send_header(conn
);
2404 if (FD_ISSET(conn
->socket
, &send_set
)) poll_send_reply(conn
);
2408 /* (handled later; ignore for now as it's a valid state) */
2411 default: errx(1, "invalid state");
2414 if (conn
->state
== DONE
) {
2415 /* clean out finished connection */
2416 if (conn
->conn_close
) {
2417 LIST_REMOVE(conn
, entries
);
2418 free_connection(conn
);
2421 recycle_connection(conn
);
2422 /* and go right back to recv_request without going through
2425 poll_recv_request(conn
);
2433 /* ---------------------------------------------------------------------------
2434 * Daemonize helpers.
2436 #define PATH_DEVNULL "/dev/null"
2437 static int lifeline
[2] = { -1, -1 };
2438 static int fd_null
= -1;
2441 daemonize_start(void)
2445 if (pipe(lifeline
) == -1)
2446 err(1, "pipe(lifeline)");
2448 fd_null
= open(PATH_DEVNULL
, O_RDWR
, 0);
2450 err(1, "open(" PATH_DEVNULL
")");
2456 /* parent: wait for child */
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
);
2467 /* child is running happily */
2470 /* child init failed, pass on its exit status */
2471 exit(WEXITSTATUS(status
));
2473 /* else we are the child: continue initializing */
2477 daemonize_finish(void)
2480 return; /* didn't daemonize_start() so we're not daemonizing */
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");
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)");
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>
2504 static int pidfile_fd
= -1;
2505 #define PIDFILE_MODE 0600
2508 pidfile_remove(void)
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"); */
2521 char buf
[16], *endptr
;
2524 fd
= open(pidfile_name
, O_RDONLY
);
2526 err(1, " after create failed");
2528 i
= read(fd
, buf
, sizeof(buf
) - 1);
2530 err(1, "read from pidfile failed");
2534 pid
= (int)strtoul(buf
, &endptr
, 10);
2535 if (endptr
!= &buf
[i
])
2536 err(1, "invalid pidfile contents: \"%s\"", buf
);
2541 pidfile_create(void)
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
);
2550 if ((errno
== EWOULDBLOCK
) || (errno
== EEXIST
))
2551 errx(1, "daemon already running with PID %d", pidfile_read());
2553 err(1, "can't create pidfile %s", pidfile_name
);
2557 if (ftruncate(fd
, 0) == -1) {
2561 err(1, "ftruncate() failed");
2564 snprintf(pidstr
, sizeof(pidstr
), "%u", getpid());
2565 if (pwrite(fd
, pidstr
, strlen(pidstr
), 0) != (ssize_t
)strlen(pidstr
)) {
2569 err(1, "pwrite() failed");
2573 /* end of pidfile helpers.
2574 * ---------------------------------------------------------------------------
2575 * Close all sockets and FILEs and exit.
2578 stop_running(int sig
)
2581 fprintf(stderr
, "\ncaught %s, stopping\n", strsignal(sig
));
2584 /* ---------------------------------------------------------------------------
2585 * Execution starts here.
2588 main(int argc
, char **argv
)
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.
2597 xasprintf(&keep_alive_field
, "Keep-Alive: timeout=%d\r\n", idletime
);
2601 if (logfile_name
!= NULL
)
2603 logfile
= fopen(logfile_name
, "ab");
2604 if (logfile
== NULL
)
2605 err(1, "opening logfile: fopen(\"%s\")", logfile_name
);
2608 if (want_daemon
) daemonize_start();
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)");
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 */
2631 if (drop_gid
!= INVALID_GID
)
2633 if (setgid(drop_gid
) == -1) err(1, "setgid(%d)", drop_gid
);
2634 printf("set gid to %d\n", drop_gid
);
2636 if (drop_uid
!= INVALID_UID
)
2638 if (setuid(drop_uid
) == -1) err(1, "setuid(%d)", drop_uid
);
2639 printf("set uid to %d\n", drop_uid
);
2642 /* create pidfile */
2643 if (pidfile_name
) pidfile_create();
2645 if (want_daemon
) daemonize_finish();
2648 while (running
) httpd_poll();
2652 if (logfile
!= NULL
) fclose(logfile
);
2653 if (pidfile_name
) pidfile_remove();
2655 /* close and free connections */
2657 struct connection
*conn
, *next
;
2659 LIST_FOREACH_SAFE(conn
, &connlist
, entries
, next
)
2661 LIST_REMOVE(conn
, entries
);
2662 free_connection(conn
);
2667 /* free the mallocs */
2670 for (i
=0; i
<mime_map_size
; i
++)
2672 free(mime_map
[i
].extension
);
2673 free(mime_map
[i
].mimetype
);
2676 free(keep_alive_field
);
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)
2691 printf("Requests: %u\n", num_requests
);
2692 printf("Bytes: %llu in, %llu out\n", total_in
, total_out
);
2698 /* vim:set tabstop=4 shiftwidth=4 expandtab tw=78: */