aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2024-11-18 01:17:24 -0800
committerGarrett D'Amore <garrett@damore.org>2024-11-18 08:33:05 -0800
commitca6cfe359fa55a5a7f4b6ae73500ffd98e6ee968 (patch)
treed69a9af2e88c9bf5bc0d565bdd2ea975f2723d52 /src
parente54e2b1a98abfdb75232a9b3218714ce34c9a34f (diff)
downloadnng-ca6cfe359fa55a5a7f4b6ae73500ffd98e6ee968.tar.gz
nng-ca6cfe359fa55a5a7f4b6ae73500ffd98e6ee968.tar.bz2
nng-ca6cfe359fa55a5a7f4b6ae73500ffd98e6ee968.zip
URL refactor part 1.
This eliminates most (but not all) of the dynamic allocations associated with URL objects. A number of convenience fields on the URL are removed, but we are able to use common buffer for most of the details.
Diffstat (limited to 'src')
-rw-r--r--src/core/url.c254
-rw-r--r--src/core/url_test.c65
-rw-r--r--src/platform/posix/posix_resolv_gai.c9
-rw-r--r--src/platform/windows/win_resolv.c10
-rw-r--r--src/sp/transport/socket/sockfd.c2
-rw-r--r--src/sp/transport/tcp/tcp_test.c13
-rw-r--r--src/sp/transport/tls/tls_tran_test.c54
-rw-r--r--src/sp/transport/udp/udp_tran_test.c13
-rw-r--r--src/sp/transport/ws/ws_test.c4
-rw-r--r--src/supplemental/http/http_msg.c16
10 files changed, 179 insertions, 261 deletions
diff --git a/src/core/url.c b/src/core/url.c
index bae5a491..c5be4f83 100644
--- a/src/core/url.c
+++ b/src/core/url.c
@@ -8,6 +8,7 @@
// found online at https://opensource.org/licenses/MIT.
//
+#include "core/defs.h"
#include "core/nng_impl.h"
#include <ctype.h>
@@ -16,6 +17,7 @@
#include <string.h>
#include "core/platform.h"
+#include "nng/nng.h"
#include "url.h"
static uint8_t
@@ -118,27 +120,19 @@ nni_url_decode(uint8_t *out, const char *in, size_t max_len)
}
static int
-url_canonify_uri(char **outp, const char *in)
+url_canonify_uri(char *out)
{
- char *out;
- size_t src, dst, len;
+ size_t src, dst;
uint8_t c;
int rv;
bool skip;
- // We know that the transform is strictly "reducing".
- if ((out = nni_strdup(in)) == NULL) {
- return (NNG_ENOMEM);
- }
- len = strlen(out);
-
// First pass, convert '%xx' for safe characters to unescaped forms.
src = dst = 0;
while ((c = out[src]) != 0) {
if (c == '%') {
if ((!isxdigit(out[src + 1])) ||
(!isxdigit(out[src + 2]))) {
- nni_free(out, len);
return (NNG_EINVAL);
}
c = url_hex_val(out[src + 1]);
@@ -224,13 +218,10 @@ url_canonify_uri(char **outp, const char *in)
// Finally lets make sure that the results are valid UTF-8.
// This guards against using UTF-8 redundancy to break security.
if ((rv = url_utf8_validate(out)) != 0) {
- nni_free(out, len);
return (rv);
}
- *outp = nni_strdup(out);
- nni_free(out, len);
- return (*outp == NULL ? NNG_ENOMEM : 0);
+ return (0);
}
static struct {
@@ -340,6 +331,7 @@ nni_url_parse(nni_url **urlp, const char *raw)
nni_url *url;
size_t len;
const char *s;
+ char *p;
char c;
int rv;
@@ -347,6 +339,7 @@ nni_url_parse(nni_url **urlp, const char *raw)
return (NNG_ENOMEM);
}
+ // TODO: remove this when NNG_OPT_URL is gone
if ((url->u_rawurl = nni_strdup(raw)) == NULL) {
rv = NNG_ENOMEM;
goto error;
@@ -374,7 +367,23 @@ nni_url_parse(nni_url **urlp, const char *raw)
rv = NNG_ENOTSUP;
goto error;
}
- s += len + 3; // strlen("://")
+ s += len;
+
+ // A little tricky. We copy the "://" here, even though we don't need
+ // it. This affords us some space for zero bytes between URL components
+ // if needed
+
+ if (strlen(s) >= sizeof(url->u_static)) {
+ url->u_buffer = nni_strdup(s);
+ url->u_bufsz = strlen(s) + 1;
+ } else {
+ snprintf(url->u_static, sizeof(url->u_static), "%s", s);
+ url->u_buffer = url->u_static;
+ url->u_bufsz = 0;
+ }
+
+ p = url->u_buffer + strlen("://");
+ s = p;
// For compatibility reasons, we treat ipc:// and inproc:// paths
// specially. These names URLs have a path name (ipc) or arbitrary
@@ -390,152 +399,119 @@ nni_url_parse(nni_url **urlp, const char *raw)
(strcmp(url->u_scheme, "unix") == 0) ||
(strcmp(url->u_scheme, "abstract") == 0) ||
(strcmp(url->u_scheme, "inproc") == 0)) {
- if ((url->u_path = nni_strdup(s)) == NULL) {
- rv = NNG_ENOMEM;
- goto error;
- }
- *urlp = url;
+ url->u_path = p;
+ *urlp = url;
return (0);
}
// Look for host part (including colon). Will be terminated by
// a path, or NUL. May also include an "@", separating a user
// field.
- for (len = 0; (c = s[len]) != '/'; len++) {
- if ((c == '\0') || (c == '#') || (c == '?')) {
+ for (;;) {
+ c = *p;
+ if ((c == '\0') || (c == '/') || (c == '#') || (c == '?')) {
+ *p = '\0';
+ memmove(url->u_buffer, s, strlen(s) + 1);
+ *p = c;
break;
}
- if (c == '@') {
- // This is a username.
- if (url->u_userinfo != NULL) { // we already have one
- rv = NNG_EINVAL;
- goto error;
- }
- if ((url->u_userinfo = nni_alloc(len + 1)) == NULL) {
- rv = NNG_ENOMEM;
- goto error;
- }
- memcpy(url->u_userinfo, s, len);
- url->u_userinfo[len] = '\0';
- s += len + 1; // skip past user@ ...
- len = 0;
- }
+ p++;
}
- // If the hostname part is just '*', skip over it. (We treat it
- // as an empty host for legacy nanomsg compatibility. This may be
- // non-RFC compliant, but we're really only interested in parsing
- // nanomsg URLs.)
- if (((len == 1) && (s[0] == '*')) ||
- ((len > 1) && (strncmp(s, "*:", 2) == 0))) {
- s++;
- len--;
- }
+ s = p;
+ url->u_path = p;
- if ((url->u_host = nni_alloc(len + 1)) == NULL) {
- rv = NNG_ENOMEM;
- goto error;
+ // shift the host back to the start of the buffer, which gives us
+ // padding so we don't have to clobber the leading "/" in the path.
+ url->u_hostname = url->u_buffer;
+
+ char *at;
+ if ((at = strchr(url->u_hostname, '@')) != NULL) {
+ url->u_userinfo = url->u_hostname;
+ *at++ = 0;
+ url->u_hostname = at;
+
+ // make sure only one '@' appears in the host (only one user
+ // info is allowed)
+ if (strchr(url->u_hostname, '@') != NULL) {
+ rv = NNG_EADDRINVAL;
+ goto error;
+ }
}
+
// Copy the host portion, but make it lower case (hostnames are
// case insensitive).
- for (size_t i = 0; i < len; i++) {
- url->u_host[i] = (char) tolower(s[i]);
+ for (int i = 0; url->u_hostname[i]; i++) {
+ url->u_hostname[i] = (char) tolower(url->u_hostname[i]);
}
- url->u_host[len] = '\0';
- s += len;
- if ((rv = url_canonify_uri(&url->u_requri, s)) != 0) {
+ if ((rv = url_canonify_uri(p)) != 0) {
goto error;
}
- s = url->u_requri;
- for (len = 0; (c = s[len]) != '\0'; len++) {
+ while ((c = *p) != '\0') {
if ((c == '?') || (c == '#')) {
break;
}
+ p++;
}
- if ((url->u_path = nni_alloc(len + 1)) == NULL) {
- rv = NNG_ENOMEM;
- goto error;
- }
- memcpy(url->u_path, s, len);
- url->u_path[len] = '\0';
-
- s += len;
-
// Look for query info portion.
- if (s[0] == '?') {
- s++;
- for (len = 0; (c = s[len]) != '\0'; len++) {
+ if (*p == '?') {
+ *p++ = '\0';
+ url->u_query = p;
+ while ((c = *p) != '\0') {
if (c == '#') {
+ *p++ = '\0';
+ url->u_fragment = p;
break;
}
+ p++;
}
- if ((url->u_query = nni_alloc(len + 1)) == NULL) {
- rv = NNG_ENOMEM;
- goto error;
- }
- memcpy(url->u_query, s, len);
- url->u_query[len] = '\0';
- s += len;
- }
-
- // Look for fragment. Will always be last, so we just use
- // strdup.
- if (s[0] == '#') {
- if ((url->u_fragment = nni_strdup(s + 1)) == NULL) {
- rv = NNG_ENOMEM;
- goto error;
- }
+ } else if (c == '#') {
+ *p++ = '\0';
+ url->u_fragment = p;
}
// Now go back to the host portion, and look for a separate
// port We also yank off the "[" part for IPv6 addresses.
- s = url->u_host;
- if (s[0] == '[') {
- s++;
- for (len = 0; s[len] != ']'; len++) {
- if (s[len] == '\0') {
+ p = url->u_hostname;
+ if (*p == '[') {
+ url->u_hostname++;
+ p++;
+ while (*p != ']') {
+ if (*p++ == '\0') {
rv = NNG_EINVAL;
goto error;
}
}
- if ((s[len + 1] != ':') && (s[len + 1] != '\0')) {
+ *p++ = '\0';
+ if ((*p != ':') && (*p != '\0')) {
rv = NNG_EINVAL;
goto error;
}
} else {
- for (len = 0; s[len] != ':'; len++) {
- if (s[len] == '\0') {
- break;
- }
+ while (*p != ':' && *p != '\0') {
+ p++;
}
}
+ if ((c = *p) == ':') {
+ *p++ = '\0';
+ }
// hostname length check
- if (len >= 256) {
+ if (strlen(url->u_hostname) >= 256) {
rv = NNG_EADDRINVAL;
goto error;
}
- if ((url->u_hostname = nni_alloc(len + 1)) == NULL) {
- rv = NNG_ENOMEM;
- goto error;
- }
- memcpy(url->u_hostname, s, len);
- url->u_hostname[len] = '\0';
- s += len;
- if (s[0] == ']') {
- s++; // skip over ']', only used with IPv6 addresses
- }
- if (s[0] == ':') {
+ if (c == ':') {
// If a colon was present, but no port value present, then
// that is an error.
- if (s[1] == '\0') {
+ if (*p == '\0') {
rv = NNG_EINVAL;
goto error;
}
- rv = nni_get_port_by_name(s + 1, &url->u_port);
+ rv = nni_get_port_by_name(p, &url->u_port);
if (rv != 0) {
goto error;
}
@@ -556,13 +532,9 @@ nni_url_free(nni_url *url)
{
if (url != NULL) {
nni_strfree(url->u_rawurl);
- nni_strfree(url->u_userinfo);
- nni_strfree(url->u_host);
- nni_strfree(url->u_hostname);
- nni_strfree(url->u_path);
- nni_strfree(url->u_query);
- nni_strfree(url->u_fragment);
- nni_strfree(url->u_requri);
+ if (url->u_bufsz != 0) {
+ nni_free(url->u_buffer, url->u_bufsz);
+ }
NNI_FREE_STRUCT(url);
}
}
@@ -585,9 +557,6 @@ nni_url_sprintf(char *str, size_t size, const nni_url *url)
if (url->u_port == nni_url_default_port(scheme)) {
do_port = false;
}
- if (strcmp(host, "*") == 0) {
- host = "";
- }
if (strchr(host, ':') != 0) {
hostob = "[";
hostcb = "]";
@@ -598,8 +567,12 @@ nni_url_sprintf(char *str, size_t size, const nni_url *url)
} else {
portstr[0] = 0;
}
- return (snprintf(str, size, "%s://%s%s%s%s%s", scheme, hostob, host,
- hostcb, portstr, url->u_requri != NULL ? url->u_requri : ""));
+ return (snprintf(str, size, "%s://%s%s%s%s%s%s%s%s%s", scheme, hostob,
+ host, hostcb, portstr, url->u_path,
+ url->u_query != NULL ? "?" : "",
+ url->u_query != NULL ? url->u_query : "",
+ url->u_fragment != NULL ? "#" : "",
+ url->u_fragment != NULL ? url->u_fragment : ""));
}
int
@@ -641,17 +614,38 @@ nni_url_clone(nni_url **dstp, const nni_url *src)
if ((dst = NNI_ALLOC_STRUCT(dst)) == NULL) {
return (NNG_ENOMEM);
}
- if (URL_COPYSTR(dst->u_rawurl, src->u_rawurl) ||
- 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_requri, src->u_requri) ||
- URL_COPYSTR(dst->u_path, src->u_path) ||
- URL_COPYSTR(dst->u_query, src->u_query) ||
- URL_COPYSTR(dst->u_fragment, src->u_fragment)) {
- nni_url_free(dst);
+ if (URL_COPYSTR(dst->u_rawurl, src->u_rawurl)) {
+ NNI_FREE_STRUCT(dst);
return (NNG_ENOMEM);
}
+ if (src->u_bufsz != 0) {
+ if ((dst->u_buffer = nni_alloc(dst->u_bufsz)) == NULL) {
+ nni_strfree(dst->u_rawurl);
+ NNI_FREE_STRUCT(dst);
+ return (NNG_ENOMEM);
+ }
+ dst->u_bufsz = src->u_bufsz;
+ memcpy(dst->u_buffer, src->u_buffer, src->u_bufsz);
+ } else {
+ memcpy(dst->u_static, src->u_static, sizeof(src->u_static));
+ dst->u_buffer =
+ dst->u_static + (src->u_buffer - src->u_static);
+ }
+
+ dst->u_hostname = dst->u_buffer + (src->u_hostname - src->u_buffer);
+ dst->u_path = dst->u_buffer + (src->u_path - src->u_buffer);
+
+ if (src->u_userinfo != NULL) {
+ dst->u_userinfo =
+ dst->u_buffer + (src->u_userinfo - src->u_buffer);
+ }
+ if (src->u_query != NULL) {
+ dst->u_query = dst->u_buffer + (src->u_query - src->u_buffer);
+ }
+ if (src->u_fragment != NULL) {
+ dst->u_fragment =
+ dst->u_buffer + (src->u_fragment - src->u_buffer);
+ }
dst->u_scheme = src->u_scheme;
dst->u_port = src->u_port;
*dstp = dst;
@@ -683,7 +677,7 @@ nni_url_to_address(nng_sockaddr *sa, const nng_url *url)
nni_aio_init(&aio, NULL, NULL);
h = url->u_hostname;
- if ((h != NULL) && ((strcmp(h, "*") == 0) || (strcmp(h, "") == 0))) {
+ if ((h != NULL) && (strcmp(h, "") == 0)) {
h = NULL;
}
diff --git a/src/core/url_test.c b/src/core/url_test.c
index b5114551..4b767188 100644
--- a/src/core/url_test.c
+++ b/src/core/url_test.c
@@ -20,11 +20,9 @@ test_url_host(void)
NUTS_PASS(nng_url_parse(&url, "http://www.google.com"));
NUTS_ASSERT(url != NULL);
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(url->u_port == 80);
NUTS_TRUE(strcmp(url->u_path, "") == 0);
- NUTS_TRUE(strcmp(url->u_requri, "") == 0);
NUTS_TRUE(url->u_query == NULL);
NUTS_TRUE(url->u_fragment == NULL);
NUTS_TRUE(url->u_userinfo == NULL);
@@ -52,11 +50,9 @@ test_url_host_port(void)
NUTS_PASS(nng_url_parse(&url, "http://www.google.com:1234"));
NUTS_ASSERT(url != NULL);
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(url->u_port == 1234);
NUTS_TRUE(strcmp(url->u_path, "") == 0);
- NUTS_TRUE(strcmp(url->u_requri, "") == 0);
NUTS_TRUE(url->u_query == NULL);
NUTS_TRUE(url->u_fragment == NULL);
NUTS_TRUE(url->u_userinfo == NULL);
@@ -71,11 +67,9 @@ test_url_host_port_path(void)
NUTS_PASS(nng_url_parse(&url, "http://www.google.com:1234/somewhere"));
NUTS_ASSERT(url != NULL);
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(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);
NUTS_TRUE(url->u_query == NULL);
NUTS_TRUE(url->u_fragment == NULL);
@@ -91,11 +85,9 @@ test_url_user_info(void)
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "http");
NUTS_MATCH(url->u_userinfo, "garrett");
- NUTS_MATCH(url->u_host, "www.google.com:1234");
NUTS_MATCH(url->u_hostname, "www.google.com");
NUTS_TRUE(url->u_port == 1234);
NUTS_MATCH(url->u_path, "/somewhere");
- NUTS_MATCH(url->u_requri, "/somewhere");
NUTS_NULL(url->u_query);
NUTS_NULL(url->u_fragment);
nng_url_free(url);
@@ -109,12 +101,10 @@ test_url_path_query_param(void)
nng_url_parse(&url, "http://www.google.com/somewhere?result=yes"));
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "http");
- NUTS_MATCH(url->u_host, "www.google.com");
NUTS_MATCH(url->u_hostname, "www.google.com");
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");
NUTS_NULL(url->u_userinfo);
NUTS_NULL(url->u_fragment);
nng_url_free(url);
@@ -129,18 +119,38 @@ test_url_query_param_anchor(void)
"somewhere?result=yes#chapter1"));
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "http");
- NUTS_MATCH(url->u_host, "www.google.com");
NUTS_MATCH(url->u_hostname, "www.google.com");
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");
- NUTS_MATCH(url->u_requri, "/somewhere?result=yes#chapter1");
NUTS_NULL(url->u_userinfo);
nng_url_free(url);
}
void
+test_url_clone(void)
+{
+ nng_url *url;
+ nng_url *src;
+ NUTS_PASS(nng_url_parse(&src,
+ "http://www.google.com/"
+ "somewhere?result=yes#chapter1"));
+ NUTS_ASSERT(src != NULL);
+ NUTS_PASS(nng_url_clone(&url, src));
+ NUTS_ASSERT(url != NULL);
+ NUTS_MATCH(url->u_scheme, "http");
+ NUTS_MATCH(url->u_hostname, "www.google.com");
+ 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");
+ NUTS_NULL(url->u_userinfo);
+ nng_url_free(url);
+ nng_url_free(src);
+}
+
+void
test_url_path_anchor(void)
{
nng_url *url;
@@ -148,12 +158,10 @@ test_url_path_anchor(void)
nng_url_parse(&url, "http://www.google.com/somewhere#chapter2"));
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "http");
- NUTS_MATCH(url->u_host, "www.google.com");
NUTS_MATCH(url->u_hostname, "www.google.com");
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");
NUTS_NULL(url->u_query);
NUTS_NULL(url->u_userinfo);
nng_url_free(url);
@@ -166,12 +174,10 @@ test_url_anchor(void)
NUTS_PASS(nng_url_parse(&url, "http://www.google.com#chapter3"));
NUTS_ASSERT(url != NULL);
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_path, "");
NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_fragment, "chapter3");
- NUTS_MATCH(url->u_requri, "#chapter3");
NUTS_NULL(url->u_query);
NUTS_NULL(url->u_userinfo);
nng_url_free(url);
@@ -184,12 +190,10 @@ test_url_query_param(void)
NUTS_PASS(nng_url_parse(&url, "http://www.google.com?color=red"));
NUTS_ASSERT(url != NULL);
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_path, "");
NUTS_TRUE(url->u_port == 80);
NUTS_MATCH(url->u_query, "color=red");
- NUTS_MATCH(url->u_requri, "?color=red");
NUTS_ASSERT(url != NULL);
NUTS_NULL(url->u_userinfo);
nng_url_free(url);
@@ -202,7 +206,6 @@ test_url_v6_host(void)
NUTS_PASS(nng_url_parse(&url, "http://[::1]"));
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "http");
- NUTS_MATCH(url->u_host, "[::1]");
NUTS_MATCH(url->u_hostname, "::1");
NUTS_MATCH(url->u_path, "");
NUTS_TRUE(url->u_port == 80);
@@ -219,7 +222,6 @@ test_url_v6_host_port(void)
NUTS_PASS(nng_url_parse(&url, "http://[::1]:29"));
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "http");
- NUTS_MATCH(url->u_host, "[::1]:29");
NUTS_MATCH(url->u_hostname, "::1");
NUTS_MATCH(url->u_path, "");
NUTS_TRUE(url->u_port == 29);
@@ -236,7 +238,6 @@ test_url_v6_host_port_path(void)
NUTS_PASS(nng_url_parse(&url, "http://[::1]:29/bottles"));
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "http");
- NUTS_MATCH(url->u_host, "[::1]:29");
NUTS_MATCH(url->u_hostname, "::1");
NUTS_MATCH(url->u_path, "/bottles");
NUTS_TRUE(url->u_port == 29);
@@ -253,7 +254,6 @@ test_url_tcp_port(void)
NUTS_PASS(nng_url_parse(&url, "tcp://:9876/"));
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "tcp");
- NUTS_MATCH(url->u_host, ":9876");
NUTS_MATCH(url->u_hostname, "");
NUTS_MATCH(url->u_path, "/");
NUTS_TRUE(url->u_port == 9876);
@@ -271,7 +271,6 @@ test_url_bare_ws(void)
NUTS_PASS(nng_url_parse(&url, "ws://"));
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "ws");
- NUTS_MATCH(url->u_host, "");
NUTS_MATCH(url->u_hostname, "");
NUTS_MATCH(url->u_path, "");
NUTS_TRUE(url->u_port == 80);
@@ -282,30 +281,12 @@ test_url_bare_ws(void)
}
void
-test_url_ws_wildcard(void)
-{
- nng_url *url;
- NUTS_PASS(nng_url_parse(&url, "ws://*:12345/foobar"));
- NUTS_ASSERT(url != NULL);
- NUTS_MATCH(url->u_scheme, "ws");
- NUTS_MATCH(url->u_host, ":12345");
- NUTS_MATCH(url->u_hostname, "");
- NUTS_MATCH(url->u_path, "/foobar");
- NUTS_TRUE(url->u_port == 12345);
- NUTS_NULL(url->u_query);
- NUTS_NULL(url->u_fragment);
- NUTS_NULL(url->u_userinfo);
- nng_url_free(url);
-}
-
-void
test_url_ssh(void)
{
nng_url *url;
NUTS_PASS(nng_url_parse(&url, "ssh://user@host.example.com"));
NUTS_ASSERT(url != NULL);
NUTS_MATCH(url->u_scheme, "ssh");
- NUTS_MATCH(url->u_host, "host.example.com");
NUTS_MATCH(url->u_hostname, "host.example.com");
NUTS_MATCH(url->u_path, "");
NUTS_TRUE(url->u_port == 22);
@@ -474,7 +455,7 @@ NUTS_TESTS = {
{ "url v6 host port path", test_url_v6_host_port_path },
{ "url tcp port", test_url_tcp_port },
{ "url bare ws", test_url_bare_ws },
- { "url ws wildcard", test_url_ws_wildcard },
+ { "url clone", test_url_clone },
{ "url ssh", test_url_ssh },
{ "url bad scheme", test_url_bad_scheme },
{ "url bad v6", test_url_bad_ipv6 },
diff --git a/src/platform/posix/posix_resolv_gai.c b/src/platform/posix/posix_resolv_gai.c
index 7a0f8e1f..c26657e9 100644
--- a/src/platform/posix/posix_resolv_gai.c
+++ b/src/platform/posix/posix_resolv_gai.c
@@ -230,9 +230,12 @@ nni_resolv_ip(const char *host, uint16_t port, int af, bool passive,
if (nni_aio_begin(aio) != 0) {
return;
}
- if (host != NULL && strlen(host) >= sizeof(item->host)) {
- nni_aio_finish_error(aio, NNG_EADDRINVAL);
- return;
+ if (host != NULL) {
+ if ((strlen(host) >= sizeof(item->host)) ||
+ (strcmp(host, "*") == 0)) {
+ nni_aio_finish_error(aio, NNG_EADDRINVAL);
+ return;
+ }
}
switch (af) {
case NNG_AF_INET:
diff --git a/src/platform/windows/win_resolv.c b/src/platform/windows/win_resolv.c
index ece14655..f9e5e1f6 100644
--- a/src/platform/windows/win_resolv.c
+++ b/src/platform/windows/win_resolv.c
@@ -190,11 +190,13 @@ nni_resolv_ip(const char *host, uint16_t port, int family, bool passive,
if (nni_aio_begin(aio) != 0) {
return;
}
- if (host != NULL && strlen(host) >= sizeof(item->host)) {
- nni_aio_finish_error(aio, NNG_EADDRINVAL);
- return;
+ if (host != NULL) {
+ if ((strlen(host) >= sizeof(item->host)) ||
+ (strcmp(host, "*") == 0)) {
+ nni_aio_finish_error(aio, NNG_EADDRINVAL);
+ return;
+ }
}
-
switch (family) {
case NNG_AF_INET:
fam = AF_INET;
diff --git a/src/sp/transport/socket/sockfd.c b/src/sp/transport/socket/sockfd.c
index 2db052ac..2313d12d 100644
--- a/src/sp/transport/socket/sockfd.c
+++ b/src/sp/transport/socket/sockfd.c
@@ -817,7 +817,7 @@ sfd_tran_listener_init(void **lp, nng_url *url, nni_listener *nlistener)
nni_sock *sock = nni_listener_sock(nlistener);
// Check for invalid URL components -- we only accept a bare scheme
- if ((strlen(url->u_host) != 0) || (strlen(url->u_path) != 0) ||
+ if ((strlen(url->u_hostname) != 0) || (strlen(url->u_path) != 0) ||
(url->u_fragment != NULL) || (url->u_userinfo != NULL) ||
(url->u_query != NULL)) {
return (NNG_EADDRINVAL);
diff --git a/src/sp/transport/tcp/tcp_test.c b/src/sp/transport/tcp/tcp_test.c
index 57c612b7..c80a259f 100644
--- a/src/sp/transport/tcp/tcp_test.c
+++ b/src/sp/transport/tcp/tcp_test.c
@@ -10,6 +10,7 @@
// found online at https://opensource.org/licenses/MIT.
//
+#include "nng/nng.h"
#include <nuts.h>
// TCP tests.
@@ -30,19 +31,9 @@ void
test_tcp_wild_card_bind(void)
{
nng_socket s1;
- nng_socket s2;
- char addr[NNG_MAXADDRLEN];
- uint16_t port;
-
- port = nuts_next_port();
NUTS_OPEN(s1);
- NUTS_OPEN(s2);
- (void) snprintf(addr, sizeof(addr), "tcp4://*:%u", port);
- NUTS_PASS(nng_listen(s1, addr, NULL, 0));
- (void) snprintf(addr, sizeof(addr), "tcp://127.0.0.1:%u", port);
- NUTS_PASS(nng_dial(s2, addr, NULL, 0));
- NUTS_CLOSE(s2);
+ NUTS_FAIL(nng_listen(s1, "tcp4://*:8080", NULL, 0), NNG_EADDRINVAL);
NUTS_CLOSE(s1);
}
diff --git a/src/sp/transport/tls/tls_tran_test.c b/src/sp/transport/tls/tls_tran_test.c
index d6e94899..be049e05 100644
--- a/src/sp/transport/tls/tls_tran_test.c
+++ b/src/sp/transport/tls/tls_tran_test.c
@@ -46,58 +46,6 @@ tls_client_config(void)
return (c);
}
-static void
-test_tls_wild_card_connect_fail(void)
-{
- nng_socket s;
- nng_dialer d;
- char addr[NNG_MAXADDRLEN];
-
- NUTS_OPEN(s);
- (void) snprintf(
- addr, sizeof(addr), "tls+tcp://*:%u", nuts_next_port());
- NUTS_FAIL(nng_dialer_create(&d, s, addr), NNG_EADDRINVAL);
- NUTS_CLOSE(s);
-}
-
-void
-test_tls_wild_card_bind(void)
-{
- nng_socket s1;
- nng_socket s2;
- nng_listener l;
- nng_dialer d;
- char addr[NNG_MAXADDRLEN];
- uint16_t port;
- nng_tls_config *cc;
- nng_tls_config *sc;
- nng_tls_config *other;
-
- port = nuts_next_port();
-
- sc = tls_server_config();
- cc = tls_client_config();
-
- NUTS_OPEN(s1);
- NUTS_OPEN(s2);
- (void) snprintf(addr, sizeof(addr), "tls+tcp4://*:%u", port);
- NUTS_PASS(nng_listener_create(&l, s1, addr));
- NUTS_PASS(nng_listener_set_tls(l, sc));
- NUTS_PASS(nng_listener_get_tls(l, &other));
- NUTS_TRUE(sc == other);
- NUTS_PASS(nng_listener_start(l, 0));
- (void) snprintf(addr, sizeof(addr), "tls+tcp://127.0.0.1:%u", port);
- NUTS_PASS(nng_dialer_create(&d, s2, addr));
- NUTS_PASS(nng_dialer_set_tls(d, cc));
- NUTS_PASS(nng_dialer_get_tls(d, &other));
- NUTS_TRUE(cc == other);
- NUTS_PASS(nng_dialer_start(d, 0));
- NUTS_CLOSE(s2);
- NUTS_CLOSE(s1);
- nng_tls_config_free(cc);
- nng_tls_config_free(sc);
-}
-
void
test_tls_port_zero_bind(void)
{
@@ -329,8 +277,6 @@ test_tls_psk(void)
NUTS_TESTS = {
- { "tls wild card connect fail", test_tls_wild_card_connect_fail },
- { "tls wild card bind", test_tls_wild_card_bind },
{ "tls port zero bind", test_tls_port_zero_bind },
{ "tls malformed address", test_tls_malformed_address },
{ "tls no delay option", test_tls_no_delay_option },
diff --git a/src/sp/transport/udp/udp_tran_test.c b/src/sp/transport/udp/udp_tran_test.c
index 151c2783..781c6ad9 100644
--- a/src/sp/transport/udp/udp_tran_test.c
+++ b/src/sp/transport/udp/udp_tran_test.c
@@ -29,20 +29,9 @@ void
test_udp_wild_card_bind(void)
{
nng_socket s1;
- nng_socket s2;
- char addr[NNG_MAXADDRLEN];
- uint16_t port;
-
- port = nuts_next_port();
NUTS_OPEN(s1);
- NUTS_OPEN(s2);
- (void) snprintf(addr, sizeof(addr), "udp4://*:%u", port);
- NUTS_PASS(nng_listen(s1, addr, NULL, 0));
- nng_msleep(500);
- (void) snprintf(addr, sizeof(addr), "udp://127.0.0.1:%u", port);
- NUTS_PASS(nng_dial(s2, addr, NULL, 0));
- NUTS_CLOSE(s2);
+ NUTS_FAIL(nng_listen(s1, "udp://*:8080", NULL, 0), NNG_EADDRINVAL);
NUTS_CLOSE(s1);
}
diff --git a/src/sp/transport/ws/ws_test.c b/src/sp/transport/ws/ws_test.c
index 0f514cfe..23158e3f 100644
--- a/src/sp/transport/ws/ws_test.c
+++ b/src/sp/transport/ws/ws_test.c
@@ -1,5 +1,5 @@
//
-// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2024 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Cody Piersall <cody.piersall@gmail.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -99,7 +99,7 @@ test_wild_card_host(void)
port = nuts_next_port();
// we use ws4 to ensure 127.0.0.1 binding
- snprintf(addr, sizeof(addr), "ws4://*:%u/test", port);
+ snprintf(addr, sizeof(addr), "ws4://:%u/test", port);
NUTS_PASS(nng_listen(s1, addr, NULL, 0));
nng_msleep(100);
diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c
index 28c89ec7..a2ab218f 100644
--- a/src/supplemental/http/http_msg.c
+++ b/src/supplemental/http/http_msg.c
@@ -617,8 +617,13 @@ nni_http_req_alloc(nni_http_req **reqp, const nni_url *url)
req->uri = NULL;
if (url != NULL) {
const char *host;
+ char host_buf[264]; // 256 + 8 for port
int rv;
- if ((req->uri = nni_strdup(url->u_requri)) == NULL) {
+ rv = nni_asprintf(&req->uri, "%s%s%s%s%s", url->u_path,
+ url->u_query ? "?" : "", url->u_query ? url->u_query : "",
+ url->u_fragment ? "#" : "",
+ url->u_fragment ? url->u_fragment : "");
+ if (rv != 0) {
NNI_FREE_STRUCT(req);
return (NNG_ENOMEM);
}
@@ -628,7 +633,14 @@ nni_http_req_alloc(nni_http_req **reqp, const nni_url *url)
if (nni_url_default_port(url->u_scheme) == url->u_port) {
host = url->u_hostname;
} else {
- host = url->u_host;
+ if (strchr(url->u_hostname, ':')) {
+ snprintf(host_buf, sizeof(host_buf), "[%s]:%u",
+ url->u_hostname, url->u_port);
+ } else {
+ snprintf(host_buf, sizeof(host_buf), "%s:%u",
+ url->u_hostname, url->u_port);
+ }
+ host = host_buf;
}
if ((rv = nni_http_req_add_header(req, "Host", host)) != 0) {
nni_http_req_free(req);