commit be5e0d5a705ef7314dadc4795d3ec5f0be443c5f
parent 6b5547375f16bd66b522ee53762b3e61a5393bd3
Author: Alexey Yerin <yyp@disroot.org>
Date: Wed, 22 Feb 2023 15:36:08 +0300
net::uri: disallow non-IPv6 addresses inside [ ... ]
Signed-off-by: Alexey Yerin <yyp@disroot.org>
Diffstat:
2 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/net/uri/+test.ha b/net/uri/+test.ha
@@ -99,6 +99,10 @@ use net::ip;
// Unexpected character
assert(parse("https://^harelang.org") is invalid);
+
+ // Something other than IPv6 address inside [ ... ]
+ assert(parse("https://[1.2.3.4]") is invalid);
+ assert(parse("https://[example]") is invalid);
};
@test fn percent_encoding() void = {
diff --git a/net/uri/parse.ha b/net/uri/parse.ha
@@ -21,7 +21,7 @@ export fn parse(in: str) (uri | invalid) = {
// Determine hier-part variant
let path = "";
- let authority = ("", 0u16, "");
+ let authority: ((str | ip::addr6), u16, str) = ("", 0u16, "");
match (strings::next(&in)) {
case let r: rune =>
switch (r) {
@@ -85,11 +85,16 @@ export fn parse(in: str) (uri | invalid) = {
return uri {
scheme = scheme,
- host = match (ip::parse(authority.0)) {
- case let a: ip::addr =>
- yield a;
- case ip::invalid =>
- yield authority.0;
+ host = match (authority.0) {
+ case let ip: ip::addr6 =>
+ yield ip;
+ case let s: str =>
+ yield match (ip::parse(s)) {
+ case let a: ip::addr =>
+ yield a;
+ case ip::invalid =>
+ yield s;
+ };
},
port = authority.1,
userinfo = authority.2,
@@ -123,11 +128,13 @@ fn parse_scheme(in: *strings::iterator) (str | invalid) = {
return strio::string(&buf);
};
-fn parse_authority(in: *strings::iterator) ((str, u16, str) | invalid) = {
+fn parse_authority(
+ in: *strings::iterator,
+) (((str | ip::addr6), u16, str) | invalid) = {
// Scan everything until '@' or ':' or '/', then decide what it is
let buf = strio::dynamic();
defer io::close(&buf)!;
- let host = "";
+ let host: (str | ip::addr6) = "";
let port = 0u16;
let userinfo = "";
@@ -158,7 +165,13 @@ fn parse_authority(in: *strings::iterator) ((str, u16, str) | invalid) = {
strio::appendrune(&buf, r)!;
};
- host = percent_decode(strio::string(&buf))?;
+ const addr = percent_decode(strio::string(&buf))?;
+ match (ip::parse(addr)) {
+ case let v6: ip::addr6 =>
+ host = v6;
+ case =>
+ return invalid;
+ };
} else if (r == ':' || !is_userinfo(r) && !is_host(r)) {
if (len(userinfo) > 0 && is_userinfo(r)) {
return invalid;
@@ -186,9 +199,13 @@ fn parse_authority(in: *strings::iterator) ((str, u16, str) | invalid) = {
};
};
- // In end of string case
- if (len(host) == 0) {
- host = percent_decode(strio::string(&buf))?;
+ match (host) {
+ case let s: str =>
+ // In end of string case
+ if (len(s) == 0) {
+ host = percent_decode(strio::string(&buf))?;
+ };
+ case => yield;
};
return (host, port, userinfo);