From cd6228dd377b2a0caa02a1e6df92f3d9ae702a95 Mon Sep 17 00:00:00 2001 From: Adam Vartanian Date: Tue, 7 Nov 2017 12:22:23 +0000 Subject: [PATCH] Adjust Uri host parsing to use last instead of first @. Malformed authority segments can currently cause the parser to produce a hostname that doesn't match the hostname produced by the WHATWG URL parsing algorithm* used by browsers, which means that a URL could be seen as having a "safe" host when checked by an Android app but actually visit a different host when passed to a browser. The WHATWG URL parsing algorithm always produces a hostname based on the last @ in the authority segment, so we do the same. * https://url.spec.whatwg.org/#authority-state resets the "buffer", which is being used to build up the host name, each time an @ is found, so it has the effect of using the content between the final @ and the end of the authority section as the hostname. Bug: 68341964 Test: vogar android.net.UriTest (on NYC branch) Test: cts -m CtsNetTestCases (on NYC branch) Change-Id: Idca79f35a886de042c94d6ab66787c2e98ac8376 --- core/java/android/net/Uri.java | 6 +++--- core/tests/coretests/src/android/net/UriTest.java | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index 2099c3f9b02f..0f9c03ecb9ca 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -1060,7 +1060,7 @@ private String parseUserInfo() { return null; } - int end = authority.indexOf('@'); + int end = authority.lastIndexOf('@'); return end == NOT_FOUND ? null : authority.substring(0, end); } @@ -1084,7 +1084,7 @@ private String parseHost() { } // Parse out user info and then port. - int userInfoSeparator = authority.indexOf('@'); + int userInfoSeparator = authority.lastIndexOf('@'); int portSeparator = authority.indexOf(':', userInfoSeparator); String encodedHost = portSeparator == NOT_FOUND @@ -1110,7 +1110,7 @@ private int parsePort() { // Make sure we look for the port separtor *after* the user info // separator. We have URLs with a ':' in the user info. - int userInfoSeparator = authority.indexOf('@'); + int userInfoSeparator = authority.lastIndexOf('@'); int portSeparator = authority.indexOf(':', userInfoSeparator); if (portSeparator == NOT_FOUND) { diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java index cd4501788be3..49a73e05ba23 100644 --- a/core/tests/coretests/src/android/net/UriTest.java +++ b/core/tests/coretests/src/android/net/UriTest.java @@ -187,6 +187,11 @@ public void testAuthorityParsing() { uri = Uri.parse("http://localhost"); assertEquals("localhost", uri.getHost()); assertEquals(-1, uri.getPort()); + + uri = Uri.parse("http://a:a@example.com:a@example2.com/path"); + assertEquals("a:a@example.com:a@example2.com", uri.getAuthority()); + assertEquals("example2.com", uri.getHost()); + assertEquals(-1, uri.getPort()); } @SmallTest