Commit 5f44484c authored by Pekka Pessi's avatar Pekka Pessi
Browse files

url.c: updated url_update() with # in username and IPv6 reference handling.

darcs-hash:20070124161401-65a35-11bd806701cb603833aeb986a2dc282b8bc0b4e9.gz
parent 6a2373d9
...@@ -108,7 +108,7 @@ int test_quote(void) ...@@ -108,7 +108,7 @@ int test_quote(void)
TEST_S(url_escape(unreserved, UNRESERVED, NULL), UNRESERVED); TEST_S(url_escape(unreserved, UNRESERVED, NULL), UNRESERVED);
TEST_S(url_unescape(unreserved, UNRESERVED), UNRESERVED); TEST_S(url_unescape(unreserved, UNRESERVED), UNRESERVED);
d = "%73ip:%55@%68"; d = "%53ip:%75@%48"; /* Sip:u@H */
u = url_hdup(home, (url_t *)d); TEST_1(u); u = url_hdup(home, (url_t *)d); TEST_1(u);
url_digest(hash1, sizeof(hash1), u, NULL); url_digest(hash1, sizeof(hash1), u, NULL);
url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL); url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
...@@ -125,9 +125,11 @@ int test_quote(void) ...@@ -125,9 +125,11 @@ int test_quote(void)
d = url_as_string(home, u); TEST_1(d); d = url_as_string(home, u); TEST_1(d);
TEST_S(d, c); TEST_S(d, c);
d = "sip:&=+$,;?/:&=+$,@host:56001;param=+$,/:@&;another=@" d = "sip:&=+$,;?/:&=+$,@[::1]:56001;param=+$,/:@&;another=@"
"?header=" RESERVED "&%3b%2f%3f%3a%40%26%3d%2b%24%2c"; "?header=" RESERVED "&%3b%2f%3f%3a%40%26%3d%2b%24%2c";
u = url_hdup(home, (url_t *)d); TEST_1(u); u = url_hdup(home, (url_t *)d); TEST_1(u);
TEST_S(u->url_user, "&=+$,;?/");
TEST_S(u->url_host, "[::1]");
TEST_S(u->url_headers, "header=" RESERVED "&%3B%2F%3F%3A%40%26%3D%2B%24%2C"); TEST_S(u->url_headers, "header=" RESERVED "&%3B%2F%3F%3A%40%26%3D%2B%24%2C");
url_digest(hash1, sizeof(hash1), u, NULL); url_digest(hash1, sizeof(hash1), u, NULL);
url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL); url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
...@@ -137,8 +139,10 @@ int test_quote(void) ...@@ -137,8 +139,10 @@ int test_quote(void)
d = url_as_string(home, u); TEST_1(d); d = url_as_string(home, u); TEST_1(d);
TEST_S(d, c); TEST_S(d, c);
d = "http://&=+$,;:&=+$,;@host:8080/foo;param=+$,/:@&;another=@?query=" RESERVED; d = "http://&=+$,;:&=+$,;@host:8080/foo;param=+$,/:@&;another=@"
"?query=" RESERVED;
u = url_hdup(home, (url_t *)d); TEST_1(u); u = url_hdup(home, (url_t *)d); TEST_1(u);
TEST_S(u->url_user, "&=+$,;"); TEST_S(u->url_password, "&=+$,;");
url_digest(hash1, sizeof(hash1), u, NULL); url_digest(hash1, sizeof(hash1), u, NULL);
url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL); url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
TEST(memcmp(hash1, hash2, sizeof(hash1)), 0); TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
...@@ -337,6 +341,9 @@ int test_sip(void) ...@@ -337,6 +341,9 @@ int test_sip(void)
TEST(u->url_type, url_sip); TEST(u->url_type, url_sip);
TEST_S(u->url_user, "#**00**#;foo=/bar"); TEST_S(u->url_user, "#**00**#;foo=/bar");
TEST_1(!url_hdup(home, (url_t*)"SIP:#**00**#;foo=/bar@#127.0.0.1"));
TEST_1(!url_hdup(home, (url_t*)"SIP:#**00**#;foo=/bar;127.0.0.1"));
for (i = 32; i <= 256; i++) { for (i = 32; i <= 256; i++) {
char pu[512]; char pu[512];
char param[512]; char param[512];
...@@ -831,6 +838,16 @@ int test_http(void) ...@@ -831,6 +838,16 @@ int test_http(void)
TEST_S(url->url_host, "some.host"); TEST_S(url->url_host, "some.host");
TEST_S(url->url_headers, "query"); TEST_S(url->url_headers, "query");
TEST_S(url->url_params, NULL); TEST_S(url->url_params, NULL);
TEST_1(u = url_hdup(home, (void *)"http://[::1]/test;ing?here"));
TEST_S(u->url_host, "[::1]");
TEST_S(u->url_path, "test;ing");
TEST_S(u->url_headers, "here");
url_digest(hash1, sizeof(hash1), u, NULL);
url_digest(hash2, sizeof(hash2), (url_t *)"http://[::1]/test;ing?here",
NULL);
TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
su_home_deinit(home); su_home_deinit(home);
......
...@@ -556,8 +556,8 @@ static ...@@ -556,8 +556,8 @@ static
int _url_d(url_t *url, char *s) int _url_d(url_t *url, char *s)
{ {
size_t n, p; size_t n, p;
char *s0, rest_c, *host; char *s0, rest_c, *host, *user;
int net_path = 1; int have_authority = 1;
memset(url, 0, sizeof(*url)); memset(url, 0, sizeof(*url));
...@@ -582,115 +582,123 @@ int _url_d(url_t *url, char *s) ...@@ -582,115 +582,123 @@ int _url_d(url_t *url, char *s)
url->url_type = url_get_type(url->url_scheme, n); url->url_type = url_get_type(url->url_scheme, n);
net_path = !url_type_is_opaque(url->url_type); have_authority = !url_type_is_opaque(url->url_type);
} }
else { else {
url->url_type = url_unknown; url->url_type = url_unknown;
} }
host = s; user = NULL, host = s;
if (url->url_type == url_sip || url->url_type == url_sips) { if (url->url_type == url_sip || url->url_type == url_sips) {
/* SIP URL may have /; in user part */ /* SIP URL may have /;? in user part but no path */
/* user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/" */
/* Some #*@#* phones include unescaped # there, too */ /* Some #*@#* phones include unescaped # there, too */
n = strcspn(s, "@#"); /* Opaque part */ n = strcspn(s, "@/;?#");
if (s[n] == '#') { p = strcspn(s + n, "@");
p = strcspn(s + n + 1, "@") + 1; if (s[n + p] == '@') {
if (s[n + p] == '@') n += p;
n += p; user = s;
else host = s + n + 1;
n = 0;
} }
n += strcspn(s + n, "/;?#"); n += strcspn(s + n, "/;?#");
} }
else if (url->url_type == url_wv) { else if (have_authority) {
/* WV URL may have / in user part */ if (url->url_type == url_wv) {
n = strcspn(s, "@#?;"); /* WV URL may have / in user part */
if (s[n] == '@') n = strcspn(s, "@#?;");
n += strcspn(s + n, ";?#"); if (s[n] == '@') {
} user = s;
else if (url->url_type == url_invalid) { host = s + n + 1;
n = strcspn(s, "#"); n += strcspn(s + n, ";?#");
} }
else if (net_path && host[0] == '/') { }
url->url_root = host[0]; /* Absolute path */ else if (host[0] == '/' && host[1] != '/') {
/* foo:/bar or /bar - no authority, just path */
url->url_root = '/'; /* Absolute path */
host = NULL, n = 0;
}
else {
if (host[0] == '/' && host[1] == '/') {
/* We have authority, / / foo or foo */
host += 2; s += 2, url->url_root = '/';
n = strcspn(s, "/?#@[]");
}
else
n = strcspn(s, "@;/?#");
if (s[n] == '@')
user = host, host = user + n + 1;
if (host[1] == '/') { /* We have host-part */ n += strcspn(s + n, ";/?#"); /* Find path, query and/or fragment */
host += 2; s += 2;
} }
else
host = NULL;
n = strcspn(s, "/;?#"); /* Find path, query and/or fragment */
} }
else { else /* !have_authority */ {
n = strcspn(s, "/;?#"); /* Find params, query and/or fragment */ user = host, host = NULL;
if (url->url_type != url_invalid)
n = strcspn(s, "/;?#"); /* Find params, query and/or fragment */
else
n = strcspn(s, "#");
} }
rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL; rest_c = s[n]; s[n] = 0; s = rest_c ? s + n + 1 : NULL;
if (host) { if (user) {
char *atsign, *port; if (host) host[-1] = '\0';
url->url_user = user;
if (!net_path) { if (url->url_type != url_unknown) {
url->url_user = host; n = strcspn(user, ":");
host = NULL; if (user[n]) {
user[n] = '\0';
url->url_password = user + n + 1;
}
} }
else if ((atsign = strchr(host, '@'))) { }
char *user;
url->url_user = user = host;
if (atsign)
*atsign++ = '\0';
host = atsign;
if (url->url_type != url_unknown) { if (host) {
char *colon = strchr(user, ':'); url->url_host = host;
if (colon) /* IPv6 (and in some cases, IPv4) addresses are quoted with [] */
*colon++ = '\0'; if (host[0] == '[') {
url->url_password = colon; n = strcspn(host, "]");
} if (host[n] && (host[n + 1] == '\0' || host[n + 1] == ':'))
n++;
else
n = 0;
}
else {
n = strcspn(host, ":");
} }
if (n == 0 && url->url_type != url_unknown)
return -1;
if ((url->url_host = host)) { if (host[n] == ':') {
/* IPv6 (and in some cases, IPv4) addresses are quoted with [] */ char *port = host + n + 1;
if (host[0] == '[') { url->url_port = port;
port = strchr(host, ']'); switch (url->url_type) {
if (!port) case url_any:
case url_sip:
case url_sips:
case url_http:
case url_https:
case url_ftp:
case url_file:
case url_rtsp:
case url_rtspu:
if (!url_canonize2(port, port, SIZE_MAX, RESERVED_MASK))
return -1;
/* Check that port is really numeric or wildcard */
/* Port can be *digit, empty string or "*" */
while (*port >= '0' && *port <= '9')
port++;
if (port != url->url_port ? port[0] != '\0'
: (port[0] != '*' || port[1] != '\0'))
return -1; return -1;
port = strchr(port + 1, ':');
}
else
port = strchr(host, ':');
if (port) {
*port++ = '\0';
url->url_port = port;
switch (url->url_type) {
case url_any:
case url_sip:
case url_sips:
case url_http:
case url_https:
case url_ftp:
case url_file:
case url_rtsp:
case url_rtspu:
if (!url_canonize2(port, port, SIZE_MAX, RESERVED_MASK))
return -1;
/* Check that port is really numeric or wildcard */
/* Port can be *digit, empty string or "*" */
while (*port >= '0' && *port <= '9')
port++;
if (port != url->url_port
? port[0] != '\0'
: port[0] != '\0'
&& (port[0] != '*' || port[1] != '\0'))
return -1;
}
} }
host[n] = 0;
} }
} }
...@@ -745,12 +753,15 @@ int url_d(url_t *url, char *s) ...@@ -745,12 +753,15 @@ int url_d(url_t *url, char *s)
if (s && !url_canonize(s, s, SIZE_MAX, SIP_USER_UNRESERVED)) if (s && !url_canonize(s, s, SIZE_MAX, SIP_USER_UNRESERVED))
return -1; return -1;
/* Having different charset in user and password does not make sense */
/* but that is how it is defined in RFC 3261 */
# define SIP_PASS_UNRESERVED "&=+$," # define SIP_PASS_UNRESERVED "&=+$,"
s = (char *)url->url_password; s = (char *)url->url_password;
if (s && !url_canonize(s, s, SIZE_MAX, SIP_PASS_UNRESERVED)) if (s && !url_canonize(s, s, SIZE_MAX, SIP_PASS_UNRESERVED))
return -1; return -1;
} else { }
else {
# define USER_UNRESERVED "&=+$,;" # define USER_UNRESERVED "&=+$,;"
s = (char *)url->url_user; s = (char *)url->url_user;
...@@ -946,7 +957,7 @@ issize_t url_e(char buffer[], isize_t n, url_t const *url) ...@@ -946,7 +957,7 @@ issize_t url_e(char buffer[], isize_t n, url_t const *url)
} }
/** Calculate the lengh of URL when encoded. /** Calculate the length of URL when encoded.
* *
*/ */
isize_t url_len(url_t const * url) isize_t url_len(url_t const * url)
...@@ -1892,8 +1903,8 @@ void canon_update(su_md5_t *md5, char const *s, size_t n, char const *allow) ...@@ -1892,8 +1903,8 @@ void canon_update(su_md5_t *md5, char const *s, size_t n, char const *allow)
static static
void url_string_update(su_md5_t *md5, char const *s) void url_string_update(su_md5_t *md5, char const *s)
{ {
size_t n; size_t n, p;
int hostpart = 1; int have_authority = 1;
enum url_type_e type = url_any; enum url_type_e type = url_any;
char const *at, *colon; char const *at, *colon;
char schema[48]; char schema[48];
...@@ -1913,7 +1924,7 @@ void url_string_update(su_md5_t *md5, char const *s) ...@@ -1913,7 +1924,7 @@ void url_string_update(su_md5_t *md5, char const *s)
type = url_get_type(schema, at - schema); type = url_get_type(schema, at - schema);
su_md5_iupdate(md5, schema, at - schema); su_md5_iupdate(md5, schema, at - schema);
hostpart = !url_type_is_opaque(type); have_authority = !url_type_is_opaque(type);
s += n + 1; s += n + 1;
} }
else { else {
...@@ -1921,62 +1932,71 @@ void url_string_update(su_md5_t *md5, char const *s) ...@@ -1921,62 +1932,71 @@ void url_string_update(su_md5_t *md5, char const *s)
} }
if (type == url_sip || type == url_sips) { if (type == url_sip || type == url_sips) {
n = strcspn(s, "@#"); /* Opaque part */ /* SIP URL may have /;? in user part but no path */
if (s[n] != '@') /* user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/" */
n = 0; /* Some #*@#* phones include unescaped # there, too */
n = strcspn(s, "@/;?#");
p = strcspn(s + n, "@");
if (s[n + p] == '@') {
n += p;
/* Ignore password in hash */
colon = memchr(s, ':', n);
p = colon ? colon - s : n;
canon_update(md5, s, p, SIP_USER_UNRESERVED);
s += n + 1; n = 0;
}
else
su_md5_iupdate(md5, "", 1); /* user */
n += strcspn(s + n, "/;?#"); n += strcspn(s + n, "/;?#");
} }
else if (type == url_wv) { /* WV URL may have / in user part */ else if (have_authority) {
n = strcspn(s, "@#?;"); if (type == url_wv) { /* WV URL may have / in user part */
if (s[n] == '@') n = strcspn(s, "@;?#");
n += strcspn(s + n, ";?#"); }
} else if (type != url_wv && s[0] == '/' && s[1] != '/') {
else if (!hostpart || s[0] != '/') { /* foo:/bar */
n = strcspn(s, "/;?#"); /* Opaque part */ su_md5_update(md5, "\0\0", 2); /* user, host */
} su_md5_striupdate(md5, url_port_default(type));
else if (s[1] == '/') { return;
s += 2; }
n = strcspn(s, "/;?#"); /* Until host, path, query or fragment */ else if (s[0] == '/' && s[1] == '/') {
} /* We have authority, / / foo or foo */
else { s += 2;
/* foo:/bar */ n = strcspn(s, "/?#@[]");
su_md5_update(md5, "\0\0", 2); /* user, host */ }
su_md5_striupdate(md5, url_port_default(type)); else
return; n = strcspn(s, "@;/?#");
if (s[n] == '@') {
/* Ignore password in hash */
colon = type != url_unknown ? memchr(s, ':', n) : NULL;
p = colon ? colon - s : n;
canon_update(md5, s, p, SIP_USER_UNRESERVED);
s += n + 1;
n = strcspn(s, "/;?#"); /* Until path, query or fragment */
}
else {
su_md5_iupdate(md5, "", 1); /* user */
n += strcspn(s + n, "/;?#"); /* Until path, query or fragment */
}
} }
else /* if (!have_authority) */ {
if (!hostpart) { n = strcspn(s, ":/;?#"); /* Until pass, path, query or fragment */
char const *colon = memchr(s, ':', n);
if (colon) n = colon - s;
canon_update(md5, s, n, ""); /* user */ canon_update(md5, s, n, ""); /* user */
su_md5_update(md5, "\0", 1); /* host, no port */ su_md5_update(md5, "\0", 1); /* host, no port */
su_md5_striupdate(md5, url_port_default(type)); su_md5_striupdate(md5, url_port_default(type));
return; return;
} }
at = memchr(s, '@', n); if (n > 0 && s[0] == '[') { /* IPv6reference */
colon = memchr(s, ']', n);
if (at) { if (colon == NULL || ++colon == s + n || *colon != ':')
char const *allow = colon = NULL;
(type == url_sip || type == url_sips)
? SIP_USER_UNRESERVED
: USER_UNRESERVED;
colon = type == url_unknown ? NULL : memchr(s, ':', at - s);
/* Updated only user part */
if (colon)
canon_update(md5, s, colon - s, allow);
else
canon_update(md5, s, at - s, allow);
n = n - (at + 1 - s);
s = at + 1;
} }
else else
su_md5_iupdate(md5, "", 1); /* user */ colon = memchr(s, ':', n);
colon = memchr(s, ':', n); /* XXX - IPv6! */
if (colon) { if (colon) {
canon_update(md5, s, colon - s, ""); /* host */ canon_update(md5, s, colon - s, ""); /* host */
canon_update(md5, colon + 1, (s + n) - (colon + 1), ""); canon_update(md5, colon + 1, (s + n) - (colon + 1), "");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment