Add strict flag to url_parse
This commit is contained in:
@@ -34,9 +34,20 @@
|
||||
#define UINT8_MAX (URL_u8) ((1 << 8)-1)
|
||||
#define UINT16_MAX (URL_u16) ((1 << 16)-1)
|
||||
|
||||
#define S(X) ((URL_String) { (X), sizeof(X)-1 })
|
||||
#define EMPTY (URL_String) { (void*) 0, 0 }
|
||||
#define SLICE(src, off, end) (URL_String) { src + off, end - off }
|
||||
|
||||
static URL_b32 streq(URL_String a, URL_String b)
|
||||
{
|
||||
if (a.len != b.len)
|
||||
return 0;
|
||||
for (int i = 0; i < a.len; i++)
|
||||
if (a.ptr[i] != b.ptr[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static URL_b32 is_alpha(char c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z')
|
||||
@@ -309,7 +320,7 @@ int url_parse_ipv6(char *src, int len, int *pcur, URL_IPv6 *out)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int url_parse(char *src, int len, int *pcur, URL *out)
|
||||
int url_parse(char *src, int len, int *pcur, bool strict, URL *out)
|
||||
{
|
||||
int cur = pcur ? *pcur : 0;
|
||||
|
||||
@@ -348,6 +359,7 @@ int url_parse(char *src, int len, int *pcur, URL *out)
|
||||
// a character not allowed in the user info, se we
|
||||
// need to backtrack in a similar way to the scheme
|
||||
URL_b32 authority = 0;
|
||||
int authority_off = cur;
|
||||
if (len - cur > 1 && src[cur] == '/' && src[cur+1] == '/') {
|
||||
cur += 2; // Consume the //
|
||||
authority = 1;
|
||||
@@ -463,6 +475,11 @@ int url_parse(char *src, int len, int *pcur, URL *out)
|
||||
}
|
||||
}
|
||||
|
||||
// Registered names are not allowed to end with a dot,
|
||||
// so unconsume the last character if it is one
|
||||
if (cur > 0 && src[cur] == '.')
|
||||
cur--;
|
||||
|
||||
} else {
|
||||
out->host_type = URL_HOST_EMPTY;
|
||||
}
|
||||
@@ -475,6 +492,13 @@ int url_parse(char *src, int len, int *pcur, URL *out)
|
||||
out->port = 0;
|
||||
if (cur < len && src[cur] == ':') {
|
||||
|
||||
// The WHATWG standard forbids port numbers with the
|
||||
// "file" protocol.
|
||||
if (!strict) {
|
||||
if (streq(out->scheme, S("file")))
|
||||
return -1;
|
||||
}
|
||||
|
||||
cur++; // Consume the ':'
|
||||
out->no_port = 0;
|
||||
|
||||
@@ -497,6 +521,20 @@ int url_parse(char *src, int len, int *pcur, URL *out)
|
||||
out->no_port = 1;
|
||||
}
|
||||
|
||||
// The WHATWG standard considers the sequence "//"
|
||||
// part of the path and not the authority if userinfo,
|
||||
// host, and port are missing
|
||||
if (!strict) {
|
||||
if (authority
|
||||
&& out->username.len == 0
|
||||
&& out->password.len == 0
|
||||
&& out->host_type == URL_HOST_EMPTY
|
||||
&& out->no_port) {
|
||||
authority = false;
|
||||
cur = authority_off;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we parse the path. This is most difficult
|
||||
// component as it changes based on what comes
|
||||
// before it.
|
||||
@@ -525,6 +563,19 @@ int url_parse(char *src, int len, int *pcur, URL *out)
|
||||
out->path = SLICE(src, off, cur);
|
||||
}
|
||||
|
||||
// For a subset of protocols, WHATWG sets the default
|
||||
// path to "/"
|
||||
if (!strict) {
|
||||
if (out->path.len == 0 && (
|
||||
streq(out->scheme, S("ftp")) ||
|
||||
streq(out->scheme, S("file")) ||
|
||||
streq(out->scheme, S("http")) ||
|
||||
streq(out->scheme, S("https")) ||
|
||||
streq(out->scheme, S("ws")) ||
|
||||
streq(out->scheme, S("wss"))))
|
||||
out->path = S("/");
|
||||
}
|
||||
|
||||
// Consume the query
|
||||
out->query = EMPTY;
|
||||
if (cur < len && src[cur] == '?') {
|
||||
|
||||
@@ -97,7 +97,7 @@ typedef struct {
|
||||
|
||||
} URL;
|
||||
|
||||
int url_parse(char *src, int len, int *pcur, URL *out);
|
||||
int url_parse(char *src, int len, int *pcur, bool strict, URL *out);
|
||||
int url_parse_ipv4(char *src, int len, int *pcur, URL_IPv4 *out);
|
||||
int url_parse_ipv6(char *src, int len, int *pcur, URL_IPv6 *out);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user