If scheme is invalid, parse everything as path
This commit is contained in:
parent
e5fb95ceb0
commit
a1f4d2bc1c
@ -78,8 +78,7 @@ struct URL
|
|||||||
*/
|
*/
|
||||||
this(const char[] source) pure @nogc
|
this(const char[] source) pure @nogc
|
||||||
{
|
{
|
||||||
auto value = source;
|
ptrdiff_t pos = -1, endPos = source.length, start;
|
||||||
ptrdiff_t pos = -1, endPos = value.length, start;
|
|
||||||
|
|
||||||
foreach (i, ref c; source)
|
foreach (i, ref c; source)
|
||||||
{
|
{
|
||||||
@ -87,7 +86,7 @@ struct URL
|
|||||||
{
|
{
|
||||||
pos = i;
|
pos = i;
|
||||||
}
|
}
|
||||||
if (endPos == value.length && (c == '?' || c == '#'))
|
if (endPos == source.length && (c == '?' || c == '#'))
|
||||||
{
|
{
|
||||||
endPos = i;
|
endPos = i;
|
||||||
}
|
}
|
||||||
@ -95,7 +94,7 @@ struct URL
|
|||||||
|
|
||||||
// Check if the colon is a part of the scheme or the port and parse
|
// Check if the colon is a part of the scheme or the port and parse
|
||||||
// the appropriate part.
|
// the appropriate part.
|
||||||
if (value.length > 1 && value[0] == '/' && value[1] == '/')
|
if (source.length > 1 && source[0] == '/' && source[1] == '/')
|
||||||
{
|
{
|
||||||
// Relative scheme.
|
// Relative scheme.
|
||||||
start = 2;
|
start = 2;
|
||||||
@ -104,44 +103,37 @@ struct URL
|
|||||||
{
|
{
|
||||||
// Validate scheme:
|
// Validate scheme:
|
||||||
// [ toLower(alpha) | digit | "+" | "-" | "." ]
|
// [ toLower(alpha) | digit | "+" | "-" | "." ]
|
||||||
foreach (ref c; value[0 .. pos])
|
foreach (ref c; source[0 .. pos])
|
||||||
{
|
{
|
||||||
if (!c.isAlphaNum && c != '+' && c != '-' && c != '.')
|
if (!c.isAlphaNum && c != '+' && c != '-' && c != '.')
|
||||||
{
|
{
|
||||||
if (endPos > pos)
|
|
||||||
{
|
|
||||||
if (!parsePort(value[pos .. $]))
|
|
||||||
{
|
|
||||||
throw make!URIException(defaultAllocator,
|
|
||||||
"Failed to parse port");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto ParsePath;
|
goto ParsePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.length == pos + 1) // only "scheme:" is available.
|
if (source.length == pos + 1) // only "scheme:" is available.
|
||||||
{
|
{
|
||||||
this.scheme = value[0 .. $ - 1];
|
this.scheme = source[0 .. $ - 1];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (value.length > pos + 1 && value[pos + 1] == '/')
|
else if (source.length > pos + 1 && source[pos + 1] == '/')
|
||||||
{
|
{
|
||||||
this.scheme = value[0 .. pos];
|
this.scheme = source[0 .. pos];
|
||||||
|
|
||||||
if (value.length > pos + 2 && value[pos + 2] == '/')
|
if (source.length > pos + 2 && source[pos + 2] == '/')
|
||||||
{
|
{
|
||||||
start = pos + 3;
|
start = pos + 3;
|
||||||
|
|
||||||
if (value.length <= start)
|
if (source.length <= start)
|
||||||
{
|
{
|
||||||
// Only "scheme://" is available.
|
// Only "scheme://" is available.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.scheme == "file" && value[start] == '/')
|
if (this.scheme == "file" && source[start] == '/')
|
||||||
{
|
{
|
||||||
// Windows drive letters.
|
// Windows drive letters.
|
||||||
if (value.length - start > 2 && value[start + 2] == ':')
|
if (source.length - start > 2
|
||||||
|
&& source[start + 2] == ':')
|
||||||
{
|
{
|
||||||
++start;
|
++start;
|
||||||
}
|
}
|
||||||
@ -158,15 +150,15 @@ struct URL
|
|||||||
{
|
{
|
||||||
// Schemas like mailto: and zlib: may not have any slash after
|
// Schemas like mailto: and zlib: may not have any slash after
|
||||||
// them.
|
// them.
|
||||||
if (!parsePort(value[pos .. $]))
|
if (!parsePort(source[pos .. $]))
|
||||||
{
|
{
|
||||||
this.scheme = value[0 .. pos];
|
this.scheme = source[0 .. pos];
|
||||||
start = pos + 1;
|
start = pos + 1;
|
||||||
goto ParsePath;
|
goto ParsePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pos == 0 && parsePort(value[pos .. $]))
|
else if (pos == 0 && parsePort(source[pos .. $]))
|
||||||
{
|
{
|
||||||
// An URL shouldn't begin with a port number.
|
// An URL shouldn't begin with a port number.
|
||||||
throw defaultAllocator.make!URIException("URL begins with port");
|
throw defaultAllocator.make!URIException("URL begins with port");
|
||||||
@ -178,13 +170,13 @@ struct URL
|
|||||||
|
|
||||||
// Parse host.
|
// Parse host.
|
||||||
pos = -1;
|
pos = -1;
|
||||||
for (ptrdiff_t i = start; i < value.length; ++i)
|
for (ptrdiff_t i = start; i < source.length; ++i)
|
||||||
{
|
{
|
||||||
if (value[i] == '@')
|
if (source[i] == '@')
|
||||||
{
|
{
|
||||||
pos = i;
|
pos = i;
|
||||||
}
|
}
|
||||||
else if (value[i] == '/')
|
else if (source[i] == '/')
|
||||||
{
|
{
|
||||||
endPos = i;
|
endPos = i;
|
||||||
break;
|
break;
|
||||||
@ -195,14 +187,14 @@ struct URL
|
|||||||
if (pos != -1)
|
if (pos != -1)
|
||||||
{
|
{
|
||||||
// *( unreserved / pct-encoded / sub-delims / ":" )
|
// *( unreserved / pct-encoded / sub-delims / ":" )
|
||||||
foreach (i, c; value[start .. pos])
|
foreach (i, c; source[start .. pos])
|
||||||
{
|
{
|
||||||
if (c == ':')
|
if (c == ':')
|
||||||
{
|
{
|
||||||
if (this.user is null)
|
if (this.user is null)
|
||||||
{
|
{
|
||||||
this.user = value[start .. start + i];
|
this.user = source[start .. start + i];
|
||||||
this.pass = value[start + i + 1 .. pos];
|
this.pass = source[start + i + 1 .. pos];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!c.isAlpha &&
|
else if (!c.isAlpha &&
|
||||||
@ -221,23 +213,23 @@ struct URL
|
|||||||
}
|
}
|
||||||
if (this.user is null)
|
if (this.user is null)
|
||||||
{
|
{
|
||||||
this.user = value[start .. pos];
|
this.user = source[start .. pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
start = ++pos;
|
start = ++pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = endPos;
|
pos = endPos;
|
||||||
if (endPos <= 1 || value[start] != '[' || value[endPos - 1] != ']')
|
if (endPos <= 1 || source[start] != '[' || source[endPos - 1] != ']')
|
||||||
{
|
{
|
||||||
// Short circuit portscan.
|
// Short circuit portscan.
|
||||||
// IPv6 embedded address.
|
// IPv6 embedded address.
|
||||||
for (ptrdiff_t i = endPos - 1; i >= start; --i)
|
for (ptrdiff_t i = endPos - 1; i >= start; --i)
|
||||||
{
|
{
|
||||||
if (value[i] == ':')
|
if (source[i] == ':')
|
||||||
{
|
{
|
||||||
pos = i;
|
pos = i;
|
||||||
if (this.port == 0 && !parsePort(value[i .. endPos]))
|
if (this.port == 0 && !parsePort(source[i .. endPos]))
|
||||||
{
|
{
|
||||||
this.scheme = this.user = this.pass = null;
|
this.scheme = this.user = this.pass = null;
|
||||||
throw defaultAllocator.make!URIException("Invalid port");
|
throw defaultAllocator.make!URIException("Invalid port");
|
||||||
@ -254,9 +246,9 @@ struct URL
|
|||||||
throw defaultAllocator.make!URIException("Invalid host");
|
throw defaultAllocator.make!URIException("Invalid host");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.host = value[start .. pos];
|
this.host = source[start .. pos];
|
||||||
|
|
||||||
if (endPos == value.length)
|
if (endPos == source.length)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -264,9 +256,9 @@ struct URL
|
|||||||
start = endPos;
|
start = endPos;
|
||||||
|
|
||||||
ParsePath:
|
ParsePath:
|
||||||
endPos = value.length;
|
endPos = source.length;
|
||||||
pos = -1;
|
pos = -1;
|
||||||
foreach (i, ref c; value[start .. $])
|
foreach (i, ref c; source[start .. $])
|
||||||
{
|
{
|
||||||
if (c == '?' && pos == -1)
|
if (c == '?' && pos == -1)
|
||||||
{
|
{
|
||||||
@ -285,15 +277,15 @@ struct URL
|
|||||||
|
|
||||||
if (pos > start)
|
if (pos > start)
|
||||||
{
|
{
|
||||||
this.path = value[start .. pos];
|
this.path = source[start .. pos];
|
||||||
}
|
}
|
||||||
if (endPos >= ++pos)
|
if (endPos >= ++pos)
|
||||||
{
|
{
|
||||||
this.query = value[pos .. endPos];
|
this.query = source[pos .. endPos];
|
||||||
}
|
}
|
||||||
if (++endPos <= value.length)
|
if (++endPos <= source.length)
|
||||||
{
|
{
|
||||||
this.fragment = value[endPos .. $];
|
this.fragment = source[endPos .. $];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,13 +306,9 @@ struct URL
|
|||||||
|
|
||||||
for (; i < port.length && port[i].isDigit() && i <= 6; ++i)
|
for (; i < port.length && port[i].isDigit() && i <= 6; ++i)
|
||||||
{
|
{
|
||||||
lPort += (port[i] - '0') / cast(float)(10 ^^ (i - 1));
|
lPort += (port[i] - '0') / cast(float) (10 ^^ (i - 1));
|
||||||
}
|
}
|
||||||
if (i == 1 && (i == port.length || port[i] == '/'))
|
if (i != 1 && (i == port.length || port[i] == '/'))
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (i == port.length || port[i] == '/')
|
|
||||||
{
|
{
|
||||||
lPort *= 10 ^^ (i - 2);
|
lPort *= 10 ^^ (i - 2);
|
||||||
if (lPort > ushort.max)
|
if (lPort > ushort.max)
|
||||||
@ -402,6 +390,11 @@ private @nogc unittest
|
|||||||
assert(u.host == "127.0.0.1");
|
assert(u.host == "127.0.0.1");
|
||||||
assert(u.port == 9000);
|
assert(u.port == 9000);
|
||||||
|
|
||||||
|
u = URL("127.0.0.1:80");
|
||||||
|
assert(u.host == "127.0.0.1");
|
||||||
|
assert(u.port == 80);
|
||||||
|
assert(u.path is null);
|
||||||
|
|
||||||
u = URL("//example.net");
|
u = URL("//example.net");
|
||||||
assert(u.host == "example.net");
|
assert(u.host == "example.net");
|
||||||
assert(u.scheme is null);
|
assert(u.scheme is null);
|
||||||
@ -413,6 +406,7 @@ private @nogc unittest
|
|||||||
u = URL("localhost:8080");
|
u = URL("localhost:8080");
|
||||||
assert(u.host == "localhost");
|
assert(u.host == "localhost");
|
||||||
assert(u.port == 8080);
|
assert(u.port == 8080);
|
||||||
|
assert(u.path is null);
|
||||||
|
|
||||||
u = URL("ftp:");
|
u = URL("ftp:");
|
||||||
assert(u.scheme == "ftp");
|
assert(u.scheme == "ftp");
|
||||||
@ -446,21 +440,9 @@ private @nogc unittest
|
|||||||
u = URL("zlib:/home/user/file.gz");
|
u = URL("zlib:/home/user/file.gz");
|
||||||
assert(u.scheme == "zlib");
|
assert(u.scheme == "zlib");
|
||||||
assert(u.path == "/home/user/file.gz");
|
assert(u.path == "/home/user/file.gz");
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
u = URL("h_tp:asdf");
|
||||||
{
|
assert(u.path == "h_tp:asdf");
|
||||||
URIException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto u = URL("h_tp:asdf");
|
|
||||||
}
|
|
||||||
catch (URIException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @nogc unittest
|
private @nogc unittest
|
||||||
@ -528,7 +510,7 @@ private @nogc unittest
|
|||||||
URIException exception;
|
URIException exception;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto u = URL(":/");
|
auto u = URL("http://blah.com:66000");
|
||||||
}
|
}
|
||||||
catch (URIException e)
|
catch (URIException e)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user