Merge cherrypicks of [4647037, 4647038, 4647883, 4647039, 4647933, 4648530, 4648550, 4648551, 4648552, 4648553, 4646931, 4646932, 4646933, 4646934, 4648391, 4647976, 4647977, 4647978, 4647526, 4646972, 4646935, 4646936, 4646937, 4646938, 4646939, 4646940, 4646941, 4648392, 4647509, 4648630, 4648631, 4647934] into pi-release-2

Change-Id: Ic9a8061d929dd9b09f5c217889fe19dc5e09e8c6
diff --git a/luni/src/test/java/libcore/java/net/URLTest.java b/luni/src/test/java/libcore/java/net/URLTest.java
index 1ff9b33..066442e 100644
--- a/luni/src/test/java/libcore/java/net/URLTest.java
+++ b/luni/src/test/java/libcore/java/net/URLTest.java
@@ -582,6 +582,26 @@
         assertEquals("http://host/a/c", url.toString()); // RI doesn't canonicalize
     }
 
+    public void testPathContainsBackslash() throws Exception {
+        URL url = new URL("http://host\\path@foo");
+        assertEquals("\\path@foo", url.getPath());
+        assertEquals("host", url.getHost());
+    }
+
+    public void testQueryContainsForwardSlash() throws Exception {
+        URL url = new URL("http://host?query/foo");
+        assertEquals("", url.getPath());
+        assertEquals("host", url.getHost());
+        assertEquals("query/foo", url.getQuery());
+    }
+
+    public void testFragmentContainsForwardSlash() throws Exception {
+        URL url = new URL("http://host#fragment/foo");
+        assertEquals("", url.getPath());
+        assertEquals("host", url.getHost());
+        assertEquals("fragment/foo", url.getRef());
+    }
+
     public void testRelativePathAndFragment() throws Exception {
         URL base = new URL("http://host/file");
         assertEquals("http://host/another#fragment", new URL(base, "another#fragment").toString());
diff --git a/ojluni/src/main/java/java/net/URLStreamHandler.java b/ojluni/src/main/java/java/net/URLStreamHandler.java
index d5380c1..01862f6 100644
--- a/ojluni/src/main/java/java/net/URLStreamHandler.java
+++ b/ojluni/src/main/java/java/net/URLStreamHandler.java
@@ -167,12 +167,25 @@
         if (!isUNCName && (start <= limit - 2) && (spec.charAt(start) == '/') &&
             (spec.charAt(start + 1) == '/')) {
             start += 2;
+            // BEGIN Android-changed: Check for all hostname termination chars. http://b/110955991
+            /*
             i = spec.indexOf('/', start);
             if (i < 0 || i > limit) {
                 i = spec.indexOf('?', start);
                 if (i < 0 || i > limit)
                     i = limit;
             }
+            */
+            LOOP: for (i = start; i < limit; i++) {
+                switch (spec.charAt(i)) {
+                    case '/':  // Start of path
+                    case '\\': // Start of path - see https://url.spec.whatwg.org/#host-state
+                    case '?':  // Start of query
+                    case '#':  // Start of fragment
+                        break LOOP;
+                }
+            }
+            // END Android-changed: Check for all hostname termination chars. http://b/110955991
 
             host = authority = spec.substring(start, i);
 
@@ -266,7 +279,9 @@
 
         // Parse the file path if any
         if (start < limit) {
-            if (spec.charAt(start) == '/') {
+            // Android-changed: Check for all hostname termination chars. http://b/110955991
+            // if (spec.charAt(start) == '/') {
+            if (spec.charAt(start) == '/' || spec.charAt(start) == '\\') {
                 path = spec.substring(start, limit);
             } else if (path != null && path.length() > 0) {
                 isRelPath = true;