From 6800bdd8b9e3fd4488bab56cd9fb12206d0631f6 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 22 Dec 2024 11:17:24 -0800 Subject: 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(-) (limited to 'src') diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index 64edf456..ba89626b 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 2d1e4b28..2ed04c4d 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 }, -- cgit v1.2.3-70-g09d2