From 96f89aa8441368158f5b347b90c13e1acbfdd149 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Mon, 14 Jul 2014 14:57:33 +0200 Subject: sync --- config.c | 2 +- http.h | 11 ++++-- httpd.c | 2 +- httpd.conf.5 | 4 +- httpd.h | 11 ++++-- parse.y | 2 +- server.c | 22 ++++++++++- server_file.c | 50 +++++++------------------ server_http.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 9 files changed, 166 insertions(+), 55 deletions(-) diff --git a/config.c b/config.c index 01a8e5e..230ec35 100644 --- a/config.c +++ b/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.1 2014/07/12 23:34:54 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.2 2014/07/13 14:17:37 reyk Exp $ */ /* * Copyright (c) 2011 - 2014 Reyk Floeter diff --git a/http.h b/http.h index d9cf13e..af2627f 100644 --- a/http.h +++ b/http.h @@ -1,4 +1,4 @@ -/* $OpenBSD: http.h,v 1.1 2014/07/12 23:34:54 reyk Exp $ */ +/* $OpenBSD: http.h,v 1.3 2014/07/13 15:11:23 reyk Exp $ */ /* * Copyright (c) 2012 - 2014 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _HTTPD_HTTP_H -#define _HTTPD_HTTP_H +#ifndef _HTTP_H +#define _HTTP_H enum httpmethod { HTTP_METHOD_NONE = 0, @@ -140,10 +140,13 @@ struct http_mediatype { /* Used during runtime */ struct http_descriptor { struct kv http_pathquery; + struct kv http_matchquery; #define http_path http_pathquery.kv_key #define http_query http_pathquery.kv_value #define http_rescode http_pathquery.kv_key #define http_resmesg http_pathquery.kv_value +#define query_key http_matchquery.kv_key +#define query_val http_matchquery.kv_value char *http_version; enum httpmethod http_method; @@ -154,4 +157,4 @@ struct http_descriptor { struct kv *http_lastheader; }; -#endif /* _HTTPD_HTTP_H */ +#endif /* _HTTP_H */ diff --git a/httpd.c b/httpd.c index 7db7288..f8f0323 100644 --- a/httpd.c +++ b/httpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.c,v 1.1 2014/07/12 23:34:54 reyk Exp $ */ +/* $OpenBSD: httpd.c,v 1.2 2014/07/13 14:17:37 reyk Exp $ */ /* * Copyright (c) 2014 Reyk Floeter diff --git a/httpd.conf.5 b/httpd.conf.5 index 2e99949..a6f90a6 100644 --- a/httpd.conf.5 +++ b/httpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: httpd.conf.5,v 1.1 2014/07/12 23:34:54 reyk Exp $ +.\" $OpenBSD: httpd.conf.5,v 1.2 2014/07/13 14:17:37 reyk Exp $ .\" .\" Copyright (c) 2014 Reyk Floeter .\" @@ -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 13 2014 $ .Dt HTTPD.CONF 5 .Os .Sh NAME diff --git a/httpd.h b/httpd.h index f4ba745..3834e80 100644 --- a/httpd.h +++ b/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.1 2014/07/12 23:34:54 reyk Exp $ */ +/* $OpenBSD: httpd.h,v 1.3 2014/07/14 00:19:48 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -68,7 +68,8 @@ enum httpchunk { TOREAD_UNLIMITED = -1, TOREAD_HTTP_HEADER = -2, TOREAD_HTTP_CHUNK_LENGTH = -3, - TOREAD_HTTP_CHUNK_TRAILER = -4 + TOREAD_HTTP_CHUNK_TRAILER = -4, + TOREAD_HTTP_NONE = -5 }; #if DEBUG > 1 @@ -264,6 +265,7 @@ struct client { struct bufferevent *clt_file; off_t clt_toread; + int clt_persist; int clt_line; size_t clt_headerlen; int clt_done; @@ -394,11 +396,14 @@ void server_read_httpchunks(struct bufferevent *, void *); int server_writeheader_kv(struct client *, struct kv *); 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 *); void server_close_http(struct client *); +int server_response(struct httpd *, struct client *); /* server_file.c */ -int server_response(struct httpd *, struct client *); +int server_file(struct httpd *, struct client *); /* httpd.c */ void event_again(struct event *, int, short, diff --git a/parse.y b/parse.y index 43e00c9..ec2be91 100644 --- a/parse.y +++ b/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.1 2014/07/12 23:34:54 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.2 2014/07/13 14:17:37 reyk Exp $ */ /* * Copyright (c) 2007 - 2014 Reyk Floeter diff --git a/server.c b/server.c index 4106d92..b72d556 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.1 2014/07/12 23:34:54 reyk Exp $ */ +/* $OpenBSD: server.c,v 1.5 2014/07/14 00:19:48 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -326,6 +326,11 @@ void server_write(struct bufferevent *bev, void *arg) { struct client *clt = arg; + struct evbuffer *dst = EVBUFFER_OUTPUT(bev); + + if (EVBUFFER_LENGTH(dst) == 0 && + clt->clt_toread == TOREAD_HTTP_NONE) + goto done; getmonotime(&clt->clt_tv_last); @@ -384,6 +389,7 @@ 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"); @@ -398,8 +404,20 @@ server_error(struct bufferevent *bev, short error, void *arg) 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); + bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE); + return; + } else + server_close(clt, "done"); return; -// server_close(con, "done"); } server_close(clt, "buffer event error"); return; diff --git a/server_file.c b/server_file.c index ff3f565..e8db8a7 100644 --- a/server_file.c +++ b/server_file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_file.c,v 1.3 2014/07/13 15:07:50 reyk Exp $ */ +/* $OpenBSD: server_file.c,v 1.4 2014/07/14 00:19:48 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -47,20 +47,16 @@ #include "http.h" int -server_response(struct httpd *env, struct client *clt) +server_file(struct httpd *env, struct client *clt) { struct http_descriptor *desc = clt->clt_desc; struct server *srv = clt->clt_server; - struct kv *ct, *cl; struct media_type *media; const char *errstr = NULL; - int fd = -1; + int fd = -1, ret; char path[MAXPATHLEN]; struct stat st; - if (desc->http_path == NULL) - goto fail; - /* * XXX This is not ready XXX * XXX Don't expect anything from this code yet, @@ -91,40 +87,20 @@ server_response(struct httpd *env, struct client *clt) if ((fd = open(path, O_RDONLY)) == -1 || fstat(fd, &st) == -1) goto fail; - kv_purge(&desc->http_headers); - - /* Add error codes */ - if (kv_setkey(&desc->http_pathquery, "200") == -1 || - kv_set(&desc->http_pathquery, "%s", - server_httperror_byid(200)) == -1) - goto fail; - - /* Add headers */ - if (kv_add(&desc->http_headers, "Server", HTTPD_SERVERNAME) == NULL || - kv_add(&desc->http_headers, "Connection", "close") == NULL || - (ct = kv_add(&desc->http_headers, "Content-Type", NULL)) == NULL || - (cl = kv_add(&desc->http_headers, "Content-Length", NULL)) == NULL) - goto fail; - - /* Set content type */ media = media_find(env->sc_mediatypes, path); - if (kv_set(ct, "%s/%s", - media == NULL ? "application" : media->media_type, - media == NULL ? "octet-stream" : media->media_subtype) == -1) - goto fail; - - /* Set content length */ - if (kv_set(cl, "%ld", st.st_size) == -1) - goto fail; - - 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) + ret = server_response_http(clt, 200, media, st.st_size); + switch (ret) { + case -1: goto fail; + case 0: + /* Connection is already finished */ + close(fd); + return (0); + default: + break; + } clt->clt_fd = fd; - clt->clt_persist = 0; if (clt->clt_file != NULL) bufferevent_free(clt->clt_file); clt->clt_file = bufferevent_new(clt->clt_fd, server_read, 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 @@ -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 @@ -608,6 +613,111 @@ server_close_http(struct client *clt) free(desc); } +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) { @@ -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 || -- cgit v1.2.3-54-g00ecf