diff options
| author | Garrett D'Amore <garrett@damore.org> | 2024-11-17 18:23:17 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2024-11-17 22:05:20 -0800 |
| commit | 85aff44e00e836eda618d4f1cf013bce38b3fd44 (patch) | |
| tree | 94b2dca800d6d254baae17932a017e031c17ce67 /src/core | |
| parent | ef82d4792bf59b1fe8053d9bb5ac924b443d8a78 (diff) | |
| download | nng-85aff44e00e836eda618d4f1cf013bce38b3fd44.tar.gz nng-85aff44e00e836eda618d4f1cf013bce38b3fd44.tar.bz2 nng-85aff44e00e836eda618d4f1cf013bce38b3fd44.zip | |
URL u_port should be a number not a string.
The idea here is to reduce the dynamic allocations used for
URLs, and also the back and forth with parsing begin strings
and port numbers. We always resolve to a port number, and
this is easier for everyone.
The real goal in the long term is to eliminate dynamic allocation
of the URL fields altogether, but that requires a little more
work. This is a step in the right direction.
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/platform.h | 6 | ||||
| -rw-r--r-- | src/core/tcp.c | 24 | ||||
| -rw-r--r-- | src/core/url.c | 84 | ||||
| -rw-r--r-- | src/core/url.h | 16 | ||||
| -rw-r--r-- | src/core/url_test.c | 55 |
5 files changed, 104 insertions, 81 deletions
diff --git a/src/core/platform.h b/src/core/platform.h index 62a321bf..783cc9fc 100644 --- a/src/core/platform.h +++ b/src/core/platform.h @@ -343,7 +343,7 @@ extern int nni_tcp_listener_get( // Symbolic service names will be looked up assuming SOCK_STREAM, so // they may not work with UDP. extern void nni_resolv_ip( - const char *, const char *, int, bool, nng_sockaddr *sa, nni_aio *); + const char *, uint16_t, int, bool, nng_sockaddr *sa, nni_aio *); // nni_parse_ip parses an IP address, without a port. extern int nni_parse_ip(const char *, nng_sockaddr *); @@ -351,6 +351,10 @@ extern int nni_parse_ip(const char *, nng_sockaddr *); // nni_parse_ip_port parses an IP address with an optional port appended. extern int nni_parse_ip_port(const char *, nng_sockaddr *); +// nni_get_port_by_name resolves a name (which may be an ASCII representation +// of a number) to a port number (the value returned is in native byte order.) +extern int nni_get_port_by_name(const char *, uint16_t *); + // // IPC (UNIX Domain Sockets & Named Pipes) Support. // diff --git a/src/core/tcp.c b/src/core/tcp.c index 7fb67228..5d324a13 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2024 Staysail Systems, Inc. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> // Copyright 2019 Devolutions <info@devolutions.net> // @@ -10,6 +10,7 @@ // #include <stdint.h> +#include <stdio.h> #include <string.h> #include <nng/nng.h> @@ -20,8 +21,8 @@ typedef struct { nng_stream_dialer ops; - char *host; - char *port; + char host[256]; + uint16_t port; int af; // address family bool closed; nng_sockaddr sa; @@ -155,8 +156,6 @@ tcp_dialer_free(void *arg) nni_tcp_dialer_fini(d->d); } nni_mtx_fini(&d->mtx); - nni_strfree(d->host); - nni_strfree(d->port); NNI_FREE_STRUCT(d); } @@ -236,17 +235,13 @@ nni_tcp_dialer_alloc(nng_stream_dialer **dp, const nng_url *url) { tcp_dialer *d; int rv; - const char *p; if ((rv = tcp_dialer_alloc(&d)) != 0) { return (rv); } - if (((p = url->u_port) == NULL) || (strlen(p) == 0)) { - p = nni_url_default_port(url->u_scheme); - } - - if ((strlen(p) == 0) || (strlen(url->u_hostname) == 0)) { + if ((url->u_port == 0) || strlen(url->u_hostname) == 0 || + strlen(url->u_hostname) >= sizeof(d->host)) { // Dialer needs both a destination hostname and port. tcp_dialer_free(d); return (NNG_EADDRINVAL); @@ -260,11 +255,8 @@ nni_tcp_dialer_alloc(nng_stream_dialer **dp, const nng_url *url) d->af = NNG_AF_UNSPEC; } - if (((d->host = nng_strdup(url->u_hostname)) == NULL) || - ((d->port = nng_strdup(p)) == NULL)) { - tcp_dialer_free(d); - return (NNG_ENOMEM); - } + snprintf(d->host, sizeof(d->host), "%s", url->u_hostname); + d->port = url->u_port; *dp = (void *) d; return (0); diff --git a/src/core/url.c b/src/core/url.c index c1318719..9bdcfd23 100644 --- a/src/core/url.c +++ b/src/core/url.c @@ -15,6 +15,7 @@ #include <stdio.h> #include <string.h> +#include "core/platform.h" #include "url.h" static uint8_t @@ -234,22 +235,26 @@ url_canonify_uri(char **outp, const char *in) static struct { const char *scheme; - const char *port; + uint16_t port; } nni_url_default_ports[] = { // This list is not exhaustive, but likely covers the main ones we // care about. Feel free to add additional ones as use cases arise. // Note also that we don't use "default" ports for SP protocols // that have no "default" port, like tcp:// or tls+tcp://. // clang-format off - { "git", "9418" }, - { "gopher", "70" }, - { "http", "80" }, - { "https", "443" }, - { "ssh", "22" }, - { "telnet", "23" }, - { "ws", "80" }, - { "wss", "443" }, - { NULL, NULL }, + { "git", 9418 }, + { "gopher", 70 }, + { "http", 80 }, + { "https", 443 }, + { "ssh", 22 }, + { "telnet", 23 }, + { "ws", 80 }, + { "ws4", 80 }, + { "ws6", 80 }, + { "wss", 443 }, + { "wss4", 443 }, + { "wss6", 443 }, + { NULL, 0 }, // clang-format on }; @@ -274,6 +279,9 @@ static const char *nni_schemes[] = { "wss", "wss4", "wss6", + "udp", + "udp4", + "udp6", // we don't support these "file", "mailto", @@ -284,10 +292,11 @@ static const char *nni_schemes[] = { "telnet", "irc", "imap", + "imaps", NULL, }; -const char * +uint16_t nni_url_default_port(const char *scheme) { const char *s; @@ -310,7 +319,7 @@ nni_url_default_port(const char *scheme) break; } } - return (""); + return (0); } // URLs usually follow the following format: @@ -503,6 +512,11 @@ nni_url_parse(nni_url **urlp, const char *raw) } } } + // hostname length check + if (len >= 256) { + rv = NNG_EADDRINVAL; + goto error; + } if ((url->u_hostname = nni_alloc(len + 1)) == NULL) { rv = NNG_ENOMEM; goto error; @@ -521,13 +535,12 @@ nni_url_parse(nni_url **urlp, const char *raw) rv = NNG_EINVAL; goto error; } - url->u_port = nni_strdup(s + 1); + rv = nni_get_port_by_name(s + 1, &url->u_port); + if (rv != 0) { + goto error; + } } else { - url->u_port = nni_strdup(nni_url_default_port(url->u_scheme)); - } - if (url->u_port == NULL) { - rv = NNG_ENOMEM; - goto error; + url->u_port = nni_url_default_port(url->u_scheme); } *urlp = url; @@ -546,7 +559,6 @@ nni_url_free(nni_url *url) nni_strfree(url->u_userinfo); nni_strfree(url->u_host); nni_strfree(url->u_hostname); - nni_strfree(url->u_port); nni_strfree(url->u_path); nni_strfree(url->u_query); nni_strfree(url->u_fragment); @@ -558,11 +570,11 @@ nni_url_free(nni_url *url) int nni_url_asprintf(char **str, const nni_url *url) { - const char *scheme = url->u_scheme; - const char *port = url->u_port; - const char *host = url->u_hostname; - const char *hostob = ""; - const char *hostcb = ""; + const char *scheme = url->u_scheme; + const char *host = url->u_hostname; + const char *hostob = ""; + const char *hostcb = ""; + bool do_port = true; if ((strcmp(scheme, "ipc") == 0) || (strcmp(scheme, "inproc") == 0) || (strcmp(scheme, "unix") == 0) || @@ -570,11 +582,8 @@ nni_url_asprintf(char **str, const nni_url *url) return (nni_asprintf(str, "%s://%s", scheme, url->u_path)); } - if (port != NULL) { - if ((strlen(port) == 0) || - (strcmp(nni_url_default_port(scheme), port) == 0)) { - port = NULL; - } + if (url->u_port == nni_url_default_port(scheme)) { + do_port = false; } if (strcmp(host, "*") == 0) { host = ""; @@ -583,9 +592,14 @@ nni_url_asprintf(char **str, const nni_url *url) hostob = "["; hostcb = "]"; } - return (nni_asprintf(str, "%s://%s%s%s%s%s%s", scheme, hostob, host, - hostcb, port != NULL ? ":" : "", port != NULL ? port : "", - url->u_requri != NULL ? url->u_requri : "")); + char portstr[8]; + if (do_port) { + snprintf(portstr, sizeof(portstr), ":%u", url->u_port); + } else { + portstr[0] = 0; + } + return (nni_asprintf(str, "%s://%s%s%s%s%s", scheme, hostob, host, + hostcb, portstr, url->u_requri != NULL ? url->u_requri : "")); } // nni_url_asprintf_port is like nni_url_asprintf, but includes a port @@ -594,12 +608,10 @@ nni_url_asprintf(char **str, const nni_url *url) int nni_url_asprintf_port(char **str, const nni_url *url, int port) { - char portstr[16]; nni_url myurl = *url; if (port > 0) { - (void) snprintf(portstr, sizeof(portstr), "%d", port); - myurl.u_port = portstr; + myurl.u_port = (uint16_t) port; } return (nni_url_asprintf(str, &myurl)); } @@ -618,7 +630,6 @@ nni_url_clone(nni_url **dstp, const nni_url *src) URL_COPYSTR(dst->u_userinfo, src->u_userinfo) || URL_COPYSTR(dst->u_host, src->u_host) || URL_COPYSTR(dst->u_hostname, src->u_hostname) || - URL_COPYSTR(dst->u_port, src->u_port) || URL_COPYSTR(dst->u_requri, src->u_requri) || URL_COPYSTR(dst->u_path, src->u_path) || URL_COPYSTR(dst->u_query, src->u_query) || @@ -627,6 +638,7 @@ nni_url_clone(nni_url **dstp, const nni_url *src) return (NNG_ENOMEM); } dst->u_scheme = src->u_scheme; + dst->u_port = src->u_port; *dstp = dst; return (0); } diff --git a/src/core/url.h b/src/core/url.h index 1761f6fd..71a093d0 100644 --- a/src/core/url.h +++ b/src/core/url.h @@ -13,13 +13,13 @@ #include "core/defs.h" -extern int nni_url_parse(nni_url **, const char *path); -extern void nni_url_free(nni_url *); -extern int nni_url_clone(nni_url **, const nni_url *); -extern const char *nni_url_default_port(const char *); -extern int nni_url_asprintf(char **, const nni_url *); -extern int nni_url_asprintf_port(char **, const nni_url *, int); -extern size_t nni_url_decode(uint8_t *, const char *, size_t); -extern int nni_url_to_address(nng_sockaddr *, const nni_url *); +extern int nni_url_parse(nni_url **, const char *path); +extern void nni_url_free(nni_url *); +extern int nni_url_clone(nni_url **, const nni_url *); +extern uint16_t nni_url_default_port(const char *); +extern int nni_url_asprintf(char **, const nni_url *); +extern int nni_url_asprintf_port(char **, const nni_url *, int); +extern size_t nni_url_decode(uint8_t *, const char *, size_t); +extern int nni_url_to_address(nng_sockaddr *, const nni_url *); #endif // CORE_URL_H diff --git a/src/core/url_test.c b/src/core/url_test.c index 232cabc8..b5114551 100644 --- a/src/core/url_test.c +++ b/src/core/url_test.c @@ -22,7 +22,7 @@ test_url_host(void) NUTS_TRUE(strcmp(url->u_scheme, "http") == 0); NUTS_TRUE(strcmp(url->u_host, "www.google.com") == 0); NUTS_TRUE(strcmp(url->u_hostname, "www.google.com") == 0); - NUTS_TRUE(strcmp(url->u_port, "80") == 0); + NUTS_TRUE(url->u_port == 80); NUTS_TRUE(strcmp(url->u_path, "") == 0); NUTS_TRUE(strcmp(url->u_requri, "") == 0); NUTS_TRUE(url->u_query == NULL); @@ -32,6 +32,20 @@ test_url_host(void) } void +test_url_host_too_long(void) +{ + nng_url *url; + char buffer[512]; // + + memset(buffer, 0, sizeof(buffer)); + snprintf(buffer, sizeof(buffer), "http://"); + for (size_t i = strlen(buffer); i < sizeof(buffer) - 1; i++) { + buffer[i] = 'a'; + } + NUTS_FAIL(nng_url_parse(&url, buffer), NNG_EADDRINVAL); +} + +void test_url_host_port(void) { nng_url *url; @@ -40,7 +54,7 @@ test_url_host_port(void) NUTS_TRUE(strcmp(url->u_scheme, "http") == 0); NUTS_TRUE(strcmp(url->u_host, "www.google.com:1234") == 0); NUTS_TRUE(strcmp(url->u_hostname, "www.google.com") == 0); - NUTS_TRUE(strcmp(url->u_port, "1234") == 0); + NUTS_TRUE(url->u_port == 1234); NUTS_TRUE(strcmp(url->u_path, "") == 0); NUTS_TRUE(strcmp(url->u_requri, "") == 0); NUTS_TRUE(url->u_query == NULL); @@ -59,7 +73,7 @@ test_url_host_port_path(void) NUTS_TRUE(strcmp(url->u_scheme, "http") == 0); NUTS_TRUE(strcmp(url->u_host, "www.google.com:1234") == 0); NUTS_TRUE(strcmp(url->u_hostname, "www.google.com") == 0); - NUTS_TRUE(strcmp(url->u_port, "1234") == 0); + NUTS_TRUE(url->u_port == 1234); NUTS_TRUE(strcmp(url->u_path, "/somewhere") == 0); NUTS_TRUE(strcmp(url->u_requri, "/somewhere") == 0); NUTS_TRUE(url->u_userinfo == NULL); @@ -79,7 +93,7 @@ test_url_user_info(void) NUTS_MATCH(url->u_userinfo, "garrett"); NUTS_MATCH(url->u_host, "www.google.com:1234"); NUTS_MATCH(url->u_hostname, "www.google.com"); - NUTS_MATCH(url->u_port, "1234"); + NUTS_TRUE(url->u_port == 1234); NUTS_MATCH(url->u_path, "/somewhere"); NUTS_MATCH(url->u_requri, "/somewhere"); NUTS_NULL(url->u_query); @@ -97,7 +111,7 @@ test_url_path_query_param(void) NUTS_MATCH(url->u_scheme, "http"); NUTS_MATCH(url->u_host, "www.google.com"); NUTS_MATCH(url->u_hostname, "www.google.com"); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_MATCH(url->u_path, "/somewhere"); NUTS_MATCH(url->u_query, "result=yes"); NUTS_MATCH(url->u_requri, "/somewhere?result=yes"); @@ -117,7 +131,7 @@ test_url_query_param_anchor(void) NUTS_MATCH(url->u_scheme, "http"); NUTS_MATCH(url->u_host, "www.google.com"); NUTS_MATCH(url->u_hostname, "www.google.com"); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_MATCH(url->u_path, "/somewhere"); NUTS_MATCH(url->u_query, "result=yes"); NUTS_MATCH(url->u_fragment, "chapter1"); @@ -136,7 +150,7 @@ test_url_path_anchor(void) NUTS_MATCH(url->u_scheme, "http"); NUTS_MATCH(url->u_host, "www.google.com"); NUTS_MATCH(url->u_hostname, "www.google.com"); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_MATCH(url->u_path, "/somewhere"); NUTS_MATCH(url->u_fragment, "chapter2"); NUTS_MATCH(url->u_requri, "/somewhere#chapter2"); @@ -155,7 +169,7 @@ test_url_anchor(void) NUTS_MATCH(url->u_host, "www.google.com"); NUTS_MATCH(url->u_hostname, "www.google.com"); NUTS_MATCH(url->u_path, ""); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_MATCH(url->u_fragment, "chapter3"); NUTS_MATCH(url->u_requri, "#chapter3"); NUTS_NULL(url->u_query); @@ -173,7 +187,7 @@ test_url_query_param(void) NUTS_MATCH(url->u_host, "www.google.com"); NUTS_MATCH(url->u_hostname, "www.google.com"); NUTS_MATCH(url->u_path, ""); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_MATCH(url->u_query, "color=red"); NUTS_MATCH(url->u_requri, "?color=red"); NUTS_ASSERT(url != NULL); @@ -191,7 +205,7 @@ test_url_v6_host(void) NUTS_MATCH(url->u_host, "[::1]"); NUTS_MATCH(url->u_hostname, "::1"); NUTS_MATCH(url->u_path, ""); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_NULL(url->u_query); NUTS_NULL(url->u_fragment); NUTS_NULL(url->u_userinfo); @@ -208,7 +222,7 @@ test_url_v6_host_port(void) NUTS_MATCH(url->u_host, "[::1]:29"); NUTS_MATCH(url->u_hostname, "::1"); NUTS_MATCH(url->u_path, ""); - NUTS_MATCH(url->u_port, "29"); + NUTS_TRUE(url->u_port == 29); NUTS_NULL(url->u_query); NUTS_NULL(url->u_fragment); NUTS_NULL(url->u_userinfo); @@ -225,7 +239,7 @@ test_url_v6_host_port_path(void) NUTS_MATCH(url->u_host, "[::1]:29"); NUTS_MATCH(url->u_hostname, "::1"); NUTS_MATCH(url->u_path, "/bottles"); - NUTS_MATCH(url->u_port, "29"); + NUTS_TRUE(url->u_port == 29); NUTS_NULL(url->u_query); NUTS_NULL(url->u_fragment); NUTS_NULL(url->u_userinfo); @@ -242,7 +256,7 @@ test_url_tcp_port(void) NUTS_MATCH(url->u_host, ":9876"); NUTS_MATCH(url->u_hostname, ""); NUTS_MATCH(url->u_path, "/"); - NUTS_MATCH(url->u_port, "9876"); + NUTS_TRUE(url->u_port == 9876); NUTS_NULL(url->u_query); NUTS_NULL(url->u_fragment); NUTS_NULL(url->u_userinfo); @@ -260,7 +274,7 @@ test_url_bare_ws(void) NUTS_MATCH(url->u_host, ""); NUTS_MATCH(url->u_hostname, ""); NUTS_MATCH(url->u_path, ""); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_NULL(url->u_query); NUTS_NULL(url->u_fragment); NUTS_NULL(url->u_userinfo); @@ -277,7 +291,7 @@ test_url_ws_wildcard(void) NUTS_MATCH(url->u_host, ":12345"); NUTS_MATCH(url->u_hostname, ""); NUTS_MATCH(url->u_path, "/foobar"); - NUTS_MATCH(url->u_port, "12345"); + NUTS_TRUE(url->u_port == 12345); NUTS_NULL(url->u_query); NUTS_NULL(url->u_fragment); NUTS_NULL(url->u_userinfo); @@ -294,7 +308,7 @@ test_url_ssh(void) NUTS_MATCH(url->u_host, "host.example.com"); NUTS_MATCH(url->u_hostname, "host.example.com"); NUTS_MATCH(url->u_path, ""); - NUTS_MATCH(url->u_port, "22"); + NUTS_TRUE(url->u_port == 22); NUTS_NULL(url->u_query); NUTS_NULL(url->u_fragment); NUTS_MATCH(url->u_userinfo, "user"); @@ -332,7 +346,7 @@ test_url_canonify(void) NUTS_ASSERT(url != NULL); NUTS_MATCH(url->u_scheme, "http"); NUTS_MATCH(url->u_hostname, "www.example.com"); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_MATCH(url->u_path, "/~garrett"); nng_url_free(url); } @@ -345,7 +359,7 @@ test_url_path_resolve(void) nng_url_parse(&url, "http://www.x.com//abc/def/./x/..///./../y")); NUTS_MATCH(url->u_scheme, "http"); NUTS_MATCH(url->u_hostname, "www.x.com"); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_MATCH(url->u_path, "/abc/y"); nng_url_free(url); } @@ -359,7 +373,7 @@ test_url_query_info_pass(void) NUTS_ASSERT(url != NULL); NUTS_MATCH(url->u_scheme, "http"); NUTS_MATCH(url->u_hostname, "www.x.com"); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_MATCH(url->u_path, "/"); NUTS_MATCH(url->u_query, "/abc/def/./x/.././../y"); nng_url_free(url); @@ -383,7 +397,7 @@ test_url_good_utf8(void) NUTS_ASSERT(url != NULL); NUTS_MATCH(url->u_scheme, "http"); NUTS_MATCH(url->u_hostname, "www.x.com"); - NUTS_MATCH(url->u_port, "80"); + NUTS_TRUE(url->u_port == 80); NUTS_MATCH(url->u_path, "/\xc2\xa2_cents"); nng_url_free(url); } @@ -446,6 +460,7 @@ test_url_decode(void) NUTS_TESTS = { { "url host", test_url_host }, + { "url host too long", test_url_host_too_long }, { "url host port", test_url_host_port }, { "url host port path", test_url_host_port_path }, { "url user info", test_url_user_info }, |
