From 6801bf4ff6b4768d779849eab9b36361e2782d13 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Thu, 24 Jul 2014 09:55:33 +0200 Subject: sync --- config.c | 8 +-- httpd.8 | 9 ++- httpd.c | 71 ++++++++++++++++++++++- httpd.conf.5 | 18 +++--- httpd.h | 16 ++++-- parse.y | 3 +- server.c | 81 +++++++++++++++----------- server_file.c | 178 ++++++++++++++++++++++++++++++++++++++++++---------------- server_http.c | 56 +++++++++--------- 9 files changed, 305 insertions(+), 135 deletions(-) diff --git a/config.c b/config.c index 230ec35..8dd395d 100644 --- a/config.c +++ b/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.2 2014/07/13 14:17:37 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.3 2014/07/23 13:26:39 reyk Exp $ */ /* * Copyright (c) 2011 - 2014 Reyk Floeter @@ -90,10 +90,8 @@ config_purge(struct httpd *env, u_int reset) what = ps->ps_what[privsep_process] & reset; if (what & CONFIG_SERVERS && env->sc_servers != NULL) { - while ((srv = TAILQ_FIRST(env->sc_servers)) != NULL) { - TAILQ_REMOVE(env->sc_servers, srv, srv_entry); - free(srv); - } + while ((srv = TAILQ_FIRST(env->sc_servers)) != NULL) + server_purge(srv); } if (what & CONFIG_MEDIA && env->sc_mediatypes != NULL) diff --git a/httpd.8 b/httpd.8 index 3c996e7..a62378d 100644 --- a/httpd.8 +++ b/httpd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: httpd.8,v 1.36 2014/07/12 23:34:54 reyk Exp $ +.\" $OpenBSD: httpd.8,v 1.39 2014/07/22 19:03:21 jmc Exp $ .\" .\" Copyright (c) 2014 Reyk Floeter .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: July 12 2014 $ +.Dd $Mdocdate: July 22 2014 $ .Dt HTTPD 8 .Os .Sh NAME @@ -28,7 +28,6 @@ .Sh DESCRIPTION .Nm is a simple HTTP server that serves static files. -.El .Sh FILES .Bl -tag -width "/var/run/httpd.sockXX" -compact .It /etc/httpd.conf @@ -36,10 +35,10 @@ Default configuration file. .It /var/run/httpd.sock .Ux Ns -domain socket used for communication with -.Xr httpctl 8 . +.Nm . .El .Sh SEE ALSO -.Xr httpd.conf 5 , +.Xr httpd.conf 5 .Sh HISTORY .Nm is based on diff --git a/httpd.c b/httpd.c index f8f0323..c87c2ad 100644 --- a/httpd.c +++ b/httpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.c,v 1.2 2014/07/13 14:17:37 reyk Exp $ */ +/* $OpenBSD: httpd.c,v 1.6 2014/07/23 23:10:27 reyk Exp $ */ /* * Copyright (c) 2014 Reyk Floeter @@ -465,6 +465,70 @@ canonicalize_host(const char *host, char *name, size_t len) return (NULL); } +const char * +canonicalize_path(const char *root, const char *input, char *path, size_t len) +{ + const char *i; + char *p, *start, *end; + size_t n; + + /* assuming input starts with '/' and is nul-terminated */ + i = input; + p = path; + + /* prepend root directory, if specified */ + if (root != NULL) { + if ((n = strlcpy(path, root, len)) >= len) + return (NULL); + len -= n; + p += n; + } + + if (*input != '/' || len < 3) + return (NULL); + + start = p; + end = p + (len - 1); + + while (*i != '\0') { + /* Detect truncation */ + if (p >= end) + return (NULL); + + /* 1. check for special path elements */ + if (i[0] == '/') { + if (i[1] == '/') { + /* a) skip repeating '//' slashes */ + while (i[1] == '/') + i++; + continue; + } else if (i[1] == '.' && i[2] == '.' && + (i[3] == '/' || i[3] == '\0')) { + /* b) revert '..' to previous directory */ + i += 3; + while (p > start && *p != '/') + p--; + *p = '\0'; + continue; + } else if (i[1] == '.' && + (i[2] == '/' || i[2] == '\0')) { + /* c) skip unnecessary '.' current dir */ + i += 2; + continue; + } + } + + /* 2. copy any other characters */ + *p++ = *i; + i++; + } + if (p == start) + *p++ = '/'; + *p++ = '\0'; + + return (path); +} + void socket_rlimit(int maxfd) { @@ -757,6 +821,11 @@ media_add(struct mediatypes *types, struct media_type *media) return (NULL); memcpy(entry, media, sizeof(*entry)); + if (media->media_encoding != NULL && + (entry->media_encoding = strdup(media->media_encoding)) == NULL) { + free(entry); + return (NULL); + } RB_INSERT(mediatypes, types, entry); return (entry); diff --git a/httpd.conf.5 b/httpd.conf.5 index a6f90a6..afef082 100644 --- a/httpd.conf.5 +++ b/httpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: httpd.conf.5,v 1.2 2014/07/13 14:17:37 reyk Exp $ +.\" $OpenBSD: httpd.conf.5,v 1.5 2014/07/22 19:03:21 jmc Exp $ .\" .\" Copyright (c) 2014 Reyk Floeter .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: July 13 2014 $ +.Dd $Mdocdate: July 22 2014 $ .Dt HTTPD.CONF 5 .Os .Sh NAME @@ -121,7 +121,7 @@ Configure the supported media types. .Nm httpd will set the .Ar Content-Type -of the response header based on the file extension that is listed in the +of the response header based on the file extension listed in the .Ic types section. If not specified, @@ -140,7 +140,7 @@ The .Ic types section must include one or more lines of the following syntax: .Bl -tag -width Ds -.It Ar type/subtype Ar name Oo Ar name ... Oc Ic ; +.It Ar type/subtype Ar name Op Ar name ... ; Set the media .Ar type and @@ -149,7 +149,7 @@ to the specified extension .Ar name . One or more names can be specified per line. .El -.Sh EAMPLES +.Sh EXAMPLES The following example will start two pre-forked servers that are listening on the primary IP address of the network interface that is a member of the @@ -165,7 +165,7 @@ server "default" { types { text/css css; - text/html html html; + text/html htm html; text/txt txt; image/gif gif; image/jpeg jpg jpeg; @@ -175,16 +175,16 @@ types { } .Ed .Pp -The syntax of the types section is compatible to the format that is used by +The syntax of the types section is compatible with the format used by .Xr nginx 8 , -so you can optionally include its +so it is possible to include its .Pa mime.types file directly: .Bd -literal -offset indent include "/etc/nginx/mime.types" .Ed .Sh SEE ALSO -.Xr httpd 8 . +.Xr httpd 8 .Sh AUTHORS .An -nosplit The diff --git a/httpd.h b/httpd.h index 79e89fa..ae275bf 100644 --- a/httpd.h +++ b/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.3 2014/07/14 00:19:48 reyk Exp $ */ +/* $OpenBSD: httpd.h,v 1.7 2014/07/23 19:03:56 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -31,6 +31,8 @@ #define HTTPD_SOCKET "/var/run/httpd.sock" #define HTTPD_USER "www" #define HTTPD_SERVERNAME "OpenBSD httpd" +#define HTTPD_DOCROOT "/htdocs" +#define HTTPD_INDEX "index.html" #define FD_RESERVE 5 #define SERVER_MAX_CLIENTS 1024 @@ -72,7 +74,7 @@ enum httpchunk { TOREAD_HTTP_NONE = -5 }; -#if DEBUG > 1 +#if DEBUG #define DPRINTF log_debug #else #define DPRINTF(x...) do {} while(0) @@ -265,10 +267,11 @@ struct client { struct bufferevent *clt_file; off_t clt_toread; + size_t clt_headerlen; int clt_persist; int clt_line; - size_t clt_headerlen; int clt_done; + int clt_inflight; struct evbuffer *clt_log; struct timeval clt_timeout; @@ -341,8 +344,6 @@ struct httpd { #define HTTPD_OPT_LOGNOTIFY 0x10 #define HTTPD_OPT_LOGALL 0x18 -extern volatile int server_inflight; - /* control.c */ int control_init(struct privsep *, struct control_sock *); int control_listen(struct control_sock *); @@ -363,6 +364,7 @@ int cmdline_symset(char *); /* server.c */ pid_t server(struct privsep *, struct privsep_proc *); int server_privinit(struct server *); +void server_purge(struct server *); int server_socket_af(struct sockaddr_storage *, in_port_t); in_port_t server_socket_getport(struct sockaddr_storage *); @@ -379,6 +381,7 @@ int server_bufferevent_write_chunk(struct client *, struct evbuffer *, size_t); int server_bufferevent_add(struct event *, int); int server_bufferevent_write(struct client *, void *, size_t); +void server_inflight_dec(struct client *, const char *); SPLAY_PROTOTYPE(client_tree, client, clt_nodes, server_client_cmp); @@ -400,7 +403,7 @@ int server_writeheader_http(struct client *); int server_writeresponse_http(struct client *); int server_response_http(struct client *, u_int, struct media_type *, size_t); -void server_reset_http(struct client *, int); +void server_reset_http(struct client *); void server_close_http(struct client *); int server_response(struct httpd *, struct client *); @@ -412,6 +415,7 @@ void event_again(struct event *, int, short, void (*)(int, short, void *), struct timeval *, struct timeval *, void *); const char *canonicalize_host(const char *, char *, size_t); +const char *canonicalize_path(const char *, const char *, char *, size_t); void imsg_event_add(struct imsgev *); int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t, pid_t, int, void *, u_int16_t); diff --git a/parse.y b/parse.y index ec2be91..be355af 100644 --- a/parse.y +++ b/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.2 2014/07/13 14:17:37 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.3 2014/07/23 22:02:02 reyk Exp $ */ /* * Copyright (c) 2007 - 2014 Reyk Floeter @@ -820,6 +820,7 @@ load_config(const char *filename, struct httpd *x_conf) (void)strlcpy(m.media_subtype, mediatypes[i].media_subtype, sizeof(m.media_subtype)); + m.media_encoding = NULL; if (media_add(conf->sc_mediatypes, &m) == NULL) { log_warnx("failed to add default media \"%s\"", diff --git a/server.c b/server.c index 876849b..38151ea 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.5 2014/07/14 00:19:48 reyk Exp $ */ +/* $OpenBSD: server.c,v 1.7 2014/07/23 13:26:39 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -148,6 +148,28 @@ server_launch(void) } } +void +server_purge(struct server *srv) +{ + struct client *clt; + + /* shutdown and remove server */ + if (event_initialized(&srv->srv_ev)) + event_del(&srv->srv_ev); + if (evtimer_initialized(&srv->srv_evt)) + evtimer_del(&srv->srv_evt); + + close(srv->srv_s); + TAILQ_REMOVE(env->sc_servers, srv, srv_entry); + + /* cleanup sessions */ + while ((clt = + SPLAY_ROOT(&srv->srv_clients)) != NULL) + server_close(clt, NULL); + + free(srv); +} + int server_socket_af(struct sockaddr_storage *ss, in_port_t port) { @@ -389,7 +411,6 @@ void server_error(struct bufferevent *bev, short error, void *arg) { struct client *clt = arg; - struct evbuffer *dst; if (error & EVBUFFER_TIMEOUT) { server_close(clt, "buffer event timeout"); @@ -403,20 +424,7 @@ server_error(struct bufferevent *bev, short error, void *arg) bufferevent_disable(bev, EV_READ|EV_WRITE); clt->clt_done = 1; - - if (bev != clt->clt_bev) { - dst = EVBUFFER_OUTPUT(clt->clt_bev); - if (EVBUFFER_LENGTH(dst)) - return; - } else - return; - - if (clt->clt_persist) { - server_reset_http(clt, 1); - bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE); - return; - } else - server_close(clt, "done"); + server_close(clt, "done"); return; } server_close(clt, "buffer event error"); @@ -448,8 +456,7 @@ server_accept(int fd, short event, void *arg) event_del(&srv->srv_ev); evtimer_add(&srv->srv_evt, &evtpause); - log_debug("%s: deferring connections %d", - __func__, getdtablecount()); + log_debug("%s: deferring connections", __func__); } return; } @@ -469,6 +476,7 @@ server_accept(int fd, short event, void *arg) clt->clt_id = ++server_cltid; clt->clt_serverid = srv->srv_conf.id; clt->clt_pid = getpid(); + clt->clt_inflight = 1; switch (ss.ss_family) { case AF_INET: clt->clt_port = ((struct sockaddr_in *)&ss)->sin_port; @@ -514,12 +522,26 @@ server_accept(int fd, short event, void *arg) * the client struct was not completly set up, but still * counted as an inflight client. account for this. */ - server_inflight--; - log_debug("%s: inflight decremented, now %d", - __func__, server_inflight); + server_inflight_dec(clt, __func__); } } +void +server_inflight_dec(struct client *clt, const char *why) +{ + if (clt != NULL) { + /* the flight already left inflight mode. */ + if (clt->clt_inflight == 0) + return; + clt->clt_inflight = 0; + } + + /* the file was never opened, thus this was an inflight client. */ + server_inflight--; + log_debug("%s: inflight decremented, now %d, %s", + __func__, server_inflight, why); +} + void server_close(struct client *clt, const char *msg) { @@ -556,23 +578,14 @@ server_close(struct client *clt, const char *msg) else if (clt->clt_output != NULL) evbuffer_free(clt->clt_output); - if (clt->clt_s != -1) { - close(clt->clt_s); - if (clt->clt_fd == -1 && 0) { - /* - * the output was never connected, - * thus this was an inflight client. - */ - server_inflight--; - log_debug("%s: clients inflight decremented, now %d", - __func__, server_inflight); - } - } - if (clt->clt_file != NULL) bufferevent_free(clt->clt_file); if (clt->clt_fd != -1) close(clt->clt_fd); + if (clt->clt_s != -1) + close(clt->clt_s); + + server_inflight_dec(clt, __func__); if (clt->clt_log != NULL) evbuffer_free(clt->clt_log); diff --git a/server_file.c b/server_file.c index 74a7106..980efa4 100644 --- a/server_file.c +++ b/server_file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_file.c,v 1.4 2014/07/14 00:19:48 reyk Exp $ */ +/* $OpenBSD: server_file.c,v 1.10 2014/07/23 22:20:37 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -46,6 +46,75 @@ #include "httpd.h" #include "http.h" +int server_file_access(struct http_descriptor *, char *, size_t, + struct stat *); +void server_file_error(struct bufferevent *, short, void *); + +int +server_file_access(struct http_descriptor *desc, char *path, size_t len, + struct stat *st) +{ + errno = 0; + if (access(path, R_OK) == -1) { + goto fail; + } else if (stat(path, st) == -1) { + goto fail; + } else if (S_ISDIR(st->st_mode)) { + /* XXX Should we support directory listing? */ + + if (!len) { + /* Recursion - the index "file" is a directory? */ + errno = EINVAL; + goto fail; + } + + /* Redirect to path with trailing "/" */ + if (path[strlen(path) - 1] != '/') { + /* Remove the document root to get the relative URL */ + if (canonicalize_path(NULL, + desc->http_path, path, len) == NULL || + strlcat(path, "/", len) >= len) { + errno = EINVAL; + goto fail; + } + + /* Indicate that the file has been moved */ + return (301); + } + + /* Otherwise append the default index file */ + if (strlcat(path, HTTPD_INDEX, len) >= len) { + errno = EACCES; + goto fail; + } + + /* Check again but set len to 0 to avoid recursion */ + return (server_file_access(desc, path, 0, st)); + } else if (!S_ISREG(st->st_mode)) { + /* Don't follow symlinks and ignore special files */ + errno = EACCES; + goto fail; + } + + return (0); + + fail: + /* Remove the document root */ + if (len && canonicalize_path(NULL, desc->http_path, path, len) == NULL) + return (500); + + switch (errno) { + case ENOENT: + return (404); + case EACCES: + return (403); + default: + return (500); + } + + /* NOTREACHED */ +} + int server_file(struct httpd *env, struct client *clt) { @@ -57,58 +126,26 @@ server_file(struct httpd *env, struct client *clt) char path[MAXPATHLEN]; struct stat st; - /* - * XXX This is not ready XXX - * XXX Don't expect anything from this code yet, - */ - - strlcpy(path, "/htdocs", sizeof(path)); - if (desc->http_path[0] != '/') - strlcat(path, "/", sizeof(path)); - strlcat(path, desc->http_path, sizeof(path)); - if (desc->http_path[strlen(desc->http_path) - 1] == '/') - strlcat(path, "index.html", sizeof(path)); - - if (access(path, R_OK) == -1) { - switch (errno) { - case EACCES: - server_abort_http(clt, 403, path); - break; - case ENOENT: - server_abort_http(clt, 404, path); - break; - default: - server_abort_http(clt, 500, path); - break; - } + if (canonicalize_path(HTTPD_DOCROOT, + desc->http_path, path, sizeof(path)) == NULL) { + /* Do not echo the uncanonicalized path */ + server_abort_http(clt, 500, "invalid request path"); return (-1); } - if ((fd = open(path, O_RDONLY)) == -1) { - /* - * Pause accept if we are out of file descriptors, or - * libevent will haunt us here too. - */ - if (errno == ENFILE || errno == EMFILE) { - struct timeval evtpause = { 1, 0 }; - - event_del(&srv->srv_ev); - evtimer_add(&srv->srv_evt, &evtpause); - log_debug("%s: deferring connections", __func__); - return (0); - } - } - - if (clt->clt_persist <= 1) { - server_inflight--; - DPRINTF("%s: inflight decremented, now %d", - __func__, server_inflight); - event_add(&srv->srv_ev, NULL); + /* Returns HTTP status code on error */ + if ((ret = server_file_access(desc, path, sizeof(path), &st)) != 0) { + server_abort_http(clt, ret, path); + return (-1); } - if (fstat(fd, &st) == -1) + /* Now open the file, should be readable or we have another problem */ + if ((fd = open(path, O_RDONLY)) == -1) goto fail; + /* File descriptor is opened, decrement inflight counter */ + server_inflight_dec(clt, __func__); + media = media_find(env->sc_mediatypes, path); ret = server_response_http(clt, 200, media, st.st_size); switch (ret) { @@ -125,8 +162,9 @@ server_file(struct httpd *env, struct client *clt) clt->clt_fd = fd; if (clt->clt_file != NULL) bufferevent_free(clt->clt_file); + clt->clt_file = bufferevent_new(clt->clt_fd, server_read, - server_write, server_error, clt); + server_write, server_file_error, clt); if (clt->clt_file == NULL) { errstr = "failed to allocate file buffer event"; goto fail; @@ -134,7 +172,8 @@ server_file(struct httpd *env, struct client *clt) bufferevent_settimeout(clt->clt_file, srv->srv_conf.timeout.tv_sec, srv->srv_conf.timeout.tv_sec); - bufferevent_enable(clt->clt_file, EV_READ|EV_WRITE); + bufferevent_enable(clt->clt_file, EV_READ); + bufferevent_disable(clt->clt_bev, EV_READ); return (0); fail: @@ -143,3 +182,46 @@ server_file(struct httpd *env, struct client *clt) server_abort_http(clt, 500, errstr); return (-1); } + +void +server_file_error(struct bufferevent *bev, short error, void *arg) +{ + struct client *clt = arg; + struct evbuffer *dst; + + if (error & EVBUFFER_TIMEOUT) { + server_close(clt, "buffer event timeout"); + return; + } + if (error & (EVBUFFER_READ|EVBUFFER_WRITE|EVBUFFER_EOF)) { + bufferevent_disable(bev, EV_READ); + + clt->clt_done = 1; + + dst = EVBUFFER_OUTPUT(clt->clt_bev); + if (EVBUFFER_LENGTH(dst)) { + /* Finish writing all data first */ + bufferevent_enable(clt->clt_bev, EV_WRITE); + return; + } + + if (clt->clt_persist) { + /* Close input file and wait for next HTTP request */ + if (clt->clt_fd != -1) + close(clt->clt_fd); + clt->clt_fd = -1; + clt->clt_toread = TOREAD_HTTP_HEADER; + server_reset_http(clt); + bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE); + return; + } + server_close(clt, "done"); + return; + } + if (error & EVBUFFER_ERROR && errno == EFBIG) { + bufferevent_enable(bev, EV_READ); + return; + } + server_close(clt, "buffer event error"); + return; +} diff --git a/server_http.c b/server_http.c index a3991e3..6e15456 100644 --- a/server_http.c +++ b/server_http.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_http.c,v 1.7 2014/07/14 09:03:08 reyk Exp $ */ +/* $OpenBSD: server_http.c,v 1.10 2014/07/23 21:43:12 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -319,9 +319,8 @@ server_read_http(struct bufferevent *bev, void *arg) done: if (clt->clt_toread <= 0) { - if (server_response(env, clt) == -1) - return; - server_reset_http(clt, 0); + server_response(env, clt); + return; } } if (clt->clt_done) { @@ -502,31 +501,17 @@ server_read_httpchunks(struct bufferevent *bev, void *arg) } void -server_reset_http(struct client *clt, int all) +server_reset_http(struct client *clt) { struct http_descriptor *desc = clt->clt_desc; - log_debug("%s: method %s done %d count %d fd %d p %d", __func__, - server_httpmethod_byid(desc->http_method), all, - getdtablecount(), clt->clt_fd, clt->clt_persist); - server_httpdesc_free(desc); desc->http_method = 0; desc->http_chunked = 0; - desc->http_lastheader = NULL; clt->clt_headerlen = 0; clt->clt_line = 0; clt->clt_done = 0; - - if (!all) - return; - - clt->clt_toread = TOREAD_HTTP_HEADER; clt->clt_bev->readcb = server_read_http; - if (clt->clt_fd != -1) { - close(clt->clt_fd); - clt->clt_fd = -1; - } } void @@ -535,7 +520,7 @@ server_abort_http(struct client *clt, u_int code, const char *msg) struct server *srv = clt->clt_server; struct bufferevent *bev = clt->clt_bev; const char *httperr = NULL, *text = ""; - char *httpmsg; + char *httpmsg, *extraheader = NULL; time_t t; struct tm *lt; char tmbuf[32], hbuf[128]; @@ -559,8 +544,21 @@ server_abort_http(struct client *clt, u_int code, const char *msg) tmbuf[strlen(tmbuf) - 1] = '\0'; /* skip final '\n' */ /* Do not send details of the Internal Server Error */ - if (code != 500) + switch (code) { + case 500: + /* Do not send details of the Internal Server Error */ + break; + case 301: + case 302: + if (asprintf(&extraheader, "Location: %s\r\n", msg) == -1) { + code = 500; + extraheader = NULL; + } + break; + default: text = msg; + break; + } /* A CSS stylesheet allows minimal customization by the user */ style = "body { background-color: white; color: black; font-family: " @@ -579,6 +577,7 @@ server_abort_http(struct client *clt, u_int code, const char *msg) "Server: %s\r\n" "Connection: close\r\n" "Content-Type: text/html\r\n" + "%s" "\r\n" "\n" @@ -594,6 +593,7 @@ server_abort_http(struct client *clt, u_int code, const char *msg) "\n" "\n", code, httperr, tmbuf, HTTPD_SERVERNAME, + extraheader == NULL ? "" : extraheader, code, httperr, style, httperr, text, HTTPD_SERVERNAME, hbuf, ntohs(srv->srv_conf.port)) == -1) goto done; @@ -603,6 +603,7 @@ server_abort_http(struct client *clt, u_int code, const char *msg) free(httpmsg); done: + free(extraheader); if (asprintf(&httpmsg, "%s (%03d %s)", msg, code, httperr) == -1) server_close(clt, msg); else { @@ -658,7 +659,9 @@ server_response(struct httpd *httpd, struct client *clt) if ((ret = server_file(httpd, clt)) == -1) return (-1); - return (ret); + server_reset_http(clt); + + return (0); fail: server_abort_http(clt, 400, "bad request"); return (-1); @@ -800,10 +803,6 @@ server_httpmethod_byname(const char *name) /* Set up key */ method.method_name = name; - /* - * RFC 2616 section 5.1.1 says that the method is case - * sensitive so we don't do a strcasecmp here. - */ if ((res = bsearch(&method, http_methods, sizeof(http_methods) / sizeof(http_methods[0]) - 1, sizeof(http_methods[0]), server_httpmethod_cmp)) != NULL) @@ -833,6 +832,11 @@ server_httpmethod_cmp(const void *a, const void *b) { const struct http_method *ma = a; const struct http_method *mb = b; + + /* + * RFC 2616 section 5.1.1 says that the method is case + * sensitive so we don't do a strcasecmp here. + */ return (strcmp(ma->method_name, mb->method_name)); } -- cgit v1.2.3-54-g00ecf