Added support for URL fragments

Added support for a URL's fragment/anchor to `split_url` & `join_url` in `core:net` plus 4 new tests to cover it.
This commit is contained in:
blob1807
2024-04-13 00:39:32 +10:00
parent 4240e0025e
commit c753711d86
2 changed files with 80 additions and 23 deletions

View File

@@ -21,7 +21,7 @@ import "core:strconv"
import "core:unicode/utf8"
import "core:encoding/hex"
split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string) {
split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string, fragment: string) {
s := url
i := strings.index(s, "://")
@@ -30,6 +30,12 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host,
s = s[i+3:]
}
i = strings.index_byte(s, '#')
if i != -1 {
fragment = s[i+1:]
s = s[:i]
}
i = strings.index(s, "?")
if i != -1 {
query_str := s[i+1:]
@@ -62,7 +68,7 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host,
return
}
join_url :: proc(scheme, host, path: string, queries: map[string]string, allocator := context.allocator) -> string {
join_url :: proc(scheme, host, path: string, queries: map[string]string, fragment: string, allocator := context.allocator) -> string {
b := strings.builder_make(allocator)
strings.builder_grow(&b, len(scheme) + 3 + len(host) + 1 + len(path))
@@ -95,6 +101,13 @@ join_url :: proc(scheme, host, path: string, queries: map[string]string, allocat
i += 1
}
if fragment != "" {
if fragment[0] != '#' {
strings.write_byte(&b, '#')
}
strings.write_string(&b, strings.trim_space(fragment))
}
return strings.to_string(b)
}

View File

@@ -473,6 +473,7 @@ client_sends_server_data :: proc(t: ^testing.T) {
URL_Test :: struct {
scheme, host, path: string,
queries: map[string]string,
fragment: string,
url: []string,
}
@@ -481,58 +482,78 @@ split_url_test :: proc(t: ^testing.T) {
test_cases := []URL_Test{
{
"http", "example.com", "/",
{},
{}, "",
{"http://example.com"},
},
{
"https", "odin-lang.org", "/",
{},
{}, "",
{"https://odin-lang.org"},
},
{
"https", "odin-lang.org", "/docs/",
{},
{}, "",
{"https://odin-lang.org/docs/"},
},
{
"https", "odin-lang.org", "/docs/overview",
{},
{}, "",
{"https://odin-lang.org/docs/overview"},
},
{
"http", "example.com", "/",
{"a" = "b"},
{"a" = "b"}, "",
{"http://example.com?a=b"},
},
{
"http", "example.com", "/",
{"a" = ""},
{"a" = ""}, "",
{"http://example.com?a"},
},
{
"http", "example.com", "/",
{"a" = "b", "c" = "d"},
{"a" = "b", "c" = "d"}, "",
{"http://example.com?a=b&c=d"},
},
{
"http", "example.com", "/",
{"a" = "", "c" = "d"},
{"a" = "", "c" = "d"}, "",
{"http://example.com?a&c=d"},
},
{
"http", "example.com", "/example",
{"a" = "", "b" = ""},
{"a" = "", "b" = ""}, "",
{"http://example.com/example?a&b"},
},
{
"https", "example.com", "/callback",
{"redirect" = "https://other.com/login"},
{"redirect" = "https://other.com/login"}, "",
{"https://example.com/callback?redirect=https://other.com/login"},
},
{
"http", "odin-lang.org", "/",
{}, "Hellope",
{"http://odin-lang.org#Hellope"}
},
{
"https", "odin-lang.org", "/",
{"a" = ""}, "Hellope",
{"https://odin-lang.org?a#Hellope"}
},
{
"http", "example.com", "/",
{"a" = "b"}, "Hellope",
{"http://example.com?a=b#Hellope"}
},
{
"https", "example.com", "/example",
{}, "Hellope",
{"https://example.com/example#Hellope"}
},
}
for test in test_cases {
scheme, host, path, queries := net.split_url(test.url[0])
scheme, host, path, queries, fragment := net.split_url(test.url[0])
defer {
delete(queries)
delete(test.queries)
@@ -551,6 +572,9 @@ split_url_test :: proc(t: ^testing.T) {
msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", expected, v)
expect(t, v == expected, msg)
}
msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.fragment, fragment)
expect(t, fragment == test.fragment, msg)
}
}
@@ -560,53 +584,73 @@ join_url_test :: proc(t: ^testing.T) {
test_cases := []URL_Test{
{
"http", "example.com", "/",
{},
{}, "",
{"http://example.com/"},
},
{
"https", "odin-lang.org", "/",
{},
{}, "",
{"https://odin-lang.org/"},
},
{
"https", "odin-lang.org", "/docs/",
{},
{}, "",
{"https://odin-lang.org/docs/"},
},
{
"https", "odin-lang.org", "/docs/overview",
{},
{}, "",
{"https://odin-lang.org/docs/overview"},
},
{
"http", "example.com", "/",
{"a" = "b"},
{"a" = "b"}, "",
{"http://example.com/?a=b"},
},
{
"http", "example.com", "/",
{"a" = ""},
{"a" = ""}, "",
{"http://example.com/?a"},
},
{
"http", "example.com", "/",
{"a" = "b", "c" = "d"},
{"a" = "b", "c" = "d"}, "",
{"http://example.com/?a=b&c=d", "http://example.com/?c=d&a=b"},
},
{
"http", "example.com", "/",
{"a" = "", "c" = "d"},
{"a" = "", "c" = "d"}, "",
{"http://example.com/?a&c=d", "http://example.com/?c=d&a"},
},
{
"http", "example.com", "/example",
{"a" = "", "b" = ""},
{"a" = "", "b" = ""}, "",
{"http://example.com/example?a&b", "http://example.com/example?b&a"},
},
{
"http", "odin-lang.org", "",
{}, "Hellope",
{"http://odin-lang.org#Hellope"}
},
{
"https", "odin-lang.org", "",
{"a" = ""}, "Hellope",
{"https://odin-lang.org?a#Hellope"}
},
{
"http", "example.com", "",
{"a" = "b"}, "Hellope",
{"http://example.com?a=b#Hellope"}
},
{
"https", "example.com", "/example",
{}, "Hellope",
{"https://example.com/example#Hellope"}
},
}
for test in test_cases {
url := net.join_url(test.scheme, test.host, test.path, test.queries)
url := net.join_url(test.scheme, test.host, test.path, test.queries, test.fragment)
defer {
delete(url)
delete(test.queries)