aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2024-12-22 12:18:33 -0800
committerGarrett D'Amore <garrett@damore.org>2024-12-22 12:18:33 -0800
commit10f6fc5141a15e368dac813a38942cb66d5ddef4 (patch)
treed6ebd5663b2aeb876840e5e2560cae77264d1abc
parent497b8e22047fb0efa3397289d23656d6483fdd6d (diff)
downloadnng-10f6fc5141a15e368dac813a38942cb66d5ddef4.tar.gz
nng-10f6fc5141a15e368dac813a38942cb66d5ddef4.tar.bz2
nng-10f6fc5141a15e368dac813a38942cb66d5ddef4.zip
HTTP handler: limit host names to 256 bytes (RFC 1035 specifies 253.)
This also makes `nng_http_handler_set_host` never fail (API break).
-rw-r--r--docs/man/nng_http_handler_set_host.3http.adoc15
-rw-r--r--docs/ref/migrate/nng1.md13
-rw-r--r--include/nng/supplemental/http/http.h2
-rw-r--r--src/supplemental/http/http_api.h2
-rw-r--r--src/supplemental/http/http_public.c5
-rw-r--r--src/supplemental/http/http_server.c46
-rw-r--r--src/supplemental/websocket/websocket.c5
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 0deae488..3f25172f 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. <info@staysail.tech>
+// Copyright 2024 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// 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 <nng/nng.h>
#include <nng/supplemental/http/http.h>
-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 8a1af631..544f15b6 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 fa485243..729e25ad 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 349f3a49..d759e27b 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 e3093d45..a60743fd 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 fa9ad2f4..e9c8bea3 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 3dfb3e8e..ba304149 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);