diff options
Diffstat (limited to 'server_http.c')
-rw-r--r-- | server_http.c | 123 |
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) |