diff options
| author | Garrett D'Amore <garrett@damore.org> | 2018-09-29 21:55:31 -0700 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2018-09-29 21:55:31 -0700 |
| commit | 25490a300910e357ac864a1916a4285e239fbf30 (patch) | |
| tree | 8d45f90b9cfaff3c038aeadadd219d3edf8acc54 /src/supplemental/http/http_server.c | |
| parent | c084742b80d6514b39824617a41eb16910c53cf4 (diff) | |
| download | nng-25490a300910e357ac864a1916a4285e239fbf30.tar.gz nng-25490a300910e357ac864a1916a4285e239fbf30.tar.bz2 nng-25490a300910e357ac864a1916a4285e239fbf30.zip | |
fixes #738 http server needs a way to collect request entity data
Diffstat (limited to 'src/supplemental/http/http_server.c')
| -rw-r--r-- | src/supplemental/http/http_server.c | 99 |
1 files changed, 79 insertions, 20 deletions
diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index f36c941d..1a7f2c25 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -35,25 +35,28 @@ struct nng_http_handler { char * host; bool tree; int refcnt; + size_t maxbody; + bool getbody; void * data; nni_cb dtor; void (*cb)(nni_aio *); }; typedef struct http_sconn { - nni_list_node node; - nni_http_conn * conn; - nni_http_server *server; - nni_http_req * req; - nni_http_res * res; - bool close; - bool closed; - bool finished; - nni_aio * cbaio; - nni_aio * rxaio; - nni_aio * txaio; - nni_aio * txdataio; - nni_reap_item reap; + nni_list_node node; + nni_http_conn * conn; + nni_http_server * server; + nni_http_req * req; + nni_http_res * res; + nni_http_handler *handler; // set if we deferred to read body + bool close; + bool closed; + bool finished; + nni_aio * cbaio; + nni_aio * rxaio; + nni_aio * txaio; + nni_aio * txdataio; + nni_reap_item reap; } http_sconn; typedef struct http_error { @@ -101,13 +104,15 @@ nni_http_handler_init( return (NNG_ENOMEM); } NNI_LIST_NODE_INIT(&h->node); - h->cb = cb; - h->data = NULL; - h->dtor = NULL; - h->host = NULL; - h->tree = false; - h->refcnt = 0; - *hp = h; + h->cb = cb; + h->data = NULL; + h->dtor = NULL; + h->host = NULL; + h->tree = false; + h->refcnt = 0; + h->maxbody = 1024 * 1024; // By default we accept up to 1MB of body + h->getbody = true; + *hp = h; return (0); } @@ -126,6 +131,13 @@ nni_http_handler_fini(nni_http_handler *h) NNI_FREE_STRUCT(h); } +void +nni_http_handler_collect_body(nni_http_handler *h, bool want, size_t maxbody) +{ + h->getbody = want; + h->maxbody = maxbody; +} + int nni_http_handler_set_data(nni_http_handler *h, void *data, nni_cb dtor) { @@ -292,6 +304,7 @@ http_sconn_txdatdone(void *arg) return; } + sc->handler = NULL; nni_http_req_reset(sc->req); nni_http_read_req(sc->conn, sc->req, sc->rxaio); } @@ -316,6 +329,7 @@ http_sconn_txdone(void *arg) nni_http_res_free(sc->res); sc->res = NULL; } + sc->handler = NULL; nni_http_req_reset(sc->req); nni_http_read_req(sc->conn, sc->req, sc->rxaio); } @@ -457,12 +471,18 @@ http_sconn_rxdone(void *arg) bool badmeth = false; bool needhost = false; const char * host; + const char * cls; if ((rv = nni_aio_result(aio)) != 0) { http_sconn_close(sc); return; } + if ((h = sc->handler) != NULL) { + nni_mtx_lock(&s->mtx); + goto finish; + } + // Validate the request -- it has to at least look like HTTP // 1.x. We flatly refuse to deal with HTTP 0.9, and we can't // cope with HTTP/2. @@ -594,6 +614,35 @@ http_sconn_rxdone(void *arg) return; } + if ((h->getbody) && + ((cls = nni_http_req_get_header(req, "Content-Length")) != NULL)) { + uint64_t len; + + if ((nni_strtou64(cls, &len) != 0) || (len > h->maxbody)) { + nni_mtx_unlock(&s->mtx); + http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST); + return; + } + if (len > 0) { + nng_iov iov; + if ((nni_http_req_alloc_data(req, (size_t) len)) != + 0) { + nni_mtx_unlock(&s->mtx); + http_sconn_error( + sc, NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR); + return; + } + nng_http_req_get_data(req, &iov.iov_buf, &iov.iov_len); + sc->handler = h; + nni_mtx_unlock(&s->mtx); + nni_aio_set_iov(sc->rxaio, 1, &iov); + nni_http_read_full(sc->conn, aio); + return; + } + } + +finish: + sc->handler = NULL; nni_aio_set_input(sc->cbaio, 0, sc->req); nni_aio_set_input(sc->cbaio, 1, h); nni_aio_set_input(sc->cbaio, 2, sc->conn); @@ -671,6 +720,7 @@ http_sconn_cbdone(void *arg) } else { // Presumably client already sent a response. // Wait for another request. + sc->handler = NULL; nni_http_req_reset(sc->req); nni_http_read_req(sc->conn, sc->req, sc->rxaio); } @@ -747,6 +797,7 @@ http_server_acccb(void *arg) sc->server = s; nni_list_append(&s->conns, sc); + sc->handler = NULL; nni_http_read_req(sc->conn, sc->req, sc->rxaio); nni_tcp_listener_accept(s->listener, s->accaio); nni_mtx_unlock(&s->mtx); @@ -1345,6 +1396,9 @@ nni_http_handler_init_file_ctype(nni_http_handler **hpp, const char *uri, return (rv); } + // We don't permit a body for getting a file. + nni_http_handler_collect_body(h, true, 0); + *hpp = h; return (0); } @@ -1505,6 +1559,8 @@ nni_http_handler_init_directory( http_file_free(hf); return (rv); } + // We don't permit a body for getting a file. + nni_http_handler_collect_body(h, true, 0); if (((rv = nni_http_handler_set_tree(h)) != 0) || ((rv = nni_http_handler_set_data(h, hf, http_file_free)) != 0)) { @@ -1596,6 +1652,9 @@ nni_http_handler_init_static(nni_http_handler **hpp, const char *uri, return (rv); } + // We don't permit a body for getting static data. + nni_http_handler_collect_body(h, true, 0); + *hpp = h; return (0); } |
