Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Url accessors #1938

Merged
merged 14 commits into from
Nov 23, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add new nni_url_parse_inline, and add more test cases for coverage.
The inline parsing will be used internally to avoid some allocations.
  • Loading branch information
gdamore committed Nov 19, 2024

Verified

This commit was signed with the committer’s verified signature.
gdamore Garrett D'Amore
commit 6499dd847ca8889ea0aa4a2fe934bcfff9466e60
61 changes: 29 additions & 32 deletions src/core/url.c
Original file line number Diff line number Diff line change
@@ -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>
//
// This software is supplied under the terms of the MIT License, a
@@ -326,23 +326,17 @@ nni_url_default_port(const char *scheme)
// scheme with a leading //, such as http:// or tcp://. So our parser
// is a bit more restricted, but sufficient for our needs.
int
nng_url_parse(nng_url **urlp, const char *raw)
nni_url_parse_inline(nng_url *url, const char *raw)
{
nng_url *url;
size_t len;
const char *s;
char *p;
char c;
int rv;

if ((url = NNI_ALLOC_STRUCT(url)) == NULL) {
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;
return (NNG_ENOMEM);
}

// Grab the scheme.
@@ -353,8 +347,7 @@ nng_url_parse(nng_url **urlp, const char *raw)
}
}
if (strncmp(s + len, "://", 3) != 0) {
rv = NNG_EINVAL;
goto error;
return (NNG_EINVAL);
}

for (int i = 0; nni_schemes[i] != NULL; i++) {
@@ -364,8 +357,7 @@ nng_url_parse(nng_url **urlp, const char *raw)
}
}
if (url->u_scheme == NULL) {
rv = NNG_ENOTSUP;
goto error;
return (NNG_ENOTSUP);
}
s += len;

@@ -400,7 +392,6 @@ nng_url_parse(nng_url **urlp, const char *raw)
(strcmp(url->u_scheme, "abstract") == 0) ||
(strcmp(url->u_scheme, "inproc") == 0)) {
url->u_path = p;
*urlp = url;
return (0);
}

@@ -434,8 +425,7 @@ nng_url_parse(nng_url **urlp, const char *raw)
// make sure only one '@' appears in the host (only one user
// info is allowed)
if (strchr(url->u_hostname, '@') != NULL) {
rv = NNG_EINVAL;
goto error;
return (NNG_EINVAL);
}
}

@@ -446,7 +436,7 @@ nng_url_parse(nng_url **urlp, const char *raw)
}

if ((rv = url_canonify_uri(p)) != 0) {
goto error;
return (rv);
}

while ((c = *p) != '\0') {
@@ -481,14 +471,12 @@ nng_url_parse(nng_url **urlp, const char *raw)
p++;
while (*p != ']') {
if (*p++ == '\0') {
rv = NNG_EINVAL;
goto error;
return (NNG_EINVAL);
}
}
*p++ = '\0';
if ((*p != ':') && (*p != '\0')) {
rv = NNG_EINVAL;
goto error;
return (NNG_EINVAL);
}
} else {
while (*p != ':' && *p != '\0') {
@@ -500,31 +488,40 @@ nng_url_parse(nng_url **urlp, const char *raw)
}
// hostname length check
if (strlen(url->u_hostname) >= 256) {
rv = NNG_EINVAL;
goto error;
return (NNG_EINVAL);
}

if (c == ':') {
// If a colon was present, but no port value present, then
// that is an error.
if (*p == '\0') {
rv = NNG_EINVAL;
goto error;
return (NNG_EINVAL);
}
rv = nni_get_port_by_name(p, &url->u_port);
if (rv != 0) {
goto error;
if (nni_get_port_by_name(p, &url->u_port) != 0) {
return (NNG_EINVAL);
}
} else {
url->u_port = nni_url_default_port(url->u_scheme);
}

*urlp = url;
return (0);
}

error:
nng_url_free(url);
return (rv);
int
nng_url_parse(nng_url **urlp, const char *raw)
{
nng_url *url;
int rv;

if ((url = NNI_ALLOC_STRUCT(url)) == NULL) {
return (NNG_ENOMEM);
}
if ((rv = nni_url_parse_inline(url, raw)) != 0) {
nng_url_free(url);
return (rv);
}
*urlp = url;
return (0);
}

void
1 change: 1 addition & 0 deletions src/core/url.h
Original file line number Diff line number Diff line change
@@ -33,5 +33,6 @@ extern int nni_url_asprintf(char **, const nng_url *);
extern int nni_url_asprintf_port(char **, const nng_url *, int);
extern size_t nni_url_decode(uint8_t *, const char *, size_t);
extern int nni_url_to_address(nng_sockaddr *, const nng_url *);
extern int nni_url_parse_inline(nng_url *, const char *);

#endif // CORE_URL_H
27 changes: 27 additions & 0 deletions src/core/url_test.c
Original file line number Diff line number Diff line change
@@ -384,6 +384,30 @@ test_url_good_utf8(void)
nng_url_free(url);
}

void
test_url_missing_port(void)
{
nng_url *url = NULL;
NUTS_FAIL(
nng_url_parse(&url, "http://www.x.com:/something"), NNG_EINVAL);
}

void
test_url_unknown_service(void)
{
nng_url *url = NULL;
NUTS_FAIL(
nng_url_parse(&url, "http://www.x.com:nosuchservice"), NNG_EINVAL);
}

void
test_url_duplicate_userinfo(void)
{
nng_url *url = NULL;
NUTS_FAIL(
nng_url_parse(&url, "http://user@@user@www.x.com"), NNG_EINVAL);
}

void
test_url_decode(void)
{
@@ -463,6 +487,9 @@ NUTS_TESTS = {
{ "url canonify", test_url_canonify },
{ "url path resolve", test_url_path_resolve },
{ "url query info pass", test_url_query_info_pass },
{ "url missing port", test_url_missing_port },
{ "url unknown service", test_url_unknown_service },
{ "url duplicate userinfo", test_url_duplicate_userinfo },
{ "url bad utf8", test_url_bad_utf8 },
{ "url good utf8", test_url_good_utf8 },
{ "url decode", test_url_decode },