commit 40f16febd26f41ab6978625f273349d2ea3a0306
parent c9fb75f584944c9e4a258fa1c2cffe2f3991681d
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sat, 22 Jul 2023 06:37:39 +0200
net/uri: Always prefix path with a slash when there's a host
Diffstat:
2 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/net/uri/+test.ha b/net/uri/+test.ha
@@ -91,6 +91,21 @@ use net::ip;
)!;
};
+@test fn edge_cases() void = {
+ const expected = "https://en.wiktionary.org/wiki/%E3%81%8A%E3%81%AF%E3%82%88%E3%81%86#Japanese";
+ const u = uri {
+ scheme = "https",
+ host = "en.wiktionary.org",
+ path = "wiki/おはよう",
+ fragment = "Japanese",
+ ...
+ };
+ let s = string(&u);
+ defer free(s);
+
+ assert_str(s, expected);
+};
+
@test fn invalid() void = {
// Scheme
assert(parse(":") is invalid);
diff --git a/net/uri/fmt.ha b/net/uri/fmt.ha
@@ -27,6 +27,7 @@ def unres_path: str = "-._~!$&'()*+,;=:@/";
export fn fmt(out: io::handle, u: *const uri) (size | io::error) = {
let n = 0z;
let slashes_w = false;
+ let has_host = false;
if (u.scheme != "") {
n += fmt::fprintf(out, "{}:", u.scheme)?;
};
@@ -39,6 +40,7 @@ export fn fmt(out: io::handle, u: *const uri) (size | io::error) = {
case let host: str =>
// file scheme is allowed an empty host
if (len(host) > 0 || u.scheme == "file") {
+ has_host = true;
if (!slashes_w) {
n += fmt::fprint(out, "//")?;
};
@@ -50,6 +52,7 @@ export fn fmt(out: io::handle, u: *const uri) (size | io::error) = {
n += percent_encode(out, host, unres)?;
};
case let addr: ip::addr =>
+ has_host = true;
if (!slashes_w) {
n += fmt::fprint(out, "//")?;
};
@@ -58,6 +61,9 @@ export fn fmt(out: io::handle, u: *const uri) (size | io::error) = {
if (u.port != 0) {
n += fmt::fprintf(out, ":{}", u.port)?;
};
+ if (has_host && len(u.path) > 0 && !strings::hasprefix(u.path, '/')) {
+ n += fmt::fprint(out, "/")?;
+ };
n += percent_encode(out, u.path, unres_path)?;
if (len(u.query) > 0) {
// Always percent-encoded, see parse and encodequery/decodequery