summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-01-23 22:03:06 -0800
committerGarrett D'Amore <garrett@damore.org>2018-01-23 22:03:06 -0800
commitced5170d6532f427f6750eee274288ceaffe05b5 (patch)
tree477ec98b087a6f9d59460943dedfb5249dcc9aba
parentb2800c58d63dc1b53557ea9294b323c3b1f90dab (diff)
downloadnng-ced5170d6532f427f6750eee274288ceaffe05b5.tar.gz
nng-ced5170d6532f427f6750eee274288ceaffe05b5.tar.bz2
nng-ced5170d6532f427f6750eee274288ceaffe05b5.zip
fixes #222 Public URL API
-rw-r--r--docs/libnng.adoc11
-rw-r--r--docs/nng_url_clone.adoc53
-rw-r--r--docs/nng_url_free.adoc51
-rw-r--r--docs/nng_url_parse.adoc111
-rw-r--r--src/core/defs.h2
-rw-r--r--src/nng.c18
-rw-r--r--src/nng.h29
-rw-r--r--tests/url.c95
8 files changed, 320 insertions, 50 deletions
diff --git a/docs/libnng.adoc b/docs/libnng.adoc
index 179b9a0e..57337f47 100644
--- a/docs/libnng.adoc
+++ b/docs/libnng.adoc
@@ -160,6 +160,17 @@ The following functions are used to register a transport for use.
| <<nng_zerotier#,nng_zerotier_register(3)>>|register ZeroTier transport
|===
+=== URL Object
+
+Common functionality is supplied for parsing and handling
+universal resource locators (URLS).
+
+|===
+| <<nng_url_clone#,nng_url_clone(3)>>|clone URL structure
+| <<nng_url_free#,nng_url_free(3)>>|free URL structure
+| <<nng_url_parse#,nng_url_parse(3)>>|create URL structure from string
+|===
+
=== TLS Configuration Objects
The following functions are used to manipulate transport layer security
diff --git a/docs/nng_url_clone.adoc b/docs/nng_url_clone.adoc
new file mode 100644
index 00000000..b1714962
--- /dev/null
+++ b/docs/nng_url_clone.adoc
@@ -0,0 +1,53 @@
+= nng_url_clone(3)
+:doctype: manpage
+:manmanual: nng
+:mansource: nng
+:manvolnum: 3
+:copyright: Copyright 2018 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 \
+ copy of which should be located in the distribution where this \
+ file was obtained (LICENSE.txt). A copy of the license may also \
+ be found online at https://opensource.org/licenses/MIT.
+
+== NAME
+
+nng_url_clone - clone URL structure
+
+== SYNOPSIS
+
+[source, c]
+-----------
+#include <nng/nng.h>
+
+int nng_url_clone(nng_url **dup, nng_url *orig);
+-----------
+
+== DESCRIPTION
+
+The `nng_url_clone()` makes a clone of the original URL structure _orig_, and
+saves the result in the location pointed by _dup_. This clone includes
+fully duplicating each of the member fields.
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+== ERRORS
+
+`NNG_ENOMEM`:: Insufficient free memory exists to duplicate a message.
+
+== SEE ALSO
+
+<<nng_url_free#,nng_url_free(3)>>,
+<<nng_url_parse#,nng_url_parse(3)>>,
+<<nng_strerror#,nng_strerror(3)>>,
+<<nng#,nng(7)>>
+
+== COPYRIGHT
+
+Copyright 2018 mailto:info@staysail.tech[Staysail Systems, Inc.] +
+Copyright 2018 mailto:info@capitar.com[Capitar IT Group BV]
+
+This document is supplied under the terms of the
+https://opensource.org/licenses/MIT[MIT License].
diff --git a/docs/nng_url_free.adoc b/docs/nng_url_free.adoc
new file mode 100644
index 00000000..1aa522f0
--- /dev/null
+++ b/docs/nng_url_free.adoc
@@ -0,0 +1,51 @@
+= nng_url_free(3)
+:doctype: manpage
+:manmanual: nng
+:mansource: nng
+:manvolnum: 3
+:copyright: Copyright 2018 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 \
+ copy of which should be located in the distribution where this \
+ file was obtained (LICENSE.txt). A copy of the license may also \
+ be found online at https://opensource.org/licenses/MIT.
+
+== NAME
+
+nng_url_free - free a URL structure
+
+== SYNOPSIS
+
+[source, c]
+-----------
+#include <nng/nng.h>
+
+void nng_url_free(nng_url *url);
+-----------
+
+== DESCRIPTION
+
+The `nng_url_free()` function deallocates the _url_ entirely, including
+any of it's members.
+
+== RETURN VALUES
+
+None.
+
+== ERRORS
+
+None.
+
+== SEE ALSO
+
+<<nng_url_clone#,nng_url_clone(3)>>,
+<<nng_url_parse#,nng_url_parse(3)>>,
+<<nng#,nng(7)>>
+
+== COPYRIGHT
+
+Copyright 2018 mailto:info@staysail.tech[Staysail Systems, Inc.] +
+Copyright 2018 mailto:info@capitar.com[Capitar IT Group BV]
+
+This document is supplied under the terms of the
+https://opensource.org/licenses/MIT[MIT License].
diff --git a/docs/nng_url_parse.adoc b/docs/nng_url_parse.adoc
new file mode 100644
index 00000000..0ea0cd1d
--- /dev/null
+++ b/docs/nng_url_parse.adoc
@@ -0,0 +1,111 @@
+= nng_url_parse(3)
+:doctype: manpage
+:manmanual: nng
+:mansource: nng
+:manvolnum: 3
+:copyright: Copyright 2018 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 \
+ copy of which should be located in the distribution where this \
+ file was obtained (LICENSE.txt). A copy of the license may also \
+ be found online at https://opensource.org/licenses/MIT.
+
+== NAME
+
+nng_url_parse - create URL structure from a string
+
+== SYNOPSIS
+
+[source, c]
+-----------
+#include <nng/nng.h>
+
+int nng_url_parse(nng_url **urlp, const char *str);
+-----------
+
+
+== DESCRIPTION
+
+The `nng_url_parse()` function parses the string _str_ containing an
+https://tools.ietf.org/html/rfc3986[RFC 3986] compliant URL, and creates
+a structure containing the results. A pointer to the resulting structure
+is stored in _urlp_.
+
+The `nng_url` structure has at least the following members:
+
+`char *u_scheme`:: The scheme, such as `http`. Always lower case.
+
+`char *u_rawurl`:: An unparsed form of the raw URL, with only minimal
+ canonicalization performed.
+
+`char *u_userinfo`:: The userinfo component if one was present,
+ `NULL` otherwise.
+
+`char *u_host`:: The full host, including hostname, and colon and port
+ if present, otehrwise the empty string.
+
+`char *u_hostname`:: The hostname if present, otherwise the empty string.
+ Always lower case.
+
+`char *u_port`:: The port if present. If not present, a default port
+ will be stored here. If no default is available, then
+ the empty string.
+
+`char *u_path`:: The path component if present, or the empty string
+ otherwise.
+
+`char *u_query`:: The query component if present, NULL otherwise.
+
+`char *u_fragment`:: The fragment if present, NULL otherwise.
+
+=== URL Canonicalization
+
+The `nng_url_parse()` function also canonicalizes the results, as
+follows:
+
+ 1. The URL is parsed into the various components.
+ 2. The `u_scheme`, `u_hostname`, `u_host`, and `u_port` members are
+ converted to lower case.
+ 3. Percent-encoded values for
+ https://tools.ietf.org/html/rfc3986#section-2.3[unreserved characters]
+ converted to their unencoded forms.
+ 4. Additionally URL percent-encoded values for characters in the path
+ and with numeric values larger than 127 (i.e. not ASCII) are decoded.
+ 5. The resulting `u_path` is checked for invalid UTF-8 sequences, consisting
+ of surrogate pairs, illegal byte sequences, or overlong encodings.
+ If this check fails, then the entire URL is considered invalid, and
+ the function returns `NNG_EINVAL`.
+ 6. Path segments consisting of `.` and `..` are resolved as per
+ https://tools.ietf.org/html/rfc3986#section-6.2.2.3[RFC 3986 6.2.2.3].
+ 7. Further, empty path segments are removed, meaning that duplicate
+ slash (`/`) separators are removed from the path.
+ 8. If a port was not specified, but the scheme defines a default
+ port, then `u_port` will be filled in with the value of the default port.
+
+
+== RETURN VALUES
+
+This function returns 0 on success, and non-zero otherwise.
+
+
+== ERRORS
+
+`NNG_ENOMEM`:: Insufficient free memory exists to allocate a message.
+`NNG_EINVAL`:: An invalid URL was supplied.
+
+
+== SEE ALSO
+
+<<nng_url_clone#,nng_url_clone(3)>>,
+<<nng_url_free#,nng_url_free(3)>>,
+<<nng_strerror#,nng_strerror(3)>>,
+<<nng#,nng(7)>>
+
+
+== COPYRIGHT
+
+Copyright 2018 mailto:info@staysail.tech[Staysail Systems, Inc.] +
+Copyright 2018 mailto:info@capitar.com[Capitar IT Group BV]
+
+This document is supplied under the terms of the
+https://opensource.org/licenses/MIT[MIT License].
diff --git a/src/core/defs.h b/src/core/defs.h
index d4a8a740..cecb4825 100644
--- a/src/core/defs.h
+++ b/src/core/defs.h
@@ -33,6 +33,7 @@ typedef struct nng_msg nni_msg;
typedef struct nng_sockaddr nni_sockaddr;
typedef struct nng_event nni_event;
typedef struct nng_notify nni_notify;
+typedef struct nng_url nni_url;
// These are our own names.
typedef struct nni_socket nni_sock;
@@ -43,7 +44,6 @@ typedef struct nni_tran_ep nni_tran_ep;
typedef struct nni_tran_ep_option nni_tran_ep_option;
typedef struct nni_tran_pipe nni_tran_pipe;
typedef struct nni_tran_pipe_option nni_tran_pipe_option;
-typedef struct nni_url nni_url;
typedef struct nni_proto_sock_ops nni_proto_sock_ops;
typedef struct nni_proto_pipe_ops nni_proto_pipe_ops;
diff --git a/src/nng.c b/src/nng.c
index 509bb333..addfc06a 100644
--- a/src/nng.c
+++ b/src/nng.c
@@ -1176,3 +1176,21 @@ nng_thread_destroy(void *arg)
NNI_FREE_STRUCT(thr);
}
+
+int
+nng_url_parse(nng_url **result, const char *ustr)
+{
+ return (nni_url_parse(result, ustr));
+}
+
+void
+nng_url_free(nng_url *url)
+{
+ nni_url_free(url);
+}
+
+int
+nng_url_clone(nng_url **dstp, const nng_url *src)
+{
+ return (nni_url_clone(dstp, src));
+} \ No newline at end of file
diff --git a/src/nng.h b/src/nng.h
index 26e851eb..a25cb25c 100644
--- a/src/nng.h
+++ b/src/nng.h
@@ -710,6 +710,35 @@ NNG_DECL int nng_tls_config_ca_file(nng_tls_config *, const char *);
NNG_DECL int nng_tls_config_cert_key_file(
nng_tls_config *, const char *, const char *);
+// URL support. We frequently want to process a URL, and these methods
+// give us a convenient way of doing so.
+
+typedef struct nng_url {
+ char *u_rawurl; // never NULL
+ char *u_scheme; // never NULL
+ char *u_userinfo; // will be NULL if not specified
+ char *u_host; // including colon and port
+ char *u_hostname; // name only, will be "" if not specified
+ char *u_port; // port, will be "" if not specified
+ char *u_path; // path, will be "" if not specified
+ char *u_query; // without '?', will be NULL if not specified
+ char *u_fragment; // without '#', will be NULL if not specified
+ char *u_rawpath; // includes query and fragment, "" if not specified
+} nng_url;
+
+// nng_url_parse parses a URL string into a structured form.
+// Note that the u_port member will be filled out with a numeric
+// port if one isn't specified and a default port is appropriate for
+// the scheme. The URL structure is allocated, along with individual
+// members. It can be freed with nng_url_free.
+NNG_DECL int nng_url_parse(nng_url **, const char *);
+
+// nng_url_free frees a URL structure that was created by nng_url_parse9().
+NNG_DECL void nng_url_free(nng_url *);
+
+// nng_url_clone clones a URL structure.
+NNG_DECL int nng_url_clone(nng_url **, const nng_url *);
+
#ifdef __cplusplus
}
#endif
diff --git a/tests/url.c b/tests/url.c
index dba0664b..a4b4457b 100644
--- a/tests/url.c
+++ b/tests/url.c
@@ -12,17 +12,14 @@
#include "convey.h"
-#include "core/nng_impl.h"
-#include "core/url.h"
-
-//#include "stubs.h"
+#include "nng.h"
TestMain("URLs", {
- nni_url *url;
+ nng_url *url;
Convey("http://www.google.com", {
- So(nni_url_parse(&url, "http://www.google.com") == 0);
+ So(nng_url_parse(&url, "http://www.google.com") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
So(strcmp(url->u_host, "www.google.com") == 0);
@@ -33,11 +30,11 @@ TestMain("URLs", {
So(url->u_query == NULL);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://www.google.com:1234", {
- So(nni_url_parse(&url, "http://www.google.com:1234") == 0);
+ So(nng_url_parse(&url, "http://www.google.com:1234") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
So(strcmp(url->u_host, "www.google.com:1234") == 0);
@@ -48,11 +45,11 @@ TestMain("URLs", {
So(url->u_query == NULL);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://www.google.com:1234/somewhere", {
- So(nni_url_parse(
+ So(nng_url_parse(
&url, "http://www.google.com:1234/somewhere") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
@@ -64,10 +61,10 @@ TestMain("URLs", {
So(url->u_userinfo == NULL);
So(url->u_query == NULL);
So(url->u_fragment == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://garrett@www.google.com:1234/somewhere", {
- So(nni_url_parse(&url,
+ So(nng_url_parse(&url,
"http://garrett@www.google.com:1234/somewhere") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
@@ -79,10 +76,10 @@ TestMain("URLs", {
So(strcmp(url->u_rawpath, "/somewhere") == 0);
So(url->u_query == NULL);
So(url->u_fragment == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://www.google.com/somewhere?result=yes", {
- So(nni_url_parse(&url,
+ So(nng_url_parse(&url,
"http://www.google.com/somewhere?result=yes") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
@@ -94,10 +91,10 @@ TestMain("URLs", {
So(strcmp(url->u_rawpath, "/somewhere?result=yes") == 0);
So(url->u_userinfo == NULL);
So(url->u_fragment == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://www.google.com/somewhere?result=yes#chapter1", {
- So(nni_url_parse(&url,
+ So(nng_url_parse(&url,
"http://www.google.com/"
"somewhere?result=yes#chapter1") == 0);
So(url != NULL);
@@ -111,10 +108,10 @@ TestMain("URLs", {
So(strcmp(url->u_rawpath, "/somewhere?result=yes#chapter1") ==
0);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://www.google.com/somewhere#chapter2", {
- So(nni_url_parse(
+ So(nng_url_parse(
&url, "http://www.google.com/somewhere#chapter2") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
@@ -126,10 +123,10 @@ TestMain("URLs", {
So(strcmp(url->u_rawpath, "/somewhere#chapter2") == 0);
So(url->u_query == NULL);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://www.google.com#chapter3", {
- So(nni_url_parse(&url, "http://www.google.com#chapter3") == 0);
+ So(nng_url_parse(&url, "http://www.google.com#chapter3") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
So(strcmp(url->u_host, "www.google.com") == 0);
@@ -140,10 +137,10 @@ TestMain("URLs", {
So(strcmp(url->u_rawpath, "#chapter3") == 0);
So(url->u_query == NULL);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://www.google.com?color=red", {
- So(nni_url_parse(&url, "http://www.google.com?color=red") ==
+ So(nng_url_parse(&url, "http://www.google.com?color=red") ==
0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
@@ -155,11 +152,11 @@ TestMain("URLs", {
So(strcmp(url->u_rawpath, "?color=red") == 0);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://[::1]", {
- So(nni_url_parse(&url, "http://[::1]") == 0);
+ So(nng_url_parse(&url, "http://[::1]") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
So(strcmp(url->u_host, "[::1]") == 0);
@@ -169,11 +166,11 @@ TestMain("URLs", {
So(url->u_query == NULL);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://[::1]:29", {
- So(nni_url_parse(&url, "http://[::1]:29") == 0);
+ So(nng_url_parse(&url, "http://[::1]:29") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
So(strcmp(url->u_host, "[::1]:29") == 0);
@@ -183,10 +180,10 @@ TestMain("URLs", {
So(url->u_query == NULL);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("http://[::1]:29/bottles", {
- So(nni_url_parse(&url, "http://[::1]:29/bottles") == 0);
+ So(nng_url_parse(&url, "http://[::1]:29/bottles") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
So(strcmp(url->u_host, "[::1]:29") == 0);
@@ -196,11 +193,11 @@ TestMain("URLs", {
So(url->u_query == NULL);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("tcp://:9876/", {
- So(nni_url_parse(&url, "tcp://:9876/") == 0);
+ So(nng_url_parse(&url, "tcp://:9876/") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "tcp") == 0);
So(strcmp(url->u_host, ":9876") == 0);
@@ -210,11 +207,11 @@ TestMain("URLs", {
So(url->u_query == NULL);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("ws://", {
- So(nni_url_parse(&url, "ws://") == 0);
+ So(nng_url_parse(&url, "ws://") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "ws") == 0);
So(strcmp(url->u_host, "") == 0);
@@ -224,11 +221,11 @@ TestMain("URLs", {
So(url->u_query == NULL);
So(url->u_fragment == NULL);
So(url->u_userinfo == NULL);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("ssh://user@host.example.com", {
- So(nni_url_parse(&url, "ssh://user@host.example.com") == 0);
+ So(nng_url_parse(&url, "ssh://user@host.example.com") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "ssh") == 0);
So(strcmp(url->u_host, "host.example.com") == 0);
@@ -238,60 +235,60 @@ TestMain("URLs", {
So(url->u_query == NULL);
So(url->u_fragment == NULL);
So(strcmp(url->u_userinfo, "user") == 0);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("Negative www.google.com", {
url = NULL;
- So(nni_url_parse(&url, "www.google.com") == NNG_EINVAL);
+ So(nng_url_parse(&url, "www.google.com") == NNG_EINVAL);
So(url == NULL);
});
Convey("Negative http:www.google.com", {
url = NULL;
- So(nni_url_parse(&url, "http:www.google.com") == NNG_EINVAL);
+ So(nng_url_parse(&url, "http:www.google.com") == NNG_EINVAL);
So(url == NULL);
});
Convey("Negative http://[::1", {
url = NULL;
- So(nni_url_parse(&url, "http://[::1") == NNG_EINVAL);
+ So(nng_url_parse(&url, "http://[::1") == NNG_EINVAL);
So(url == NULL);
});
Convey("Negative http://[::1]bogus", {
url = NULL;
- So(nni_url_parse(&url, "http://[::1]bogus") == NNG_EINVAL);
+ So(nng_url_parse(&url, "http://[::1]bogus") == NNG_EINVAL);
So(url == NULL);
});
Convey("Canonicalization works", {
url = NULL;
- So(nni_url_parse(&url,
+ So(nng_url_parse(&url,
"hTTp://www.EXAMPLE.com/bogus/.%2e/%7egarrett") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
So(strcmp(url->u_hostname, "www.example.com") == 0);
So(strcmp(url->u_port, "80") == 0);
So(strcmp(url->u_path, "/~garrett") == 0);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("Path resolution works", {
url = NULL;
- So(nni_url_parse(&url,
+ So(nng_url_parse(&url,
"http://www.x.com//abc/def/./x/..///./../y") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
So(strcmp(url->u_hostname, "www.x.com") == 0);
So(strcmp(url->u_port, "80") == 0);
So(strcmp(url->u_path, "/abc/y") == 0);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("Query info unmolested", {
url = NULL;
- So(nni_url_parse(
+ So(nng_url_parse(
&url, "http://www.x.com/?/abc/def/./x/.././../y") == 0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
@@ -299,25 +296,25 @@ TestMain("URLs", {
So(strcmp(url->u_port, "80") == 0);
So(strcmp(url->u_path, "/") == 0);
So(strcmp(url->u_query, "/abc/def/./x/.././../y") == 0);
- nni_url_free(url);
+ nng_url_free(url);
});
Convey("Bad UTF-8 fails", {
url = NULL;
- So(nni_url_parse(&url, "http://x.com/x%80x") == NNG_EINVAL);
- So(nni_url_parse(&url, "http://x.com/x%c0%81") == NNG_EINVAL);
+ So(nng_url_parse(&url, "http://x.com/x%80x") == NNG_EINVAL);
+ So(nng_url_parse(&url, "http://x.com/x%c0%81") == NNG_EINVAL);
});
Convey("Valid UTF-8 works", {
url = NULL;
- So(nni_url_parse(&url, "http://www.x.com/%c2%a2_centsign") ==
+ So(nng_url_parse(&url, "http://www.x.com/%c2%a2_centsign") ==
0);
So(url != NULL);
So(strcmp(url->u_scheme, "http") == 0);
So(strcmp(url->u_hostname, "www.x.com") == 0);
So(strcmp(url->u_port, "80") == 0);
So(strcmp(url->u_path, "/\xc2\xa2_centsign") == 0);
- nni_url_free(url);
+ nng_url_free(url);
});
})