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