diff options
Diffstat (limited to 'server_http.c')
-rw-r--r-- | server_http.c | 117 |
1 files changed, 113 insertions, 4 deletions
diff --git a/server_http.c b/server_http.c index 674e92b..ad2add8 100644 --- a/server_http.c +++ b/server_http.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_http.c,v 1.3 2014/07/13 09:46:19 beck Exp $ */ +/* $OpenBSD: server_http.c,v 1.7 2014/07/14 09:03:08 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org> @@ -321,9 +321,8 @@ server_read_http(struct bufferevent *bev, void *arg) if (clt->clt_toread <= 0) { if (server_response(env, clt) == -1) return; + clt->clt_done = 0; } - - server_reset_http(clt); } if (clt->clt_done) { server_close(clt, "done"); @@ -513,6 +512,12 @@ server_reset_http(struct client *clt) clt->clt_headerlen = 0; clt->clt_line = 0; clt->clt_done = 0; + 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 @@ -609,6 +614,111 @@ server_close_http(struct client *clt) } int +server_response(struct httpd *httpd, struct client *clt) +{ + struct http_descriptor *desc = clt->clt_desc; + struct kv *kv, key; + int ret; + + if (desc->http_path == NULL) + goto fail; + + if (strcmp(desc->http_version, "HTTP/1.1") == 0) { + /* Host header is mandatory */ + key.kv_key = "Host"; + if ((kv = kv_find(&desc->http_headers, &key)) == NULL) + goto fail; + + /* Is the connection persistent? */ + key.kv_key = "Connection"; + if ((kv = kv_find(&desc->http_headers, &key)) != NULL && + strcasecmp("close", kv->kv_value) == 0) + clt->clt_persist = 0; + else + clt->clt_persist++; + } else { + /* Is the connection persistent? */ + key.kv_key = "Connection"; + if ((kv = kv_find(&desc->http_headers, &key)) != NULL && + strcasecmp("keep-alive", kv->kv_value) == 0) + clt->clt_persist++; + else + clt->clt_persist = 0; + } + + if ((ret = server_file(httpd, clt)) == -1) + return (-1); + + return (ret); + fail: + server_abort_http(clt, 400, "bad request"); + return (-1); +} + +int +server_response_http(struct client *clt, u_int code, + struct media_type *media, size_t size) +{ + struct http_descriptor *desc = clt->clt_desc; + const char *error; + struct kv *ct, *cl; + + if (desc == NULL || (error = server_httperror_byid(code)) == NULL) + 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) + return (-1); + + /* Add headers */ + if (kv_add(&desc->http_headers, "Server", HTTPD_SERVERNAME) == NULL) + return (-1); + + /* Is it a persistent connection? */ + if (clt->clt_persist) { + if (kv_add(&desc->http_headers, + "Connection", "keep-alive") == NULL) + return (-1); + } else if (kv_add(&desc->http_headers, "Connection", "close") == NULL) + return (-1); + + /* Set media type */ + if ((ct = kv_add(&desc->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) + return (-1); + + /* Set content length, if specified */ + if (size && ((cl = + kv_add(&desc->http_headers, "Content-Length", NULL)) == NULL || + kv_set(cl, "%ld", size) == -1)) + return (-1); + + /* Write completed header */ + if (server_writeresponse_http(clt) == -1 || + server_bufferevent_print(clt, "\r\n") == -1 || + server_writeheader_http(clt) == -1 || + server_bufferevent_print(clt, "\r\n") == -1) + return (-1); + + if (desc->http_method == HTTP_METHOD_HEAD) { + bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE); + if (clt->clt_persist) + clt->clt_toread = TOREAD_HTTP_HEADER; + else + clt->clt_toread = TOREAD_HTTP_NONE; + clt->clt_done = 0; + return (0); + } + + return (1); +} + +int server_writeresponse_http(struct client *clt) { struct http_descriptor *desc = (struct http_descriptor *)clt->clt_desc; @@ -642,7 +752,6 @@ server_writeheader_kv(struct client *clt, struct kv *hdr) key = hdr->kv_key; ptr = hdr->kv_value; - DPRINTF("%s: ptr %s", __func__, ptr); if (server_bufferevent_print(clt, key) == -1 || (ptr != NULL && (server_bufferevent_print(clt, ": ") == -1 || |