diff options
| author | Garrett D'Amore <garrett@damore.org> | 2018-01-05 14:44:10 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2018-01-05 15:17:27 -0800 |
| commit | 1b2f22fd68a2e50cabdfe2e036096cc9e7a05a1f (patch) | |
| tree | 95fc90338cbe38a46e561511604cf8ed079934fd /src/supplemental/http | |
| parent | 224dae56a379aa309fca261d61e7e356b14a536f (diff) | |
| download | nng-1b2f22fd68a2e50cabdfe2e036096cc9e7a05a1f.tar.gz nng-1b2f22fd68a2e50cabdfe2e036096cc9e7a05a1f.tar.bz2 nng-1b2f22fd68a2e50cabdfe2e036096cc9e7a05a1f.zip | |
Convert existing websocket and http code to use new URL framework.
This also fixes a use-after-free bug in the HTTP framework, where the
handler could be deleted why callbacks were still using it. (We now
reference count the handlers.)
Diffstat (limited to 'src/supplemental/http')
| -rw-r--r-- | src/supplemental/http/server.c | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/src/supplemental/http/server.c b/src/supplemental/http/server.c index cce73765..01f1230d 100644 --- a/src/supplemental/http/server.c +++ b/src/supplemental/http/server.c @@ -35,6 +35,7 @@ typedef struct http_handler { char * h_host; bool h_is_upgrader; bool h_is_dir; + int h_refcnt; void (*h_cb)(nni_aio *); void (*h_free)(void *); } http_handler; @@ -72,6 +73,7 @@ struct nni_http_server { static nni_list http_servers; static nni_mtx http_servers_lk; +static void http_handler_fini(http_handler *); static void http_sconn_reap(void *arg) @@ -372,6 +374,7 @@ http_sconn_rxdone(void *arg) strncpy(uri, val, urisz); path = http_uri_canonify(uri); + nni_mtx_lock(&s->mtx); NNI_LIST_FOREACH (&s->handlers, h) { size_t len; if (h->h_host != NULL) { @@ -438,6 +441,7 @@ http_sconn_rxdone(void *arg) nni_free(uri, urisz); if (h == NULL) { + nni_mtx_unlock(&s->mtx); if (badmeth) { http_sconn_error( sc, NNI_HTTP_STATUS_METHOD_NOT_ALLOWED); @@ -450,23 +454,27 @@ http_sconn_rxdone(void *arg) nni_aio_set_input(sc->cbaio, 0, sc->http); nni_aio_set_input(sc->cbaio, 1, sc->req); nni_aio_set_input(sc->cbaio, 2, h->h_arg); - nni_aio_set_data(sc->cbaio, 1, h); // Technically, probably callback should initialize this with // start, but we do it instead. if (nni_aio_start(sc->cbaio, NULL, NULL) == 0) { + nni_aio_set_data(sc->cbaio, 1, h); + h->h_refcnt++; h->h_cb(sc->cbaio); } + nni_mtx_unlock(&s->mtx); } static void http_sconn_cbdone(void *arg) { - http_sconn * sc = arg; - nni_aio * aio = sc->cbaio; - nni_http_res *res; - http_handler *h; + http_sconn * sc = arg; + nni_aio * aio = sc->cbaio; + nni_http_res * res; + http_handler * h; + nni_http_server *s = sc->server; + bool upgrader; if (nni_aio_result(aio) != 0) { // Hard close, no further feedback. @@ -477,10 +485,18 @@ http_sconn_cbdone(void *arg) h = nni_aio_get_data(aio, 1); res = nni_aio_get_output(aio, 0); + nni_mtx_lock(&s->mtx); + upgrader = h->h_is_upgrader; + h->h_refcnt--; + if (h->h_refcnt == 0) { + http_handler_fini(h); + } + nni_mtx_unlock(&s->mtx); + // If its an upgrader, and they didn't give us back a response, it // means that they took over, and we should just discard this session, // without closing the underlying channel. - if ((h->h_is_upgrader) && (res == NULL)) { + if (upgrader && (res == NULL)) { sc->http = NULL; // the underlying HTTP is not closed sc->req = NULL; sc->res = NULL; @@ -795,13 +811,11 @@ http_server_add_handler(void **hp, nni_http_server *s, nni_http_handler *hh, h->h_is_upgrader = hh->h_is_upgrader; h->h_free = freeit; - // Ignore the port part of the host. + // When registering the handler, only register *host*, not port. if (hh->h_host != NULL) { - int rv; - rv = nni_tran_parse_host_port(hh->h_host, &h->h_host, NULL); - if (rv != 0) { + if ((h->h_host = nni_strdup(hh->h_host)) == NULL) { http_handler_fini(h); - return (rv); + return (NNG_ENOMEM); } } @@ -847,6 +861,7 @@ http_server_add_handler(void **hp, nni_http_server *s, nni_http_handler *hh, return (NNG_EADDRINUSE); } } + h->h_refcnt = 1; nni_list_append(&s->handlers, h); nni_mtx_unlock(&s->mtx); if (hp != NULL) { @@ -869,9 +884,11 @@ nni_http_server_del_handler(nni_http_server *s, void *harg) nni_mtx_lock(&s->mtx); nni_list_node_remove(&h->node); + h->h_refcnt--; + if (h->h_refcnt == 0) { + http_handler_fini(h); + } nni_mtx_unlock(&s->mtx); - - http_handler_fini(h); } // Very limited MIME type map. Used only if the handler does not |
