aboutsummaryrefslogtreecommitdiff
path: root/server_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'server_http.c')
-rw-r--r--server_http.c123
1 files changed, 88 insertions, 35 deletions
diff --git a/server_http.c b/server_http.c
index af996a5..6ba5c15 100644
--- a/server_http.c
+++ b/server_http.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server_http.c,v 1.45 2014/08/21 19:23:10 chrisz Exp $ */
+/* $OpenBSD: server_http.c,v 1.48 2014/09/05 15:06:05 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -86,9 +86,15 @@ server_httpdesc_init(struct client *clt)
if ((desc = calloc(1, sizeof(*desc))) == NULL)
return (-1);
+ RB_INIT(&desc->http_headers);
+ clt->clt_descreq = desc;
+ if ((desc = calloc(1, sizeof(*desc))) == NULL) {
+ /* req will be cleaned up later */
+ return (-1);
+ }
RB_INIT(&desc->http_headers);
- clt->clt_desc = desc;
+ clt->clt_descresp = desc;
return (0);
}
@@ -96,6 +102,8 @@ server_httpdesc_init(struct client *clt)
void
server_httpdesc_free(struct http_descriptor *desc)
{
+ if (desc == NULL)
+ return;
if (desc->http_path != NULL) {
free(desc->http_path);
desc->http_path = NULL;
@@ -118,6 +126,8 @@ server_httpdesc_free(struct http_descriptor *desc)
}
kv_purge(&desc->http_headers);
desc->http_lastheader = NULL;
+ desc->http_method = 0;
+ desc->http_chunked = 0;
}
void
@@ -125,7 +135,7 @@ server_read_http(struct bufferevent *bev, void *arg)
{
struct client *clt = arg;
struct server_config *srv_conf = clt->clt_srv_conf;
- struct http_descriptor *desc = clt->clt_desc;
+ struct http_descriptor *desc = clt->clt_descreq;
struct evbuffer *src = EVBUFFER_INPUT(bev);
char *line = NULL, *key, *value;
const char *errstr;
@@ -304,11 +314,36 @@ server_read_http(struct bufferevent *bev, void *arg)
case HTTP_METHOD_GET:
case HTTP_METHOD_HEAD:
case HTTP_METHOD_OPTIONS:
+ /* WebDAV methods */
+ case HTTP_METHOD_COPY:
clt->clt_toread = 0;
break;
case HTTP_METHOD_POST:
case HTTP_METHOD_PUT:
case HTTP_METHOD_RESPONSE:
+ /* WebDAV methods */
+ case HTTP_METHOD_PROPFIND:
+ case HTTP_METHOD_PROPPATCH:
+ case HTTP_METHOD_MKCOL:
+ case HTTP_METHOD_LOCK:
+ case HTTP_METHOD_UNLOCK:
+ case HTTP_METHOD_VERSION_CONTROL:
+ case HTTP_METHOD_REPORT:
+ case HTTP_METHOD_CHECKOUT:
+ case HTTP_METHOD_CHECKIN:
+ case HTTP_METHOD_UNCHECKOUT:
+ case HTTP_METHOD_MKWORKSPACE:
+ case HTTP_METHOD_UPDATE:
+ case HTTP_METHOD_LABEL:
+ case HTTP_METHOD_MERGE:
+ case HTTP_METHOD_BASELINE_CONTROL:
+ case HTTP_METHOD_MKACTIVITY:
+ case HTTP_METHOD_ORDERPATCH:
+ case HTTP_METHOD_ACL:
+ case HTTP_METHOD_MKREDIRECTREF:
+ case HTTP_METHOD_UPDATEREDIRECTREF:
+ case HTTP_METHOD_SEARCH:
+ case HTTP_METHOD_PATCH:
/* HTTP request payload */
if (clt->clt_toread > 0)
bev->readcb = server_read_httpcontent;
@@ -320,10 +355,8 @@ server_read_http(struct bufferevent *bev, void *arg)
}
break;
default:
- /* HTTP handler */
- clt->clt_toread = TOREAD_HTTP_HEADER;
- bev->readcb = server_read_http;
- break;
+ server_abort_http(clt, 405, "method not allowed");
+ return;
}
if (desc->http_chunked) {
/* Chunked transfer encoding */
@@ -518,12 +551,10 @@ server_read_httpchunks(struct bufferevent *bev, void *arg)
void
server_reset_http(struct client *clt)
{
- struct http_descriptor *desc = clt->clt_desc;
struct server *srv = clt->clt_srv;
-
- server_httpdesc_free(desc);
- desc->http_method = 0;
- desc->http_chunked = 0;
+
+ server_httpdesc_free(clt->clt_descreq);
+ server_httpdesc_free(clt->clt_descresp);
clt->clt_headerlen = 0;
clt->clt_line = 0;
clt->clt_done = 0;
@@ -670,12 +701,17 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
void
server_close_http(struct client *clt)
{
- struct http_descriptor *desc = clt->clt_desc;
+ struct http_descriptor *desc;
- if (desc == NULL)
- return;
+ desc = clt->clt_descreq;
+ server_httpdesc_free(desc);
+ free(desc);
+ clt->clt_descreq = NULL;
+
+ desc = clt->clt_descresp;
server_httpdesc_free(desc);
free(desc);
+ clt->clt_descresp = NULL;
}
int
@@ -683,7 +719,8 @@ server_response(struct httpd *httpd, struct client *clt)
{
char path[MAXPATHLEN];
char hostname[MAXHOSTNAMELEN];
- struct http_descriptor *desc = clt->clt_desc;
+ struct http_descriptor *desc = clt->clt_descreq;
+ struct http_descriptor *resp = clt->clt_descresp;
struct server *srv = clt->clt_srv;
struct server_config *srv_conf = &srv->srv_conf;
struct kv *kv, key, *host;
@@ -733,6 +770,12 @@ server_response(struct httpd *httpd, struct client *clt)
if (host != NULL) {
/* XXX maybe better to turn srv_hosts into a tree */
TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
+#ifdef DEBUG
+ if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) {
+ DPRINTF("%s: virtual host \"%s\" host \"%s\"",
+ __func__, srv_conf->name, host->kv_value);
+ }
+#endif
if ((srv_conf->flags & SRVFLAG_LOCATION) == 0 &&
fnmatch(srv_conf->name, host->kv_value,
FNM_CASEFOLD) == 0) {
@@ -760,6 +803,11 @@ server_response(struct httpd *httpd, struct client *clt)
if ((desc->http_host = strdup(hostname)) == NULL)
goto fail;
+ /* Now fill in the mandatory parts of the response descriptor */
+ resp->http_method = desc->http_method;
+ if ((resp->http_version = strdup(desc->http_version)) == NULL)
+ goto fail;
+
/* Now search for the location */
srv_conf = server_getlocation(clt, desc->http_path);
@@ -777,6 +825,12 @@ server_getlocation(struct client *clt, const char *path)
/* Now search for the location */
TAILQ_FOREACH(location, &srv->srv_hosts, entry) {
+#ifdef DEBUG
+ if (location->flags & SRVFLAG_LOCATION) {
+ DPRINTF("%s: location \"%s\" path \"%s\"",
+ __func__, location->location, path);
+ }
+#endif
if ((location->flags & SRVFLAG_LOCATION) &&
location->id == srv_conf->id &&
fnmatch(location->location, path, FNM_CASEFOLD) == 0) {
@@ -793,7 +847,8 @@ int
server_response_http(struct client *clt, u_int code,
struct media_type *media, size_t size, time_t mtime)
{
- struct http_descriptor *desc = clt->clt_desc;
+ struct http_descriptor *desc = clt->clt_descreq;
+ struct http_descriptor *resp = clt->clt_descresp;
const char *error;
struct kv *ct, *cl;
char tmbuf[32];
@@ -804,27 +859,25 @@ server_response_http(struct client *clt, u_int code,
if (server_log_http(clt, code, size) == -1)
return (-1);
- kv_purge(&desc->http_headers);
-
/* Add error codes */
- if (kv_setkey(&desc->http_pathquery, "%lu", code) == -1 ||
- kv_set(&desc->http_pathquery, "%s", error) == -1)
+ if (kv_setkey(&resp->http_pathquery, "%lu", code) == -1 ||
+ kv_set(&resp->http_pathquery, "%s", error) == -1)
return (-1);
/* Add headers */
- if (kv_add(&desc->http_headers, "Server", HTTPD_SERVERNAME) == NULL)
+ if (kv_add(&resp->http_headers, "Server", HTTPD_SERVERNAME) == NULL)
return (-1);
/* Is it a persistent connection? */
if (clt->clt_persist) {
- if (kv_add(&desc->http_headers,
+ if (kv_add(&resp->http_headers,
"Connection", "keep-alive") == NULL)
return (-1);
- } else if (kv_add(&desc->http_headers, "Connection", "close") == NULL)
+ } else if (kv_add(&resp->http_headers, "Connection", "close") == NULL)
return (-1);
/* Set media type */
- if ((ct = kv_add(&desc->http_headers, "Content-Type", NULL)) == NULL ||
+ if ((ct = kv_add(&resp->http_headers, "Content-Type", NULL)) == NULL ||
kv_set(ct, "%s/%s",
media == NULL ? "application" : media->media_type,
media == NULL ? "octet-stream" : media->media_subtype) == -1)
@@ -832,28 +885,28 @@ server_response_http(struct client *clt, u_int code,
/* Set content length, if specified */
if ((cl =
- kv_add(&desc->http_headers, "Content-Length", NULL)) == NULL ||
+ kv_add(&resp->http_headers, "Content-Length", NULL)) == NULL ||
kv_set(cl, "%ld", size) == -1)
return (-1);
/* Set last modification time */
if (server_http_time(mtime, tmbuf, sizeof(tmbuf)) <= 0 ||
- kv_add(&desc->http_headers, "Last-Modified", tmbuf) == NULL)
+ kv_add(&resp->http_headers, "Last-Modified", tmbuf) == NULL)
return (-1);
/* Date header is mandatory and should be added as late as possible */
if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0 ||
- kv_add(&desc->http_headers, "Date", tmbuf) == NULL)
+ kv_add(&resp->http_headers, "Date", tmbuf) == NULL)
return (-1);
/* Write completed header */
if (server_writeresponse_http(clt) == -1 ||
server_bufferevent_print(clt, "\r\n") == -1 ||
- server_headers(clt, server_writeheader_http, NULL) == -1 ||
+ server_headers(clt, resp, server_writeheader_http, NULL) == -1 ||
server_bufferevent_print(clt, "\r\n") == -1)
return (-1);
- if (size == 0 || desc->http_method == HTTP_METHOD_HEAD) {
+ if (size == 0 || resp->http_method == HTTP_METHOD_HEAD) {
bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE);
if (clt->clt_persist)
clt->clt_toread = TOREAD_HTTP_HEADER;
@@ -869,7 +922,7 @@ server_response_http(struct client *clt, u_int code,
int
server_writeresponse_http(struct client *clt)
{
- struct http_descriptor *desc = (struct http_descriptor *)clt->clt_desc;
+ struct http_descriptor *desc = clt->clt_descresp;
DPRINTF("version: %s rescode: %s resmsg: %s", desc->http_version,
desc->http_rescode, desc->http_resmesg);
@@ -913,11 +966,11 @@ server_writeheader_http(struct client *clt, struct kv *hdr, void *arg)
}
int
-server_headers(struct client *clt,
+server_headers(struct client *clt, void *descp,
int (*hdr_cb)(struct client *, struct kv *, void *), void *arg)
{
struct kv *hdr, *kv;
- struct http_descriptor *desc = (struct http_descriptor *)clt->clt_desc;
+ struct http_descriptor *desc = descp;
RB_FOREACH(hdr, kvtree, &desc->http_headers) {
if ((hdr_cb)(clt, hdr, arg) == -1)
@@ -951,7 +1004,7 @@ server_httpmethod_byname(const char *name)
const char *
server_httpmethod_byid(u_int id)
{
- const char *name = NULL;
+ const char *name = "<UNKNOWN>";
int i;
for (i = 0; http_methods[i].method_name != NULL; i++) {
@@ -1015,7 +1068,7 @@ server_log_http(struct client *clt, u_int code, size_t len)
return (-1);
if ((srv_conf->flags & SRVFLAG_LOG) == 0)
return (0);
- if ((desc = clt->clt_desc) == NULL)
+ if ((desc = clt->clt_descreq) == NULL)
return (-1);
if ((t = time(NULL)) == -1)