From 6800bdd8b9e3fd4488bab56cd9fb12206d0631f6 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 11:17:24 -0800 Subject: [PATCH 01/10] http handler: avoid method allocation We limit HTTP method lengths to 32.. there are no currently defined HTTP methods that need more than 19 bytes (including trailing zero.) Generally most servers will not have vast numbers of handlers, so the cost of allocating some storage up front to avoid the dynamic allocation is worth while. --- src/supplemental/http/http_server.c | 34 ++++++++++-------------- src/supplemental/http/http_server_test.c | 15 +++++++++++ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index 64edf4568..ba89626be 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -25,7 +25,7 @@ struct nng_http_handler { nni_list_node node; char *uri; - char *method; + char method[32]; char *host; nng_sockaddr host_addr; bool host_ip; @@ -114,8 +114,7 @@ nni_http_handler_init( if ((uri == NULL) || (strlen(uri) == 0) || (strcmp(uri, "/") == 0)) { uri = ""; } - if (((h->uri = nni_strdup(uri)) == NULL) || - ((h->method = nni_strdup("GET")) == NULL)) { + if ((h->uri = nni_strdup(uri)) == NULL) { nni_http_handler_fini(h); return (NNG_ENOMEM); } @@ -126,9 +125,10 @@ nni_http_handler_init( 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; + h->maxbody = 1024 * 1024; // Up to 1MB of body + h->getbody = true; + strcpy(h->method, "GET"); + *hp = h; return (0); } @@ -145,7 +145,6 @@ nni_http_handler_fini(nni_http_handler *h) } nni_strfree(h->host); nni_strfree(h->uri); - nni_strfree(h->method); NNI_FREE_STRUCT(h); } @@ -252,21 +251,16 @@ nni_http_handler_set_host(nni_http_handler *h, const char *host) int nni_http_handler_set_method(nni_http_handler *h, const char *method) { - char *dup; - if (nni_atomic_get_bool(&h->busy) != 0) { return (NNG_EBUSY); } if (method == NULL) { - nni_strfree(h->method); - h->method = NULL; - return (0); + method = ""; } - if ((dup = nni_strdup(method)) == NULL) { - return (NNG_ENOMEM); + if (strlen(method) >= sizeof(h->method)) { + return (NNG_EINVAL); } - nni_strfree(h->method); - h->method = dup; + (void) snprintf(h->method, sizeof(h->method), "%s", method); return (0); } @@ -663,7 +657,7 @@ http_sconn_rxdone(void *arg) continue; // Some other substring, not matched. } - if ((h->method == NULL) || (h->method[0] == '\0')) { + if (h->method[0] == '\0') { // Handler wants to process *all* methods. break; } @@ -1220,11 +1214,11 @@ nni_http_server_add_handler(nni_http_server *s, nni_http_handler *h) ((h->host == NULL) && (h2->host != NULL))) { continue; // Host specified for just one. } - if (((h->method == NULL) && (h2->method != NULL)) || - ((h2->method == NULL) && (h->method != NULL))) { + if (((h->method[0] == 0) && (h2->method[0] != 0)) || + ((h2->method[0] == 0) && (h->method[0] != 0))) { continue; // Method specified for just one. } - if ((h->method != NULL) && + if ((h->method[0] != 0) && (strcmp(h2->method, h->method) != 0)) { // Different methods, so again we are fine. continue; diff --git a/src/supplemental/http/http_server_test.c b/src/supplemental/http/http_server_test.c index 2d1e4b287..2ed04c4dc 100644 --- a/src/supplemental/http/http_server_test.c +++ b/src/supplemental/http/http_server_test.c @@ -338,6 +338,20 @@ test_server_missing_host(void) server_free(&st); } +void +test_server_method_too_long(void) +{ + nng_http_handler *h; + + NUTS_PASS(nng_http_handler_alloc_static( + &h, "/home.html", doc1, strlen(doc1), "text/html")); + + NUTS_FAIL(nng_http_handler_set_method(h, + "THISMETHODISFARFARTOOLONGTOBEVALIDASAMETHODASITISLONGER" + "THANTHIRTYTWOBYTES"), + NNG_EINVAL); +} + void test_server_wrong_method(void) { @@ -898,6 +912,7 @@ NUTS_TESTS = { { "server bad version", test_server_bad_version }, { "server missing host", test_server_missing_host }, { "server wrong method", test_server_wrong_method }, + { "server method too long", test_server_method_too_long }, { "server post handler", test_server_post_handler }, { "server get redirect", test_server_get_redirect }, { "server tree redirect", test_server_tree_redirect }, From 8d1b52931b1d7ad8fabffe0098b9bc31c0b61a9b Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 11:40:36 -0800 Subject: [PATCH 02/10] http: method on request structure is now static This saves yet another allocation. It also no longer returns a value making this a breaking change. --- demo/rest/server.c | 33 ++++++++++----------- docs/man/nng_http_req_set_method.3http.adoc | 15 +++------- docs/ref/migrate/nng1.md | 4 +++ include/nng/supplemental/http/http.h | 2 +- src/supplemental/http/http_api.h | 2 +- src/supplemental/http/http_msg.c | 30 ++++++++++--------- src/supplemental/http/http_public.c | 5 ++-- src/supplemental/http/http_server_test.c | 14 ++++----- 8 files changed, 51 insertions(+), 54 deletions(-) diff --git a/demo/rest/server.c b/demo/rest/server.c index 5a59756c9..ee4047b55 100644 --- a/demo/rest/server.c +++ b/demo/rest/server.c @@ -73,11 +73,11 @@ typedef enum { } job_state; typedef struct rest_job { - nng_aio * http_aio; // aio from HTTP we must reply to - nng_http_res * http_res; // HTTP response object + nng_aio *http_aio; // aio from HTTP we must reply to + nng_http_res *http_res; // HTTP response object job_state state; // 0 = sending, 1 = receiving - nng_msg * msg; // request message - nng_aio * aio; // request flow + nng_msg *msg; // request message + nng_aio *aio; // request flow nng_ctx ctx; // context on the request socket struct rest_job *next; // next on the freelist } rest_job; @@ -86,7 +86,7 @@ nng_socket req_sock; // We maintain a queue of free jobs. This way we don't have to // deallocate them from the callback; we just reuse them. -nng_mtx * job_lock; +nng_mtx *job_lock; rest_job *job_freelist; static void rest_job_cb(void *arg); @@ -139,7 +139,7 @@ static void rest_http_fatal(rest_job *job, const char *fmt, int rv) { char buf[128]; - nng_aio * aio = job->http_aio; + nng_aio *aio = job->http_aio; nng_http_res *res = job->http_res; job->http_res = NULL; @@ -156,7 +156,7 @@ static void rest_job_cb(void *arg) { rest_job *job = arg; - nng_aio * aio = job->aio; + nng_aio *aio = job->aio; int rv; switch (job->state) { @@ -205,13 +205,13 @@ void rest_handle(nng_aio *aio) { struct rest_job *job; - nng_http_req * req = nng_aio_get_input(aio, 0); - nng_http_conn * conn = nng_aio_get_input(aio, 2); - const char * clen; + nng_http_req *req = nng_aio_get_input(aio, 0); + nng_http_conn *conn = nng_aio_get_input(aio, 2); + const char *clen; size_t sz; nng_iov iov; int rv; - void * data; + void *data; if ((job = rest_get_job()) == NULL) { nng_aio_finish(aio, NNG_ENOMEM); @@ -241,10 +241,10 @@ rest_handle(nng_aio *aio) void rest_start(uint16_t port) { - nng_http_server * server; + nng_http_server *server; nng_http_handler *handler; char rest_addr[128]; - nng_url * url; + nng_url *url; int rv; if ((rv = nng_mtx_alloc(&job_lock)) != 0) { @@ -282,9 +282,8 @@ rest_start(uint16_t port) fatal("nng_http_handler_alloc", rv); } - if ((rv = nng_http_handler_set_method(handler, "POST")) != 0) { - fatal("nng_http_handler_set_method", rv); - } + nng_http_handler_set_method(handler, "POST"); + // We want to collect the body, and we (arbitrarily) limit this to // 128KB. The default limit is 1MB. You can explicitly collect // the data yourself with another HTTP read transaction by disabling @@ -317,7 +316,7 @@ inproc_server(void *arg) { nng_socket s; int rv; - nng_msg * msg; + nng_msg *msg; if (((rv = nng_rep0_open(&s)) != 0) || ((rv = nng_listen(s, INPROC_URL, NULL, 0)) != 0)) { diff --git a/docs/man/nng_http_req_set_method.3http.adoc b/docs/man/nng_http_req_set_method.3http.adoc index bc80b8328..9cd4f638a 100644 --- a/docs/man/nng_http_req_set_method.3http.adoc +++ b/docs/man/nng_http_req_set_method.3http.adoc @@ -20,7 +20,7 @@ nng_http_req_set_method - set HTTP request method #include #include -int nng_http_req_set_method(nng_http_req *req, const char *method); +void nng_http_req_set_method(nng_http_req *req, const char *method); ---- == DESCRIPTION @@ -32,17 +32,10 @@ be upper case. The default value method for newly allocated requests is "GET". -A local copy of the _method_ is made in the request _req_. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. +If the method is longer than 32 bytes, it may be silently truncated. +(There are no methods defined that are this long.) -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. +A local copy of the _method_ is made in the request _req_. == SEE ALSO diff --git a/docs/ref/migrate/nng1.md b/docs/ref/migrate/nng1.md index bff5b5815..bca68e386 100644 --- a/docs/ref/migrate/nng1.md +++ b/docs/ref/migrate/nng1.md @@ -219,6 +219,10 @@ accessors functions are provided: - `u_host` is removed - use [`nng_url_hostname`] and [`nng_url_port`] to construct if needed - `u_rawurl` is removed - a "cooked" URL can be obtained from the new [`nng_url_sprintf`] function. +## HTTP API + +The [`nng_http_req_set_method`] no longer returns a value. It never fails, but it may truncate an unreasonably long value. + ## Security Descriptors (Windows Only) The `NNG_OPT_IPC_SECURITY_DESCRIPTOR` option is removed, and replaced diff --git a/include/nng/supplemental/http/http.h b/include/nng/supplemental/http/http.h index bb163949a..8cceae9e2 100644 --- a/include/nng/supplemental/http/http.h +++ b/include/nng/supplemental/http/http.h @@ -136,7 +136,7 @@ NNG_DECL const char *nng_http_req_get_header( // nng_http_req_set_method is used to change the method of a request. // The method should be an upper case HTTP method, like POST, or DELETE. // Null sets the default ("GET"). -NNG_DECL int nng_http_req_set_method(nng_http_req *, const char *); +NNG_DECL void nng_http_req_set_method(nng_http_req *, const char *); // nng_http_req_set_version is used to change the version of a request. // Normally the version is "HTTP/1.1". Note that the framework does diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 46a022113..27559a489 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -135,7 +135,7 @@ extern int nni_http_res_alloc_data(nni_http_res *, size_t); extern const char *nni_http_req_get_method(const nni_http_req *); extern const char *nni_http_req_get_version(const nni_http_req *); extern const char *nni_http_req_get_uri(const nni_http_req *); -extern int nni_http_req_set_method(nni_http_req *, const char *); +extern void nni_http_req_set_method(nni_http_req *, const char *); extern int nni_http_req_set_version(nni_http_req *, const char *); extern int nni_http_req_set_uri(nni_http_req *, const char *); extern uint16_t nni_http_res_get_status(const nni_http_res *); diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c index afe2a3b64..564a47636 100644 --- a/src/supplemental/http/http_msg.c +++ b/src/supplemental/http/http_msg.c @@ -38,7 +38,7 @@ typedef struct nni_http_entity { struct nng_http_req { nni_list hdrs; nni_http_entity data; - char *meth; + char meth[32]; char *uri; const char *vers; char *buf; @@ -100,14 +100,14 @@ nni_http_req_reset(nni_http_req *req) { http_headers_reset(&req->hdrs); http_entity_reset(&req->data); - nni_strfree(req->meth); nni_strfree(req->uri); - req->meth = req->uri = NULL; + req->uri = NULL; nni_free(req->buf, req->bufsz); + nni_http_req_set_method(req, NULL); + nni_http_req_set_version(req, NNG_HTTP_VERSION_1_1); req->bufsz = 0; req->buf = NULL; req->parsed = false; - req->vers = NNG_HTTP_VERSION_1_1; } void @@ -532,7 +532,7 @@ http_req_prepare(nni_http_req *req) return (NNG_EINVAL); } rv = http_asprintf(&req->buf, &req->bufsz, &req->hdrs, "%s %s %s\r\n", - req->meth != NULL ? req->meth : "GET", req->uri, req->vers); + req->meth, req->uri, req->vers); return (rv); } @@ -611,9 +611,9 @@ nni_http_req_alloc(nni_http_req **reqp, const nng_url *url) req->data.data = NULL; req->data.size = 0; req->data.own = false; - req->vers = NNG_HTTP_VERSION_1_1; - req->meth = NULL; req->uri = NULL; + nni_http_req_set_version(req, NNG_HTTP_VERSION_1_1); + nni_http_req_set_method(req, "GET"); if (url != NULL) { const char *host; char host_buf[264]; // 256 + 8 for port @@ -673,7 +673,7 @@ nni_http_res_alloc(nni_http_res **resp) const char * nni_http_req_get_method(const nni_http_req *req) { - return (req->meth != NULL ? req->meth : "GET"); + return (req->meth); } const char * @@ -735,13 +735,15 @@ nni_http_req_set_uri(nni_http_req *req, const char *uri) return (http_set_string(&req->uri, uri)); } -int +void nni_http_req_set_method(nni_http_req *req, const char *meth) { - if ((meth != NULL) && (strcmp(meth, "GET") == 0)) { - meth = NULL; + if (meth == NULL) { + meth = "GET"; } - return (http_set_string(&req->meth, meth)); + // this may truncate the method, but nobody should be sending + // methods so long. + (void) snprintf(req->meth, sizeof(req->meth), "%s", meth); } int @@ -811,8 +813,8 @@ http_req_parse_line(nni_http_req *req, void *line) *version = '\0'; version++; - if (((rv = nni_http_req_set_method(req, method)) != 0) || - ((rv = nni_http_req_set_uri(req, uri)) != 0) || + nni_http_req_set_method(req, method); + if (((rv = nni_http_req_set_uri(req, uri)) != 0) || ((rv = nni_http_req_set_version(req, version)) != 0)) { return (rv); } diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index 161aefd88..c9983df55 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -280,15 +280,14 @@ nng_http_req_get_uri(const nng_http_req *req) #endif } -int +void nng_http_req_set_method(nng_http_req *req, const char *meth) { #ifdef NNG_SUPP_HTTP - return (nni_http_req_set_method(req, meth)); + nni_http_req_set_method(req, meth); #else NNI_ARG_UNUSED(req); NNI_ARG_UNUSED(meth); - return (NNG_ENOTSUP); #endif } diff --git a/src/supplemental/http/http_server_test.c b/src/supplemental/http/http_server_test.c index 2ed04c4dc..ddae77d33 100644 --- a/src/supplemental/http/http_server_test.c +++ b/src/supplemental/http/http_server_test.c @@ -363,7 +363,7 @@ test_server_wrong_method(void) server_setup(&st, h); - NUTS_PASS(nng_http_req_set_method(st.req, "POST")); + nng_http_req_set_method(st.req, "POST"); NUTS_PASS(nng_http_req_set_uri(st.req, "/home.html")); nng_http_conn_write_req(st.conn, st.req, st.aio); @@ -400,7 +400,7 @@ test_server_post_handler(void) snprintf(txdata, sizeof(txdata), "1234"); nng_http_req_set_uri(st.req, "/post"); nng_http_req_set_data(st.req, txdata, strlen(txdata)); - NUTS_PASS(nng_http_req_set_method(st.req, "POST")); + nng_http_req_set_method(st.req, "POST"); NUTS_PASS(httpdo(st.url, st.req, st.res, (void **) &rxdata, &size)); NUTS_TRUE(nng_http_res_get_status(st.res) == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(txdata)); @@ -410,7 +410,7 @@ test_server_post_handler(void) server_reset(&st); NUTS_PASS(nng_http_req_set_uri(st.req, "/post")); - NUTS_PASS(nng_http_req_set_method(st.req, "GET")); + nng_http_req_set_method(st.req, "GET"); NUTS_PASS(nng_http_req_set_data(st.req, txdata, strlen(txdata))); NUTS_PASS(httpdo(st.url, st.req, st.res, &data, &size)); @@ -501,7 +501,7 @@ test_server_post_redirect(void) snprintf(txdata, sizeof(txdata), "1234"); NUTS_PASS(nng_http_req_set_uri(st.req, "/here")); nng_http_req_set_data(st.req, txdata, strlen(txdata)); - NUTS_PASS(nng_http_req_set_method(st.req, "POST")); + nng_http_req_set_method(st.req, "POST"); NUTS_PASS(httpdo(st.url, st.req, st.res, (void **) &data, &size)); NUTS_TRUE(nng_http_res_get_status(st.res) == 301); dest = nng_http_res_get_header(st.res, "Location"); @@ -521,14 +521,14 @@ test_server_post_echo_tree(void) char *rxdata; NUTS_PASS(nng_http_handler_alloc(&h, "/", httpecho)); - NUTS_PASS(nng_http_handler_set_method(h, "POST")); + nng_http_handler_set_method(h, "POST"); NUTS_PASS(nng_http_handler_set_tree(h)); server_setup(&st, h); snprintf(txdata, sizeof(txdata), "1234"); nng_http_req_set_data(st.req, txdata, strlen(txdata)); - NUTS_PASS(nng_http_req_set_method(st.req, "POST")); + nng_http_req_set_method(st.req, "POST"); NUTS_PASS(nng_http_req_set_uri(st.req, "/some_sub/directory")); NUTS_PASS(httpdo(st.url, st.req, st.res, (void **) &rxdata, &size)); NUTS_TRUE(nng_http_res_get_status(st.res) == NNG_HTTP_STATUS_OK); @@ -866,7 +866,7 @@ test_serve_index_not_post(void) server_setup(&st, h); NUTS_PASS(nng_http_req_set_uri(st.req, "/subdir2/index.html")); - NUTS_PASS(nng_http_req_set_method(st.req, "POST")); + nng_http_req_set_method(st.req, "POST"); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_METHOD_NOT_ALLOWED); nng_strfree(ctype); From 497b8e22047fb0efa3397289d23656d6483fdd6d Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 11:52:04 -0800 Subject: [PATCH 03/10] http: setting response status never fails (breaking API change) --- docs/man/nng_http_res_set_status.3http.adoc | 11 +---------- docs/ref/migrate/nng1.md | 3 ++- include/nng/supplemental/http/http.h | 2 +- src/supplemental/http/http_api.h | 2 +- src/supplemental/http/http_msg.c | 8 ++++---- src/supplemental/http/http_public.c | 5 ++--- src/supplemental/http/http_server.c | 13 +++++++++---- src/supplemental/http/http_server_test.c | 4 ++-- src/supplemental/websocket/websocket.c | 6 +----- 9 files changed, 23 insertions(+), 31 deletions(-) diff --git a/docs/man/nng_http_res_set_status.3http.adoc b/docs/man/nng_http_res_set_status.3http.adoc index e57764d4d..a13749414 100644 --- a/docs/man/nng_http_res_set_status.3http.adoc +++ b/docs/man/nng_http_res_set_status.3http.adoc @@ -20,7 +20,7 @@ nng_http_res_set_status - set HTTP response status #include #include -int nng_http_res_set_status(nng_http_res *res, uint16_t status); +void nng_http_res_set_status(nng_http_res *res, uint16_t status); ---- == DESCRIPTION @@ -106,15 +106,6 @@ TIP: It is a good idea to also set the reason message with xref:nng_http_res_set_reason.3http.adoc[`nng_http_set_reason()`]. This will help any humans who may have to diagnose a failure. -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOTSUP`:: No support for HTTP in the library. - == SEE ALSO [.text-left] diff --git a/docs/ref/migrate/nng1.md b/docs/ref/migrate/nng1.md index bca68e386..8a1af631e 100644 --- a/docs/ref/migrate/nng1.md +++ b/docs/ref/migrate/nng1.md @@ -221,7 +221,8 @@ accessors functions are provided: ## HTTP API -The [`nng_http_req_set_method`] no longer returns a value. It never fails, but it may truncate an unreasonably long value. +- [`nng_http_req_set_method`] no longer returns a value. It never fails, but it may truncate an unreasonably long value. +- [`nng_http_res_set_status`] no longer returns a value, and cannot fail. ## Security Descriptors (Windows Only) diff --git a/include/nng/supplemental/http/http.h b/include/nng/supplemental/http/http.h index 8cceae9e2..fa485243a 100644 --- a/include/nng/supplemental/http/http.h +++ b/include/nng/supplemental/http/http.h @@ -183,7 +183,7 @@ NNG_DECL void nng_http_res_free(nng_http_res *); NNG_DECL uint16_t nng_http_res_get_status(const nng_http_res *); // nng_http_res_set_status sets the HTTP status code. -NNG_DECL int nng_http_res_set_status(nng_http_res *, uint16_t); +NNG_DECL void nng_http_res_set_status(nng_http_res *, uint16_t); // nng_http_res_get_reason returns the human readable status message // that the server responds (or responded) with. diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 27559a489..349f3a497 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -139,7 +139,7 @@ extern void nni_http_req_set_method(nni_http_req *, const char *); extern int nni_http_req_set_version(nni_http_req *, const char *); extern int nni_http_req_set_uri(nni_http_req *, const char *); extern uint16_t nni_http_res_get_status(const nni_http_res *); -extern int nni_http_res_set_status(nni_http_res *, uint16_t); +extern void nni_http_res_set_status(nni_http_res *, uint16_t); extern const char *nni_http_res_get_version(const nni_http_res *); extern int nni_http_res_set_version(nni_http_res *, const char *); extern const char *nni_http_res_get_reason(const nni_http_res *); diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c index 564a47636..1a288beed 100644 --- a/src/supplemental/http/http_msg.c +++ b/src/supplemental/http/http_msg.c @@ -746,11 +746,10 @@ nni_http_req_set_method(nni_http_req *req, const char *meth) (void) snprintf(req->meth, sizeof(req->meth), "%s", meth); } -int +void nni_http_res_set_status(nni_http_res *res, uint16_t status) { res->code = status; - return (0); } uint16_t @@ -849,8 +848,9 @@ http_res_parse_line(nni_http_res *res, uint8_t *line) return (NNG_EPROTO); } - if (((rv = nni_http_res_set_status(res, (uint16_t) status)) != 0) || - ((rv = nni_http_res_set_version(res, version)) != 0) || + nni_http_res_set_status(res, (uint16_t) status); + + if (((rv = nni_http_res_set_version(res, version)) != 0) || ((rv = nni_http_res_set_reason(res, reason)) != 0)) { return (rv); } diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index c9983df55..e3093d454 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -348,15 +348,14 @@ nng_http_res_get_reason(const nng_http_res *res) #endif } -int +void nng_http_res_set_status(nng_http_res *res, uint16_t status) { #ifdef NNG_SUPP_HTTP - return (nni_http_res_set_status(res, status)); + nni_http_res_set_status(res, status); #else NNI_ARG_UNUSED(res); NNI_ARG_UNUSED(status); - return (NNG_ENOTSUP); #endif } diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index ba89626be..fa9ad2f4a 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -1416,7 +1416,6 @@ http_handle_file(nni_aio *aio) return; } if (((rv = nni_http_res_alloc(&res)) != 0) || - ((rv = nni_http_res_set_status(res, NNG_HTTP_STATUS_OK)) != 0) || ((rv = nni_http_res_set_header(res, "Content-Type", ctype)) != 0) || ((rv = nni_http_res_copy_data(res, data, size)) != 0)) { @@ -1426,6 +1425,8 @@ http_handle_file(nni_aio *aio) return; } + nni_http_res_set_status(res, NNG_HTTP_STATUS_OK); + nni_free(data, size); nni_aio_set_output(aio, 0, res); nni_aio_finish(aio, 0, 0); @@ -1610,7 +1611,6 @@ http_handle_dir(nni_aio *aio) } if (((rv = nni_http_res_alloc(&res)) != 0) || - ((rv = nni_http_res_set_status(res, NNG_HTTP_STATUS_OK)) != 0) || ((rv = nni_http_res_set_header(res, "Content-Type", ctype)) != 0) || ((rv = nni_http_res_copy_data(res, data, size)) != 0)) { @@ -1620,6 +1620,8 @@ http_handle_dir(nni_aio *aio) return; } + nni_http_res_set_status(res, NNG_HTTP_STATUS_OK); + nni_free(data, size); nni_aio_set_output(aio, 0, res); nni_aio_finish(aio, 0, 0); @@ -1707,7 +1709,6 @@ http_handle_redirect(nni_aio *aio) // discard it. if ((rv != 0) || ((rv = nni_http_res_alloc(&r)) != 0) || ((rv = nni_http_alloc_html_error(&html, hr->code, msg)) != 0) || - ((rv = nni_http_res_set_status(r, hr->code)) != 0) || ((rv = nni_http_res_set_header(r, "Connection", "close")) != 0) || ((rv = nni_http_res_set_header( r, "Content-Type", "text/html; charset=UTF-8")) != 0) || @@ -1722,6 +1723,9 @@ http_handle_redirect(nni_aio *aio) nni_aio_finish_error(aio, rv); return; } + + nni_http_res_set_status(r, hr->code); + if (loc != hr->where) { nni_strfree(loc); } @@ -1807,13 +1811,14 @@ http_handle_static(nni_aio *aio) if (((rv = nni_http_res_alloc(&r)) != 0) || ((rv = nni_http_res_set_header(r, "Content-Type", ctype)) != 0) || - ((rv = nni_http_res_set_status(r, NNG_HTTP_STATUS_OK)) != 0) || ((rv = nni_http_res_set_data(r, hs->data, hs->size)) != 0)) { nni_http_res_free(r); nni_aio_finish_error(aio, rv); return; } + nni_http_res_set_status(r, NNG_HTTP_STATUS_OK); + nni_aio_set_output(aio, 0, r); nni_aio_finish(aio, 0, 0); } diff --git a/src/supplemental/http/http_server_test.c b/src/supplemental/http/http_server_test.c index ddae77d33..f29fa52b1 100644 --- a/src/supplemental/http/http_server_test.c +++ b/src/supplemental/http/http_server_test.c @@ -155,12 +155,12 @@ httpecho(nng_aio *aio) if (((rv = nng_http_res_alloc(&res)) != 0) || ((rv = nng_http_res_copy_data(res, body, len)) != 0) || ((rv = nng_http_res_set_header( - res, "Content-type", "text/plain")) != 0) || - ((rv = nng_http_res_set_status(res, NNG_HTTP_STATUS_OK)) != 0)) { + res, "Content-type", "text/plain")) != 0)) { nng_http_res_free(res); nng_aio_finish(aio, rv); return; } + nng_http_res_set_status(res, NNG_HTTP_STATUS_OK); nng_aio_set_output(aio, 0, res); nng_aio_finish(aio, 0); } diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c index e7372a49e..3dfb3e8e3 100644 --- a/src/supplemental/websocket/websocket.c +++ b/src/supplemental/websocket/websocket.c @@ -1604,11 +1604,7 @@ ws_handler(nni_aio *aio) goto err; } - if (nni_http_res_set_status(res, NNG_HTTP_STATUS_SWITCHING) != 0) { - nni_http_res_free(res); - status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; - goto err; - } + nni_http_res_set_status(res, NNG_HTTP_STATUS_SWITCHING); if ((SETH("Connection", "Upgrade") != 0) || (SETH("Upgrade", "websocket") != 0) || From 10f6fc5141a15e368dac813a38942cb66d5ddef4 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 12:18:33 -0800 Subject: [PATCH 04/10] HTTP handler: limit host names to 256 bytes (RFC 1035 specifies 253.) This also makes `nng_http_handler_set_host` never fail (API break). --- docs/man/nng_http_handler_set_host.3http.adoc | 15 ++---- docs/ref/migrate/nng1.md | 13 +++++- include/nng/supplemental/http/http.h | 2 +- src/supplemental/http/http_api.h | 2 +- src/supplemental/http/http_public.c | 5 +- src/supplemental/http/http_server.c | 46 +++++++------------ src/supplemental/websocket/websocket.c | 5 +- 7 files changed, 39 insertions(+), 49 deletions(-) diff --git a/docs/man/nng_http_handler_set_host.3http.adoc b/docs/man/nng_http_handler_set_host.3http.adoc index 0deae4888..3f25172ff 100644 --- a/docs/man/nng_http_handler_set_host.3http.adoc +++ b/docs/man/nng_http_handler_set_host.3http.adoc @@ -1,6 +1,6 @@ = nng_http_handler_set_host(3http) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2024 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -20,7 +20,7 @@ nng_http_handler_set_host - set host for HTTP handler #include #include -int nng_http_handler_set_host(nng_http_handler *handler, const char *host); +void nng_http_handler_set_host(nng_http_handler *handler, const char *host); ---- == DESCRIPTION @@ -41,15 +41,8 @@ ports, the port number can be elided. The matching test only considers the hostname or IP address, and ignores any trailing port number. -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. +NOTE: This should not be used with an IP address normally, as `Host:` header +is used with virtual hosts in HTTP/1.1, and not supported for HTTP/1.0. == SEE ALSO diff --git a/docs/ref/migrate/nng1.md b/docs/ref/migrate/nng1.md index 8a1af631e..544f15b6f 100644 --- a/docs/ref/migrate/nng1.md +++ b/docs/ref/migrate/nng1.md @@ -221,8 +221,19 @@ accessors functions are provided: ## HTTP API -- [`nng_http_req_set_method`] no longer returns a value. It never fails, but it may truncate an unreasonably long value. +A few limits on string lengths of certain values are now applied, which allows us to preallocate values +and eliminate certain unreasonable error paths. If values longer than these are supplied in certain APIs +they may be silently truncated to the limit: + +- Hostnames are limited per RFC 1035 to 253 characters (not including terminating "." or zero byte.) +- HTTP Method names are limited to 32 bytes (the longest IANA registered method is currently 18 bytes, used for WebDAV.) +- The fixed part of URI pathnames used with HTTP handlers is limited to 1024 bytes. + +The following API changes are present: + +- [`nng_http_req_set_method`] no longer returns a value, and cannot fail. - [`nng_http_res_set_status`] no longer returns a value, and cannot fail. +- [`nng_http_handler_set_host`] no longer returns a value and cannot fail. ## Security Descriptors (Windows Only) diff --git a/include/nng/supplemental/http/http.h b/include/nng/supplemental/http/http.h index fa485243a..729e25ad6 100644 --- a/include/nng/supplemental/http/http.h +++ b/include/nng/supplemental/http/http.h @@ -362,7 +362,7 @@ NNG_DECL int nng_http_handler_set_method(nng_http_handler *, const char *); // default, then the Host: header is not considered when matching the // handler.) Note that the Host: header must match *exactly* (except // that case is not considered.) -NNG_DECL int nng_http_handler_set_host(nng_http_handler *, const char *); +NNG_DECL void nng_http_handler_set_host(nng_http_handler *, const char *); // nng_http_handler_collect_body is used to indicate the server should // check for, and process, data sent by the client, which will be attached diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 349f3a497..d759e27b3 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -322,7 +322,7 @@ extern int nni_http_handler_set_tree_exclusive(nni_http_handler *); // on port number as we assume that clients MUST have gotten that part right // as we do not support virtual hosting on multiple separate ports; the // server only listens on a single port. -extern int nni_http_handler_set_host(nni_http_handler *, const char *); +extern void nni_http_handler_set_host(nni_http_handler *, const char *); // nni_http_handler_set_method limits the handler to only being called // for the given HTTP method. By default a handler is called for GET diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index e3093d454..a60743fde 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -609,15 +609,14 @@ nng_http_handler_collect_body(nng_http_handler *h, bool want, size_t len) #endif } -int +void nng_http_handler_set_host(nng_http_handler *h, const char *host) { #ifdef NNG_SUPP_HTTP - return (nni_http_handler_set_host(h, host)); + nni_http_handler_set_host(h, host); #else NNI_ARG_UNUSED(h); NNI_ARG_UNUSED(host); - return (NNG_ENOTSUP); #endif } diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index fa9ad2f4a..e9c8bea33 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -26,7 +26,7 @@ struct nng_http_handler { nni_list_node node; char *uri; char method[32]; - char *host; + char host[256]; // RFC 1035 nng_sockaddr host_addr; bool host_ip; bool tree; @@ -122,12 +122,12 @@ nni_http_handler_init( h->cb = cb; h->data = NULL; h->dtor = NULL; - h->host = NULL; h->tree = false; h->tree_exclusive = false; h->maxbody = 1024 * 1024; // Up to 1MB of body h->getbody = true; - strcpy(h->method, "GET"); + (void) strcpy(h->method, "GET"); + (void) strcpy(h->host, ""); *hp = h; return (0); } @@ -143,7 +143,6 @@ nni_http_handler_fini(nni_http_handler *h) if (h->dtor != NULL) { h->dtor(h->data); } - nni_strfree(h->host); nni_strfree(h->uri); NNI_FREE_STRUCT(h); } @@ -203,19 +202,15 @@ nni_http_handler_set_tree_exclusive(nni_http_handler *h) return (0); } -int +void nni_http_handler_set_host(nni_http_handler *h, const char *host) { - char *dup; + NNI_ASSERT(!nni_atomic_get_bool(&h->busy)); - if (nni_atomic_get_bool(&h->busy) != 0) { - return (NNG_EBUSY); - } if ((host == NULL) || (strcmp(host, "*") == 0) || strcmp(host, "") == 0) { - nni_strfree(h->host); - h->host = NULL; - return (0); + (void) strcpy(h->host, ""); + return; } if (nni_parse_ip(host, &h->host_addr) == 0) { uint8_t wild[16] = { 0 }; @@ -224,28 +219,21 @@ nni_http_handler_set_host(nni_http_handler *h, const char *host) switch (h->host_addr.s_family) { case NNG_AF_INET: if (h->host_addr.s_in.sa_addr == 0) { - nni_strfree(h->host); - h->host = NULL; - return (0); + (void) strcpy(h->host, ""); + return; } break; case NNG_AF_INET6: if (memcmp(h->host_addr.s_in6.sa_addr, wild, 16) == 0) { - nni_strfree(h->host); - h->host = NULL; - return (0); + (void) strcpy(h->host, ""); + return; } break; } h->host_ip = true; } - if ((dup = nni_strdup(host)) == NULL) { - return (NNG_ENOMEM); - } - nni_strfree(h->host); - h->host = dup; - return (0); + (void) snprintf(h->host, sizeof(h->host), "%s", host); } int @@ -499,7 +487,7 @@ http_handler_host_match(nni_http_handler *h, const char *host) nng_sockaddr sa; size_t len; - if (h->host == NULL) { + if ((len = strlen(h->host)) == '\0') { return (true); } if (host == NULL) { @@ -529,8 +517,6 @@ http_handler_host_match(nni_http_handler *h, const char *host) } } - len = strlen(h->host); - if ((nni_strncasecmp(host, h->host, len) != 0)) { return (false); } @@ -1205,13 +1191,13 @@ nni_http_server_add_handler(nni_http_server *s, nni_http_handler *h) NNI_LIST_FOREACH (&s->handlers, h2) { size_t len2; - if ((h2->host != NULL) && (h->host != NULL) && + if ((h2->host[0] != 0) && (h->host[0] != 0) && (nni_strcasecmp(h2->host, h->host) != 0)) { // Hosts don't match, so we are safe. continue; } - if (((h2->host == NULL) && (h->host != NULL)) || - ((h->host == NULL) && (h2->host != NULL))) { + if (((h2->host[0] == 0) && (h->host[0] != 0)) || + ((h->host[0] == 0) && (h2->host[0] != 0))) { continue; // Host specified for just one. } if (((h->method[0] == 0) && (h2->method[0] != 0)) || diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c index 3dfb3e8e3..ba3041495 100644 --- a/src/supplemental/websocket/websocket.c +++ b/src/supplemental/websocket/websocket.c @@ -2150,8 +2150,9 @@ nni_ws_listener_alloc(nng_stream_listener **wslp, const nng_url *url) return (rv); } - if (((rv = nni_http_handler_set_host(l->handler, host)) != 0) || - ((rv = nni_http_handler_set_data(l->handler, l, 0)) != 0) || + nni_http_handler_set_host(l->handler, host); + + if (((rv = nni_http_handler_set_data(l->handler, l, 0)) != 0) || ((rv = nni_http_server_init(&l->server, url)) != 0)) { ws_listener_free(l); return (rv); From 2662596f105fc98ae1d2aa3b6137261bb351a8df Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 12:27:49 -0800 Subject: [PATCH 05/10] HTTP: nng_http_handler_set_method no longer fails --- docs/man/nng_http_handler_set_method.3http.adoc | 15 ++------------- docs/ref/migrate/nng1.md | 10 ++++++---- include/nng/supplemental/http/http.h | 2 +- src/supplemental/http/http_api.h | 2 +- src/supplemental/http/http_public.c | 5 ++--- src/supplemental/http/http_server.c | 16 +++++----------- src/supplemental/http/http_server_test.c | 9 ++++----- 7 files changed, 21 insertions(+), 38 deletions(-) diff --git a/docs/man/nng_http_handler_set_method.3http.adoc b/docs/man/nng_http_handler_set_method.3http.adoc index f79f0faf7..17c4481df 100644 --- a/docs/man/nng_http_handler_set_method.3http.adoc +++ b/docs/man/nng_http_handler_set_method.3http.adoc @@ -20,7 +20,7 @@ nng_http_handler_set_method - set HTTP handler method #include #include -int nng_http_handler_set_method(nng_http_handler *handler, const char *method); +void nng_http_handler_set_method(nng_http_handler *handler, const char *method); ---- == DESCRIPTION @@ -36,22 +36,11 @@ NOTE: The server will automatically call "GET" handlers if the client sends a "HEAD" request, and will suppress HTTP body data in the responses sent for such requests. -NOTE: No validation of the _method_ is performed, but HTTP specifications -insist that the actual method sent over the wire be capitalized. +NOTE: If _method_ is longer than 32-bytes, it may be truncated silently. The handler may always examine the actual method used using the xref:nng_http_req_get_method.3http.adoc[`nng_http_req_get_method()`] function. -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient free memory exists. -`NNG_ENOTSUP`:: No support for HTTP in the library. - == SEE ALSO [.text-left] diff --git a/docs/ref/migrate/nng1.md b/docs/ref/migrate/nng1.md index 544f15b6f..8035f854c 100644 --- a/docs/ref/migrate/nng1.md +++ b/docs/ref/migrate/nng1.md @@ -229,11 +229,13 @@ they may be silently truncated to the limit: - HTTP Method names are limited to 32 bytes (the longest IANA registered method is currently 18 bytes, used for WebDAV.) - The fixed part of URI pathnames used with HTTP handlers is limited to 1024 bytes. -The following API changes are present: +The following API calls have changed so that they are `void` returns, and cannot fail. +They may silently truncate data, and the handler methods may not have any effect if the handler is already in use. -- [`nng_http_req_set_method`] no longer returns a value, and cannot fail. -- [`nng_http_res_set_status`] no longer returns a value, and cannot fail. -- [`nng_http_handler_set_host`] no longer returns a value and cannot fail. +- [`nng_http_req_set_method`] +- [`nng_http_res_set_status`] +- [`nng_http_handler_set_host`] +- [`nng_http_handler_set_method`] ## Security Descriptors (Windows Only) diff --git a/include/nng/supplemental/http/http.h b/include/nng/supplemental/http/http.h index 729e25ad6..4bcc6ec63 100644 --- a/include/nng/supplemental/http/http.h +++ b/include/nng/supplemental/http/http.h @@ -355,7 +355,7 @@ NNG_DECL int nng_http_handler_alloc_directory( // called for. By default this is GET. If NULL is supplied for the // method, then the handler is executed regardless of method, and must // inspect the method itself. -NNG_DECL int nng_http_handler_set_method(nng_http_handler *, const char *); +NNG_DECL void nng_http_handler_set_method(nng_http_handler *, const char *); // nng_http_handler_set_host sets the Host: that the handler will be // called for (to allow for virtual hosts). If the value is NULL (the diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index d759e27b3..0748b1f94 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -332,7 +332,7 @@ extern void nni_http_handler_set_host(nni_http_handler *, const char *); // is obligated to inspect the method. (Note: the passed method must be // in upper case and should come from a statically allocated string; the // server does not make its own copy.) -extern int nni_http_handler_set_method(nni_http_handler *, const char *); +extern void nni_http_handler_set_method(nni_http_handler *, const char *); // nni_http_handler_set_data sets an opaque data element on the handler, // which will be available to the callback via nni_http_handler_get_data. diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index a60743fde..58550a3f2 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -583,15 +583,14 @@ nng_http_handler_alloc_static(nng_http_handler **hp, const char *uri, #endif } -int +void nng_http_handler_set_method(nng_http_handler *h, const char *meth) { #ifdef NNG_SUPP_HTTP - return (nni_http_handler_set_method(h, meth)); + nni_http_handler_set_method(h, meth); #else NNI_ARG_UNUSED(h); NNI_ARG_UNUSED(meth); - return (NNG_ENOTSUP); #endif } diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index e9c8bea33..6a5941586 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -236,20 +236,14 @@ nni_http_handler_set_host(nni_http_handler *h, const char *host) (void) snprintf(h->host, sizeof(h->host), "%s", host); } -int +void nni_http_handler_set_method(nni_http_handler *h, const char *method) { - if (nni_atomic_get_bool(&h->busy) != 0) { - return (NNG_EBUSY); - } + NNI_ASSERT(!nni_atomic_get_bool(&h->busy)); if (method == NULL) { method = ""; } - if (strlen(method) >= sizeof(h->method)) { - return (NNG_EINVAL); - } (void) snprintf(h->method, sizeof(h->method), "%s", method); - return (0); } static nni_list http_servers = @@ -1757,9 +1751,9 @@ nni_http_handler_init_redirect(nni_http_handler **hpp, const char *uri, return (rv); } - if (((rv = nni_http_handler_set_method(h, NULL)) != 0) || - ((rv = nni_http_handler_set_data(h, hr, http_redirect_free)) != - 0)) { + nni_http_handler_set_method(h, NULL); + + if ((rv = nni_http_handler_set_data(h, hr, http_redirect_free)) != 0) { http_redirect_free(hr); nni_http_handler_fini(h); return (rv); diff --git a/src/supplemental/http/http_server_test.c b/src/supplemental/http/http_server_test.c index f29fa52b1..e1d13ad24 100644 --- a/src/supplemental/http/http_server_test.c +++ b/src/supplemental/http/http_server_test.c @@ -346,10 +346,9 @@ test_server_method_too_long(void) NUTS_PASS(nng_http_handler_alloc_static( &h, "/home.html", doc1, strlen(doc1), "text/html")); - NUTS_FAIL(nng_http_handler_set_method(h, - "THISMETHODISFARFARTOOLONGTOBEVALIDASAMETHODASITISLONGER" - "THANTHIRTYTWOBYTES"), - NNG_EINVAL); + nng_http_handler_set_method(h, + "THISMETHODISFARFARTOOLONGTOBEVALIDASAMETHODASITISLONGER" + "THANTHIRTYTWOBYTES"); } void @@ -393,7 +392,7 @@ test_server_post_handler(void) void *data; NUTS_PASS(nng_http_handler_alloc(&h, "/post", httpecho)); - NUTS_PASS(nng_http_handler_set_method(h, "POST")); + nng_http_handler_set_method(h, "POST"); server_setup(&st, h); From a946d79e8d0eb3a47f75d6e1e98a28462c584d67 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 12:32:15 -0800 Subject: [PATCH 06/10] http: handler set tree no longer returns a value (API break) --- docs/man/nng_http_handler_set_tree.3http.adoc | 16 +++------------- include/nng/supplemental/http/http.h | 4 ++-- src/supplemental/http/http_api.h | 4 ++-- src/supplemental/http/http_public.c | 10 ++++------ src/supplemental/http/http_server.c | 18 ++++++------------ src/supplemental/http/http_server_test.c | 12 ++++++------ 6 files changed, 23 insertions(+), 41 deletions(-) diff --git a/docs/man/nng_http_handler_set_tree.3http.adoc b/docs/man/nng_http_handler_set_tree.3http.adoc index f0ecc4c9f..3ee73de0e 100644 --- a/docs/man/nng_http_handler_set_tree.3http.adoc +++ b/docs/man/nng_http_handler_set_tree.3http.adoc @@ -1,6 +1,6 @@ = nng_http_handler_set_tree(3http) -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2024 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2020 Dirac Research // @@ -20,9 +20,9 @@ nng_http_handler_set_tree - set HTTP handler to match trees #include #include -int nng_http_handler_set_tree(nng_http_handler *handler); +void nng_http_handler_set_tree(nng_http_handler *handler); -int nng_http_handler_set_tree_exclusive(nng_http_handler *handler); +void nng_http_handler_set_tree_exclusive(nng_http_handler *handler); ---- == DESCRIPTION @@ -48,16 +48,6 @@ generated when a more specific child does not exist. This can provide a better experience for users than the standard 404 error handling. -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient free memory exists. -`NNG_ENOTSUP`:: No support for HTTP in the library. - == SEE ALSO [.text-left] diff --git a/include/nng/supplemental/http/http.h b/include/nng/supplemental/http/http.h index 4bcc6ec63..a25768e92 100644 --- a/include/nng/supplemental/http/http.h +++ b/include/nng/supplemental/http/http.h @@ -378,7 +378,7 @@ NNG_DECL int nng_http_handler_collect_body(nng_http_handler *, bool, size_t); // for a hierarchical tree, rather than just a single path, so it will be // called for all child paths supplied. By default the handler is only // called for an exact path match. -NNG_DECL int nng_http_handler_set_tree(nng_http_handler *); +NNG_DECL void nng_http_handler_set_tree(nng_http_handler *); // nng_http_handler_set_tree_exclusive indicates that the handler is being // registered for a heirarchical tree *exclusively*, rather than just a single @@ -386,7 +386,7 @@ NNG_DECL int nng_http_handler_set_tree(nng_http_handler *); // handler is only called for an exact path match. Exclusive means that any // other handler on a conflicting path will induce an address conflict error // when added to a server. -NNG_DECL int nng_http_handler_set_tree_exclusive(nng_http_handler *); +NNG_DECL void nng_http_handler_set_tree_exclusive(nng_http_handler *); // nng_http_handler_set_data is used to store additional data, along with // a possible clean up routine. (The clean up is a custom de-allocator and diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 0748b1f94..47e46b535 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -304,14 +304,14 @@ extern void nni_http_handler_collect_body(nni_http_handler *, bool, size_t); // nni_http_handler_set_tree marks the handler as servicing the entire // tree (e.g. a directory), rather than just a leaf node. The handler // will probably need to inspect the URL of the request. -extern int nni_http_handler_set_tree(nni_http_handler *); +extern void 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 *); +extern void 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 diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index 58550a3f2..f85eca64c 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -619,25 +619,23 @@ nng_http_handler_set_host(nng_http_handler *h, const char *host) #endif } -int +void nng_http_handler_set_tree(nng_http_handler *h) { #ifdef NNG_SUPP_HTTP - return (nni_http_handler_set_tree(h)); + nni_http_handler_set_tree(h); #else NNI_ARG_UNUSED(h); - return (NNG_ENOTSUP); #endif } -int +void nng_http_handler_set_tree_exclusive(nng_http_handler *h) { #ifdef NNG_SUPP_HTTP - return (nni_http_handler_set_tree_exclusive(h)); + nni_http_handler_set_tree_exclusive(h); #else NNI_ARG_UNUSED(h); - return (NNG_ENOTSUP); #endif } diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index 6a5941586..38204ca51 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -180,26 +180,20 @@ nni_http_handler_get_uri(nni_http_handler *h) return (h->uri); } -int +void nni_http_handler_set_tree(nni_http_handler *h) { - if (nni_atomic_get_bool(&h->busy) != 0) { - return (NNG_EBUSY); - } + NNI_ASSERT(!nni_atomic_get_bool(&h->busy)); h->tree = true; h->tree_exclusive = false; - return (0); } -int +void nni_http_handler_set_tree_exclusive(nni_http_handler *h) { - if (nni_atomic_get_bool(&h->busy) != 0) { - return (NNG_EBUSY); - } + NNI_ASSERT(!nni_atomic_get_bool(&h->busy)); h->tree = true; h->tree_exclusive = true; - return (0); } void @@ -1629,9 +1623,9 @@ nni_http_handler_init_directory( } // We don't permit a body for getting a file. nni_http_handler_collect_body(h, true, 0); + nni_http_handler_set_tree_exclusive(h); - if (((rv = nni_http_handler_set_tree_exclusive(h)) != 0) || - ((rv = nni_http_handler_set_data(h, hf, http_file_free)) != 0)) { + if ((rv = nni_http_handler_set_data(h, hf, http_file_free)) != 0) { http_file_free(hf); nni_http_handler_fini(h); return (rv); diff --git a/src/supplemental/http/http_server_test.c b/src/supplemental/http/http_server_test.c index e1d13ad24..0f6227f2e 100644 --- a/src/supplemental/http/http_server_test.c +++ b/src/supplemental/http/http_server_test.c @@ -464,7 +464,7 @@ test_server_tree_redirect(void) // We'll use a 303 to ensure codes carry thru NUTS_PASS(nng_http_handler_alloc_redirect( &h, "/here", 303, "http://127.0.0.1/there")); - NUTS_PASS(nng_http_handler_set_tree(h)); + nng_http_handler_set_tree(h); server_setup(&st, h); NUTS_PASS(nng_http_req_set_uri(st.req, "/here/i/go/again")); @@ -521,7 +521,7 @@ test_server_post_echo_tree(void) NUTS_PASS(nng_http_handler_alloc(&h, "/", httpecho)); nng_http_handler_set_method(h, "POST"); - NUTS_PASS(nng_http_handler_set_tree(h)); + nng_http_handler_set_tree(h); server_setup(&st, h); @@ -587,20 +587,20 @@ test_server_multiple_trees(void) NUTS_PASS(nni_file_put(file2, doc2, strlen(doc2))); NUTS_PASS(nng_http_handler_alloc_directory(&h, "/", workdir)); - NUTS_PASS(nng_http_handler_set_tree(h)); + nng_http_handler_set_tree(h); server_setup(&st, h); NUTS_PASS(nng_http_handler_alloc_directory(&h, "/", workdir)); - NUTS_PASS(nng_http_handler_set_tree(h)); + nng_http_handler_set_tree(h); NUTS_FAIL(nng_http_server_add_handler(st.s, h), NNG_EADDRINUSE); nng_http_handler_free(h); NUTS_PASS(nng_http_handler_alloc_directory(&h, "/subdir", workdir2)); - NUTS_PASS(nng_http_handler_set_tree(h)); + nng_http_handler_set_tree(h); NUTS_PASS(nng_http_server_add_handler(st.s, h)); NUTS_PASS(nng_http_handler_alloc_directory(&h, "/subdir", workdir2)); - NUTS_PASS(nng_http_handler_set_tree(h)); + nng_http_handler_set_tree(h); NUTS_FAIL(nng_http_server_add_handler(st.s, h), NNG_EADDRINUSE); nng_http_handler_free(h); From 8c14ed19b5c72f060f31767e5bc4106054e41192 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 12:34:46 -0800 Subject: [PATCH 07/10] nng_http_server_collect_body now void return (API break) --- demo/rest/server.c | 6 ++---- docs/man/nng_http_handler_collect_body.3http.adoc | 11 +---------- docs/ref/migrate/nng1.md | 3 +++ include/nng/supplemental/http/http.h | 2 +- src/supplemental/http/http_public.c | 4 +--- 5 files changed, 8 insertions(+), 18 deletions(-) diff --git a/demo/rest/server.c b/demo/rest/server.c index ee4047b55..1e1ccc96d 100644 --- a/demo/rest/server.c +++ b/demo/rest/server.c @@ -289,10 +289,8 @@ rest_start(uint16_t port) // the data yourself with another HTTP read transaction by disabling // this, but that's a lot of work, especially if you want to handle // chunked transfers. - if ((rv = nng_http_handler_collect_body(handler, true, 1024 * 128)) != - 0) { - fatal("nng_http_handler_collect_body", rv); - } + nng_http_handler_collect_body(handler, true, 1024 * 128); + if ((rv = nng_http_server_add_handler(server, handler)) != 0) { fatal("nng_http_handler_add_handler", rv); } diff --git a/docs/man/nng_http_handler_collect_body.3http.adoc b/docs/man/nng_http_handler_collect_body.3http.adoc index b614f6758..d02919cd4 100644 --- a/docs/man/nng_http_handler_collect_body.3http.adoc +++ b/docs/man/nng_http_handler_collect_body.3http.adoc @@ -20,7 +20,7 @@ nng_http_handler_collect_body - set HTTP handler to collect request body #include #include -int nng_http_handler_collect_body(nng_http_handler *handler, bool want, size_t maxsz); +void nng_http_handler_collect_body(nng_http_handler *handler, bool want, size_t maxsz); ---- == DESCRIPTION @@ -60,15 +60,6 @@ This is considered a bug, and is a deficiency for full HTTP/1.1 compliance. However, few clients send data in this format, so in practice this should create few limitations. -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOTSUP`:: No support for HTTP in the library. - == SEE ALSO [.text-left] diff --git a/docs/ref/migrate/nng1.md b/docs/ref/migrate/nng1.md index 8035f854c..8186e5cbb 100644 --- a/docs/ref/migrate/nng1.md +++ b/docs/ref/migrate/nng1.md @@ -234,8 +234,11 @@ They may silently truncate data, and the handler methods may not have any effect - [`nng_http_req_set_method`] - [`nng_http_res_set_status`] +- [`nng_http_handler_collect_body`] - [`nng_http_handler_set_host`] - [`nng_http_handler_set_method`] +- [`nng_http_handler_set_tree`] +- [`nng_http_handler_set_tree_exclusive`] ## Security Descriptors (Windows Only) diff --git a/include/nng/supplemental/http/http.h b/include/nng/supplemental/http/http.h index a25768e92..e94aa0b3d 100644 --- a/include/nng/supplemental/http/http.h +++ b/include/nng/supplemental/http/http.h @@ -372,7 +372,7 @@ NNG_DECL void nng_http_handler_set_host(nng_http_handler *, const char *); // then a 400 Bad Request will be sent back to the client. To set an // unlimited value, use (size_t)-1. To preclude the client from sending // *any* data, use 0. (The static and file handlers use 0 by default.) -NNG_DECL int nng_http_handler_collect_body(nng_http_handler *, bool, size_t); +NNG_DECL void nng_http_handler_collect_body(nng_http_handler *, bool, size_t); // nng_http_handler_set_tree indicates that the handler is being registered // for a hierarchical tree, rather than just a single path, so it will be diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index f85eca64c..1dccbdf6e 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -594,17 +594,15 @@ nng_http_handler_set_method(nng_http_handler *h, const char *meth) #endif } -int +void nng_http_handler_collect_body(nng_http_handler *h, bool want, size_t len) { #ifdef NNG_SUPP_HTTP nni_http_handler_collect_body(h, want, len); - return (0); #else NNI_ARG_UNUSED(h); NNI_ARG_UNUSED(want); NNI_ARG_UNUSED(len); - return (NNG_ENOTSUP); #endif } From 113e3606bd1a763850db1afee336bb0d5d434317 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 12:41:44 -0800 Subject: [PATCH 08/10] http: nng_http_handler_set_data is now void return (API break) --- docs/man/nng_http_handler_set_data.3http.adoc | 14 ++------ docs/ref/migrate/nng1.md | 6 +++- include/nng/supplemental/http/http.h | 2 +- src/supplemental/http/http_api.h | 2 +- src/supplemental/http/http_public.c | 5 ++- src/supplemental/http/http_server.c | 32 ++++--------------- src/supplemental/websocket/websocket.c | 4 +-- 7 files changed, 19 insertions(+), 46 deletions(-) diff --git a/docs/man/nng_http_handler_set_data.3http.adoc b/docs/man/nng_http_handler_set_data.3http.adoc index cb94adbc6..94cb9b4c2 100644 --- a/docs/man/nng_http_handler_set_data.3http.adoc +++ b/docs/man/nng_http_handler_set_data.3http.adoc @@ -1,6 +1,6 @@ = nng_http_handler_set_data(3http) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2024 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -20,7 +20,7 @@ nng_http_handler_set_data - set extra data for HTTP handler #include #include -int nng_http_handler_set_data(nng_http_handler *handler, void *data, +void nng_http_handler_set_data(nng_http_handler *handler, void *data, void (*dtor)(void *)); ---- @@ -36,16 +36,6 @@ then it will be called with _data_ as its argument. The intended use of this function is deallocate any resources associated with _data_. -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. - == SEE ALSO [.text-left] diff --git a/docs/ref/migrate/nng1.md b/docs/ref/migrate/nng1.md index 8186e5cbb..4390de249 100644 --- a/docs/ref/migrate/nng1.md +++ b/docs/ref/migrate/nng1.md @@ -230,16 +230,20 @@ they may be silently truncated to the limit: - The fixed part of URI pathnames used with HTTP handlers is limited to 1024 bytes. The following API calls have changed so that they are `void` returns, and cannot fail. -They may silently truncate data, and the handler methods may not have any effect if the handler is already in use. +They may silently truncate data. - [`nng_http_req_set_method`] - [`nng_http_res_set_status`] - [`nng_http_handler_collect_body`] +- [`nng_http_handler_set_data`] - [`nng_http_handler_set_host`] - [`nng_http_handler_set_method`] - [`nng_http_handler_set_tree`] - [`nng_http_handler_set_tree_exclusive`] +The HTTP handler objects may not be modified once in use. Previously this would fail with `NNG_EBUSY`. +These checks are removed now, but debug builds will assert if an application tries to do so. + ## Security Descriptors (Windows Only) The `NNG_OPT_IPC_SECURITY_DESCRIPTOR` option is removed, and replaced diff --git a/include/nng/supplemental/http/http.h b/include/nng/supplemental/http/http.h index e94aa0b3d..f00c63a9b 100644 --- a/include/nng/supplemental/http/http.h +++ b/include/nng/supplemental/http/http.h @@ -392,7 +392,7 @@ NNG_DECL void nng_http_handler_set_tree_exclusive(nng_http_handler *); // a possible clean up routine. (The clean up is a custom de-allocator and // will be called with the supplied data as an argument, when the handler // is being de-allocated.) -NNG_DECL int nng_http_handler_set_data( +NNG_DECL void nng_http_handler_set_data( nng_http_handler *, void *, void (*)(void *)); // nng_http_handler_get_data returns the data that was previously stored. diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 47e46b535..5e2d52fa6 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -338,7 +338,7 @@ extern void nni_http_handler_set_method(nni_http_handler *, const char *); // which will be available to the callback via nni_http_handler_get_data. // The callback is an optional destructor, and will be called with the // data as its argument, when the handler is being destroyed. -extern int nni_http_handler_set_data(nni_http_handler *, void *, nni_cb); +extern void nni_http_handler_set_data(nni_http_handler *, void *, nni_cb); // nni_http_handler_get_data returns the data that was previously stored // by nni_http_handler_set_data. diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index 1dccbdf6e..49638b665 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -637,16 +637,15 @@ nng_http_handler_set_tree_exclusive(nng_http_handler *h) #endif } -int +void nng_http_handler_set_data(nng_http_handler *h, void *dat, void (*dtor)(void *)) { #ifdef NNG_SUPP_HTTP - return (nni_http_handler_set_data(h, dat, dtor)); + nni_http_handler_set_data(h, dat, dtor); #else NNI_ARG_UNUSED(h); NNI_ARG_UNUSED(dat); NNI_ARG_UNUSED(dtor); - return (NNG_ENOTSUP); #endif } diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index 38204ca51..82f11eac4 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -154,15 +154,12 @@ nni_http_handler_collect_body(nni_http_handler *h, bool want, size_t maxbody) h->maxbody = maxbody; } -int +void nni_http_handler_set_data(nni_http_handler *h, void *data, nni_cb dtor) { - if (nni_atomic_get_bool(&h->busy)) { - return (NNG_EBUSY); - } + NNI_ASSERT(!nni_atomic_get_bool(&h->busy)); h->data = data; h->dtor = dtor; - return (0); } void * @@ -1448,11 +1445,7 @@ nni_http_handler_init_file_ctype(nni_http_handler **hpp, const char *uri, return (rv); } - if ((rv = nni_http_handler_set_data(h, hf, http_file_free)) != 0) { - http_file_free(hf); - nni_http_handler_fini(h); - return (rv); - } + nni_http_handler_set_data(h, hf, http_file_free); // We don't permit a body for getting a file. nni_http_handler_collect_body(h, true, 0); @@ -1624,12 +1617,7 @@ nni_http_handler_init_directory( // We don't permit a body for getting a file. nni_http_handler_collect_body(h, true, 0); nni_http_handler_set_tree_exclusive(h); - - if ((rv = nni_http_handler_set_data(h, hf, http_file_free)) != 0) { - http_file_free(hf); - nni_http_handler_fini(h); - return (rv); - } + nni_http_handler_set_data(h, hf, http_file_free); *hpp = h; return (0); @@ -1747,11 +1735,7 @@ nni_http_handler_init_redirect(nni_http_handler **hpp, const char *uri, nni_http_handler_set_method(h, NULL); - if ((rv = nni_http_handler_set_data(h, hr, http_redirect_free)) != 0) { - http_redirect_free(hr); - nni_http_handler_fini(h); - return (rv); - } + nni_http_handler_set_data(h, hr, http_redirect_free); // We don't need to collect the body at all, because the handler // just discards the content and closes the connection. @@ -1833,11 +1817,7 @@ nni_http_handler_init_static(nni_http_handler **hpp, const char *uri, return (rv); } - if ((rv = nni_http_handler_set_data(h, hs, http_static_free)) != 0) { - http_static_free(hs); - nni_http_handler_fini(h); - return (rv); - } + nni_http_handler_set_data(h, hs, http_static_free); // We don't permit a body for getting static data. nni_http_handler_collect_body(h, true, 0); diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c index ba3041495..b7afc938d 100644 --- a/src/supplemental/websocket/websocket.c +++ b/src/supplemental/websocket/websocket.c @@ -2151,9 +2151,9 @@ nni_ws_listener_alloc(nng_stream_listener **wslp, const nng_url *url) } nni_http_handler_set_host(l->handler, host); + nni_http_handler_set_data(l->handler, l, 0); - if (((rv = nni_http_handler_set_data(l->handler, l, 0)) != 0) || - ((rv = nni_http_server_init(&l->server, url)) != 0)) { + if ((rv = nni_http_server_init(&l->server, url)) != 0) { ws_listener_free(l); return (rv); } From d60a16af349de45477efc566760130b51ff7cf1e Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 12:52:52 -0800 Subject: [PATCH 09/10] http server test: fix leak in test --- src/supplemental/http/http_server_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/supplemental/http/http_server_test.c b/src/supplemental/http/http_server_test.c index 0f6227f2e..3c9cb5450 100644 --- a/src/supplemental/http/http_server_test.c +++ b/src/supplemental/http/http_server_test.c @@ -349,6 +349,8 @@ test_server_method_too_long(void) nng_http_handler_set_method(h, "THISMETHODISFARFARTOOLONGTOBEVALIDASAMETHODASITISLONGER" "THANTHIRTYTWOBYTES"); + + nng_http_handler_free(h); } void From a24b4f11799806e08638162901039fd23efe48be Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 12:57:19 -0800 Subject: [PATCH 10/10] http: limit handler uri to 1K This is just the part of the tree that will be matched when looking up a handler. Requests may come in with very much longer URIs, and be matched to the handler as a "subdirectory". This approach makes it possible to avoid a dynamic allocation on the handler, at the cost of pre-allocating 1KB with the handler object. This size can be overridden using a NNG_HTTP_MAX_URI at compile time. --- docs/man/nng_http_handler_alloc.3http.adoc | 6 ++++++ docs/ref/migrate/nng1.md | 3 ++- src/supplemental/http/http_server.c | 12 ++++++------ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/man/nng_http_handler_alloc.3http.adoc b/docs/man/nng_http_handler_alloc.3http.adoc index c7d4699fe..7795bbf5b 100644 --- a/docs/man/nng_http_handler_alloc.3http.adoc +++ b/docs/man/nng_http_handler_alloc.3http.adoc @@ -51,6 +51,12 @@ by the _path_ argument. Only the path component of the Request URI is considered when determining whether the handler should be called. +This implementation limits the _path_ length to 1024 bytes, including the +zero termination byte. This does not prevent requests with much longer +URIs from being supported, doing so will require setting the handler +to matching a parent path in the tree using +xref:nng_http_handler_set_tree.3http.adoc[`nng_http_handler_set_tree`()]. + Additionally each handler has a method it is registered to handle (the default is `GET`, see xref:nng_http_handler_set_method.3http.adoc[`nng_http_handler_set_method()`]), and diff --git a/docs/ref/migrate/nng1.md b/docs/ref/migrate/nng1.md index 4390de249..0d6ae86d7 100644 --- a/docs/ref/migrate/nng1.md +++ b/docs/ref/migrate/nng1.md @@ -227,7 +227,8 @@ they may be silently truncated to the limit: - Hostnames are limited per RFC 1035 to 253 characters (not including terminating "." or zero byte.) - HTTP Method names are limited to 32 bytes (the longest IANA registered method is currently 18 bytes, used for WebDAV.) -- The fixed part of URI pathnames used with HTTP handlers is limited to 1024 bytes. +- The fixed part of URI pathnames used with HTTP handlers is limited to 1024 bytes. (Longer URIs may be accepted + by using [`nng_http_handler_set_tree`] and matching a parent of the directory component.) The following API calls have changed so that they are `void` returns, and cannot fail. They may silently truncate data. diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index 82f11eac4..e068ae987 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -22,9 +22,13 @@ #include "http_api.h" +#ifndef NNG_HTTP_MAX_URI +#define NNG_HTTP_MAX_URI 1024 +#endif + struct nng_http_handler { nni_list_node node; - char *uri; + char uri[NNG_HTTP_MAX_URI]; char method[32]; char host[256]; // RFC 1035 nng_sockaddr host_addr; @@ -114,10 +118,7 @@ nni_http_handler_init( if ((uri == NULL) || (strlen(uri) == 0) || (strcmp(uri, "/") == 0)) { uri = ""; } - if ((h->uri = nni_strdup(uri)) == NULL) { - nni_http_handler_fini(h); - return (NNG_ENOMEM); - } + (void) snprintf(h->uri, sizeof(h->uri), "%s", uri); NNI_LIST_NODE_INIT(&h->node); h->cb = cb; h->data = NULL; @@ -143,7 +144,6 @@ nni_http_handler_fini(nni_http_handler *h) if (h->dtor != NULL) { h->dtor(h->data); } - nni_strfree(h->uri); NNI_FREE_STRUCT(h); }