aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@esdenera.com>2014-07-24 09:55:33 +0200
committerReyk Floeter <reyk@esdenera.com>2014-07-24 09:55:33 +0200
commit6801bf4ff6b4768d779849eab9b36361e2782d13 (patch)
treeed026d5df9815f18fdf2e9ac9648ebc6993692d5
parent435ab22dd5d9496a355be35e6540f0063f656465 (diff)
downloadhttpd-6801bf4ff6b4768d779849eab9b36361e2782d13.tar.gz
httpd-6801bf4ff6b4768d779849eab9b36361e2782d13.zip
sync
-rw-r--r--config.c8
-rw-r--r--httpd.89
-rw-r--r--httpd.c71
-rw-r--r--httpd.conf.518
-rw-r--r--httpd.h16
-rw-r--r--parse.y3
-rw-r--r--server.c81
-rw-r--r--server_file.c178
-rw-r--r--server_http.c56
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 <reyk@openbsd.org>
@@ -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 <reyk@openbsd.org>
.\"
@@ -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 <reyk@openbsd.org>
@@ -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 <reyk@openbsd.org>
.\"
@@ -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 <reyk@openbsd.org>
@@ -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 <reyk@openbsd.org>
@@ -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 <reyk@openbsd.org>
@@ -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,13 +522,27 @@ 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)
{
char ibuf[128], obuf[128], *ptr = NULL;
@@ -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 <reyk@openbsd.org>
@@ -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 <reyk@openbsd.org>
@@ -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"
"<!DOCTYPE HTML PUBLIC "
"\"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
@@ -594,6 +593,7 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
"</body>\n"
"</html>\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));
}