aboutsummaryrefslogtreecommitdiff
path: root/normalize/normalize_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'normalize/normalize_test.go')
-rw-r--r--normalize/normalize_test.go782
1 files changed, 782 insertions, 0 deletions
diff --git a/normalize/normalize_test.go b/normalize/normalize_test.go
new file mode 100644
index 0000000..177ae01
--- /dev/null
+++ b/normalize/normalize_test.go
@@ -0,0 +1,782 @@
+package normalize
+
+import (
+ "fmt"
+ "net/url"
+ "testing"
+ "unicode"
+)
+
+type testCase struct {
+ nm string
+ src string
+ flgs NormalizationFlags
+ res string
+ parsed bool
+}
+
+var (
+ cases = [...]*testCase{
+ {
+ "LowerScheme",
+ "HTTP://www.SRC.ca",
+ FlagLowercaseScheme,
+ "http://www.SRC.ca",
+ false,
+ },
+ {
+ "LowerScheme2",
+ "http://www.SRC.ca",
+ FlagLowercaseScheme,
+ "http://www.SRC.ca",
+ false,
+ },
+ {
+ "LowerHost",
+ "HTTP://www.SRC.ca/",
+ FlagLowercaseHost,
+ "http://www.src.ca/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "UpperEscapes",
+ `http://www.whatever.com/Some%aa%20Special%8Ecases/`,
+ FlagUppercaseEscapes,
+ "http://www.whatever.com/Some%AA%20Special%8Ecases/",
+ false,
+ },
+ {
+ "UnnecessaryEscapes",
+ `http://www.toto.com/%41%42%2E%44/%32%33%52%2D/%5f%7E`,
+ FlagDecodeUnnecessaryEscapes,
+ "http://www.toto.com/AB.D/23R-/_~",
+ false,
+ },
+ {
+ "RemoveDefaultPort",
+ "HTTP://www.SRC.ca:80/",
+ FlagRemoveDefaultPort,
+ "http://www.SRC.ca/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "RemoveDefaultPort2",
+ "HTTP://www.SRC.ca:80",
+ FlagRemoveDefaultPort,
+ "http://www.SRC.ca", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "RemoveDefaultPort3",
+ "HTTP://www.SRC.ca:8080",
+ FlagRemoveDefaultPort,
+ "http://www.SRC.ca:8080", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "Safe",
+ "HTTP://www.SRC.ca:80/to%1ato%8b%ee/OKnow%41%42%43%7e",
+ FlagsSafe,
+ "http://www.src.ca/to%1Ato%8B%EE/OKnowABC~",
+ false,
+ },
+ {
+ "BothLower",
+ "HTTP://www.SRC.ca:80/to%1ato%8b%ee/OKnow%41%42%43%7e",
+ FlagLowercaseHost | FlagLowercaseScheme,
+ "http://www.src.ca:80/to%1Ato%8B%EE/OKnowABC~",
+ false,
+ },
+ {
+ "RemoveTrailingSlash",
+ "HTTP://www.SRC.ca:80/",
+ FlagRemoveTrailingSlash,
+ "http://www.SRC.ca:80", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "RemoveTrailingSlash2",
+ "HTTP://www.SRC.ca:80/toto/titi/",
+ FlagRemoveTrailingSlash,
+ "http://www.SRC.ca:80/toto/titi", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "RemoveTrailingSlash3",
+ "HTTP://www.SRC.ca:80/toto/titi/fin/?a=1",
+ FlagRemoveTrailingSlash,
+ "http://www.SRC.ca:80/toto/titi/fin?a=1", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "AddTrailingSlash",
+ "HTTP://www.SRC.ca:80",
+ FlagAddTrailingSlash,
+ "http://www.SRC.ca:80/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "AddTrailingSlash2",
+ "HTTP://www.SRC.ca:80/toto/titi.html",
+ FlagAddTrailingSlash,
+ "http://www.SRC.ca:80/toto/titi.html/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "AddTrailingSlash3",
+ "HTTP://www.SRC.ca:80/toto/titi/fin?a=1",
+ FlagAddTrailingSlash,
+ "http://www.SRC.ca:80/toto/titi/fin/?a=1", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "RemoveDotSegments",
+ "HTTP://root/a/b/./../../c/",
+ FlagRemoveDotSegments,
+ "http://root/c/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "RemoveDotSegments2",
+ "HTTP://root/../a/b/./../c/../d",
+ FlagRemoveDotSegments,
+ "http://root/a/d", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "UsuallySafe",
+ "HTTP://www.SRC.ca:80/to%1ato%8b%ee/./c/d/../OKnow%41%42%43%7e/?a=b#test",
+ FlagsUsuallySafeGreedy,
+ "http://www.src.ca/to%1Ato%8B%EE/c/OKnowABC~?a=b#test",
+ false,
+ },
+ {
+ "RemoveDirectoryIndex",
+ "HTTP://root/a/b/c/default.aspx",
+ FlagRemoveDirectoryIndex,
+ "http://root/a/b/c/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "RemoveDirectoryIndex2",
+ "HTTP://root/a/b/c/default#a=b",
+ FlagRemoveDirectoryIndex,
+ "http://root/a/b/c/default#a=b", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "RemoveFragment",
+ "HTTP://root/a/b/c/default#toto=tata",
+ FlagRemoveFragment,
+ "http://root/a/b/c/default", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ {
+ "ForceHTTP",
+ "https://root/a/b/c/default#toto=tata",
+ FlagForceHTTP,
+ "http://root/a/b/c/default#toto=tata",
+ false,
+ },
+ {
+ "RemoveDuplicateSlashes",
+ "https://root/a//b///c////default#toto=tata",
+ FlagRemoveDuplicateSlashes,
+ "https://root/a/b/c/default#toto=tata",
+ false,
+ },
+ {
+ "RemoveDuplicateSlashes2",
+ "https://root//a//b///c////default#toto=tata",
+ FlagRemoveDuplicateSlashes,
+ "https://root/a/b/c/default#toto=tata",
+ false,
+ },
+ {
+ "RemoveWWW",
+ "https://www.root/a/b/c/",
+ FlagRemoveWWW,
+ "https://root/a/b/c/",
+ false,
+ },
+ {
+ "RemoveWWW2",
+ "https://WwW.Root/a/b/c/",
+ FlagRemoveWWW,
+ "https://Root/a/b/c/",
+ false,
+ },
+ {
+ "AddWWW",
+ "https://Root/a/b/c/",
+ FlagAddWWW,
+ "https://www.Root/a/b/c/",
+ false,
+ },
+ {
+ "SortQuery",
+ "http://root/toto/?b=4&a=1&c=3&b=2&a=5",
+ FlagSortQuery,
+ "http://root/toto/?a=1&a=5&b=2&b=4&c=3",
+ false,
+ },
+ {
+ "RemoveEmptyQuerySeparator",
+ "http://root/toto/?",
+ FlagRemoveEmptyQuerySeparator,
+ "http://root/toto/",
+ false,
+ },
+ {
+ "Unsafe",
+ "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
+ FlagsUnsafeGreedy,
+ "http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3",
+ false,
+ },
+ {
+ "Safe2",
+ "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
+ FlagsSafe,
+ "https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
+ false,
+ },
+ {
+ "UsuallySafe2",
+ "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
+ FlagsUsuallySafeGreedy,
+ "https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid",
+ false,
+ },
+ {
+ "AddTrailingSlashBug",
+ "http://src.ca/",
+ FlagsAllNonGreedy,
+ "http://www.src.ca/",
+ false,
+ },
+ {
+ "SourceModified",
+ "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
+ FlagsUnsafeGreedy,
+ "http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3",
+ true,
+ },
+ {
+ "IPv6-1",
+ "http://[2001:db8:1f70::999:de8:7648:6e8]/test",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://[2001:db8:1f70::999:de8:7648:6e8]/test",
+ false,
+ },
+ {
+ "IPv6-2",
+ "http://[::ffff:192.168.1.1]/test",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://[::ffff:192.168.1.1]/test",
+ false,
+ },
+ {
+ "IPv6-3",
+ "http://[::ffff:192.168.1.1]:80/test",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://[::ffff:192.168.1.1]/test",
+ false,
+ },
+ {
+ "IPv6-4",
+ "htTps://[::fFff:192.168.1.1]:443/test",
+ FlagsSafe | FlagRemoveDotSegments,
+ "https://[::ffff:192.168.1.1]/test",
+ false,
+ },
+ {
+ "FTP",
+ "ftp://user:pass@ftp.foo.net/foo/bar",
+ FlagsSafe | FlagRemoveDotSegments,
+ "ftp://user:pass@ftp.foo.net/foo/bar",
+ false,
+ },
+ {
+ "Standard-1",
+ "http://www.foo.com:80/foo",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://www.foo.com/foo",
+ false,
+ },
+ {
+ "Standard-2",
+ "http://www.foo.com:8000/foo",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://www.foo.com:8000/foo",
+ false,
+ },
+ {
+ "Standard-3",
+ "http://www.foo.com/%7ebar",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://www.foo.com/~bar",
+ false,
+ },
+ {
+ "Standard-4",
+ "http://www.foo.com/%7Ebar",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://www.foo.com/~bar",
+ false,
+ },
+ {
+ "Standard-5",
+ "http://USER:pass@www.Example.COM/foo/bar",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://USER:pass@www.example.com/foo/bar",
+ false,
+ },
+ {
+ "Standard-6",
+ "http://test.example/?a=%26&b=1",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://test.example/?a=%26&b=1",
+ false,
+ },
+ {
+ "Standard-7",
+ "http://test.example/%25/?p=%20val%20%25",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://test.example/%25/?p=%20val%20%25",
+ false,
+ },
+ {
+ "Standard-8",
+ "http://test.example/path/with a%20space+/",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://test.example/path/with%20a%20space+/",
+ false,
+ },
+ {
+ "Standard-9",
+ "http://test.example/?",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://test.example/",
+ false,
+ },
+ {
+ "Standard-10",
+ "http://a.COM/path/?b&a",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://a.com/path/?b&a",
+ false,
+ },
+ {
+ "StandardCasesAddTrailingSlash",
+ "http://test.example?",
+ FlagsSafe | FlagAddTrailingSlash,
+ "http://test.example/",
+ false,
+ },
+ {
+ "OctalIP-1",
+ "http://0123.011.0.4/",
+ FlagsSafe | FlagDecodeOctalHost,
+ "http://0123.011.0.4/",
+ false,
+ },
+ {
+ "OctalIP-2",
+ "http://0102.0146.07.0223/",
+ FlagsSafe | FlagDecodeOctalHost,
+ "http://66.102.7.147/",
+ false,
+ },
+ {
+ "OctalIP-3",
+ "http://0102.0146.07.0223.:23/",
+ FlagsSafe | FlagDecodeOctalHost,
+ "http://66.102.7.147.:23/",
+ false,
+ },
+ {
+ "OctalIP-4",
+ "http://USER:pass@0102.0146.07.0223../",
+ FlagsSafe | FlagDecodeOctalHost,
+ "http://USER:pass@66.102.7.147../",
+ false,
+ },
+ {
+ "DWORDIP-1",
+ "http://123.1113982867/",
+ FlagsSafe | FlagDecodeDWORDHost,
+ "http://123.1113982867/",
+ false,
+ },
+ {
+ "DWORDIP-2",
+ "http://1113982867/",
+ FlagsSafe | FlagDecodeDWORDHost,
+ "http://66.102.7.147/",
+ false,
+ },
+ {
+ "DWORDIP-3",
+ "http://1113982867.:23/",
+ FlagsSafe | FlagDecodeDWORDHost,
+ "http://66.102.7.147.:23/",
+ false,
+ },
+ {
+ "DWORDIP-4",
+ "http://USER:pass@1113982867../",
+ FlagsSafe | FlagDecodeDWORDHost,
+ "http://USER:pass@66.102.7.147../",
+ false,
+ },
+ {
+ "HexIP-1",
+ "http://0x123.1113982867/",
+ FlagsSafe | FlagDecodeHexHost,
+ "http://0x123.1113982867/",
+ false,
+ },
+ {
+ "HexIP-2",
+ "http://0x42660793/",
+ FlagsSafe | FlagDecodeHexHost,
+ "http://66.102.7.147/",
+ false,
+ },
+ {
+ "HexIP-3",
+ "http://0x42660793.:23/",
+ FlagsSafe | FlagDecodeHexHost,
+ "http://66.102.7.147.:23/",
+ false,
+ },
+ {
+ "HexIP-4",
+ "http://USER:pass@0x42660793../",
+ FlagsSafe | FlagDecodeHexHost,
+ "http://USER:pass@66.102.7.147../",
+ false,
+ },
+ {
+ "UnnecessaryHostDots-1",
+ "http://.www.foo.com../foo/bar.html",
+ FlagsSafe | FlagRemoveUnnecessaryHostDots,
+ "http://www.foo.com/foo/bar.html",
+ false,
+ },
+ {
+ "UnnecessaryHostDots-2",
+ "http://www.foo.com./foo/bar.html",
+ FlagsSafe | FlagRemoveUnnecessaryHostDots,
+ "http://www.foo.com/foo/bar.html",
+ false,
+ },
+ {
+ "UnnecessaryHostDots-3",
+ "http://www.foo.com.:81/foo",
+ FlagsSafe | FlagRemoveUnnecessaryHostDots,
+ "http://www.foo.com:81/foo",
+ false,
+ },
+ {
+ "UnnecessaryHostDots-4",
+ "http://www.example.com./",
+ FlagsSafe | FlagRemoveUnnecessaryHostDots,
+ "http://www.example.com/",
+ false,
+ },
+ {
+ "EmptyPort-1",
+ "http://www.thedraymin.co.uk:/main/?p=308",
+ FlagsSafe | FlagRemoveEmptyPortSeparator,
+ "http://www.thedraymin.co.uk/main/?p=308",
+ false,
+ },
+ {
+ "EmptyPort-2",
+ "http://www.src.ca:",
+ FlagsSafe | FlagRemoveEmptyPortSeparator,
+ "http://www.src.ca",
+ false,
+ },
+ {
+ "Slashes-1",
+ "http://test.example/foo/bar/.",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/bar/",
+ false,
+ },
+ {
+ "Slashes-2",
+ "http://test.example/foo/bar/./",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/bar/",
+ false,
+ },
+ {
+ "Slashes-3",
+ "http://test.example/foo/bar/..",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/",
+ false,
+ },
+ {
+ "Slashes-4",
+ "http://test.example/foo/bar/../",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/",
+ false,
+ },
+ {
+ "Slashes-5",
+ "http://test.example/foo/bar/../baz",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/baz",
+ false,
+ },
+ {
+ "Slashes-6",
+ "http://test.example/foo/bar/../..",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/",
+ false,
+ },
+ {
+ "Slashes-7",
+ "http://test.example/foo/bar/../../",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/",
+ false,
+ },
+ {
+ "Slashes-8",
+ "http://test.example/foo/bar/../../baz",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/baz",
+ false,
+ },
+ {
+ "Slashes-9",
+ "http://test.example/foo/bar/../../../baz",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/baz",
+ false,
+ },
+ {
+ "Slashes-10",
+ "http://test.example/foo/bar/../../../../baz",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/baz",
+ false,
+ },
+ {
+ "Slashes-11",
+ "http://test.example/./foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo",
+ false,
+ },
+ {
+ "Slashes-12",
+ "http://test.example/../foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo",
+ false,
+ },
+ {
+ "Slashes-13",
+ "http://test.example/foo.",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo.",
+ false,
+ },
+ {
+ "Slashes-14",
+ "http://test.example/.foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/.foo",
+ false,
+ },
+ {
+ "Slashes-15",
+ "http://test.example/foo..",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo..",
+ false,
+ },
+ {
+ "Slashes-16",
+ "http://test.example/..foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/..foo",
+ false,
+ },
+ {
+ "Slashes-17",
+ "http://test.example/./../foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo",
+ false,
+ },
+ {
+ "Slashes-18",
+ "http://test.example/./foo/.",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/",
+ false,
+ },
+ {
+ "Slashes-19",
+ "http://test.example/foo/./bar",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/bar",
+ false,
+ },
+ {
+ "Slashes-20",
+ "http://test.example/foo/../bar",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/bar",
+ false,
+ },
+ {
+ "Slashes-21",
+ "http://test.example/foo//",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/",
+ false,
+ },
+ {
+ "Slashes-22",
+ "http://test.example/foo///bar//",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/bar/",
+ false,
+ },
+ {
+ "Relative",
+ "foo/bar",
+ FlagsAllGreedy,
+ "foo/bar",
+ false,
+ },
+ {
+ "Relative-1",
+ "./../foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "foo",
+ false,
+ },
+ {
+ "Relative-2",
+ "./foo/bar/../baz/../bang/..",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "foo/",
+ false,
+ },
+ {
+ "Relative-3",
+ "foo///bar//",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "foo/bar/",
+ false,
+ },
+ {
+ "Relative-4",
+ "www.youtube.com",
+ FlagsUsuallySafeGreedy,
+ "www.youtube.com",
+ false,
+ },
+ {
+ "Issue-#24",
+ "///foo///bar///",
+ FlagRemoveDuplicateSlashes | FlagRemoveTrailingSlash,
+ "/foo/bar",
+ false,
+ },
+ /*&testCase{
+ "UrlNorm-5",
+ "http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://ja.wikipedia.org/wiki/\xe3\x82\xad\xe3\x83\xa3\xe3\x82\xbf\xe3\x83\x94\xe3\x83\xa9\xe3\x83\xbc\xe3\x82\xb8\xe3\x83\xa3\xe3\x83\x91\xe3\x83\xb3",
+ false,
+ },
+ &testCase{
+ "UrlNorm-1",
+ "http://test.example/?a=%e3%82%82%26",
+ FlagsAllGreedy,
+ "http://test.example/?a=\xe3\x82\x82%26",
+ false,
+ },*/
+ }
+)
+
+func TestRunner(t *testing.T) {
+ for _, tc := range cases {
+ runCase(tc, t)
+ }
+}
+
+func runCase(tc *testCase, t *testing.T) {
+ t.Logf("running %s...", tc.nm)
+ if tc.parsed {
+ u, e := url.Parse(tc.src)
+ if e != nil {
+ t.Errorf("%s - FAIL : %s", tc.nm, e)
+ return
+ } else {
+ NormalizeURL(u, tc.flgs)
+ if s := u.String(); s != tc.res {
+ t.Errorf("%s - FAIL expected '%s', got '%s'", tc.nm, tc.res, s)
+ }
+ }
+ } else {
+ if s, e := NormalizeURLString(tc.src, tc.flgs); e != nil {
+ t.Errorf("%s - FAIL : %s", tc.nm, e)
+ } else if s != tc.res {
+ t.Errorf("%s - FAIL expected '%s', got '%s'", tc.nm, tc.res, s)
+ }
+ }
+}
+
+func TestDecodeUnnecessaryEscapesAll(t *testing.T) {
+ var url = "http://host/"
+
+ for i := 0; i < 256; i++ {
+ url += fmt.Sprintf("%%%02x", i)
+ }
+ s, err := NormalizeURLString(url, FlagDecodeUnnecessaryEscapes)
+ if err != nil {
+ t.Fatalf("parse error: %s", err)
+ }
+
+ const want = "http://host/%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20!%22%23$%25&'()*+,-./0123456789:;%3C=%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ[%5C]%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF"
+ if s != want {
+ t.Errorf("DecodeUnnecessaryEscapesAll:\nwant\n%s\ngot\n%s", want, s)
+ }
+}
+
+func TestEncodeNecessaryEscapesAll(t *testing.T) {
+ const base = "http://host/"
+ var path []byte
+
+ for i := 0; i < 256; i++ {
+ // Since go1.12, url.Parse fails if the raw URL contains ASCII control characters,
+ // meaning anything < 0x20 and 0x7f (DEL), so do not add those bytes to the constructed url.
+ // See https://github.com/PuerkitoBio/purell/issues/28
+ if i != 0x25 && !unicode.IsControl(rune(i)) {
+ path = append(path, byte(i))
+ }
+ }
+ s, err := NormalizeURLString(base+string(path), FlagEncodeNecessaryEscapes)
+ if err != nil {
+ t.Fatalf("parse error: %s", err)
+ }
+
+ const want = "http://host/%20!%22#$&'()*+,-./0123456789:;%3C=%3E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[%5C]%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF"
+ if s != want {
+ t.Errorf("EncodeNecessaryEscapesAll:\nwant\n%s\ngot\n%s", want, s)
+ }
+}