diff options
| author | Robert Bielik <robert.bielik@dirac.com> | 2020-01-28 07:43:09 +0100 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2020-01-27 22:43:09 -0800 |
| commit | 2545add6240145b419357b9260ae5e8c0d95ba6c (patch) | |
| tree | 155ae2ccfc4c720df7206c7fc81f68531624bc35 /src/supplemental/http | |
| parent | 9414a69a9575564d04022aef9bd898028e52bf09 (diff) | |
| download | nng-2545add6240145b419357b9260ae5e8c0d95ba6c.tar.gz nng-2545add6240145b419357b9260ae5e8c0d95ba6c.tar.bz2 nng-2545add6240145b419357b9260ae5e8c0d95ba6c.zip | |
Add possibility to explicitly set a tree handler as exclusive (#1158)
- Default tree handler behavior is now non-exclusive
- Add 'longest uri first' ordering for http handlers
Diffstat (limited to 'src/supplemental/http')
| -rw-r--r-- | src/supplemental/http/http_api.h | 7 | ||||
| -rw-r--r-- | src/supplemental/http/http_public.c | 11 | ||||
| -rw-r--r-- | src/supplemental/http/http_server.c | 81 |
3 files changed, 80 insertions, 19 deletions
diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 45738318..6be681a9 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -301,6 +301,13 @@ extern void nni_http_handler_collect_body(nni_http_handler *, bool, size_t); // will probably need to inspect the URL of the request. extern int nni_http_handler_set_tree(nni_http_handler *); +// nni_http_handler_set_tree_exclusive marks the handler as servicing the +// entire tree (e.g. a directory) exclusively, rather than just a leaf node. +// When servicing a tree exclusively, other handlers sharing parts of the uri +// will induce an address conflict when adding them to a server. The handler +// will probably need to inspect the URL of the request. +extern int nni_http_handler_set_tree_exclusive(nni_http_handler *); + // nni_http_handler_set_host limits the handler to only being called for // the given Host: field. This can be used to set up multiple virtual // hosts. Note that host names must match exactly. If NULL or an empty diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index d2e876ab..60ca2693 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -636,6 +636,17 @@ nng_http_handler_set_tree(nng_http_handler *h) } int +nng_http_handler_set_tree_exclusive(nng_http_handler *h) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_handler_set_tree_exclusive(h)); +#else + NNI_ARG_UNUSED(h); + return (NNG_ENOTSUP); +#endif +} + +int nng_http_handler_set_data(nng_http_handler *h, void *dat, void (*dtor)(void *)) { #ifdef NNG_SUPP_HTTP diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index da12c20d..5eadf6d5 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -3,6 +3,7 @@ // Copyright 2018 Capitar IT Group BV <info@capitar.com> // Copyright 2018 QXSoftware <lh563566994@126.com> // Copyright 2019 Devolutions <info@devolutions.net> +// Copyright 2020 Dirac Research <robert.bielik@dirac.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -37,6 +38,7 @@ struct nng_http_handler { char * method; char * host; bool tree; + bool tree_exclusive; nni_atomic_u64 ref; nni_atomic_bool busy; size_t maxbody; @@ -110,11 +112,12 @@ 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->cb = cb; + h->data = NULL; + h->dtor = NULL; + h->host = NULL; + h->tree = false; + h->tree_exclusive = false; h->maxbody = 1024 * 1024; // By default we accept up to 1MB of body h->getbody = true; *hp = h; @@ -177,7 +180,19 @@ nni_http_handler_set_tree(nni_http_handler *h) if (nni_atomic_get_bool(&h->busy) != 0) { return (NNG_EBUSY); } - h->tree = true; + h->tree = true; + h->tree_exclusive = false; + return (0); +} + +int +nni_http_handler_set_tree_exclusive(nni_http_handler *h) +{ + if (nni_atomic_get_bool(&h->busy) != 0) { + return (NNG_EBUSY); + } + h->tree = true; + h->tree_exclusive = true; return (0); } @@ -1115,8 +1130,8 @@ nni_http_server_add_handler(nni_http_server *s, nni_http_handler *h) } nni_mtx_lock(&s->mtx); - // General rule for finding a conflict is that if either string - // is a strict substring of the other, then we have a + // General rule for finding a conflict is that if either uri + // string is an exact duplicate of the other, then we have a // collision. (But only if the methods match, and the host // matches.) Note that a wild card host matches both. NNI_LIST_FOREACH (&s->handlers, h2) { @@ -1146,26 +1161,54 @@ nni_http_server_add_handler(nni_http_server *s, nni_http_handler *h) while ((len2 > 0) && (h2->uri[len2 - 1] == '/')) { len2--; // ignore trailing '/' } - if (strncmp(h->uri, h2->uri, len > len2 ? len2 : len) != 0) { - continue; // prefixes don't match. - } - if (len2 > len) { - if ((h2->uri[len] == '/') && (h->tree)) { - nni_mtx_unlock(&s->mtx); - return (NNG_EADDRINUSE); + if ((h2->tree && h2->tree_exclusive) || + (h->tree && h->tree_exclusive)) { + // Old behavior + if (strncmp(h->uri, h2->uri, + len > len2 ? len2 : len) != 0) { + continue; // prefixes don't match. } - } else if (len > len2) { - if ((h->uri[len2] == '/') && (h2->tree)) { + + if (len2 > len) { + if ((h2->uri[len] == '/') && (h->tree)) { + nni_mtx_unlock(&s->mtx); + return (NNG_EADDRINUSE); + } + } else if (len > len2) { + if ((h->uri[len2] == '/') && (h2->tree)) { + nni_mtx_unlock(&s->mtx); + return (NNG_EADDRINUSE); + } + } else { nni_mtx_unlock(&s->mtx); return (NNG_EADDRINUSE); } } else { + if (len != len2) { + continue; // length mismatch + } + + if (strcmp(h->uri, h2->uri) != 0) { + continue; // not a duplicate + } + nni_mtx_unlock(&s->mtx); return (NNG_EADDRINUSE); } } - nni_list_append(&s->handlers, h); + + // Maintain list of handlers in longest uri first order + NNI_LIST_FOREACH (&s->handlers, h2) { + size_t len2 = strlen(h2->uri); + if (len > len2) { + nni_list_insert_before(&s->handlers, h, h2); + break; + } + } + if (h2 == NULL) { + nni_list_append(&s->handlers, h); + } // Note that we have borrowed the reference count on the handler. // Thus we own it, and if the server is destroyed while we have it, @@ -1533,7 +1576,7 @@ nni_http_handler_init_directory( // 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) || + if (((rv = nni_http_handler_set_tree_exclusive(h)) != 0) || ((rv = nni_http_handler_set_data(h, hf, http_file_free)) != 0)) { http_file_free(hf); nni_http_handler_fini(h); |
