8 "golang.org/x/net/idna"
11 func TestDomainPrefixBasic(t
*testing
.T
) {
12 // Tests expecting no error.
13 for _
, test
:= range []struct {
14 domain
, expected
string
20 // Should not apply mappings such as case folding and
22 {"b\u00fccher.de", "xn--bcher-de-65a"},
23 {"B\u00fccher.de", "xn--Bcher-de-65a"},
24 {"bu\u0308cher.de", "xn--bucher-de-hkf"},
26 // Check some that differ between IDNA 2003 and IDNA 2008.
27 // https://unicode.org/reports/tr46/#Deviations
28 // https://util.unicode.org/UnicodeJsps/idna.jsp
29 {"faß.de", "xn--fa-de-mqa"},
30 {"βόλοσ.com", "xn---com-4ld8c2a6a8e"},
32 // Lengths of 63 and 64. 64 is too long for a DNS label, but
33 // domainPrefixBasic is not expected to check for that.
34 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
35 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
37 // https://amp.dev/documentation/guides-and-tutorials/learn/amp-caches-and-cors/amp-cache-urls/#basic-algorithm
38 {"example.com", "example-com"},
39 {"foo.example.com", "foo-example-com"},
40 {"foo-example.com", "foo--example-com"},
41 {"xn--57hw060o.com", "xn---com-p33b41770a"},
42 {"\u26a1\U0001f60a.com", "xn---com-p33b41770a"},
43 {"en-us.example.com", "0-en--us-example-com-0"},
45 output
, err
:= domainPrefixBasic(test
.domain
)
46 if err
!= nil || output
!= test
.expected
{
47 t
.Errorf("%+q → (%+q, %v), expected (%+q, %v)",
48 test
.domain
, output
, err
, test
.expected
, nil)
52 // Tests expecting an error.
53 for _
, domain
:= range []string{
56 output
, err
:= domainPrefixBasic(domain
)
57 if err
== nil || output
!= "" {
58 t
.Errorf("%+q → (%+q, %v), expected (%+q, non-nil)",
59 domain
, output
, err
, "")
64 func TestDomainPrefixFallback(t
*testing
.T
) {
65 for _
, test
:= range []struct {
66 domain
, expected
string
70 "4oymiquy7qobjgx36tejs35zeqt24qpemsnzgtfeswmrw6csxbkq",
74 "un42n5xov642kxrxrqiyanhcoupgql5lt4wtbkyt2ijflbwodfdq",
77 // These checked against the output of
78 // https://github.com/ampproject/amp-toolbox/tree/84cb3057e5f6c54d64369ddd285db1cb36237ee8/packages/cache-url,
79 // using the widget at
80 // https://amp.dev/documentation/guides-and-tutorials/learn/amp-caches-and-cors/amp-cache-urls/#url-format.
82 "000000000000000000000000000000000000000000000000000000000000.com",
83 "stejanx4hsijaoj4secyecy4nvqodk56kw72whwcmvdbtucibf5a",
86 "00000000000000000000000000000000000000000000000000000000000a.com",
87 "jdcvbsorpnc3hcjrhst56nfm6ymdpovlawdbm2efyxpvlt4cpbya",
90 "00000000000000000000000000000000000000000000000000000000000\u03bb.com",
91 "qhzqeumjkfpcpuic3vqruyjswcr7y7gcm3crqyhhywvn3xrhchfa",
94 output
:= domainPrefixFallback(test
.domain
)
95 if output
!= test
.expected
{
96 t
.Errorf("%+q → %+q, expected %+q",
97 test
.domain
, output
, test
.expected
)
102 // Checks that domainPrefix chooses domainPrefixBasic or domainPrefixFallback as
103 // appropriate; i.e., always returns string that is a valid DNS label and is
105 func TestDomainPrefix(t
*testing
.T
) {
106 // A validating IDNA profile, which checks label length and that the
107 // label contains only certain ASCII characters. It does not do the
108 // ValidateLabels check, because that depends on the input having
109 // certain properties.
111 idna
.VerifyDNSLength(true),
112 idna
.StrictDomainName(true),
114 for _
, domain
:= range []string{
117 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // 63 bytes
118 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // 64 bytes
122 output
:= domainPrefix(domain
)
123 if bytes
.IndexByte([]byte(output
), '.') != -1 {
124 t
.Errorf("%+q → %+q contains a dot", domain
, output
)
126 _
, err
:= profile
.ToUnicode(output
)
128 t
.Errorf("%+q → error %v", domain
, err
)
133 func mustParseURL(rawurl
string) *url
.URL
{
134 u
, err
:= url
.Parse(rawurl
)
141 func TestCacheURL(t
*testing
.T
) {
142 // Tests expecting no error.
143 for _
, test
:= range []struct {
149 // With or without trailing slash on pubURL.
151 "http://example.com/",
152 "https://amp.cache/",
154 "https://example-com.amp.cache/c/example.com",
157 "http://example.com",
158 "https://amp.cache/",
160 "https://example-com.amp.cache/c/example.com",
164 "https://example.com/",
165 "https://amp.cache/",
167 "https://example-com.amp.cache/c/s/example.com",
169 // The content type should be escaped if necessary.
171 "http://example.com/",
172 "https://amp.cache/",
174 "https://example-com.amp.cache/%2F/example.com",
176 // Retain pubURL path, query, and fragment, including escaping.
178 "http://example.com/my%2Fpath/index.html?a=1#fragment",
179 "https://amp.cache/",
181 "https://example-com.amp.cache/c/example.com/my%2Fpath/index.html?a=1#fragment",
183 // Retain scheme, userinfo, port, and path of cacheURL, escaping
184 // whatever is necessary.
186 "http://example.com",
187 "http://cache%2Fuser:cache%40pass@amp.cache:123/with/../../path/..%2f../",
189 "http://cache%2Fuser:cache%40pass@example-com.amp.cache:123/path/..%2f../c/example.com",
191 // Port numbers in pubURL are allowed, if they're the default
194 "http://example.com:80/",
195 "https://amp.cache/",
197 "https://example-com.amp.cache/c/example.com",
200 "https://example.com:443/",
201 "https://amp.cache/",
203 "https://example-com.amp.cache/c/s/example.com",
205 // "?" at the end of cacheURL is okay, as long as the query is
208 "http://example.com/",
209 "https://amp.cache/?",
211 "https://example-com.amp.cache/c/example.com",
214 // https://developers.google.com/amp/cache/overview#example-requesting-document-using-tls
216 "https://example.com/amp_document.html",
217 "https://cdn.ampproject.org/",
219 "https://example-com.cdn.ampproject.org/c/s/example.com/amp_document.html",
221 // https://developers.google.com/amp/cache/overview#example-requesting-image-using-plain-http
223 "http://example.com/logo.png",
224 "https://cdn.ampproject.org/",
226 "https://example-com.cdn.ampproject.org/i/example.com/logo.png",
228 // https://developers.google.com/amp/cache/overview#query-parameter-example
230 "https://example.com/g?value=Hello%20World",
231 "https://cdn.ampproject.org/",
233 "https://example-com.cdn.ampproject.org/c/s/example.com/g?value=Hello%20World",
236 pubURL
:= mustParseURL(test
.pub
)
237 cacheURL
:= mustParseURL(test
.cache
)
238 outputURL
, err
:= CacheURL(pubURL
, cacheURL
, test
.contentType
)
240 t
.Errorf("%+q %+q %+q → error %v",
241 test
.pub
, test
.cache
, test
.contentType
, err
)
244 if outputURL
.String() != test
.expected
{
245 t
.Errorf("%+q %+q %+q → %+q, expected %+q",
246 test
.pub
, test
.cache
, test
.contentType
, outputURL
, test
.expected
)
251 // Tests expecting an error.
252 for _
, test
:= range []struct {
257 // Empty content type.
259 "http://example.com/",
260 "https://amp.cache/",
265 "http:///index.html",
266 "https://amp.cache/",
272 "https://amp.cache/",
275 // Unrecognized scheme.
277 "ftp://example.com/",
278 "https://amp.cache/",
281 // Wrong port number for scheme.
283 "http://example.com:443/",
284 "https://amp.cache/",
287 // userinfo in pubURL.
289 "http://user@example.com/",
290 "https://amp.cache/",
294 "http://user:pass@example.com/",
295 "https://amp.cache/",
298 // cacheURL may not contain a query.
300 "http://example.com/",
301 "https://amp.cache/?a=1",
304 // cacheURL may not contain a fragment.
306 "http://example.com/",
307 "https://amp.cache/#fragment",
311 pubURL
:= mustParseURL(test
.pub
)
312 cacheURL
:= mustParseURL(test
.cache
)
313 outputURL
, err
:= CacheURL(pubURL
, cacheURL
, test
.contentType
)
315 t
.Errorf("%+q %+q %+q → %+q, expected error",
316 test
.pub
, test
.cache
, test
.contentType
, outputURL
)