1 // Copyright 2019 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.url; 6 7 import static org.mockito.ArgumentMatchers.any; 8 import static org.mockito.Mockito.doThrow; 9 10 import androidx.test.filters.SmallTest; 11 12 import org.junit.Assert; 13 import org.junit.Before; 14 import org.junit.Test; 15 import org.junit.runner.RunWith; 16 import org.mockito.Mock; 17 import org.mockito.MockitoAnnotations; 18 19 import org.chromium.base.test.BaseJUnit4ClassRunner; 20 import org.chromium.base.test.util.Batch; 21 import org.chromium.content_public.browser.test.NativeLibraryTestUtils; 22 23 import java.net.URISyntaxException; 24 25 /** 26 * Tests for {@link GURL}. GURL relies heavily on the native implementation, and the lion's share of 27 * the logic is tested there. This test is primarily to make sure everything is plumbed through 28 * correctly. 29 */ 30 @RunWith(BaseJUnit4ClassRunner.class) 31 @Batch(Batch.UNIT_TESTS) 32 public class GURLJavaTest { 33 @Mock GURL.Natives mGURLMocks; 34 35 @Before setUp()36 public void setUp() { 37 MockitoAnnotations.initMocks(this); 38 39 NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); 40 GURLJavaTestHelper.nativeInitializeICU(); 41 } 42 deepAssertEquals(GURL expected, GURL actual)43 /* package */ static void deepAssertEquals(GURL expected, GURL actual) { 44 Assert.assertEquals(expected, actual); 45 Assert.assertEquals(expected.getScheme(), actual.getScheme()); 46 Assert.assertEquals(expected.getUsername(), actual.getUsername()); 47 Assert.assertEquals(expected.getPassword(), actual.getPassword()); 48 Assert.assertEquals(expected.getHost(), actual.getHost()); 49 Assert.assertEquals(expected.getPort(), actual.getPort()); 50 Assert.assertEquals(expected.getPath(), actual.getPath()); 51 Assert.assertEquals(expected.getQuery(), actual.getQuery()); 52 Assert.assertEquals(expected.getRef(), actual.getRef()); 53 } 54 prependLengthToSerialization(String serialization)55 private String prependLengthToSerialization(String serialization) { 56 return Integer.toString(serialization.length()) + GURL.SERIALIZER_DELIMITER + serialization; 57 } 58 59 @SmallTest 60 @Test testGURLEquivalence()61 public void testGURLEquivalence() { 62 GURLJavaTestHelper.nativeTestGURLEquivalence(); 63 } 64 65 // Equivalent of GURLTest.Components 66 @SmallTest 67 @Test 68 @SuppressWarnings(value = "AuthLeak") testComponents()69 public void testComponents() { 70 GURL empty = new GURL(""); 71 Assert.assertTrue(empty.isEmpty()); 72 Assert.assertFalse(empty.isValid()); 73 74 GURL url = new GURL("http://user:pass@google.com:99/foo;bar?q=a#ref"); 75 Assert.assertFalse(url.isEmpty()); 76 Assert.assertTrue(url.isValid()); 77 Assert.assertTrue(url.getScheme().equals("http")); 78 79 Assert.assertEquals("http://user:pass@google.com:99/foo;bar?q=a#ref", url.getSpec()); 80 81 Assert.assertEquals("http", url.getScheme()); 82 Assert.assertEquals("user", url.getUsername()); 83 Assert.assertEquals("pass", url.getPassword()); 84 Assert.assertEquals("google.com", url.getHost()); 85 Assert.assertEquals("99", url.getPort()); 86 Assert.assertEquals("/foo;bar", url.getPath()); 87 Assert.assertEquals("q=a", url.getQuery()); 88 Assert.assertEquals("ref", url.getRef()); 89 90 // Test parsing userinfo with special characters. 91 GURL urlSpecialPass = new GURL("http://user:%40!$&'()*+,;=:@google.com:12345"); 92 Assert.assertTrue(urlSpecialPass.isValid()); 93 // GURL canonicalizes some delimiters. 94 Assert.assertEquals("%40!$&%27()*+,%3B%3D%3A", urlSpecialPass.getPassword()); 95 Assert.assertEquals("google.com", urlSpecialPass.getHost()); 96 Assert.assertEquals("12345", urlSpecialPass.getPort()); 97 } 98 99 // Equivalent of GURLTest.Empty 100 @SmallTest 101 @Test testEmpty()102 public void testEmpty() { 103 GURLJni.TEST_HOOKS.setInstanceForTesting(mGURLMocks); 104 doThrow(new RuntimeException("Should not need to parse empty URL")) 105 .when(mGURLMocks) 106 .init(any(), any()); 107 GURL url = new GURL(""); 108 Assert.assertFalse(url.isValid()); 109 Assert.assertEquals("", url.getSpec()); 110 111 Assert.assertEquals("", url.getScheme()); 112 Assert.assertEquals("", url.getUsername()); 113 Assert.assertEquals("", url.getPassword()); 114 Assert.assertEquals("", url.getHost()); 115 Assert.assertEquals("", url.getPort()); 116 Assert.assertEquals("", url.getPath()); 117 Assert.assertEquals("", url.getQuery()); 118 Assert.assertEquals("", url.getRef()); 119 GURLJni.TEST_HOOKS.setInstanceForTesting(null); 120 } 121 122 // Test that GURL and URI return the correct Origin. 123 @SmallTest 124 @Test 125 @SuppressWarnings(value = "AuthLeak") testOrigin()126 public void testOrigin() throws URISyntaxException { 127 final String kExpectedOrigin1 = "http://google.com:21/"; 128 final String kExpectedOrigin2 = ""; 129 GURL url1 = new GURL("filesystem:http://user:pass@google.com:21/blah#baz"); 130 GURL url2 = new GURL("javascript:window.alert(\"hello,world\");"); 131 URI uri = new URI("filesystem:http://user:pass@google.com:21/blah#baz"); 132 133 Assert.assertEquals(kExpectedOrigin1, url1.getOrigin().getSpec()); 134 Assert.assertEquals(kExpectedOrigin2, url2.getOrigin().getSpec()); 135 URI origin = uri.getOrigin(); 136 Assert.assertEquals(kExpectedOrigin1, origin.getSpec()); 137 } 138 139 @SmallTest 140 @Test testWideInput()141 public void testWideInput() throws URISyntaxException { 142 final String kExpectedSpec = "http://xn--1xa.com/"; 143 144 GURL url = new GURL("http://\u03C0.com"); 145 Assert.assertEquals(kExpectedSpec, url.getSpec()); 146 Assert.assertEquals("http", url.getScheme()); 147 Assert.assertEquals("", url.getUsername()); 148 Assert.assertEquals("", url.getPassword()); 149 Assert.assertEquals("xn--1xa.com", url.getHost()); 150 Assert.assertEquals("", url.getPort()); 151 Assert.assertEquals("/", url.getPath()); 152 Assert.assertEquals("", url.getQuery()); 153 Assert.assertEquals("", url.getRef()); 154 } 155 156 @SmallTest 157 @Test 158 @SuppressWarnings(value = "AuthLeak") testSerialization()159 public void testSerialization() { 160 GURL cases[] = { 161 // Common Standard URLs. 162 new GURL("https://www.google.com"), 163 new GURL("https://www.google.com/"), 164 new GURL("https://www.google.com/maps.htm"), 165 new GURL("https://www.google.com/maps/"), 166 new GURL("https://www.google.com/index.html"), 167 new GURL("https://www.google.com/index.html?q=maps"), 168 new GURL("https://www.google.com/index.html#maps/"), 169 new GURL("https://foo:bar@www.google.com/maps.htm"), 170 new GURL("https://www.google.com/maps/au/index.html"), 171 new GURL("https://www.google.com/maps/au/north"), 172 new GURL("https://www.google.com/maps/au/north/"), 173 new GURL("https://www.google.com/maps/au/index.html?q=maps#fragment/"), 174 new GURL("http://www.google.com:8000/maps/au/index.html?q=maps#fragment/"), 175 new GURL("https://www.google.com/maps/au/north/?q=maps#fragment"), 176 new GURL("https://www.google.com/maps/au/north?q=maps#fragment"), 177 // Less common standard URLs. 178 new GURL("filesystem:http://www.google.com/temporary/bar.html?baz=22"), 179 new GURL("file:///temporary/bar.html?baz=22"), 180 new GURL("ftp://foo/test/index.html"), 181 new GURL("gopher://foo/test/index.html"), 182 new GURL("ws://foo/test/index.html"), 183 // Non-standard, 184 new GURL("chrome://foo/bar.html"), 185 new GURL("httpa://foo/test/index.html"), 186 new GURL("blob:https://foo.bar/test/index.html"), 187 new GURL("about:blank"), 188 new GURL("data:foobar"), 189 new GURL("scheme:opaque_data"), 190 // Invalid URLs. 191 new GURL("foobar"), 192 // URLs containing the delimiter 193 new GURL("https://www.google.ca/" + GURL.SERIALIZER_DELIMITER + ",foo"), 194 new GURL("https://www.foo" + GURL.SERIALIZER_DELIMITER + "bar.com"), 195 }; 196 197 GURLJni.TEST_HOOKS.setInstanceForTesting(mGURLMocks); 198 doThrow( 199 new RuntimeException( 200 "Should not re-initialize for deserialization when the " 201 + "version hasn't changed.")) 202 .when(mGURLMocks) 203 .init(any(), any()); 204 for (GURL url : cases) { 205 GURL out = GURL.deserialize(url.serialize()); 206 deepAssertEquals(url, out); 207 } 208 GURLJni.TEST_HOOKS.setInstanceForTesting(null); 209 } 210 211 /** 212 * Tests that we re-parse the URL from the spec, which must always be the last token in the 213 * serialization, if the serialization version differs. 214 */ 215 @SmallTest 216 @Test testSerializationWithVersionSkew()217 public void testSerializationWithVersionSkew() { 218 GURL url = new GURL("https://www.google.com"); 219 String serialization = 220 (GURL.SERIALIZER_VERSION + 1) 221 + ",0,0,0,0,foo,https://url.bad,blah,0," 222 .replace(',', GURL.SERIALIZER_DELIMITER) 223 + url.getSpec(); 224 serialization = prependLengthToSerialization(serialization); 225 GURL out = GURL.deserialize(serialization); 226 deepAssertEquals(url, out); 227 } 228 229 /** Tests that fields that aren't visible to java code are correctly serialized. */ 230 @SmallTest 231 @Test testSerializationOfPrivateFields()232 public void testSerializationOfPrivateFields() { 233 String serialization = 234 GURL.SERIALIZER_VERSION 235 + ",true," 236 // Outer Parsed. 237 + "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,false,true," 238 // Inner Parsed. 239 + "17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,true,false," 240 + "chrome://foo/bar.html"; 241 serialization = serialization.replace(',', GURL.SERIALIZER_DELIMITER); 242 serialization = prependLengthToSerialization(serialization); 243 GURL url = GURL.deserialize(serialization); 244 Assert.assertEquals(url.serialize(), serialization); 245 } 246 247 /** Tests serialized GURL truncated by storage. */ 248 @SmallTest 249 @Test testTruncatedDeserialization()250 public void testTruncatedDeserialization() { 251 String serialization = "123,1,true,1,2,3,4,5,6,7,8,9,10"; 252 serialization = serialization.replace(',', GURL.SERIALIZER_DELIMITER); 253 GURL url = GURL.deserialize(serialization); 254 Assert.assertEquals(url, GURL.emptyGURL()); 255 } 256 257 /** Tests serialized GURL truncated by storage. */ 258 @SmallTest 259 @Test testCorruptedSerializations()260 public void testCorruptedSerializations() { 261 String serialization = new GURL("https://www.google.ca").serialize(); 262 // Replace the scheme length (5) with an extra delimiter. 263 String corruptedParsed = serialization.replace('5', GURL.SERIALIZER_DELIMITER); 264 GURL url = GURL.deserialize(corruptedParsed); 265 Assert.assertEquals(GURL.emptyGURL(), url); 266 267 String corruptedVersion = 268 serialization.replaceFirst(Integer.toString(GURL.SERIALIZER_VERSION), "x"); 269 url = GURL.deserialize(corruptedVersion); 270 Assert.assertEquals(GURL.emptyGURL(), url); 271 } 272 273 // Test that domainIs is hooked up correctly. 274 @SmallTest 275 @Test testDomainIs()276 public void testDomainIs() { 277 GURL url1 = new GURL("https://www.google.com"); 278 GURL url2 = new GURL("https://www.notgoogle.com"); 279 280 Assert.assertTrue(url1.domainIs("com")); 281 Assert.assertTrue(url2.domainIs("com")); 282 Assert.assertTrue(url1.domainIs("google.com")); 283 Assert.assertFalse(url2.domainIs("google.com")); 284 285 Assert.assertTrue(url1.domainIs("www.google.com")); 286 Assert.assertFalse(url1.domainIs("images.google.com")); 287 } 288 289 // Test that replaceComponents is hooked up correctly. 290 @SmallTest 291 @Test 292 @SuppressWarnings(value = "AuthLeak") testReplaceComponents()293 public void testReplaceComponents() { 294 GURL url = new GURL("http://user:pass@google.com:99/foo;bar?q=a#ref"); 295 296 GURL unchanged = url.replaceComponents(null, false, null, false); 297 Assert.assertEquals("user", unchanged.getUsername()); 298 Assert.assertEquals("pass", unchanged.getPassword()); 299 300 GURL cleared = url.replaceComponents(null, true, null, true); 301 Assert.assertTrue(cleared.getUsername().isEmpty()); 302 Assert.assertTrue(cleared.getPassword().isEmpty()); 303 304 GURL changed = url.replaceComponents("newusername", false, "newpassword", false); 305 Assert.assertEquals("newusername", changed.getUsername()); 306 Assert.assertEquals("newpassword", changed.getPassword()); 307 } 308 309 // Tests Mojom conversion. 310 @SmallTest 311 @Test testMojomConvertion()312 public void testMojomConvertion() { 313 // Valid: 314 Assert.assertEquals( 315 "https://www.google.com/", new GURL("https://www.google.com/").toMojom().url); 316 317 // Null: 318 Assert.assertEquals("", new GURL(null).toMojom().url); 319 320 // Empty: 321 Assert.assertEquals("", new GURL("").toMojom().url); 322 323 // Invalid: 324 Assert.assertEquals("", new GURL(new String(new byte[] {1, 1, 1})).toMojom().url); 325 326 // Too long. 327 Assert.assertEquals( 328 "", 329 new GURL("https://www.google.com/".concat("a".repeat(2 * 1024 * 1024))) 330 .toMojom() 331 .url); 332 } 333 } 334