1781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller/* 2781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * Copyright (C) 2015 Square, Inc. 3781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * 4781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License"); 5781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * you may not use this file except in compliance with the License. 6781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * You may obtain a copy of the License at 7781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * 8781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * http://www.apache.org/licenses/LICENSE-2.0 9781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * 10781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * Unless required by applicable law or agreed to in writing, software 11781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS, 12781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * See the License for the specific language governing permissions and 14781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * limitations under the License. 15781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller */ 16781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerpackage com.squareup.okhttp; 17781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 18781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport com.squareup.okhttp.UrlComponentEncodingTester.Component; 19781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport com.squareup.okhttp.UrlComponentEncodingTester.Encoding; 20781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport java.util.Arrays; 21781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport org.junit.Test; 22781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 23781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport static org.junit.Assert.assertEquals; 24781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 25781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerpublic final class HttpUrlTest { 26781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void parseTrimsAsciiWhitespace() throws Exception { 27781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl expected = HttpUrl.parse("http://host/"); 28781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(expected, HttpUrl.parse("http://host/\f\n\t \r")); // Leading. 29781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(expected, HttpUrl.parse("\r\n\f \thttp://host/")); // Trailing. 30781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(expected, HttpUrl.parse(" http://host/ ")); // Both. 31781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(expected, HttpUrl.parse(" http://host/ ")); // Both. 32781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(expected, HttpUrl.parse("http://host/").resolve(" ")); 33781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(expected, HttpUrl.parse("http://host/").resolve(" . ")); 34781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 35781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 36781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void parseDoesNotTrimOtherWhitespaceCharacters() throws Exception { 37781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller // Whitespace characters list from Google's Guava team: http://goo.gl/IcR9RD 38781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%0B", HttpUrl.parse("http://h/\u000b").path()); // line tabulation 39781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%1C", HttpUrl.parse("http://h/\u001c").path()); // information separator 4 40781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%1D", HttpUrl.parse("http://h/\u001d").path()); // information separator 3 41781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%1E", HttpUrl.parse("http://h/\u001e").path()); // information separator 2 42781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%1F", HttpUrl.parse("http://h/\u001f").path()); // information separator 1 43781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%C2%85", HttpUrl.parse("http://h/\u0085").path()); // next line 44781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%C2%A0", HttpUrl.parse("http://h/\u00a0").path()); // non-breaking space 45781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E1%9A%80", HttpUrl.parse("http://h/\u1680").path()); // ogham space mark 46781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E1%A0%8E", HttpUrl.parse("http://h/\u180e").path()); // mongolian vowel separator 47781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%80", HttpUrl.parse("http://h/\u2000").path()); // en quad 48781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%81", HttpUrl.parse("http://h/\u2001").path()); // em quad 49781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%82", HttpUrl.parse("http://h/\u2002").path()); // en space 50781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%83", HttpUrl.parse("http://h/\u2003").path()); // em space 51781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%84", HttpUrl.parse("http://h/\u2004").path()); // three-per-em space 52781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%85", HttpUrl.parse("http://h/\u2005").path()); // four-per-em space 53781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%86", HttpUrl.parse("http://h/\u2006").path()); // six-per-em space 54781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%87", HttpUrl.parse("http://h/\u2007").path()); // figure space 55781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%88", HttpUrl.parse("http://h/\u2008").path()); // punctuation space 56781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%89", HttpUrl.parse("http://h/\u2009").path()); // thin space 57781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%8A", HttpUrl.parse("http://h/\u200a").path()); // hair space 58781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%8B", HttpUrl.parse("http://h/\u200b").path()); // zero-width space 59781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%8C", HttpUrl.parse("http://h/\u200c").path()); // zero-width non-joiner 60781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%8D", HttpUrl.parse("http://h/\u200d").path()); // zero-width joiner 61781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%8E", HttpUrl.parse("http://h/\u200e").path()); // left-to-right mark 62781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%8F", HttpUrl.parse("http://h/\u200f").path()); // right-to-left mark 63781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%A8", HttpUrl.parse("http://h/\u2028").path()); // line separator 64781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%A9", HttpUrl.parse("http://h/\u2029").path()); // paragraph separator 65781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%80%AF", HttpUrl.parse("http://h/\u202f").path()); // narrow non-breaking space 66781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E2%81%9F", HttpUrl.parse("http://h/\u205f").path()); // medium mathematical space 67781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%E3%80%80", HttpUrl.parse("http://h/\u3000").path()); // ideographic space 68781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 69781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 70781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void scheme() throws Exception { 71781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("http://host/")); 72781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("Http://host/")); 73781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("http://host/")); 74781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("HTTP://host/")); 75781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("https://host/"), HttpUrl.parse("https://host/")); 76781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("https://host/"), HttpUrl.parse("HTTPS://host/")); 77781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("httpp://host/")); 78781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("0ttp://host/")); 79781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("ht+tp://host/")); 80781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("ht.tp://host/")); 81781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("ht-tp://host/")); 82781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("ht1tp://host/")); 83781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("httpss://host/")); 84781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 85781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 86781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void parseNoScheme() throws Exception { 87781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("//host")); 88781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("/path")); 89781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("path")); 90781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("?query")); 91781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("#fragment")); 92781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 93781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 94781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void resolveNoScheme() throws Exception { 95781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl base = HttpUrl.parse("http://host/a/b"); 96781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host2/"), base.resolve("//host2")); 97781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("/path")); 98781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/path"), base.resolve("path")); 99781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b?query"), base.resolve("?query")); 100781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b#fragment"), base.resolve("#fragment")); 101781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b"), base.resolve("")); 102781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("\\path")); 103781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 104781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 105781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void resolveUnsupportedScheme() throws Exception { 106781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl base = HttpUrl.parse("http://a/"); 107781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, base.resolve("ftp://b")); 108781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, base.resolve("ht+tp://b")); 109781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, base.resolve("ht-tp://b")); 110781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, base.resolve("ht.tp://b")); 111781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 112781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 113781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void resolveSchemeLikePath() throws Exception { 114781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl base = HttpUrl.parse("http://a/"); 115781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://a/http//b/"), base.resolve("http//b/")); 116781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://a/ht+tp//b/"), base.resolve("ht+tp//b/")); 117781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://a/ht-tp//b/"), base.resolve("ht-tp//b/")); 118781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://a/ht.tp//b/"), base.resolve("ht.tp//b/")); 119781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 120781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 121781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void parseAuthoritySlashCountDoesntMatter() throws Exception { 122781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:host/path")); 123781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:/host/path")); 124781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\host/path")); 125781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http://host/path")); 126781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\/host/path")); 127781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:/\\host/path")); 128781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\\\host/path")); 129781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:///host/path")); 130781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\//host/path")); 131781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:/\\/host/path")); 132781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http://\\host/path")); 133781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\\\/host/path")); 134781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:/\\\\host/path")); 135781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:\\\\\\host/path")); 136781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http:////host/path")); 137781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 138781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 139781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void resolveAuthoritySlashCountDoesntMatterWithDifferentScheme() throws Exception { 140781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl base = HttpUrl.parse("https://a/b/c"); 141781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:host/path")); 142781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/host/path")); 143781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\host/path")); 144781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http://host/path")); 145781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\/host/path")); 146781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\host/path")); 147781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\host/path")); 148781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:///host/path")); 149781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\//host/path")); 150781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\/host/path")); 151781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http://\\host/path")); 152781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\/host/path")); 153781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\\\host/path")); 154781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\\\host/path")); 155781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:////host/path")); 156781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 157781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 158781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void resolveAuthoritySlashCountMattersWithSameScheme() throws Exception { 159781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl base = HttpUrl.parse("http://a/b/c"); 160781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://a/b/host/path"), base.resolve("http:host/path")); 161781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://a/host/path"), base.resolve("http:/host/path")); 162781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://a/host/path"), base.resolve("http:\\host/path")); 163781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http://host/path")); 164781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\/host/path")); 165781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\host/path")); 166781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\host/path")); 167781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:///host/path")); 168781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\//host/path")); 169781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\/host/path")); 170781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http://\\host/path")); 171781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\/host/path")); 172781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:/\\\\host/path")); 173781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:\\\\\\host/path")); 174781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), base.resolve("http:////host/path")); 175781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 176781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 177781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void username() throws Exception { 178781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http://@host/path")); 179781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://user@host/path"), HttpUrl.parse("http://user@host/path")); 180781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 181781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 182781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void authorityWithMultipleAtSigns() throws Exception { 183781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://foo%40bar@baz/path"), 184781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://foo@bar@baz/path")); 185781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://foo:pass1%40bar%3Apass2@baz/path"), 186781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://foo:pass1@bar:pass2@baz/path")); 187781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 188781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 189781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void usernameAndPassword() throws Exception { 190781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://username:password@host/path"), 191781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://username:password@host/path")); 192781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://username@host/path"), 193781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://username:@host/path")); 194781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 195781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 196781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void passwordWithEmptyUsername() throws Exception { 197781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller // Chrome doesn't mind, but Firefox rejects URLs with empty usernames and non-empty passwords. 198781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/path"), HttpUrl.parse("http://:@host/path")); 199781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("password%40", HttpUrl.parse("http://:password@@host/path").password()); 200781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 201781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 202781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void unprintableCharactersArePercentEncoded() throws Exception { 203781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%00", HttpUrl.parse("http://host/\u0000").path()); 204781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%08", HttpUrl.parse("http://host/\u0008").path()); 205781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("/%EF%BF%BD", HttpUrl.parse("http://host/\ufffd").path()); 206781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 207781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 208781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void usernameCharacters() throws Exception { 209781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller new UrlComponentEncodingTester() 210781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .override(Encoding.PERCENT, '[', ']', '{', '}', '|', '^', '\'', ';', '=', '@') 211781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .override(Encoding.SKIP, ':', '/', '\\', '?', '#') 212781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .test(Component.USER); 213781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 214781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 215781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void passwordCharacters() throws Exception { 216781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller new UrlComponentEncodingTester() 217781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .override(Encoding.PERCENT, '[', ']', '{', '}', '|', '^', '\'', ':', ';', '=', '@') 218781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .override(Encoding.SKIP, '/', '\\', '?', '#') 219781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .test(Component.PASSWORD); 220781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 221781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 222781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void hostContainsIllegalCharacter() throws Exception { 223781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("http://\n/")); 224781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("http:// /")); 225781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("http://%20/")); 226781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 227781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 228781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void hostIpv6() throws Exception { 229781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller // Square braces are absent from host()... 230781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("::1", HttpUrl.parse("http://[::1]/").host()); 231781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 232781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller // ... but they're included in toString(). 233781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("http://[::1]/", HttpUrl.parse("http://[::1]/").toString()); 234781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 235781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller // IPv6 colons don't interfere with port numbers or passwords. 236781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(8080, HttpUrl.parse("http://[::1]:8080/").port()); 237781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("password", HttpUrl.parse("http://user:password@[::1]/").password()); 238781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("::1", HttpUrl.parse("http://user:password@[::1]:8080/").host()); 239781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 240781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller // Permit the contents of IPv6 addresses to be percent-encoded... 241781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("::1", HttpUrl.parse("http://[%3A%3A%31]/").host()); 242781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 243781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller // Including the Square braces themselves! (This is what Chrome does.) 244781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("::1", HttpUrl.parse("http://%5B%3A%3A1%5D/").host()); 245781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 246781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 247781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void port() throws Exception { 248781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/"), HttpUrl.parse("http://host:80/")); 249781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host:99/"), HttpUrl.parse("http://host:99/")); 250781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(65535, HttpUrl.parse("http://host:65535/").port()); 251781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("http://host:0/")); 252781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("http://host:65536/")); 253781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("http://host:-1/")); 254781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("http://host:a/")); 255781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("http://host:%39%39/")); 256781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 257781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 258781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void pathCharacters() throws Exception { 259781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller new UrlComponentEncodingTester() 260781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .override(Encoding.PERCENT, '^', '{', '}', '|') 261781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .override(Encoding.SKIP, '\\', '?', '#') 262781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .test(Component.PATH); 263781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 264781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 265781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void queryCharacters() throws Exception { 266781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller new UrlComponentEncodingTester() 267781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .override(Encoding.IDENTITY, '?', '`') 268781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .override(Encoding.PERCENT, '\'') 269781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .override(Encoding.SKIP, '#') 270781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .test(Component.QUERY); 271781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 272781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 273781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void fragmentCharacters() throws Exception { 274781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller new UrlComponentEncodingTester() 275781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .override(Encoding.IDENTITY, ' ', '"', '#', '<', '>', '?', '`') 276781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller .test(Component.FRAGMENT); 277781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller // TODO(jwilson): don't percent-encode non-ASCII characters. (But do encode control characters!) 278781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 279781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 280781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void relativePath() throws Exception { 281781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 282781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b/d/e/f"), base.resolve("d/e/f")); 283781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/d/e/f"), base.resolve("../../d/e/f")); 284781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("..")); 285781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/"), base.resolve("../..")); 286781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/"), base.resolve("../../..")); 287781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b/"), base.resolve(".")); 288781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("././..")); 289781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b/c/"), base.resolve("c/d/../e/../")); 290781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b/..e/"), base.resolve("..e/")); 291781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b/e/f../"), base.resolve("e/f../")); 292781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("%2E.")); 293781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/"), base.resolve(".%2E")); 294781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("%2E%2E")); 295781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("%2e.")); 296781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/"), base.resolve(".%2e")); 297781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/"), base.resolve("%2e%2e")); 298781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b/"), base.resolve("%2E")); 299781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b/"), base.resolve("%2e")); 300781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 301781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 302781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void pathWithBackslash() throws Exception { 303781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 304781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b/d/e/f"), base.resolve("d\\e\\f")); 305781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/d/e/f"), base.resolve("../..\\d\\e\\f")); 306781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/"), base.resolve("..\\..")); 307781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 308781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 309781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void relativePathWithSameScheme() throws Exception { 310781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl base = HttpUrl.parse("http://host/a/b/c"); 311781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/a/b/d/e/f"), base.resolve("http:d/e/f")); 312781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(HttpUrl.parse("http://host/d/e/f"), base.resolve("http:../../d/e/f")); 313781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 314781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 315781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void decodeUsername() { 316781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("user", HttpUrl.parse("http://user@host/").decodeUsername()); 317781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("\uD83C\uDF69", HttpUrl.parse("http://%F0%9F%8D%A9@host/").decodeUsername()); 318781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 319781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 320781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void decodePassword() { 321781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("password", HttpUrl.parse("http://user:password@host/").decodePassword()); 322781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(null, HttpUrl.parse("http://user:@host/").decodePassword()); 323781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals("\uD83C\uDF69", HttpUrl.parse("http://user:%F0%9F%8D%A9@host/").decodePassword()); 324781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 325781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 326781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void decodeSlashCharacterInDecodedPathSegment() { 327781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("a/b/c"), 328781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/a%2Fb%2Fc").decodePathSegments()); 329781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 330781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 331781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void decodeEmptyPathSegments() { 332781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList(""), 333781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/").decodePathSegments()); 334781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 335781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 336781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void percentDecode() throws Exception { 337781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("\u0000"), 338781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/%00").decodePathSegments()); 339781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("a", "\u2603", "c"), 340781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/a/%E2%98%83/c").decodePathSegments()); 341781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("a", "\uD83C\uDF69", "c"), 342781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/a/%F0%9F%8D%A9/c").decodePathSegments()); 343781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("a", "b", "c"), 344781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/a/%62/c").decodePathSegments()); 345781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("a", "z", "c"), 346781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/a/%7A/c").decodePathSegments()); 347781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("a", "z", "c"), 348781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/a/%7a/c").decodePathSegments()); 349781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 350781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 351781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void malformedPercentEncoding() { 352781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("a%f", "b"), 353781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/a%f/b").decodePathSegments()); 354781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("%", "b"), 355781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/%/b").decodePathSegments()); 356781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("%"), 357781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/%").decodePathSegments()); 358781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 359781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller 360781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller @Test public void malformedUtf8Encoding() { 361781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller // Replace a partial UTF-8 sequence with the Unicode replacement character. 362781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller assertEquals(Arrays.asList("a", "\ufffdx", "c"), 363781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller HttpUrl.parse("http://host/a/%E2%98x/c").decodePathSegments()); 364781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller } 365781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller} 366