1 /* 2 * Copyright (C) 2015 Square, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.squareup.okhttp; 17 18 import com.squareup.okhttp.UrlComponentEncodingTester.Component; 19 import com.squareup.okhttp.UrlComponentEncodingTester.Encoding; 20 import java.net.MalformedURLException; 21 import java.net.URI; 22 import java.net.URL; 23 import java.net.UnknownHostException; 24 import java.util.Arrays; 25 import java.util.Collections; 26 import java.util.LinkedHashSet; 27 import org.junit.Ignore; 28 import org.junit.Test; 29 30 import static java.util.Collections.singletonList; 31 import static org.junit.Assert.assertEquals; 32 import static org.junit.Assert.assertFalse; 33 import static org.junit.Assert.assertNull; 34 import static org.junit.Assert.fail; 35 36 public final class HttpUrlTest { parseTrimsAsciiWhitespace()37 @Test public void parseTrimsAsciiWhitespace() throws Exception { 38 HttpUrl expected = HttpUrl.parse("http://host/"); 39 assertEquals(expected, HttpUrl.parse("http://host/\f\n\t \r")); // Leading. 40 assertEquals(expected, HttpUrl.parse("\r\n\f \thttp://host/")); // Trailing. 41 assertEquals(expected, HttpUrl.parse(" http://host/ ")); // Both. 42 assertEquals(expected, HttpUrl.parse(" http://host/ ")); // Both. 43 assertEquals(expected, HttpUrl.parse("http://host/").resolve(" ")); 44 assertEquals(expected, HttpUrl.parse("http://host/").resolve(" . ")); 45 } 46 parseHostAsciiNonPrintable()47 @Test public void parseHostAsciiNonPrintable() throws Exception { 48 String host = "host\u0001"; 49 assertNull(HttpUrl.parse("http://" + host + "/")); 50 } 51 parseDoesNotTrimOtherWhitespaceCharacters()52 @Test public void parseDoesNotTrimOtherWhitespaceCharacters() throws Exception { 53 // Whitespace characters list from Google's Guava team: http://goo.gl/IcR9RD 54 assertEquals("/%0B", HttpUrl.parse("http://h/\u000b").encodedPath()); // line tabulation 55 assertEquals("/%1C", HttpUrl.parse("http://h/\u001c").encodedPath()); // information separator 4 56 assertEquals("/%1D", HttpUrl.parse("http://h/\u001d").encodedPath()); // information separator 3 57 assertEquals("/%1E", HttpUrl.parse("http://h/\u001e").encodedPath()); // information separator 2 58 assertEquals("/%1F", HttpUrl.parse("http://h/\u001f").encodedPath()); // information separator 1 59 assertEquals("/%C2%85", HttpUrl.parse("http://h/\u0085").encodedPath()); // next line 60 assertEquals("/%C2%A0", HttpUrl.parse("http://h/\u00a0").encodedPath()); // non-breaking space 61 assertEquals("/%E1%9A%80", HttpUrl.parse("http://h/\u1680").encodedPath()); // ogham space mark 62 assertEquals("/%E1%A0%8E", HttpUrl.parse("http://h/\u180e").encodedPath()); // mongolian vowel separator 63 assertEquals("/%E2%80%80", HttpUrl.parse("http://h/\u2000").encodedPath()); // en quad 64 assertEquals("/%E2%80%81", HttpUrl.parse("http://h/\u2001").encodedPath()); // em quad 65 assertEquals("/%E2%80%82", HttpUrl.parse("http://h/\u2002").encodedPath()); // en space 66 assertEquals("/%E2%80%83", HttpUrl.parse("http://h/\u2003").encodedPath()); // em space 67 assertEquals("/%E2%80%84", HttpUrl.parse("http://h/\u2004").encodedPath()); // three-per-em space 68 assertEquals("/%E2%80%85", HttpUrl.parse("http://h/\u2005").encodedPath()); // four-per-em space 69 assertEquals("/%E2%80%86", HttpUrl.parse("http://h/\u2006").encodedPath()); // six-per-em space 70 assertEquals("/%E2%80%87", HttpUrl.parse("http://h/\u2007").encodedPath()); // figure space 71 assertEquals("/%E2%80%88", HttpUrl.parse("http://h/\u2008").encodedPath()); // punctuation space 72 assertEquals("/%E2%80%89", HttpUrl.parse("http://h/\u2009").encodedPath()); // thin space 73 assertEquals("/%E2%80%8A", HttpUrl.parse("http://h/\u200a").encodedPath()); // hair space 74 assertEquals("/%E2%80%8B", HttpUrl.parse("http://h/\u200b").encodedPath()); // zero-width space 75 assertEquals("/%E2%80%8C", HttpUrl.parse("http://h/\u200c").encodedPath()); // zero-width non-joiner 76 assertEquals("/%E2%80%8D", HttpUrl.parse("http://h/\u200d").encodedPath()); // zero-width joiner 77 assertEquals("/%E2%80%8E", HttpUrl.parse("http://h/\u200e").encodedPath()); // left-to-right mark 78 assertEquals("/%E2%80%8F", HttpUrl.parse("http://h/\u200f").encodedPath()); // right-to-left mark 79 assertEquals("/%E2%80%A8", HttpUrl.parse("http://h/\u2028").encodedPath()); // line separator 80 assertEquals("/%E2%80%A9", HttpUrl.parse("http://h/\u2029").encodedPath()); // paragraph separator 81 assertEquals("/%E2%80%AF", HttpUrl.parse("http://h/\u202f").encodedPath()); // narrow non-breaking space 82 assertEquals("/%E2%81%9F", HttpUrl.parse("http://h/\u205f").encodedPath()); // medium mathematical space 83 assertEquals("/%E3%80%80", HttpUrl.parse("http://h/\u3000").encodedPath()); // ideographic space 84 } 85 scheme()86 @Test public void scheme() throws Exception { 87 assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("http://host/")); 88 assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("Http://host/")); 89 assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("http://host/")); 90 assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("HTTP://host/")); 91 assertEquals(HttpUrl.parse("https://host/"), HttpUrl.parse("https://host/")); 92 assertEquals(HttpUrl.parse("https://host/"), HttpUrl.parse("HTTPS://host/")); 93 assertEquals(HttpUrl.Builder.ParseResult.UNSUPPORTED_SCHEME, 94 new HttpUrl.Builder().parse(null, "image640://480.png")); 95 assertEquals(null, HttpUrl.parse("httpp://host/")); 96 assertEquals(null, HttpUrl.parse("0ttp://host/")); 97 assertEquals(null, HttpUrl.parse("ht+tp://host/")); 98 assertEquals(null, HttpUrl.parse("ht.tp://host/")); 99 assertEquals(null, HttpUrl.parse("ht-tp://host/")); 100 assertEquals(null, HttpUrl.parse("ht1tp://host/")); 101 assertEquals(null, HttpUrl.parse("httpss://host/")); 102 } 103 parseNoScheme()104 @Test public void parseNoScheme() throws Exception { 105 assertEquals(null, HttpUrl.parse("//host")); 106 assertEquals(null, HttpUrl.parse("/path")); 107 assertEquals(null, HttpUrl.parse("path")); 108 assertEquals(null, HttpUrl.parse("?query")); 109 assertEquals(null, HttpUrl.parse("#fragment")); 110 } 111 resolveNoScheme()112 @Test public void resolveNoScheme() throws Exception { 113 HttpUrl base = HttpUrl.parse("http://host/a/b"); 114 // ANDROID-BEGIN: http://b/29983827 115 // assertEquals(HttpUrl.parse("http://host2/"), base.resolve("//host2")); 116 assertEquals(HttpUrl.parse("http://host2"), base.resolve("//host2")); 117 // ANDROID-END: http://b/29983827 118 assertEquals(HttpUrl.parse("http://host2"), base.resolve("//host2")); 119 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("/path")); 120 assertEquals(HttpUrl.parse("http://host/a/path"), base.resolve("path")); 121 assertEquals(HttpUrl.parse("http://host/a/b?query"), base.resolve("?query")); 122 assertEquals(HttpUrl.parse("http://host/a/b#fragment"), base.resolve("#fragment")); 123 assertEquals(HttpUrl.parse("http://host/a/b"), base.resolve("")); 124 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("\\path")); 125 } 126 127 // ANDROID-BEGIN: http://b/29983827 encodedPath_pathVariations()128 @Test public void encodedPath_pathVariations() throws Exception { 129 assertEquals("", HttpUrl.parse("http://example.com").encodedPath()); 130 assertEquals("", HttpUrl.parse("http://example.com#fragment").encodedPath()); 131 assertEquals("", HttpUrl.parse("http://example.com?arg=value").encodedPath()); 132 assertEquals("/", HttpUrl.parse("http://example.com/").encodedPath()); 133 assertEquals("/", HttpUrl.parse("http://example.com/#fragment").encodedPath()); 134 assertEquals("/", HttpUrl.parse("http://example.com/?arg=value").encodedPath()); 135 assertEquals("/foo", HttpUrl.parse("http://example.com/foo").encodedPath()); 136 assertEquals("/foo/", HttpUrl.parse("http://example.com/foo/").encodedPath()); 137 } 138 newBuilder_pathVariations()139 @Test public void newBuilder_pathVariations() throws Exception { 140 assertNewBuilderRoundtrip("http://example.com"); 141 assertNewBuilderRoundtrip("http://example.com/"); 142 assertNewBuilderRoundtrip("http://example.com/foo"); 143 assertNewBuilderRoundtrip("http://example.com/foo/"); 144 } 145 assertNewBuilderRoundtrip(String urlString)146 private void assertNewBuilderRoundtrip(String urlString) { 147 HttpUrl url = HttpUrl.parse(urlString); 148 assertEquals(url, url.newBuilder().build()); 149 } 150 equals_emptyPathNotSameAsSlash()151 @Test public void equals_emptyPathNotSameAsSlash() throws Exception { 152 assertFalse(HttpUrl.parse("http://example.com").equals(HttpUrl.parse("http://example.com/"))); 153 } 154 parse_pathVariations()155 @Test public void parse_pathVariations() throws Exception { 156 parseThenAssertToStringEquals("http://example.com"); 157 parseThenAssertToStringEquals("https://example.com"); 158 parseThenAssertToStringEquals("http://example.com?value=42"); 159 parseThenAssertToStringEquals("http://example.com:3434"); 160 parseThenAssertToStringEquals("http://example.com#hello"); 161 162 parseThenAssertToStringEquals("http://example.com/"); 163 parseThenAssertToStringEquals("https://example.com/"); 164 parseThenAssertToStringEquals("http://example.com/foo/bar"); 165 parseThenAssertToStringEquals("http://example.com/foo/bar/"); 166 parseThenAssertToStringEquals("http://example.com/foo/bar?value=100"); 167 parseThenAssertToStringEquals("http://example.com/?value=200"); 168 169 { 170 HttpUrl httpUrl = HttpUrl.parse("http://example.com/foo/.."); 171 assertEquals("http://example.com/", httpUrl.toString()); 172 } 173 174 { 175 HttpUrl httpUrl = HttpUrl.parse("http://example.com/.."); 176 assertEquals("http://example.com/", httpUrl.toString()); 177 } 178 } 179 parseThenAssertToStringEquals(String url)180 private static void parseThenAssertToStringEquals(String url) { 181 HttpUrl httpUrl = HttpUrl.parse(url); 182 assertEquals(url, httpUrl.toString()); 183 } 184 resolve_pathVariations()185 @Test public void resolve_pathVariations() throws Exception { 186 HttpUrl baseWithoutSlash = HttpUrl.parse("http://example.com"); 187 assertResolveResult("http://example.com#section", baseWithoutSlash, "#section"); 188 assertResolveResult("http://example.com?attitude=friendly", baseWithoutSlash, 189 "?attitude=friendly"); 190 assertResolveResult("http://example.com", baseWithoutSlash, ""); 191 assertResolveResult("http://example.com/", baseWithoutSlash, "/"); 192 assertResolveResult("http://example.com/foo", baseWithoutSlash, "/foo"); 193 assertResolveResult("http://example.com/foo", baseWithoutSlash, "foo"); 194 195 assertResolveResult("http://other.com", baseWithoutSlash, "http://other.com"); 196 assertResolveResult("http://other.com/", baseWithoutSlash, "http://other.com/"); 197 assertResolveResult("http://other.com/foo", baseWithoutSlash, "http://other.com/foo"); 198 199 HttpUrl baseWithSlash = HttpUrl.parse("http://example.com/"); 200 assertResolveResult("http://example.com/#section", baseWithSlash, "#section"); 201 assertResolveResult("http://example.com/?attitude=friendly", baseWithSlash, 202 "?attitude=friendly"); 203 assertResolveResult("http://example.com/", baseWithSlash, ""); 204 assertResolveResult("http://example.com/", baseWithSlash, "/"); 205 assertResolveResult("http://example.com/foo", baseWithSlash, "/foo"); 206 assertResolveResult("http://example.com/foo", baseWithSlash, "foo"); 207 208 assertResolveResult("http://other.com", baseWithSlash, "http://other.com"); 209 assertResolveResult("http://other.com/", baseWithSlash, "http://other.com/"); 210 assertResolveResult("http://other.com/foo", baseWithSlash, "http://other.com/foo"); 211 } 212 assertResolveResult(String expected, HttpUrl base, String link)213 private void assertResolveResult(String expected, HttpUrl base, String link) { 214 assertEquals(HttpUrl.parse(expected), base.resolve(link)); 215 assertEquals(expected, base.resolve(link).toString()); 216 } 217 // ANDROID-END: http://b/29983827 218 resolveUnsupportedScheme()219 @Test public void resolveUnsupportedScheme() throws Exception { 220 HttpUrl base = HttpUrl.parse("http://a/"); 221 assertEquals(null, base.resolve("ftp://b")); 222 assertEquals(null, base.resolve("ht+tp://b")); 223 assertEquals(null, base.resolve("ht-tp://b")); 224 assertEquals(null, base.resolve("ht.tp://b")); 225 } 226 resolveSchemeLikePath()227 @Test public void resolveSchemeLikePath() throws Exception { 228 HttpUrl base = HttpUrl.parse("http://a/"); 229 assertEquals(HttpUrl.parse("http://a/http//b/"), base.resolve("http//b/")); 230 assertEquals(HttpUrl.parse("http://a/ht+tp//b/"), base.resolve("ht+tp//b/")); 231 assertEquals(HttpUrl.parse("http://a/ht-tp//b/"), base.resolve("ht-tp//b/")); 232 assertEquals(HttpUrl.parse("http://a/ht.tp//b/"), base.resolve("ht.tp//b/")); 233 } 234 parseAuthoritySlashCountDoesntMatter()235 @Test public void parseAuthoritySlashCountDoesntMatter() throws Exception { 236 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:host/path")); 237 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:/host/path")); 238 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\host/path")); 239 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http://host/path")); 240 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\/host/path")); 241 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:/\\host/path")); 242 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\\\host/path")); 243 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:///host/path")); 244 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\//host/path")); 245 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:/\\/host/path")); 246 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http://\\host/path")); 247 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\\\/host/path")); 248 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:/\\\\host/path")); 249 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\\\\\host/path")); 250 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:////host/path")); 251 } 252 resolveAuthoritySlashCountDoesntMatterWithDifferentScheme()253 @Test public void resolveAuthoritySlashCountDoesntMatterWithDifferentScheme() throws Exception { 254 HttpUrl base = HttpUrl.parse("https://a/b/c"); 255 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:host/path")); 256 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/host/path")); 257 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\host/path")); 258 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http://host/path")); 259 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\/host/path")); 260 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\host/path")); 261 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\host/path")); 262 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:///host/path")); 263 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\//host/path")); 264 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\/host/path")); 265 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http://\\host/path")); 266 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\/host/path")); 267 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\\\host/path")); 268 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\\\host/path")); 269 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:////host/path")); 270 } 271 resolveAuthoritySlashCountMattersWithSameScheme()272 @Test public void resolveAuthoritySlashCountMattersWithSameScheme() throws Exception { 273 HttpUrl base = HttpUrl.parse("http://a/b/c"); 274 assertEquals(HttpUrl.parse("http://a/b/host/path"), base.resolve("http:host/path")); 275 assertEquals(HttpUrl.parse("http://a/host/path"), base.resolve("http:/host/path")); 276 assertEquals(HttpUrl.parse("http://a/host/path"), base.resolve("http:\\host/path")); 277 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http://host/path")); 278 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\/host/path")); 279 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\host/path")); 280 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\host/path")); 281 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:///host/path")); 282 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\//host/path")); 283 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\/host/path")); 284 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http://\\host/path")); 285 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\/host/path")); 286 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\\\host/path")); 287 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\\\host/path")); 288 assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:////host/path")); 289 } 290 username()291 @Test public void username() throws Exception { 292 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http://@host/path")); 293 assertEquals(HttpUrl.parse("http://user@host/path"), HttpUrl.parse("http://user@host/path")); 294 } 295 296 /** Given multiple '@' characters, the last one is the delimiter. */ authorityWithMultipleAtSigns()297 @Test public void authorityWithMultipleAtSigns() throws Exception { 298 HttpUrl httpUrl = HttpUrl.parse("http://foo@bar@baz/path"); 299 assertEquals("foo@bar", httpUrl.username()); 300 assertEquals("", httpUrl.password()); 301 assertEquals(HttpUrl.parse("http://foo%40bar@baz/path"), httpUrl); 302 } 303 304 /** Given multiple ':' characters, the first one is the delimiter. */ authorityWithMultipleColons()305 @Test public void authorityWithMultipleColons() throws Exception { 306 HttpUrl httpUrl = HttpUrl.parse("http://foo:pass1@bar:pass2@baz/path"); 307 assertEquals("foo", httpUrl.username()); 308 assertEquals("pass1@bar:pass2", httpUrl.password()); 309 assertEquals(HttpUrl.parse("http://foo:pass1%40bar%3Apass2@baz/path"), httpUrl); 310 } 311 usernameAndPassword()312 @Test public void usernameAndPassword() throws Exception { 313 assertEquals(HttpUrl.parse("http://username:password@host/path"), 314 HttpUrl.parse("http://username:password@host/path")); 315 assertEquals(HttpUrl.parse("http://username@host/path"), 316 HttpUrl.parse("http://username:@host/path")); 317 } 318 passwordWithEmptyUsername()319 @Test public void passwordWithEmptyUsername() throws Exception { 320 // Chrome doesn't mind, but Firefox rejects URLs with empty usernames and non-empty passwords. 321 assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http://:@host/path")); 322 assertEquals("password%40", HttpUrl.parse("http://:password@@host/path").encodedPassword()); 323 } 324 unprintableCharactersArePercentEncoded()325 @Test public void unprintableCharactersArePercentEncoded() throws Exception { 326 assertEquals("/%00", HttpUrl.parse("http://host/\u0000").encodedPath()); 327 assertEquals("/%08", HttpUrl.parse("http://host/\u0008").encodedPath()); 328 assertEquals("/%EF%BF%BD", HttpUrl.parse("http://host/\ufffd").encodedPath()); 329 } 330 usernameCharacters()331 @Test public void usernameCharacters() throws Exception { 332 new UrlComponentEncodingTester() 333 .override(Encoding.PERCENT, '[', ']', '{', '}', '|', '^', '\'', ';', '=', '@') 334 .override(Encoding.SKIP, ':', '/', '\\', '?', '#') 335 .skipForUri('%') 336 .test(Component.USER); 337 } 338 passwordCharacters()339 @Test public void passwordCharacters() throws Exception { 340 new UrlComponentEncodingTester() 341 .override(Encoding.PERCENT, '[', ']', '{', '}', '|', '^', '\'', ':', ';', '=', '@') 342 .override(Encoding.SKIP, '/', '\\', '?', '#') 343 .skipForUri('%') 344 .test(Component.PASSWORD); 345 } 346 hostContainsIllegalCharacter()347 @Test public void hostContainsIllegalCharacter() throws Exception { 348 assertEquals(null, HttpUrl.parse("http://\n/")); 349 assertEquals(null, HttpUrl.parse("http:// /")); 350 assertEquals(null, HttpUrl.parse("http://%20/")); 351 } 352 hostnameLowercaseCharactersMappedDirectly()353 @Test public void hostnameLowercaseCharactersMappedDirectly() throws Exception { 354 assertEquals("abcd", HttpUrl.parse("http://abcd").host()); 355 assertEquals("xn--4xa", HttpUrl.parse("http://σ").host()); 356 } 357 hostnameUppercaseCharactersConvertedToLowercase()358 @Test public void hostnameUppercaseCharactersConvertedToLowercase() throws Exception { 359 assertEquals("abcd", HttpUrl.parse("http://ABCD").host()); 360 assertEquals("xn--4xa", HttpUrl.parse("http://Σ").host()); 361 } 362 hostnameIgnoredCharacters()363 @Test public void hostnameIgnoredCharacters() throws Exception { 364 // The soft hyphen () should be ignored. 365 assertEquals("abcd", HttpUrl.parse("http://AB\u00adCD").host()); 366 } 367 hostnameMultipleCharacterMapping()368 @Test public void hostnameMultipleCharacterMapping() throws Exception { 369 // Map the single character telephone symbol (℡) to the string "tel". 370 assertEquals("tel", HttpUrl.parse("http://\u2121").host()); 371 } 372 hostnameMappingLastMappedCodePoint()373 @Test public void hostnameMappingLastMappedCodePoint() throws Exception { 374 assertEquals("xn--pu5l", HttpUrl.parse("http://\uD87E\uDE1D").host()); 375 } 376 377 @Ignore("The java.net.IDN implementation doesn't ignore characters that it should.") hostnameMappingLastIgnoredCodePoint()378 @Test public void hostnameMappingLastIgnoredCodePoint() throws Exception { 379 assertEquals("abcd", HttpUrl.parse("http://ab\uDB40\uDDEFcd").host()); 380 } 381 hostnameMappingLastDisallowedCodePoint()382 @Test public void hostnameMappingLastDisallowedCodePoint() throws Exception { 383 assertEquals(null, HttpUrl.parse("http://\uDBFF\uDFFF")); 384 } 385 hostIpv6()386 @Test public void hostIpv6() throws Exception { 387 // Square braces are absent from host()... 388 assertEquals("::1", HttpUrl.parse("http://[::1]/").host()); 389 390 // ... but they're included in toString(). 391 assertEquals("http://[::1]/", HttpUrl.parse("http://[::1]/").toString()); 392 393 // IPv6 colons don't interfere with port numbers or passwords. 394 assertEquals(8080, HttpUrl.parse("http://[::1]:8080/").port()); 395 assertEquals("password", HttpUrl.parse("http://user:password@[::1]/").password()); 396 assertEquals("::1", HttpUrl.parse("http://user:password@[::1]:8080/").host()); 397 398 // Permit the contents of IPv6 addresses to be percent-encoded... 399 assertEquals("::1", HttpUrl.parse("http://[%3A%3A%31]/").host()); 400 401 // Including the Square braces themselves! (This is what Chrome does.) 402 assertEquals("::1", HttpUrl.parse("http://%5B%3A%3A1%5D/").host()); 403 } 404 hostIpv6AddressDifferentFormats()405 @Test public void hostIpv6AddressDifferentFormats() throws Exception { 406 // Multiple representations of the same address; see http://tools.ietf.org/html/rfc5952. 407 String a3 = "2001:db8::1:0:0:1"; 408 assertEquals(a3, HttpUrl.parse("http://[2001:db8:0:0:1:0:0:1]").host()); 409 assertEquals(a3, HttpUrl.parse("http://[2001:0db8:0:0:1:0:0:1]").host()); 410 assertEquals(a3, HttpUrl.parse("http://[2001:db8::1:0:0:1]").host()); 411 assertEquals(a3, HttpUrl.parse("http://[2001:db8::0:1:0:0:1]").host()); 412 assertEquals(a3, HttpUrl.parse("http://[2001:0db8::1:0:0:1]").host()); 413 assertEquals(a3, HttpUrl.parse("http://[2001:db8:0:0:1::1]").host()); 414 assertEquals(a3, HttpUrl.parse("http://[2001:db8:0000:0:1::1]").host()); 415 assertEquals(a3, HttpUrl.parse("http://[2001:DB8:0:0:1::1]").host()); 416 } 417 hostIpv6AddressLeadingCompression()418 @Test public void hostIpv6AddressLeadingCompression() throws Exception { 419 assertEquals("::1", HttpUrl.parse("http://[::0001]").host()); 420 assertEquals("::1", HttpUrl.parse("http://[0000::0001]").host()); 421 assertEquals("::1", HttpUrl.parse("http://[0000:0000:0000:0000:0000:0000:0000:0001]").host()); 422 assertEquals("::1", HttpUrl.parse("http://[0000:0000:0000:0000:0000:0000::0001]").host()); 423 } 424 hostIpv6AddressTrailingCompression()425 @Test public void hostIpv6AddressTrailingCompression() throws Exception { 426 assertEquals("1::", HttpUrl.parse("http://[0001:0000::]").host()); 427 assertEquals("1::", HttpUrl.parse("http://[0001::0000]").host()); 428 assertEquals("1::", HttpUrl.parse("http://[0001::]").host()); 429 assertEquals("1::", HttpUrl.parse("http://[1::]").host()); 430 } 431 hostIpv6AddressTooManyDigitsInGroup()432 @Test public void hostIpv6AddressTooManyDigitsInGroup() throws Exception { 433 assertEquals(null, HttpUrl.parse("http://[00000:0000:0000:0000:0000:0000:0000:0001]")); 434 assertEquals(null, HttpUrl.parse("http://[::00001]")); 435 } 436 hostIpv6AddressMisplacedColons()437 @Test public void hostIpv6AddressMisplacedColons() throws Exception { 438 assertEquals(null, HttpUrl.parse("http://[:0000:0000:0000:0000:0000:0000:0000:0001]")); 439 assertEquals(null, HttpUrl.parse("http://[:::0000:0000:0000:0000:0000:0000:0000:0001]")); 440 assertEquals(null, HttpUrl.parse("http://[:1]")); 441 assertEquals(null, HttpUrl.parse("http://[:::1]")); 442 assertEquals(null, HttpUrl.parse("http://[0000:0000:0000:0000:0000:0000:0001:]")); 443 assertEquals(null, HttpUrl.parse("http://[0000:0000:0000:0000:0000:0000:0000:0001:]")); 444 assertEquals(null, HttpUrl.parse("http://[0000:0000:0000:0000:0000:0000:0000:0001::]")); 445 assertEquals(null, HttpUrl.parse("http://[0000:0000:0000:0000:0000:0000:0000:0001:::]")); 446 assertEquals(null, HttpUrl.parse("http://[1:]")); 447 assertEquals(null, HttpUrl.parse("http://[1:::]")); 448 assertEquals(null, HttpUrl.parse("http://[1:::1]")); 449 assertEquals(null, HttpUrl.parse("http://[00000:0000:0000:0000::0000:0000:0000:0001]")); 450 } 451 hostIpv6AddressTooManyGroups()452 @Test public void hostIpv6AddressTooManyGroups() throws Exception { 453 assertEquals(null, HttpUrl.parse("http://[00000:0000:0000:0000:0000:0000:0000:0000:0001]")); 454 } 455 hostIpv6AddressTooMuchCompression()456 @Test public void hostIpv6AddressTooMuchCompression() throws Exception { 457 assertEquals(null, HttpUrl.parse("http://[0000::0000:0000:0000:0000::0001]")); 458 assertEquals(null, HttpUrl.parse("http://[::0000:0000:0000:0000::0001]")); 459 } 460 hostIpv6ScopedAddress()461 @Test public void hostIpv6ScopedAddress() throws Exception { 462 // java.net.InetAddress parses scoped addresses. These aren't valid in URLs. 463 assertEquals(null, HttpUrl.parse("http://[::1%2544]")); 464 } 465 hostIpv6WithIpv4Suffix()466 @Test public void hostIpv6WithIpv4Suffix() throws Exception { 467 assertEquals("::1:ffff:ffff", HttpUrl.parse("http://[::1:255.255.255.255]/").host()); 468 assertEquals("::1:0:0", HttpUrl.parse("http://[0:0:0:0:0:1:0.0.0.0]/").host()); 469 } 470 hostIpv6WithIpv4SuffixWithOctalPrefix()471 @Test public void hostIpv6WithIpv4SuffixWithOctalPrefix() throws Exception { 472 // Chrome interprets a leading '0' as octal; Firefox rejects them. (We reject them.) 473 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:0.0.0.000000]/")); 474 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:0.010.0.010]/")); 475 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:0.0.0.000001]/")); 476 } 477 hostIpv6WithIpv4SuffixWithHexadecimalPrefix()478 @Test public void hostIpv6WithIpv4SuffixWithHexadecimalPrefix() throws Exception { 479 // Chrome interprets a leading '0x' as hexadecimal; Firefox rejects them. (We reject them.) 480 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:0.0x10.0.0x10]/")); 481 } 482 hostIpv6WithMalformedIpv4Suffix()483 @Test public void hostIpv6WithMalformedIpv4Suffix() throws Exception { 484 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:0.0:0.0]/")); 485 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:0.0-0.0]/")); 486 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:.255.255.255]/")); 487 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:255..255.255]/")); 488 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:255.255..255]/")); 489 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:0:1:255.255]/")); 490 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:256.255.255.255]/")); 491 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:ff.255.255.255]/")); 492 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:0:1:255.255.255.255]/")); 493 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:1:255.255.255.255]/")); 494 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:1:0.0.0.0:1]/")); 495 assertEquals(null, HttpUrl.parse("http://[0:0.0.0.0:1:0:0:0:0:1]/")); 496 assertEquals(null, HttpUrl.parse("http://[0.0.0.0:0:0:0:0:0:1]/")); 497 } 498 hostIpv6WithIncompleteIpv4Suffix()499 @Test public void hostIpv6WithIncompleteIpv4Suffix() throws Exception { 500 // To Chrome & Safari these are well-formed; Firefox disagrees. (We're consistent with Firefox). 501 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:255.255.255.]/")); 502 assertEquals(null, HttpUrl.parse("http://[0:0:0:0:0:1:255.255.255]/")); 503 } 504 hostIpv6CanonicalForm()505 @Test public void hostIpv6CanonicalForm() throws Exception { 506 assertEquals("abcd:ef01:2345:6789:abcd:ef01:2345:6789", 507 HttpUrl.parse("http://[abcd:ef01:2345:6789:abcd:ef01:2345:6789]/").host()); 508 assertEquals("a::b:0:0:0", HttpUrl.parse("http://[a:0:0:0:b:0:0:0]/").host()); 509 assertEquals("a:b:0:0:c::", HttpUrl.parse("http://[a:b:0:0:c:0:0:0]/").host()); 510 assertEquals("a:b::c:0:0", HttpUrl.parse("http://[a:b:0:0:0:c:0:0]/").host()); 511 assertEquals("a::b:0:0:0", HttpUrl.parse("http://[a:0:0:0:b:0:0:0]/").host()); 512 assertEquals("::a:b:0:0:0", HttpUrl.parse("http://[0:0:0:a:b:0:0:0]/").host()); 513 assertEquals("::a:0:0:0:b", HttpUrl.parse("http://[0:0:0:a:0:0:0:b]/").host()); 514 assertEquals("::a:b:c:d:e:f:1", HttpUrl.parse("http://[0:a:b:c:d:e:f:1]/").host()); 515 assertEquals("a:b:c:d:e:f:1::", HttpUrl.parse("http://[a:b:c:d:e:f:1:0]/").host()); 516 assertEquals("ff01::101", HttpUrl.parse("http://[FF01:0:0:0:0:0:0:101]/").host()); 517 assertEquals("1::", HttpUrl.parse("http://[1:0:0:0:0:0:0:0]/").host()); 518 assertEquals("::1", HttpUrl.parse("http://[0:0:0:0:0:0:0:1]/").host()); 519 assertEquals("::", HttpUrl.parse("http://[0:0:0:0:0:0:0:0]/").host()); 520 } 521 hostIpv4CanonicalForm()522 @Test public void hostIpv4CanonicalForm() throws Exception { 523 assertEquals("255.255.255.255", HttpUrl.parse("http://255.255.255.255/").host()); 524 assertEquals("1.2.3.4", HttpUrl.parse("http://1.2.3.4/").host()); 525 assertEquals("0.0.0.0", HttpUrl.parse("http://0.0.0.0/").host()); 526 } 527 528 @Ignore("java.net.IDN strips trailing trailing dots on Java 7, but not on Java 8.") hostWithTrailingDot()529 @Test public void hostWithTrailingDot() throws Exception { 530 assertEquals("host.", HttpUrl.parse("http://host./").host()); 531 } 532 port()533 @Test public void port() throws Exception { 534 assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("http://host:80/")); 535 assertEquals(HttpUrl.parse("http://host:99/"), HttpUrl.parse("http://host:99/")); 536 assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("http://host:/")); 537 assertEquals(65535, HttpUrl.parse("http://host:65535/").port()); 538 assertEquals(null, HttpUrl.parse("http://host:0/")); 539 assertEquals(null, HttpUrl.parse("http://host:65536/")); 540 assertEquals(null, HttpUrl.parse("http://host:-1/")); 541 assertEquals(null, HttpUrl.parse("http://host:a/")); 542 assertEquals(null, HttpUrl.parse("http://host:%39%39/")); 543 } 544 pathCharacters()545 @Test public void pathCharacters() throws Exception { 546 new UrlComponentEncodingTester() 547 .override(Encoding.PERCENT, '^', '{', '}', '|') 548 .override(Encoding.SKIP, '\\', '?', '#') 549 .skipForUri('%', '[', ']') 550 .test(Component.PATH); 551 } 552 queryCharacters()553 @Test public void queryCharacters() throws Exception { 554 new UrlComponentEncodingTester() 555 .override(Encoding.IDENTITY, '?', '`') 556 // ANDROID-CHANGED: http://b/30405333 557 // .override(Encoding.PERCENT, '\'') 558 .override(Encoding.IDENTITY, '\'') 559 // ANDROID-CHANGED end. 560 .override(Encoding.SKIP, '#', '+') 561 .skipForUri('%', '\\', '^', '`', '{', '|', '}') 562 .test(Component.QUERY); 563 } 564 fragmentCharacters()565 @Test public void fragmentCharacters() throws Exception { 566 new UrlComponentEncodingTester() 567 .override(Encoding.IDENTITY, ' ', '"', '#', '<', '>', '?', '`') 568 .skipForUri('%', ' ', '"', '#', '<', '>', '\\', '^', '`', '{', '|', '}') 569 .identityForNonAscii() 570 .test(Component.FRAGMENT); 571 } 572 fragmentNonAscii()573 @Test public void fragmentNonAscii() throws Exception { 574 HttpUrl url = HttpUrl.parse("http://host/#Σ"); 575 assertEquals("http://host/#Σ", url.toString()); 576 assertEquals("Σ", url.fragment()); 577 assertEquals("Σ", url.encodedFragment()); 578 assertEquals("http://host/#Σ", url.uri().toString()); 579 } 580 fragmentNonAsciiThatOffendsJavaNetUri()581 @Test public void fragmentNonAsciiThatOffendsJavaNetUri() throws Exception { 582 HttpUrl url = HttpUrl.parse("http://host/#\u0080"); 583 assertEquals("http://host/#\u0080", url.toString()); 584 assertEquals("\u0080", url.fragment()); 585 assertEquals("\u0080", url.encodedFragment()); 586 assertEquals(new URI("http://host/#"), url.uri()); // Control characters may be stripped! 587 } 588 fragmentPercentEncodedNonAscii()589 @Test public void fragmentPercentEncodedNonAscii() throws Exception { 590 HttpUrl url = HttpUrl.parse("http://host/#%C2%80"); 591 assertEquals("http://host/#%C2%80", url.toString()); 592 assertEquals("\u0080", url.fragment()); 593 assertEquals("%C2%80", url.encodedFragment()); 594 assertEquals("http://host/#%C2%80", url.uri().toString()); 595 } 596 fragmentPercentEncodedPartialCodePoint()597 @Test public void fragmentPercentEncodedPartialCodePoint() throws Exception { 598 HttpUrl url = HttpUrl.parse("http://host/#%80"); 599 assertEquals("http://host/#%80", url.toString()); 600 assertEquals("\ufffd", url.fragment()); // Unicode replacement character. 601 assertEquals("%80", url.encodedFragment()); 602 assertEquals("http://host/#%80", url.uri().toString()); 603 } 604 relativePath()605 @Test public void relativePath() throws Exception { 606 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 607 assertEquals(HttpUrl.parse("http://host/a/b/d/e/f"), base.resolve("d/e/f")); 608 assertEquals(HttpUrl.parse("http://host/d/e/f"), base.resolve("../../d/e/f")); 609 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("..")); 610 assertEquals(HttpUrl.parse("http://host/"), base.resolve("../..")); 611 assertEquals(HttpUrl.parse("http://host/"), base.resolve("../../..")); 612 assertEquals(HttpUrl.parse("http://host/a/b/"), base.resolve(".")); 613 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("././..")); 614 assertEquals(HttpUrl.parse("http://host/a/b/c/"), base.resolve("c/d/../e/../")); 615 assertEquals(HttpUrl.parse("http://host/a/b/..e/"), base.resolve("..e/")); 616 assertEquals(HttpUrl.parse("http://host/a/b/e/f../"), base.resolve("e/f../")); 617 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("%2E.")); 618 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve(".%2E")); 619 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("%2E%2E")); 620 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("%2e.")); 621 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve(".%2e")); 622 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("%2e%2e")); 623 assertEquals(HttpUrl.parse("http://host/a/b/"), base.resolve("%2E")); 624 assertEquals(HttpUrl.parse("http://host/a/b/"), base.resolve("%2e")); 625 } 626 relativePathWithTrailingSlash()627 @Test public void relativePathWithTrailingSlash() throws Exception { 628 HttpUrl base = HttpUrl.parse("http://host/a/b/c/"); 629 assertEquals(HttpUrl.parse("http://host/a/b/"), base.resolve("..")); 630 assertEquals(HttpUrl.parse("http://host/a/b/"), base.resolve("../")); 631 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("../..")); 632 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("../../")); 633 assertEquals(HttpUrl.parse("http://host/"), base.resolve("../../..")); 634 assertEquals(HttpUrl.parse("http://host/"), base.resolve("../../../")); 635 assertEquals(HttpUrl.parse("http://host/"), base.resolve("../../../..")); 636 assertEquals(HttpUrl.parse("http://host/"), base.resolve("../../../../")); 637 assertEquals(HttpUrl.parse("http://host/a"), base.resolve("../../../../a")); 638 assertEquals(HttpUrl.parse("http://host/"), base.resolve("../../../../a/..")); 639 assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("../../../../a/b/..")); 640 } 641 pathWithBackslash()642 @Test public void pathWithBackslash() throws Exception { 643 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 644 assertEquals(HttpUrl.parse("http://host/a/b/d/e/f"), base.resolve("d\\e\\f")); 645 assertEquals(HttpUrl.parse("http://host/d/e/f"), base.resolve("../..\\d\\e\\f")); 646 assertEquals(HttpUrl.parse("http://host/"), base.resolve("..\\..")); 647 } 648 relativePathWithSameScheme()649 @Test public void relativePathWithSameScheme() throws Exception { 650 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 651 assertEquals(HttpUrl.parse("http://host/a/b/d/e/f"), base.resolve("http:d/e/f")); 652 assertEquals(HttpUrl.parse("http://host/d/e/f"), base.resolve("http:../../d/e/f")); 653 } 654 decodeUsername()655 @Test public void decodeUsername() { 656 assertEquals("user", HttpUrl.parse("http://user@host/").username()); 657 assertEquals("\uD83C\uDF69", HttpUrl.parse("http://%F0%9F%8D%A9@host/").username()); 658 } 659 decodePassword()660 @Test public void decodePassword() { 661 assertEquals("password", HttpUrl.parse("http://user:password@host/").password()); 662 assertEquals("", HttpUrl.parse("http://user:@host/").password()); 663 assertEquals("\uD83C\uDF69", HttpUrl.parse("http://user:%F0%9F%8D%A9@host/").password()); 664 } 665 decodeSlashCharacterInDecodedPathSegment()666 @Test public void decodeSlashCharacterInDecodedPathSegment() { 667 assertEquals(Arrays.asList("a/b/c"), 668 HttpUrl.parse("http://host/a%2Fb%2Fc").pathSegments()); 669 } 670 decodeEmptyPathSegments()671 @Test public void decodeEmptyPathSegments() { 672 assertEquals(Arrays.asList(""), 673 HttpUrl.parse("http://host/").pathSegments()); 674 } 675 percentDecode()676 @Test public void percentDecode() throws Exception { 677 assertEquals(Arrays.asList("\u0000"), 678 HttpUrl.parse("http://host/%00").pathSegments()); 679 assertEquals(Arrays.asList("a", "\u2603", "c"), 680 HttpUrl.parse("http://host/a/%E2%98%83/c").pathSegments()); 681 assertEquals(Arrays.asList("a", "\uD83C\uDF69", "c"), 682 HttpUrl.parse("http://host/a/%F0%9F%8D%A9/c").pathSegments()); 683 assertEquals(Arrays.asList("a", "b", "c"), 684 HttpUrl.parse("http://host/a/%62/c").pathSegments()); 685 assertEquals(Arrays.asList("a", "z", "c"), 686 HttpUrl.parse("http://host/a/%7A/c").pathSegments()); 687 assertEquals(Arrays.asList("a", "z", "c"), 688 HttpUrl.parse("http://host/a/%7a/c").pathSegments()); 689 } 690 malformedPercentEncoding()691 @Test public void malformedPercentEncoding() { 692 assertEquals(Arrays.asList("a%f", "b"), 693 HttpUrl.parse("http://host/a%f/b").pathSegments()); 694 assertEquals(Arrays.asList("%", "b"), 695 HttpUrl.parse("http://host/%/b").pathSegments()); 696 assertEquals(Arrays.asList("%"), 697 HttpUrl.parse("http://host/%").pathSegments()); 698 } 699 malformedUtf8Encoding()700 @Test public void malformedUtf8Encoding() { 701 // Replace a partial UTF-8 sequence with the Unicode replacement character. 702 assertEquals(Arrays.asList("a", "\ufffdx", "c"), 703 HttpUrl.parse("http://host/a/%E2%98x/c").pathSegments()); 704 } 705 incompleteUrlComposition()706 @Test public void incompleteUrlComposition() throws Exception { 707 try { 708 new HttpUrl.Builder().scheme("http").build(); 709 fail(); 710 } catch (IllegalStateException expected) { 711 assertEquals("host == null", expected.getMessage()); 712 } 713 try { 714 new HttpUrl.Builder().host("host").build(); 715 fail(); 716 } catch (IllegalStateException expected) { 717 assertEquals("scheme == null", expected.getMessage()); 718 } 719 } 720 minimalUrlComposition()721 @Test public void minimalUrlComposition() throws Exception { 722 HttpUrl url = new HttpUrl.Builder().scheme("http").host("host").build(); 723 assertEquals("http://host/", url.toString()); 724 assertEquals("http", url.scheme()); 725 assertEquals("", url.username()); 726 assertEquals("", url.password()); 727 assertEquals("host", url.host()); 728 assertEquals(80, url.port()); 729 assertEquals("/", url.encodedPath()); 730 assertEquals(null, url.query()); 731 assertEquals(null, url.fragment()); 732 } 733 fullUrlComposition()734 @Test public void fullUrlComposition() throws Exception { 735 HttpUrl url = new HttpUrl.Builder() 736 .scheme("http") 737 .username("username") 738 .password("password") 739 .host("host") 740 .port(8080) 741 .addPathSegment("path") 742 .query("query") 743 .fragment("fragment") 744 .build(); 745 assertEquals("http://username:password@host:8080/path?query#fragment", url.toString()); 746 assertEquals("http", url.scheme()); 747 assertEquals("username", url.username()); 748 assertEquals("password", url.password()); 749 assertEquals("host", url.host()); 750 assertEquals(8080, url.port()); 751 assertEquals("/path", url.encodedPath()); 752 assertEquals("query", url.query()); 753 assertEquals("fragment", url.fragment()); 754 } 755 changingSchemeChangesDefaultPort()756 @Test public void changingSchemeChangesDefaultPort() throws Exception { 757 assertEquals(443, HttpUrl.parse("http://example.com") 758 .newBuilder() 759 .scheme("https") 760 .build().port()); 761 762 assertEquals(80, HttpUrl.parse("https://example.com") 763 .newBuilder() 764 .scheme("http") 765 .build().port()); 766 767 assertEquals(1234, HttpUrl.parse("https://example.com:1234") 768 .newBuilder() 769 .scheme("http") 770 .build().port()); 771 } 772 composeEncodesWhitespace()773 @Test public void composeEncodesWhitespace() throws Exception { 774 HttpUrl url = new HttpUrl.Builder() 775 .scheme("http") 776 .username("a\r\n\f\t b") 777 .password("c\r\n\f\t d") 778 .host("host") 779 .addPathSegment("e\r\n\f\t f") 780 .query("g\r\n\f\t h") 781 .fragment("i\r\n\f\t j") 782 .build(); 783 assertEquals("http://a%0D%0A%0C%09%20b:c%0D%0A%0C%09%20d@host" 784 + "/e%0D%0A%0C%09%20f?g%0D%0A%0C%09%20h#i%0D%0A%0C%09 j", url.toString()); 785 assertEquals("a\r\n\f\t b", url.username()); 786 assertEquals("c\r\n\f\t d", url.password()); 787 assertEquals("e\r\n\f\t f", url.pathSegments().get(0)); 788 assertEquals("g\r\n\f\t h", url.query()); 789 assertEquals("i\r\n\f\t j", url.fragment()); 790 } 791 composeFromUnencodedComponents()792 @Test public void composeFromUnencodedComponents() throws Exception { 793 HttpUrl url = new HttpUrl.Builder() 794 .scheme("http") 795 .username("a:\u0001@/\\?#%b") 796 .password("c:\u0001@/\\?#%d") 797 .host("ef") 798 .port(8080) 799 .addPathSegment("g:\u0001@/\\?#%h") 800 .query("i:\u0001@/\\?#%j") 801 .fragment("k:\u0001@/\\?#%l") 802 .build(); 803 assertEquals("http://a%3A%01%40%2F%5C%3F%23%25b:c%3A%01%40%2F%5C%3F%23%25d@ef:8080/" 804 + "g:%01@%2F%5C%3F%23%25h?i:%01@/\\?%23%25j#k:%01@/\\?#%25l", url.toString()); 805 assertEquals("http", url.scheme()); 806 assertEquals("a:\u0001@/\\?#%b", url.username()); 807 assertEquals("c:\u0001@/\\?#%d", url.password()); 808 assertEquals(Arrays.asList("g:\u0001@/\\?#%h"), url.pathSegments()); 809 assertEquals("i:\u0001@/\\?#%j", url.query()); 810 assertEquals("k:\u0001@/\\?#%l", url.fragment()); 811 assertEquals("a%3A%01%40%2F%5C%3F%23%25b", url.encodedUsername()); 812 assertEquals("c%3A%01%40%2F%5C%3F%23%25d", url.encodedPassword()); 813 assertEquals("/g:%01@%2F%5C%3F%23%25h", url.encodedPath()); 814 assertEquals("i:%01@/\\?%23%25j", url.encodedQuery()); 815 assertEquals("k:%01@/\\?#%25l", url.encodedFragment()); 816 } 817 composeFromEncodedComponents()818 @Test public void composeFromEncodedComponents() throws Exception { 819 HttpUrl url = new HttpUrl.Builder() 820 .scheme("http") 821 .encodedUsername("a:\u0001@/\\?#%25b") 822 .encodedPassword("c:\u0001@/\\?#%25d") 823 .host("ef") 824 .port(8080) 825 .addEncodedPathSegment("g:\u0001@/\\?#%25h") 826 .encodedQuery("i:\u0001@/\\?#%25j") 827 .encodedFragment("k:\u0001@/\\?#%25l") 828 .build(); 829 assertEquals("http://a%3A%01%40%2F%5C%3F%23%25b:c%3A%01%40%2F%5C%3F%23%25d@ef:8080/" 830 + "g:%01@%2F%5C%3F%23%25h?i:%01@/\\?%23%25j#k:%01@/\\?#%25l", url.toString()); 831 assertEquals("http", url.scheme()); 832 assertEquals("a:\u0001@/\\?#%b", url.username()); 833 assertEquals("c:\u0001@/\\?#%d", url.password()); 834 assertEquals(Arrays.asList("g:\u0001@/\\?#%h"), url.pathSegments()); 835 assertEquals("i:\u0001@/\\?#%j", url.query()); 836 assertEquals("k:\u0001@/\\?#%l", url.fragment()); 837 assertEquals("a%3A%01%40%2F%5C%3F%23%25b", url.encodedUsername()); 838 assertEquals("c%3A%01%40%2F%5C%3F%23%25d", url.encodedPassword()); 839 assertEquals("/g:%01@%2F%5C%3F%23%25h", url.encodedPath()); 840 assertEquals("i:%01@/\\?%23%25j", url.encodedQuery()); 841 assertEquals("k:%01@/\\?#%25l", url.encodedFragment()); 842 } 843 composeWithEncodedPath()844 @Test public void composeWithEncodedPath() throws Exception { 845 HttpUrl url = new HttpUrl.Builder() 846 .scheme("http") 847 .host("host") 848 .encodedPath("/a%2Fb/c") 849 .build(); 850 assertEquals("http://host/a%2Fb/c", url.toString()); 851 assertEquals("/a%2Fb/c", url.encodedPath()); 852 assertEquals(Arrays.asList("a/b", "c"), url.pathSegments()); 853 } 854 composeMixingPathSegments()855 @Test public void composeMixingPathSegments() throws Exception { 856 HttpUrl url = new HttpUrl.Builder() 857 .scheme("http") 858 .host("host") 859 .encodedPath("/a%2fb/c") 860 .addPathSegment("d%25e") 861 .addEncodedPathSegment("f%25g") 862 .build(); 863 assertEquals("http://host/a%2fb/c/d%2525e/f%25g", url.toString()); 864 assertEquals("/a%2fb/c/d%2525e/f%25g", url.encodedPath()); 865 assertEquals(Arrays.asList("a%2fb", "c", "d%2525e", "f%25g"), url.encodedPathSegments()); 866 assertEquals(Arrays.asList("a/b", "c", "d%25e", "f%g"), url.pathSegments()); 867 } 868 composeWithAddSegment()869 @Test public void composeWithAddSegment() throws Exception { 870 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 871 assertEquals("/a/b/c/", base.newBuilder().addPathSegment("").build().encodedPath()); 872 assertEquals("/a/b/c/d", 873 base.newBuilder().addPathSegment("").addPathSegment("d").build().encodedPath()); 874 assertEquals("/a/b/", base.newBuilder().addPathSegment("..").build().encodedPath()); 875 assertEquals("/a/b/", base.newBuilder().addPathSegment("").addPathSegment("..").build() 876 .encodedPath()); 877 assertEquals("/a/b/c/", base.newBuilder().addPathSegment("").addPathSegment("").build() 878 .encodedPath()); 879 } 880 pathSize()881 @Test public void pathSize() throws Exception { 882 assertEquals(1, HttpUrl.parse("http://host/").pathSize()); 883 assertEquals(3, HttpUrl.parse("http://host/a/b/c").pathSize()); 884 } 885 addPathSegmentDotDoesNothing()886 @Test public void addPathSegmentDotDoesNothing() throws Exception { 887 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 888 assertEquals("/a/b/c", base.newBuilder().addPathSegment(".").build().encodedPath()); 889 } 890 addPathSegmentEncodes()891 @Test public void addPathSegmentEncodes() throws Exception { 892 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 893 assertEquals("/a/b/c/%252e", 894 base.newBuilder().addPathSegment("%2e").build().encodedPath()); 895 assertEquals("/a/b/c/%252e%252e", 896 base.newBuilder().addPathSegment("%2e%2e").build().encodedPath()); 897 } 898 addPathSegmentDotDotPopsDirectory()899 @Test public void addPathSegmentDotDotPopsDirectory() throws Exception { 900 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 901 assertEquals("/a/b/", base.newBuilder().addPathSegment("..").build().encodedPath()); 902 } 903 addPathSegmentDotAndIgnoredCharacter()904 @Test public void addPathSegmentDotAndIgnoredCharacter() throws Exception { 905 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 906 assertEquals("/a/b/c/.%0A", base.newBuilder().addPathSegment(".\n").build().encodedPath()); 907 } 908 addEncodedPathSegmentDotAndIgnoredCharacter()909 @Test public void addEncodedPathSegmentDotAndIgnoredCharacter() throws Exception { 910 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 911 assertEquals("/a/b/c", base.newBuilder().addEncodedPathSegment(".\n").build().encodedPath()); 912 } 913 addEncodedPathSegmentDotDotAndIgnoredCharacter()914 @Test public void addEncodedPathSegmentDotDotAndIgnoredCharacter() throws Exception { 915 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 916 assertEquals("/a/b/", base.newBuilder().addEncodedPathSegment("..\n").build().encodedPath()); 917 } 918 setPathSegment()919 @Test public void setPathSegment() throws Exception { 920 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 921 assertEquals("/d/b/c", base.newBuilder().setPathSegment(0, "d").build().encodedPath()); 922 assertEquals("/a/d/c", base.newBuilder().setPathSegment(1, "d").build().encodedPath()); 923 assertEquals("/a/b/d", base.newBuilder().setPathSegment(2, "d").build().encodedPath()); 924 } 925 setPathSegmentEncodes()926 @Test public void setPathSegmentEncodes() throws Exception { 927 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 928 assertEquals("/%2525/b/c", base.newBuilder().setPathSegment(0, "%25").build().encodedPath()); 929 assertEquals("/.%0A/b/c", base.newBuilder().setPathSegment(0, ".\n").build().encodedPath()); 930 assertEquals("/%252e/b/c", base.newBuilder().setPathSegment(0, "%2e").build().encodedPath()); 931 } 932 setPathSegmentAcceptsEmpty()933 @Test public void setPathSegmentAcceptsEmpty() throws Exception { 934 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 935 assertEquals("//b/c", base.newBuilder().setPathSegment(0, "").build().encodedPath()); 936 assertEquals("/a/b/", base.newBuilder().setPathSegment(2, "").build().encodedPath()); 937 } 938 setPathSegmentRejectsDot()939 @Test public void setPathSegmentRejectsDot() throws Exception { 940 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 941 try { 942 base.newBuilder().setPathSegment(0, "."); 943 fail(); 944 } catch (IllegalArgumentException expected) { 945 } 946 } 947 setPathSegmentRejectsDotDot()948 @Test public void setPathSegmentRejectsDotDot() throws Exception { 949 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 950 try { 951 base.newBuilder().setPathSegment(0, ".."); 952 fail(); 953 } catch (IllegalArgumentException expected) { 954 } 955 } 956 setPathSegmentWithSlash()957 @Test public void setPathSegmentWithSlash() throws Exception { 958 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 959 HttpUrl url = base.newBuilder().setPathSegment(1, "/").build(); 960 assertEquals("/a/%2F/c", url.encodedPath()); 961 } 962 setPathSegmentOutOfBounds()963 @Test public void setPathSegmentOutOfBounds() throws Exception { 964 try { 965 new HttpUrl.Builder().setPathSegment(1, "a"); 966 fail(); 967 } catch (IndexOutOfBoundsException expected) { 968 } 969 } 970 setEncodedPathSegmentEncodes()971 @Test public void setEncodedPathSegmentEncodes() throws Exception { 972 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 973 assertEquals("/%25/b/c", 974 base.newBuilder().setEncodedPathSegment(0, "%25").build().encodedPath()); 975 } 976 setEncodedPathSegmentRejectsDot()977 @Test public void setEncodedPathSegmentRejectsDot() throws Exception { 978 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 979 try { 980 base.newBuilder().setEncodedPathSegment(0, "."); 981 fail(); 982 } catch (IllegalArgumentException expected) { 983 } 984 } 985 setEncodedPathSegmentRejectsDotAndIgnoredCharacter()986 @Test public void setEncodedPathSegmentRejectsDotAndIgnoredCharacter() throws Exception { 987 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 988 try { 989 base.newBuilder().setEncodedPathSegment(0, ".\n"); 990 fail(); 991 } catch (IllegalArgumentException expected) { 992 } 993 } 994 setEncodedPathSegmentRejectsDotDot()995 @Test public void setEncodedPathSegmentRejectsDotDot() throws Exception { 996 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 997 try { 998 base.newBuilder().setEncodedPathSegment(0, ".."); 999 fail(); 1000 } catch (IllegalArgumentException expected) { 1001 } 1002 } 1003 setEncodedPathSegmentRejectsDotDotAndIgnoredCharacter()1004 @Test public void setEncodedPathSegmentRejectsDotDotAndIgnoredCharacter() throws Exception { 1005 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 1006 try { 1007 base.newBuilder().setEncodedPathSegment(0, "..\n"); 1008 fail(); 1009 } catch (IllegalArgumentException expected) { 1010 } 1011 } 1012 setEncodedPathSegmentWithSlash()1013 @Test public void setEncodedPathSegmentWithSlash() throws Exception { 1014 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 1015 HttpUrl url = base.newBuilder().setEncodedPathSegment(1, "/").build(); 1016 assertEquals("/a/%2F/c", url.encodedPath()); 1017 } 1018 setEncodedPathSegmentOutOfBounds()1019 @Test public void setEncodedPathSegmentOutOfBounds() throws Exception { 1020 try { 1021 new HttpUrl.Builder().setEncodedPathSegment(1, "a"); 1022 fail(); 1023 } catch (IndexOutOfBoundsException expected) { 1024 } 1025 } 1026 removePathSegment()1027 @Test public void removePathSegment() throws Exception { 1028 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 1029 HttpUrl url = base.newBuilder() 1030 .removePathSegment(0) 1031 .build(); 1032 assertEquals("/b/c", url.encodedPath()); 1033 } 1034 removePathSegmentDoesntRemovePath()1035 @Test public void removePathSegmentDoesntRemovePath() throws Exception { 1036 HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 1037 HttpUrl url = base.newBuilder() 1038 .removePathSegment(0) 1039 .removePathSegment(0) 1040 .removePathSegment(0) 1041 .build(); 1042 // ANDROID-BEGIN: http://b/29983827 Behavior changed. Test name is now incorrect. 1043 // assertEquals(Arrays.asList(""), url.pathSegments()); 1044 // assertEquals("/", url.encodedPath()); 1045 assertEquals(Collections.emptyList(), url.pathSegments()); 1046 assertEquals("http://host", url.toString()); 1047 // ANDROID-END: http://b/29983827 1048 } 1049 removePathSegmentOutOfBounds()1050 @Test public void removePathSegmentOutOfBounds() throws Exception { 1051 try { 1052 new HttpUrl.Builder().removePathSegment(1); 1053 fail(); 1054 } catch (IndexOutOfBoundsException expected) { 1055 } 1056 } 1057 toJavaNetUrl()1058 @Test public void toJavaNetUrl() throws Exception { 1059 HttpUrl httpUrl = HttpUrl.parse("http://username:password@host/path?query#fragment"); 1060 URL javaNetUrl = httpUrl.url(); 1061 assertEquals("http://username:password@host/path?query#fragment", javaNetUrl.toString()); 1062 } 1063 toUri()1064 @Test public void toUri() throws Exception { 1065 HttpUrl httpUrl = HttpUrl.parse("http://username:password@host/path?query#fragment"); 1066 URI uri = httpUrl.uri(); 1067 assertEquals("http://username:password@host/path?query#fragment", uri.toString()); 1068 } 1069 toUriSpecialQueryCharacters()1070 @Test public void toUriSpecialQueryCharacters() throws Exception { 1071 HttpUrl httpUrl = HttpUrl.parse("http://host/?d=abc!@[]^`{}|\\"); 1072 URI uri = httpUrl.uri(); 1073 assertEquals("http://host/?d=abc!@[]%5E%60%7B%7D%7C%5C", uri.toString()); 1074 } 1075 toUriWithUsernameNoPassword()1076 @Test public void toUriWithUsernameNoPassword() throws Exception { 1077 HttpUrl httpUrl = new HttpUrl.Builder() 1078 .scheme("http") 1079 .username("user") 1080 .host("host") 1081 .build(); 1082 assertEquals("http://user@host/", httpUrl.toString()); 1083 assertEquals("http://user@host/", httpUrl.uri().toString()); 1084 } 1085 toUriUsernameSpecialCharacters()1086 @Test public void toUriUsernameSpecialCharacters() throws Exception { 1087 HttpUrl url = new HttpUrl.Builder() 1088 .scheme("http") 1089 .host("host") 1090 .username("=[]:;\"~|?#@^/$%*") 1091 .build(); 1092 assertEquals("http://%3D%5B%5D%3A%3B%22~%7C%3F%23%40%5E%2F$%25*@host/", url.toString()); 1093 assertEquals("http://%3D%5B%5D%3A%3B%22~%7C%3F%23%40%5E%2F$%25*@host/", url.uri().toString()); 1094 } 1095 toUriPasswordSpecialCharacters()1096 @Test public void toUriPasswordSpecialCharacters() throws Exception { 1097 HttpUrl url = new HttpUrl.Builder() 1098 .scheme("http") 1099 .host("host") 1100 .username("user") 1101 .password("=[]:;\"~|?#@^/$%*") 1102 .build(); 1103 assertEquals("http://user:%3D%5B%5D%3A%3B%22~%7C%3F%23%40%5E%2F$%25*@host/", url.toString()); 1104 assertEquals("http://user:%3D%5B%5D%3A%3B%22~%7C%3F%23%40%5E%2F$%25*@host/", 1105 url.uri().toString()); 1106 } 1107 toUriPathSpecialCharacters()1108 @Test public void toUriPathSpecialCharacters() throws Exception { 1109 HttpUrl url = new HttpUrl.Builder() 1110 .scheme("http") 1111 .host("host") 1112 .addPathSegment("=[]:;\"~|?#@^/$%*") 1113 .build(); 1114 assertEquals("http://host/=[]:;%22~%7C%3F%23@%5E%2F$%25*", url.toString()); 1115 assertEquals("http://host/=%5B%5D:;%22~%7C%3F%23@%5E%2F$%25*", url.uri().toString()); 1116 } 1117 toUriQueryParameterNameSpecialCharacters()1118 @Test public void toUriQueryParameterNameSpecialCharacters() throws Exception { 1119 HttpUrl url = new HttpUrl.Builder() 1120 .scheme("http") 1121 .host("host") 1122 .addQueryParameter("=[]:;\"~|?#@^/$%*", "a") 1123 .build(); 1124 assertEquals("http://host/?%3D[]:;%22~|?%23@^/$%25*=a", url.toString()); 1125 assertEquals("http://host/?%3D[]:;%22~%7C?%23@%5E/$%25*=a", url.uri().toString()); 1126 } 1127 toUriQueryParameterValueSpecialCharacters()1128 @Test public void toUriQueryParameterValueSpecialCharacters() throws Exception { 1129 HttpUrl url = new HttpUrl.Builder() 1130 .scheme("http") 1131 .host("host") 1132 .addQueryParameter("a", "=[]:;\"~|?#@^/$%*") 1133 .build(); 1134 assertEquals("http://host/?a=%3D[]:;%22~|?%23@^/$%25*", url.toString()); 1135 assertEquals("http://host/?a=%3D[]:;%22~%7C?%23@%5E/$%25*", url.uri().toString()); 1136 } 1137 toUriQueryValueSpecialCharacters()1138 @Test public void toUriQueryValueSpecialCharacters() throws Exception { 1139 HttpUrl url = new HttpUrl.Builder() 1140 .scheme("http") 1141 .host("host") 1142 .query("=[]:;\"~|?#@^/$%*") 1143 .build(); 1144 assertEquals("http://host/?=[]:;%22~|?%23@^/$%25*", url.toString()); 1145 assertEquals("http://host/?=[]:;%22~%7C?%23@%5E/$%25*", url.uri().toString()); 1146 } 1147 toUriFragmentSpecialCharacters()1148 @Test public void toUriFragmentSpecialCharacters() throws Exception { 1149 HttpUrl url = new HttpUrl.Builder() 1150 .scheme("http") 1151 .host("host") 1152 .fragment("=[]:;\"~|?#@^/$%*") 1153 .build(); 1154 assertEquals("http://host/#=[]:;\"~|?#@^/$%25*", url.toString()); 1155 assertEquals("http://host/#=[]:;%22~%7C?%23@%5E/$%25*", url.uri().toString()); 1156 } 1157 toUriWithControlCharacters()1158 @Test public void toUriWithControlCharacters() throws Exception { 1159 // Percent-encoded in the path. 1160 assertEquals(new URI("http://host/a%00b"), HttpUrl.parse("http://host/a\u0000b").uri()); 1161 assertEquals(new URI("http://host/a%C2%80b"), HttpUrl.parse("http://host/a\u0080b").uri()); 1162 assertEquals(new URI("http://host/a%C2%9Fb"), HttpUrl.parse("http://host/a\u009fb").uri()); 1163 // Percent-encoded in the query. 1164 assertEquals(new URI("http://host/?a%00b"), HttpUrl.parse("http://host/?a\u0000b").uri()); 1165 assertEquals(new URI("http://host/?a%C2%80b"), HttpUrl.parse("http://host/?a\u0080b").uri()); 1166 assertEquals(new URI("http://host/?a%C2%9Fb"), HttpUrl.parse("http://host/?a\u009fb").uri()); 1167 // Stripped from the fragment. 1168 assertEquals(new URI("http://host/#a%00b"), HttpUrl.parse("http://host/#a\u0000b").uri()); 1169 assertEquals(new URI("http://host/#ab"), HttpUrl.parse("http://host/#a\u0080b").uri()); 1170 assertEquals(new URI("http://host/#ab"), HttpUrl.parse("http://host/#a\u009fb").uri()); 1171 } 1172 toUriWithSpaceCharacters()1173 @Test public void toUriWithSpaceCharacters() throws Exception { 1174 // Percent-encoded in the path. 1175 assertEquals(new URI("http://host/a%0Bb"), HttpUrl.parse("http://host/a\u000bb").uri()); 1176 assertEquals(new URI("http://host/a%20b"), HttpUrl.parse("http://host/a b").uri()); 1177 assertEquals(new URI("http://host/a%E2%80%89b"), HttpUrl.parse("http://host/a\u2009b").uri()); 1178 assertEquals(new URI("http://host/a%E3%80%80b"), HttpUrl.parse("http://host/a\u3000b").uri()); 1179 // Percent-encoded in the query. 1180 assertEquals(new URI("http://host/?a%0Bb"), HttpUrl.parse("http://host/?a\u000bb").uri()); 1181 assertEquals(new URI("http://host/?a%20b"), HttpUrl.parse("http://host/?a b").uri()); 1182 assertEquals(new URI("http://host/?a%E2%80%89b"), HttpUrl.parse("http://host/?a\u2009b").uri()); 1183 assertEquals(new URI("http://host/?a%E3%80%80b"), HttpUrl.parse("http://host/?a\u3000b").uri()); 1184 // Stripped from the fragment. 1185 assertEquals(new URI("http://host/#a%0Bb"), HttpUrl.parse("http://host/#a\u000bb").uri()); 1186 assertEquals(new URI("http://host/#a%20b"), HttpUrl.parse("http://host/#a b").uri()); 1187 assertEquals(new URI("http://host/#ab"), HttpUrl.parse("http://host/#a\u2009b").uri()); 1188 assertEquals(new URI("http://host/#ab"), HttpUrl.parse("http://host/#a\u3000b").uri()); 1189 } 1190 toUriWithNonHexPercentEscape()1191 @Test public void toUriWithNonHexPercentEscape() throws Exception { 1192 assertEquals(new URI("http://host/%25xx"), HttpUrl.parse("http://host/%xx").uri()); 1193 } 1194 toUriWithTruncatedPercentEscape()1195 @Test public void toUriWithTruncatedPercentEscape() throws Exception { 1196 assertEquals(new URI("http://host/%25a"), HttpUrl.parse("http://host/%a").uri()); 1197 assertEquals(new URI("http://host/%25"), HttpUrl.parse("http://host/%").uri()); 1198 } 1199 fromJavaNetUrl()1200 @Test public void fromJavaNetUrl() throws Exception { 1201 URL javaNetUrl = new URL("http://username:password@host/path?query#fragment"); 1202 HttpUrl httpUrl = HttpUrl.get(javaNetUrl); 1203 assertEquals("http://username:password@host/path?query#fragment", httpUrl.toString()); 1204 } 1205 1206 // ANDROID-BEGIN 1207 @Ignore // Android's URL implementation does not support mailto: 1208 // ANDROID-END fromJavaNetUrlUnsupportedScheme()1209 @Test public void fromJavaNetUrlUnsupportedScheme() throws Exception { 1210 URL javaNetUrl = new URL("mailto:user@example.com"); 1211 assertEquals(null, HttpUrl.get(javaNetUrl)); 1212 } 1213 fromUri()1214 @Test public void fromUri() throws Exception { 1215 URI uri = new URI("http://username:password@host/path?query#fragment"); 1216 HttpUrl httpUrl = HttpUrl.get(uri); 1217 assertEquals("http://username:password@host/path?query#fragment", httpUrl.toString()); 1218 } 1219 fromUriUnsupportedScheme()1220 @Test public void fromUriUnsupportedScheme() throws Exception { 1221 URI uri = new URI("mailto:user@example.com"); 1222 assertEquals(null, HttpUrl.get(uri)); 1223 } 1224 fromUriPartial()1225 @Test public void fromUriPartial() throws Exception { 1226 URI uri = new URI("/path"); 1227 assertEquals(null, HttpUrl.get(uri)); 1228 } 1229 fromJavaNetUrl_checked()1230 @Test public void fromJavaNetUrl_checked() throws Exception { 1231 HttpUrl httpUrl = HttpUrl.getChecked("http://username:password@host/path?query#fragment"); 1232 assertEquals("http://username:password@host/path?query#fragment", httpUrl.toString()); 1233 } 1234 fromJavaNetUrlUnsupportedScheme_checked()1235 @Test public void fromJavaNetUrlUnsupportedScheme_checked() throws Exception { 1236 try { 1237 HttpUrl.getChecked("mailto:user@example.com"); 1238 fail(); 1239 } catch (MalformedURLException e) { 1240 } 1241 } 1242 fromJavaNetUrlBadHost_checked()1243 @Test public void fromJavaNetUrlBadHost_checked() throws Exception { 1244 try { 1245 HttpUrl.getChecked("http://hostw ithspace/"); 1246 fail(); 1247 } catch (UnknownHostException expected) { 1248 } 1249 } 1250 composeQueryWithComponents()1251 @Test public void composeQueryWithComponents() throws Exception { 1252 HttpUrl base = HttpUrl.parse("http://host/"); 1253 HttpUrl url = base.newBuilder().addQueryParameter("a+=& b", "c+=& d").build(); 1254 assertEquals("http://host/?a%2B%3D%26%20b=c%2B%3D%26%20d", url.toString()); 1255 assertEquals("c+=& d", url.queryParameterValue(0)); 1256 assertEquals("a+=& b", url.queryParameterName(0)); 1257 assertEquals("c+=& d", url.queryParameter("a+=& b")); 1258 assertEquals(Collections.singleton("a+=& b"), url.queryParameterNames()); 1259 assertEquals(singletonList("c+=& d"), url.queryParameterValues("a+=& b")); 1260 assertEquals(1, url.querySize()); 1261 assertEquals("a+=& b=c+=& d", url.query()); // Ambiguous! (Though working as designed.) 1262 assertEquals("a%2B%3D%26%20b=c%2B%3D%26%20d", url.encodedQuery()); 1263 } 1264 composeQueryWithEncodedComponents()1265 @Test public void composeQueryWithEncodedComponents() throws Exception { 1266 HttpUrl base = HttpUrl.parse("http://host/"); 1267 HttpUrl url = base.newBuilder().addEncodedQueryParameter("a+=& b", "c+=& d").build(); 1268 assertEquals("http://host/?a+%3D%26%20b=c+%3D%26%20d", url.toString()); 1269 assertEquals("c =& d", url.queryParameter("a =& b")); 1270 } 1271 composeQueryRemoveQueryParameter()1272 @Test public void composeQueryRemoveQueryParameter() throws Exception { 1273 HttpUrl url = HttpUrl.parse("http://host/").newBuilder() 1274 .addQueryParameter("a+=& b", "c+=& d") 1275 .removeAllQueryParameters("a+=& b") 1276 .build(); 1277 assertEquals("http://host/", url.toString()); 1278 assertEquals(null, url.queryParameter("a+=& b")); 1279 } 1280 composeQueryRemoveEncodedQueryParameter()1281 @Test public void composeQueryRemoveEncodedQueryParameter() throws Exception { 1282 HttpUrl url = HttpUrl.parse("http://host/").newBuilder() 1283 .addEncodedQueryParameter("a+=& b", "c+=& d") 1284 .removeAllEncodedQueryParameters("a+=& b") 1285 .build(); 1286 assertEquals("http://host/", url.toString()); 1287 assertEquals(null, url.queryParameter("a =& b")); 1288 } 1289 composeQuerySetQueryParameter()1290 @Test public void composeQuerySetQueryParameter() throws Exception { 1291 HttpUrl url = HttpUrl.parse("http://host/").newBuilder() 1292 .addQueryParameter("a+=& b", "c+=& d") 1293 .setQueryParameter("a+=& b", "ef") 1294 .build(); 1295 assertEquals("http://host/?a%2B%3D%26%20b=ef", url.toString()); 1296 assertEquals("ef", url.queryParameter("a+=& b")); 1297 } 1298 composeQuerySetEncodedQueryParameter()1299 @Test public void composeQuerySetEncodedQueryParameter() throws Exception { 1300 HttpUrl url = HttpUrl.parse("http://host/").newBuilder() 1301 .addEncodedQueryParameter("a+=& b", "c+=& d") 1302 .setEncodedQueryParameter("a+=& b", "ef") 1303 .build(); 1304 assertEquals("http://host/?a+%3D%26%20b=ef", url.toString()); 1305 assertEquals("ef", url.queryParameter("a =& b")); 1306 } 1307 composeQueryMultipleEncodedValuesForParameter()1308 @Test public void composeQueryMultipleEncodedValuesForParameter() throws Exception { 1309 HttpUrl url = HttpUrl.parse("http://host/").newBuilder() 1310 .addQueryParameter("a+=& b", "c+=& d") 1311 .addQueryParameter("a+=& b", "e+=& f") 1312 .build(); 1313 assertEquals("http://host/?a%2B%3D%26%20b=c%2B%3D%26%20d&a%2B%3D%26%20b=e%2B%3D%26%20f", 1314 url.toString()); 1315 assertEquals(2, url.querySize()); 1316 assertEquals(Collections.singleton("a+=& b"), url.queryParameterNames()); 1317 assertEquals(Arrays.asList("c+=& d", "e+=& f"), url.queryParameterValues("a+=& b")); 1318 } 1319 absentQueryIsZeroNameValuePairs()1320 @Test public void absentQueryIsZeroNameValuePairs() throws Exception { 1321 HttpUrl url = HttpUrl.parse("http://host/").newBuilder() 1322 .query(null) 1323 .build(); 1324 assertEquals(0, url.querySize()); 1325 } 1326 emptyQueryIsSingleNameValuePairWithEmptyKey()1327 @Test public void emptyQueryIsSingleNameValuePairWithEmptyKey() throws Exception { 1328 HttpUrl url = HttpUrl.parse("http://host/").newBuilder() 1329 .query("") 1330 .build(); 1331 assertEquals(1, url.querySize()); 1332 assertEquals("", url.queryParameterName(0)); 1333 assertEquals(null, url.queryParameterValue(0)); 1334 } 1335 ampersandQueryIsTwoNameValuePairsWithEmptyKeys()1336 @Test public void ampersandQueryIsTwoNameValuePairsWithEmptyKeys() throws Exception { 1337 HttpUrl url = HttpUrl.parse("http://host/").newBuilder() 1338 .query("&") 1339 .build(); 1340 assertEquals(2, url.querySize()); 1341 assertEquals("", url.queryParameterName(0)); 1342 assertEquals(null, url.queryParameterValue(0)); 1343 assertEquals("", url.queryParameterName(1)); 1344 assertEquals(null, url.queryParameterValue(1)); 1345 } 1346 removeAllDoesNotRemoveQueryIfNoParametersWereRemoved()1347 @Test public void removeAllDoesNotRemoveQueryIfNoParametersWereRemoved() throws Exception { 1348 HttpUrl url = HttpUrl.parse("http://host/").newBuilder() 1349 .query("") 1350 .removeAllQueryParameters("a") 1351 .build(); 1352 assertEquals("http://host/?", url.toString()); 1353 } 1354 queryParametersWithoutValues()1355 @Test public void queryParametersWithoutValues() throws Exception { 1356 HttpUrl url = HttpUrl.parse("http://host/?foo&bar&baz"); 1357 assertEquals(3, url.querySize()); 1358 assertEquals(new LinkedHashSet<>(Arrays.asList("foo", "bar", "baz")), 1359 url.queryParameterNames()); 1360 assertEquals(null, url.queryParameterValue(0)); 1361 assertEquals(null, url.queryParameterValue(1)); 1362 assertEquals(null, url.queryParameterValue(2)); 1363 assertEquals(singletonList((String) null), url.queryParameterValues("foo")); 1364 assertEquals(singletonList((String) null), url.queryParameterValues("bar")); 1365 assertEquals(singletonList((String) null), url.queryParameterValues("baz")); 1366 } 1367 queryParametersWithEmptyValues()1368 @Test public void queryParametersWithEmptyValues() throws Exception { 1369 HttpUrl url = HttpUrl.parse("http://host/?foo=&bar=&baz="); 1370 assertEquals(3, url.querySize()); 1371 assertEquals(new LinkedHashSet<>(Arrays.asList("foo", "bar", "baz")), 1372 url.queryParameterNames()); 1373 assertEquals("", url.queryParameterValue(0)); 1374 assertEquals("", url.queryParameterValue(1)); 1375 assertEquals("", url.queryParameterValue(2)); 1376 assertEquals(singletonList(""), url.queryParameterValues("foo")); 1377 assertEquals(singletonList(""), url.queryParameterValues("bar")); 1378 assertEquals(singletonList(""), url.queryParameterValues("baz")); 1379 } 1380 queryParametersWithRepeatedName()1381 @Test public void queryParametersWithRepeatedName() throws Exception { 1382 HttpUrl url = HttpUrl.parse("http://host/?foo[]=1&foo[]=2&foo[]=3"); 1383 assertEquals(3, url.querySize()); 1384 assertEquals(Collections.singleton("foo[]"), url.queryParameterNames()); 1385 assertEquals("1", url.queryParameterValue(0)); 1386 assertEquals("2", url.queryParameterValue(1)); 1387 assertEquals("3", url.queryParameterValue(2)); 1388 assertEquals(Arrays.asList("1", "2", "3"), url.queryParameterValues("foo[]")); 1389 } 1390 queryParameterLookupWithNonCanonicalEncoding()1391 @Test public void queryParameterLookupWithNonCanonicalEncoding() throws Exception { 1392 HttpUrl url = HttpUrl.parse("http://host/?%6d=m&+=%20"); 1393 assertEquals("m", url.queryParameterName(0)); 1394 assertEquals(" ", url.queryParameterName(1)); 1395 assertEquals("m", url.queryParameter("m")); 1396 assertEquals(" ", url.queryParameter(" ")); 1397 } 1398 roundTripBuilder()1399 @Test public void roundTripBuilder() throws Exception { 1400 HttpUrl url = new HttpUrl.Builder() 1401 .scheme("http") 1402 .username("%") 1403 .password("%") 1404 .host("host") 1405 .addPathSegment("%") 1406 .query("%") 1407 .fragment("%") 1408 .build(); 1409 assertEquals("http://%25:%25@host/%25?%25#%25", url.toString()); 1410 assertEquals("http://%25:%25@host/%25?%25#%25", url.newBuilder().build().toString()); 1411 assertEquals("http://%25:%25@host/%25?%25", url.resolve("").toString()); 1412 } 1413 1414 /** 1415 * Although HttpUrl prefers percent-encodings in uppercase, it should preserve the exact 1416 * structure of the original encoding. 1417 */ rawEncodingRetained()1418 @Test public void rawEncodingRetained() throws Exception { 1419 String urlString = "http://%6d%6D:%6d%6D@host/%6d%6D?%6d%6D#%6d%6D"; 1420 HttpUrl url = HttpUrl.parse(urlString); 1421 assertEquals("%6d%6D", url.encodedUsername()); 1422 assertEquals("%6d%6D", url.encodedPassword()); 1423 assertEquals("/%6d%6D", url.encodedPath()); 1424 assertEquals(Arrays.asList("%6d%6D"), url.encodedPathSegments()); 1425 assertEquals("%6d%6D", url.encodedQuery()); 1426 assertEquals("%6d%6D", url.encodedFragment()); 1427 assertEquals(urlString, url.toString()); 1428 assertEquals(urlString, url.newBuilder().build().toString()); 1429 assertEquals("http://%6d%6D:%6d%6D@host/%6d%6D?%6d%6D", url.resolve("").toString()); 1430 } 1431 clearFragment()1432 @Test public void clearFragment() throws Exception { 1433 HttpUrl url = HttpUrl.parse("http://host/#fragment") 1434 .newBuilder() 1435 .fragment(null) 1436 .build(); 1437 assertEquals("http://host/", url.toString()); 1438 assertEquals(null, url.fragment()); 1439 assertEquals(null, url.encodedFragment()); 1440 } 1441 clearEncodedFragment()1442 @Test public void clearEncodedFragment() throws Exception { 1443 HttpUrl url = HttpUrl.parse("http://host/#fragment") 1444 .newBuilder() 1445 .encodedFragment(null) 1446 .build(); 1447 assertEquals("http://host/", url.toString()); 1448 assertEquals(null, url.fragment()); 1449 assertEquals(null, url.encodedFragment()); 1450 } 1451 } 1452