From c66c57f70f745780e9e70fec8de2400145ffeb6d Mon Sep 17 00:00:00 2001 From: Gareth Pendleton Date: Tue, 9 Sep 2025 12:17:54 +0100 Subject: [PATCH] feat: Added IPvFuture parsing --- src/uri/internal/parser.gleam | 37 ++++++++++++++++++++++++++++++++--- src/uri/internal/utils.gleam | 3 +-- test/uri_test.gleam | 24 +++++++++++------------ 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/uri/internal/parser.gleam b/src/uri/internal/parser.gleam index f39dc27..51e8144 100644 --- a/src/uri/internal/parser.gleam +++ b/src/uri/internal/parser.gleam @@ -165,7 +165,7 @@ fn parse_empty(str: String) -> Result(#(Uri, String), Nil) { fn parse_authority(str: String) -> Result(#(Uri, String), Nil) { case str { "//" <> rest -> { - parse_authority_part(rest) |> echo + parse_authority_part(rest) } _ -> Error(Nil) } @@ -363,7 +363,38 @@ fn parse_h16_colon(str: String) { } fn parse_ipfuture(str: String) { - Error(Nil) + case str { + "v" <> rest -> { + use #(v, rest) <- result.try(get_multiple(utils.parse_hex_digit, rest)) + + case rest { + "." <> rest -> { + use #(i, rest) <- result.try(get_multiple( + fn(str) { + list.fold_until( + [ + parse_unreserved, + parse_sub_delim, + fn(str: String) { + case str { + ":" as l <> rest -> Ok(#(l, rest)) + _ -> Error(Nil) + } + }, + ], + Error(Nil), + get_parser_fn(str), + ) + }, + rest, + )) + Ok(#("v" <> v <> "." <> i, rest)) + } + _ -> Error(Nil) + } + } + _ -> Error(Nil) + } } fn get_multiple( @@ -491,7 +522,7 @@ fn do_parse_pchar_nc(str: String) { fn parse_reg_name(str: String) { // can't error - case do_parse_reg_name(str, "") |> echo { + case do_parse_reg_name(str, "") { Error(Nil) -> Ok(#("", str)) Ok(#(reg_name, rest)) -> Ok(#(reg_name, rest)) } diff --git a/src/uri/internal/utils.gleam b/src/uri/internal/utils.gleam index 3ebf15d..2c7b394 100644 --- a/src/uri/internal/utils.gleam +++ b/src/uri/internal/utils.gleam @@ -153,7 +153,7 @@ fn do_remove_dot_segments(path: String, acc: String) -> String { } fn remove_segment(path: String) -> String { - path |> echo |> string.reverse |> do_remove_segment |> string.reverse + path |> string.reverse |> do_remove_segment |> string.reverse } fn do_remove_segment(path: String) -> String { @@ -295,7 +295,6 @@ fn do_percent_decode( _ -> { case int.bitwise_and(char, 224) { 192 -> { - "2bytes" |> echo use #(char, rest) <- result.try(decode_2byte_utf(hd1 <> hd2, rest)) do_percent_decode(splitter, rest, acc <> before <> char) diff --git a/test/uri_test.gleam b/test/uri_test.gleam index 38d85f1..612182a 100644 --- a/test/uri_test.gleam +++ b/test/uri_test.gleam @@ -234,6 +234,15 @@ pub fn parse_host_tests() { uri.parse("//[2001:0db8:0000:0000:0000:0000:1428:G7ab]") |> should.be_error }), + it("ipvFuture parse", fn() { + uri.parse("//[v9.abc:def]") + |> should.equal(Ok(Uri(..types.empty_uri, host: Some("v9.abc:def")))) + uri.parse("//[v9b.abc:def]") + |> should.equal(Ok(Uri(..types.empty_uri, host: Some("v9b.abc:def")))) + + uri.parse("//[vz.abc:def]") |> should.be_error + uri.parse("//[va1.abc:d@ef]") |> should.be_error + }), ]) } @@ -840,31 +849,26 @@ pub fn merge_tests() { let uri1 = uri.parse("http://google.com/weebl/eh") |> should.be_ok let uri2 = uri.parse("baz") |> should.be_ok uri.merge(uri1, uri2) - |> echo |> should.equal(uri.parse("http://google.com/weebl/baz")) let uri1 = uri.parse("http://google.com/weebl/") |> should.be_ok let uri2 = uri.parse("baz") |> should.be_ok uri.merge(uri1, uri2) - |> echo |> should.equal(uri.parse("http://google.com/weebl/baz")) let uri1 = uri.parse("http://google.com") |> should.be_ok let uri2 = uri.parse("baz") |> should.be_ok uri.merge(uri1, uri2) - |> echo |> should.equal(uri.parse("http://google.com/baz")) }), it("base with relative segments merge", fn() { let uri1 = uri.parse("http://google.com") |> should.be_ok let uri2 = uri.parse("/.././bob/../../../baz") |> should.be_ok uri.merge(uri1, uri2) - |> echo |> should.equal(uri.parse("http://google.com/baz")) }), it("base with empty uri merge", fn() { let uri1 = uri.parse("http://google.com/weebl/bob") |> should.be_ok let uri2 = uri.parse("") |> should.be_ok uri.merge(uri1, uri2) - |> echo |> should.equal(uri.parse("http://google.com/weebl/bob")) }), @@ -872,24 +876,20 @@ pub fn merge_tests() { let uri1 = uri.parse("http://google.com/weebl/bob") |> should.be_ok let uri2 = uri.parse("#fragment") |> should.be_ok uri.merge(uri1, uri2) - |> echo |> should.equal(uri.parse("http://google.com/weebl/bob#fragment")) }), it("base with query merge", fn() { let uri1 = uri.parse("http://google.com/weebl/bob") |> should.be_ok let uri2 = uri.parse("?query") |> should.be_ok uri.merge(uri1, uri2) - |> echo |> should.equal(uri.parse("http://google.com/weebl/bob?query")) let uri1 = uri.parse("http://google.com/weebl/bob?query1") |> should.be_ok let uri2 = uri.parse("?query2") |> should.be_ok uri.merge(uri1, uri2) - |> echo |> should.equal(uri.parse("http://google.com/weebl/bob?query2")) let uri1 = uri.parse("http://google.com/weebl/bob?query1") |> should.be_ok let uri2 = uri.parse("") |> should.be_ok uri.merge(uri1, uri2) - |> echo |> should.equal(uri.parse("http://google.com/weebl/bob?query1")) }), ]) @@ -1185,19 +1185,17 @@ pub fn equivalence_tests() { uri.are_equivalent(uri1, uri2) |> should.be_true let uri1 = uri.parse("http://example.com") |> should.be_ok - let uri2 = uri.parse("HTTP://EX%41MPLE.COM") |> should.be_ok |> echo + let uri2 = uri.parse("HTTP://EX%41MPLE.COM") |> should.be_ok uri.are_equivalent(uri1, uri2) |> should.be_true let uri1 = uri.parse("http://example.com/a/b/c") |> should.be_ok - let uri2 = - uri.parse("HTTP://EXaMPLE.COM/a/d/../b/e/../c") |> should.be_ok |> echo + let uri2 = uri.parse("HTTP://EXaMPLE.COM/a/d/../b/e/../c") |> should.be_ok uri.are_equivalent(uri1, uri2) |> should.be_true let uri1 = uri.parse("http://example.com/a/b/c") |> should.be_ok let uri2 = uri.parse("HTTP://EXaMPLE.COM/a/../../../../a/b/e/../c") |> should.be_ok - |> echo uri.are_equivalent(uri1, uri2) |> should.be_true }), ])