aboutsummaryrefslogtreecommitdiff
path: root/httpd/server_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'httpd/server_http.c')
-rw-r--r--httpd/server_http.c157
1 files changed, 141 insertions, 16 deletions
diff --git a/httpd/server_http.c b/httpd/server_http.c
index b69805a..e64de0d 100644
--- a/httpd/server_http.c
+++ b/httpd/server_http.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: server_http.c,v 1.109 2016/07/27 11:02:41 reyk Exp $ */
+/* $OpenBSD: server_http.c,v 1.117 2017/05/15 10:40:47 jsg Exp $ */
/*
- * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006 - 2017 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -49,17 +49,12 @@ int server_http_authenticate(struct server_config *,
char *server_expand_http(struct client *, const char *,
char *, size_t);
-static struct httpd *env = NULL;
-
static struct http_method http_methods[] = HTTP_METHODS;
static struct http_error http_errors[] = HTTP_ERRORS;
void
-server_http(struct httpd *x_env)
+server_http(void)
{
- if (x_env != NULL)
- env = x_env;
-
DPRINTF("%s: sorting lookup tables, pid %d", __func__, getpid());
/* Sort the HTTP lookup arrays */
@@ -221,16 +216,34 @@ server_read_http(struct bufferevent *bev, void *arg)
goto done;
}
- while (!clt->clt_done && (line =
- evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT)) != NULL) {
- linelen = strlen(line);
+ while (!clt->clt_headersdone) {
+ if (!clt->clt_line) {
+ /* Peek into the buffer to see if it looks like HTTP */
+ key = EVBUFFER_DATA(src);
+ if (!isalpha(*key)) {
+ server_abort_http(clt, 400,
+ "invalid request line");
+ goto abort;
+ }
+ }
+
+ if ((line = evbuffer_readln(src,
+ &linelen, EVBUFFER_EOL_CRLF_STRICT)) == NULL) {
+ /* No newline found after too many bytes */
+ if (size > SERVER_MAXHEADERLENGTH) {
+ server_abort_http(clt, 413,
+ "request line too long");
+ goto abort;
+ }
+ break;
+ }
/*
* An empty line indicates the end of the request.
* libevent already stripped the \r\n for us.
*/
if (!linelen) {
- clt->clt_done = 1;
+ clt->clt_headersdone = 1;
free(line);
break;
}
@@ -365,7 +378,7 @@ server_read_http(struct bufferevent *bev, void *arg)
free(line);
}
- if (clt->clt_done) {
+ if (clt->clt_headersdone) {
if (desc->http_method == HTTP_METHOD_NONE) {
server_abort_http(clt, 406, "no method");
return;
@@ -377,7 +390,6 @@ server_read_http(struct bufferevent *bev, void *arg)
clt->clt_toread = TOREAD_UNLIMITED;
bev->readcb = server_read;
break;
- case HTTP_METHOD_DELETE:
case HTTP_METHOD_GET:
case HTTP_METHOD_HEAD:
/* WebDAV methods */
@@ -385,6 +397,7 @@ server_read_http(struct bufferevent *bev, void *arg)
case HTTP_METHOD_MOVE:
clt->clt_toread = 0;
break;
+ case HTTP_METHOD_DELETE:
case HTTP_METHOD_OPTIONS:
case HTTP_METHOD_POST:
case HTTP_METHOD_PUT:
@@ -435,7 +448,7 @@ server_read_http(struct bufferevent *bev, void *arg)
done:
if (clt->clt_toread != 0)
bufferevent_disable(bev, EV_READ);
- server_response(env, clt);
+ server_response(httpd_env, clt);
return;
}
if (clt->clt_done) {
@@ -615,6 +628,101 @@ server_read_httpchunks(struct bufferevent *bev, void *arg)
}
void
+server_read_httprange(struct bufferevent *bev, void *arg)
+{
+ struct client *clt = arg;
+ struct evbuffer *src = EVBUFFER_INPUT(bev);
+ size_t size;
+ struct media_type *media;
+ struct range_data *r = &clt->clt_ranges;
+ struct range *range;
+
+ getmonotime(&clt->clt_tv_last);
+
+ if (r->range_toread > 0) {
+ size = EVBUFFER_LENGTH(src);
+ if (!size)
+ return;
+
+ /* Read chunk data */
+ if ((off_t)size > r->range_toread) {
+ size = r->range_toread;
+ if (server_bufferevent_write_chunk(clt, src, size)
+ == -1)
+ goto fail;
+ r->range_toread = 0;
+ } else {
+ if (server_bufferevent_write_buffer(clt, src) == -1)
+ goto fail;
+ r->range_toread -= size;
+ }
+ if (r->range_toread < 1)
+ r->range_toread = TOREAD_HTTP_RANGE;
+ DPRINTF("%s: done, size %lu, to read %lld", __func__,
+ size, r->range_toread);
+ }
+
+ switch (r->range_toread) {
+ case TOREAD_HTTP_RANGE:
+ if (r->range_index >= r->range_count) {
+ if (r->range_count > 1) {
+ /* Add end marker */
+ if (server_bufferevent_printf(clt,
+ "\r\n--%llu--\r\n",
+ clt->clt_boundary) == -1)
+ goto fail;
+ }
+ r->range_toread = TOREAD_HTTP_NONE;
+ break;
+ }
+
+ range = &r->range[r->range_index];
+
+ if (r->range_count > 1) {
+ media = r->range_media;
+ if (server_bufferevent_printf(clt,
+ "\r\n--%llu\r\n"
+ "Content-Type: %s/%s\r\n"
+ "Content-Range: bytes %lld-%lld/%zu\r\n\r\n",
+ clt->clt_boundary,
+ media->media_type, media->media_subtype,
+ range->start, range->end, r->range_total) == -1)
+ goto fail;
+ }
+ r->range_toread = range->end - range->start + 1;
+
+ if (lseek(clt->clt_fd, range->start, SEEK_SET) == -1)
+ goto fail;
+
+ /* Throw away bytes that are already in the input buffer */
+ evbuffer_drain(src, EVBUFFER_LENGTH(src));
+
+ /* Increment for the next part */
+ r->range_index++;
+ break;
+ case TOREAD_HTTP_NONE:
+ case 0:
+ break;
+ }
+
+ if (clt->clt_done)
+ goto done;
+
+ if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(clt->clt_bev)) > (size_t)
+ SERVER_MAX_PREFETCH * clt->clt_sndbufsiz) {
+ bufferevent_disable(clt->clt_srvbev, EV_READ);
+ clt->clt_srvbev_throttled = 1;
+ }
+
+ return;
+ done:
+ (*bev->errorcb)(bev, EVBUFFER_READ, bev->cbarg);
+ return;
+ fail:
+ server_close(clt, strerror(errno));
+}
+
+void
server_reset_http(struct client *clt)
{
struct server *srv = clt->clt_srv;
@@ -624,8 +732,9 @@ server_reset_http(struct client *clt)
server_httpdesc_free(clt->clt_descreq);
server_httpdesc_free(clt->clt_descresp);
clt->clt_headerlen = 0;
- clt->clt_line = 0;
+ clt->clt_headersdone = 0;
clt->clt_done = 0;
+ clt->clt_line = 0;
clt->clt_chunk = 0;
free(clt->clt_remote_user);
clt->clt_remote_user = NULL;
@@ -778,6 +887,8 @@ server_abort_http(struct client *clt, unsigned int code, const char *msg)
msg = buf;
break;
case 401:
+ if (msg == NULL)
+ break;
if (stravis(&escapedmsg, msg, VIS_DQ) == -1) {
code = 500;
extraheader = NULL;
@@ -789,6 +900,8 @@ server_abort_http(struct client *clt, unsigned int code, const char *msg)
}
break;
case 416:
+ if (msg == NULL)
+ break;
if (asprintf(&extraheader,
"Content-Range: %s\r\n", msg) == -1) {
code = 500;
@@ -959,6 +1072,14 @@ server_expand_http(struct client *clt, const char *val, char *buf,
if (ret != 0)
return (NULL);
}
+ if (strstr(val, "$HTTP_HOST") != NULL) {
+ if (desc->http_host == NULL)
+ return (NULL);
+ if ((str = url_encode(desc->http_host)) == NULL)
+ return (NULL);
+ expand_string(buf, len, "$HTTP_HOST", str);
+ free(str);
+ }
if (strstr(val, "$REMOTE_") != NULL) {
if (strstr(val, "$REMOTE_ADDR") != NULL) {
if (print_host(&clt->clt_ss,
@@ -1095,6 +1216,10 @@ server_response(struct httpd *httpd, struct client *clt)
if (clt->clt_persist >= srv_conf->maxrequests)
clt->clt_persist = 0;
+ /* pipelining should end after the first "idempotent" method */
+ if (clt->clt_pipelining && clt->clt_toread > 0)
+ clt->clt_persist = 0;
+
/*
* Do we have a Host header and matching configuration?
* XXX the Host can also appear in the URL path.