Merge changes I0f3ea18f,I7204e8ab

* changes:
  Update sun.net to OpenJDK8u121-b13.
  Add missing / improve existing change markers in sun.net.
diff --git a/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java b/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
index 2f5400c..6588e2d 100644
--- a/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
@@ -42,6 +42,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.Random;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Semaphore;
@@ -55,10 +56,10 @@
 public class FtpURLConnectionTest extends TestCase {
 
     private static final String FILE_PATH = "test/file/for/FtpURLConnectionTest.txt";
-    private static final String USER = "user";
-    private static final String PASSWORD = "password";
     private static final String SERVER_HOSTNAME = "localhost";
-    private static final String USER_HOME_DIR = "/home/user";
+    private static final String VALID_USER = "user";
+    private static final String VALID_PASSWORD = "password";
+    private static final String VALID_USER_HOME_DIR = "/home/user";
 
     private FakeFtpServer fakeFtpServer;
     private UnixFakeFileSystem fileSystem;
@@ -68,10 +69,11 @@
         super.setUp();
         fakeFtpServer = new FakeFtpServer();
         fakeFtpServer.setServerControlPort(0 /* allocate port number automatically */);
-        fakeFtpServer.addUserAccount(new UserAccount(USER, PASSWORD, USER_HOME_DIR));
+        fakeFtpServer.addUserAccount(new UserAccount(VALID_USER, VALID_PASSWORD,
+                VALID_USER_HOME_DIR));
         fileSystem = new UnixFakeFileSystem();
         fakeFtpServer.setFileSystem(fileSystem);
-        fileSystem.add(new DirectoryEntry(USER_HOME_DIR));
+        fileSystem.add(new DirectoryEntry(VALID_USER_HOME_DIR));
         fakeFtpServer.start();
     }
 
@@ -83,17 +85,45 @@
 
     public void testInputUrl() throws Exception {
         byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
-        URL fileUrl = addFileEntry(FILE_PATH, fileContents);
+        addFileEntry(FILE_PATH, fileContents);
+        URL fileUrl = getFileUrlWithCredentials(VALID_USER, VALID_PASSWORD, FILE_PATH);
         URLConnection connection = fileUrl.openConnection();
         assertContents(fileContents, connection.getInputStream());
     }
 
+    public void testInputUrl_invalidUserOrPassword() throws Exception {
+        checkInputUrl_invalidUserOrPassword("wrong_user", VALID_PASSWORD);
+        checkInputUrl_invalidUserOrPassword(VALID_USER, "wrong password");
+    }
+
+    public void testInputUrl_missingPassword() throws Exception {
+        URL noPasswordUrl = getFileUrlWithCredentials(VALID_USER, null, FILE_PATH);
+        URLConnection noPasswordConnection = noPasswordUrl.openConnection();
+        try {
+            noPasswordConnection.getInputStream();
+            fail();
+        } catch (IOException expected) {
+        }
+    }
+
+    private void checkInputUrl_invalidUserOrPassword(String user, String password)
+            throws IOException {
+        URL fileUrl = getFileUrlWithCredentials(user, password, FILE_PATH);
+        URLConnection connection = fileUrl.openConnection();
+        try {
+            connection.getInputStream();
+            fail();
+        } catch (sun.net.ftp.FtpLoginException expected) {
+            assertEquals("Invalid username/password", expected.getMessage());
+        }
+    }
+
     public void testOutputUrl() throws Exception {
         byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
         addFileEntry("test/output-url/existing file.txt", fileContents);
         byte[] newFileContents = "contents of brand new file".getBytes(UTF_8);
         String filePath = "test/output-url/file that is newly created.txt";
-        URL fileUrl = new URL(getFileUrlString(filePath));
+        URL fileUrl = getFileUrlWithCredentials(VALID_USER, VALID_PASSWORD, filePath);
         URLConnection connection = fileUrl.openConnection();
         connection.setDoInput(false);
         connection.setDoOutput(true);
@@ -218,7 +248,7 @@
     }
 
     private InputStream openFileSystemContents(String fileName) throws IOException {
-        String fullFileName = USER_HOME_DIR + "/" + fileName;
+        String fullFileName = VALID_USER_HOME_DIR + "/" + fileName;
         FileEntry entry = (FileEntry) fileSystem.getEntry(fullFileName);
         assertNotNull("File must exist with name " + fullFileName, entry);
         return entry.createInputStream();
@@ -243,18 +273,13 @@
         }
     }
 
-    private String getFileUrlString(String filePath) {
+    private URL getFileUrlWithCredentials(String user, String password, String filePath) {
+        Objects.requireNonNull(user);
+        Objects.requireNonNull(filePath);
         int serverPort = fakeFtpServer.getServerControlPort();
-        String urlString = String.format(Locale.US, "ftp://%s:%s@%s:%s/%s",
-                USER, PASSWORD, SERVER_HOSTNAME, serverPort, filePath);
-        return urlString;
-    }
-
-    private URL addFileEntry(String filePath, byte[] fileContents) {
-        FileEntry fileEntry = new FileEntry(USER_HOME_DIR + "/" + filePath);
-        fileEntry.setContents(fileContents);
-        fileSystem.add(fileEntry);
-        String urlString = getFileUrlString(filePath);
+        String credentials = user + (password == null ? "" : (":" + password));
+        String urlString = String.format(Locale.US, "ftp://%s@%s:%s/%s",
+                credentials, SERVER_HOSTNAME, serverPort, filePath);
         try {
             return new URL(urlString);
         } catch (MalformedURLException e) {
@@ -263,6 +288,13 @@
         }
     }
 
+    private URL addFileEntry(String filePath, byte[] fileContents) {
+        FileEntry fileEntry = new FileEntry(VALID_USER_HOME_DIR + "/" + filePath);
+        fileEntry.setContents(fileContents);
+        fileSystem.add(fileEntry);
+        return getFileUrlWithCredentials(VALID_USER, VALID_PASSWORD, filePath);
+    }
+
     /**
      * A {@link ProxySelector} that selects the same (given) Proxy for all URIs.
      */
diff --git a/luni/src/test/java/libcore/sun/net/util/IPAddressUtilTest.java b/luni/src/test/java/libcore/sun/net/util/IPAddressUtilTest.java
new file mode 100644
index 0000000..9294309
--- /dev/null
+++ b/luni/src/test/java/libcore/sun/net/util/IPAddressUtilTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.sun.net.util;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+import static sun.net.util.IPAddressUtil.textToNumericFormatV4;
+
+public class IPAddressUtilTest extends TestCase {
+
+    public void test_textToNumericFormatV4_valid() {
+        assertBytesEquals(0, 0, 0, 0, textToNumericFormatV4("0.0.0.0"));
+        assertBytesEquals(1, 2, 3, 4, textToNumericFormatV4("1.2.3.4"));
+        assertBytesEquals(255, 255, 255, 255, textToNumericFormatV4("255.255.255.255"));
+        assertBytesEquals(123, 23, 255, 37, textToNumericFormatV4("123.23.255.37"));
+        assertBytesEquals(192, 168, 0, 42, textToNumericFormatV4("192.168.0.42"));
+    }
+
+    public void test_textToNumericFormatV4_invalid() {
+        // Wrong number of components
+        assertNull(textToNumericFormatV4("1"));
+        assertNull(textToNumericFormatV4("1.2"));
+        assertNull(textToNumericFormatV4("1.2.3"));
+        assertNull(textToNumericFormatV4("1.2.3.4.5"));
+
+        // Extra dots in various places
+        assertNull(textToNumericFormatV4("1..3.4"));
+        assertNull(textToNumericFormatV4("1..2.3.4"));
+        assertNull(textToNumericFormatV4(".1.2.3"));
+        assertNull(textToNumericFormatV4(".1.2.3.4"));
+        assertNull(textToNumericFormatV4("1.2.3.4."));
+
+        // Out of bounds values
+        assertNull(textToNumericFormatV4("256.2.3.4"));
+        assertNull(textToNumericFormatV4("1.256.3.4"));
+        assertNull(textToNumericFormatV4("1.2.256.4"));
+        assertNull(textToNumericFormatV4("1.2.3.256"));
+        assertNull(textToNumericFormatV4("1.-2.3.4"));
+    }
+
+    private static void assertBytesEquals(int a, int b, int c, int d, byte[] actual) {
+        byte[] expected = new byte[] { (byte) a, (byte) b, (byte) c, (byte) d };
+        assertTrue("Expected " + Arrays.toString(expected) + ", got " + Arrays.toString(actual),
+                Arrays.equals(expected, actual));
+    }
+
+}
diff --git a/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java b/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java
index 94005e0..0b58a99 100644
--- a/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java
+++ b/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java
@@ -43,6 +43,17 @@
  */
 public class ExtendedOptionsImpl {
 
+    // Android-removed: System.loadLibrary("net") is not available on Android.
+    /*
+    static {
+        AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
+            System.loadLibrary("net");
+            return null;
+        });
+        init();
+    }
+    */
+
     private ExtendedOptionsImpl() {}
 
     public static void checkSetOptionPermission(SocketOption<?> option) {
@@ -71,6 +82,9 @@
         }
     }
 
+    // Android-removed: Native initialization logic that doesn't exist on Android.
+    // private static native void init();
+
     /*
      * Extension native implementations
      *
diff --git a/ojluni/src/main/java/sun/net/NetHooks.java b/ojluni/src/main/java/sun/net/NetHooks.java
index 05100d9..153096e 100644
--- a/ojluni/src/main/java/sun/net/NetHooks.java
+++ b/ojluni/src/main/java/sun/net/NetHooks.java
@@ -38,43 +38,45 @@
 
 public final class NetHooks {
 
-    // Android-removed: No SDP support.
-    // /**
-    //  * A provider with hooks to allow sockets be converted prior to binding or
-    //  * connecting a TCP socket.
-    //  *
-    //  * <p> Concrete implementations of this class should define a zero-argument
-    //  * constructor and implement the abstract methods specified below.
-    //  */
-    //  public static abstract class Provider {
-    //     /**
-    //      * Initializes a new instance of this class.
-    //      */
-    //     protected Provider() {}
-    //
-    //    /**
-    //      * Invoked prior to binding a TCP socket.
-    //      */
-    //     public abstract void implBeforeTcpBind(FileDescriptor fdObj,
-    //                                            InetAddress address,
-    //                                            int port)
-    //         throws IOException;
-    //
-    //     /**
-    //      * Invoked prior to connecting an unbound TCP socket.
-    //      */
-    //     public abstract void implBeforeTcpConnect(FileDescriptor fdObj,
-    //                                              InetAddress address,
-    //                                              int port)
-    //         throws IOException;
-    // }
+    // Android-removed: Android doesn't support Session Description Protocol (SDP).
+    /*
+    /**
+     * A provider with hooks to allow sockets be converted prior to binding or
+     * connecting a TCP socket.
+     *
+     * <p> Concrete implementations of this class should define a zero-argument
+     * constructor and implement the abstract methods specified below.
+     *
+    public static abstract class Provider {
+        /**
+         * Initializes a new instance of this class.
+         *
+        protected Provider() {}
+
+        /**
+         * Invoked prior to binding a TCP socket.
+         *
+        public abstract void implBeforeTcpBind(FileDescriptor fdObj,
+                                               InetAddress address,
+                                               int port)
+            throws IOException;
+
+        /**
+         * Invoked prior to connecting an unbound TCP socket.
+         *
+        public abstract void implBeforeTcpConnect(FileDescriptor fdObj,
+                                                 InetAddress address,
+                                                 int port)
+            throws IOException;
+    }
+    */
 
     /**
      * For now, we load the SDP provider on Solaris. In the future this may
      * be changed to use the ServiceLoader facility to allow the deployment of
      * other providers.
      */
-    // Android-removed: No SDP support
+    // Android-removed: Android doesn't support Session Description Protocol (SDP).
     // private static final Provider provider = new sun.net.sdp.SdpProvider();
 
     /**
@@ -85,7 +87,7 @@
                                      int port)
         throws IOException
     {
-        // Android-removed: No SDP support
+        // Android-removed: Android doesn't support Session Description Protocol (SDP).
         // provider.implBeforeTcpBind(fdObj, address, port);
     }
 
diff --git a/ojluni/src/main/java/sun/net/NetworkClient.java b/ojluni/src/main/java/sun/net/NetworkClient.java
index 1b311bc..0f76bf6 100644
--- a/ojluni/src/main/java/sun/net/NetworkClient.java
+++ b/ojluni/src/main/java/sun/net/NetworkClient.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -139,7 +139,7 @@
                                         serverSocket.getOutputStream()),
                                         true, encoding);
         } catch (UnsupportedEncodingException e) {
-            throw new InternalError(encoding +"encoding not found");
+            throw new InternalError(encoding +"encoding not found", e);
         }
         serverInput = new BufferedInputStream(serverSocket.getInputStream());
     }
@@ -244,7 +244,7 @@
      * Sets the read timeout.
      *
      * Note: Public URLConnection (and protocol specific implementations)
-     * protect against negative timeout values being set. This implemenation,
+     * protect against negative timeout values being set. This implementation,
      * and protocol specific implementations, use -1 to represent the default
      * read timeout.
      *
diff --git a/ojluni/src/main/java/sun/net/TelnetOutputStream.java b/ojluni/src/main/java/sun/net/TelnetOutputStream.java
index 432e975..74f6c9c 100644
--- a/ojluni/src/main/java/sun/net/TelnetOutputStream.java
+++ b/ojluni/src/main/java/sun/net/TelnetOutputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -81,7 +81,7 @@
     }
 
     /**
-     * set the stickyCRLF flag. Tells wether the terminal considers CRLF as a single
+     * set the stickyCRLF flag. Tells whether the terminal considers CRLF as a single
      * char.
      *
      * @param   on      the <code>boolean</code> to set the flag to.
diff --git a/ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java b/ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java
index 6ba9b9a..fac57e2 100644
--- a/ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java
+++ b/ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,13 +33,14 @@
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.StringTokenizer;
 import java.io.IOException;
-import sun.misc.RegexpPool;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.StringJoiner;
+import java.util.regex.Pattern;
 import sun.net.NetProperties;
 import sun.net.SocksProxy;
+import static java.util.regex.Pattern.quote;
 
 /**
  * Supports proxy settings using system properties This proxy selector
@@ -87,9 +88,31 @@
 
     private static boolean hasSystemProxies = false;
 
+    // Android-removed: Nonfunctional init logic: "net" library does not exist on Android.
+    /*
+    static {
+        final String key = "java.net.useSystemProxies";
+        Boolean b = AccessController.doPrivileged(
+            new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return NetProperties.getBoolean(key);
+                }});
+        if (b != null && b.booleanValue()) {
+            java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<Void>() {
+                    public Void run() {
+                        System.loadLibrary("net");
+                        return null;
+                    }
+                });
+            hasSystemProxies = init();
+        }
+    }
+    */
+
     /**
      * How to deal with "non proxy hosts":
-     * since we do have to generate a RegexpPool we don't want to do that if
+     * since we do have to generate a pattern we don't want to do that if
      * it's not necessary. Therefore we do cache the result, on a per-protocol
      * basis, and change it only when the "source", i.e. the system property,
      * did change.
@@ -101,17 +124,19 @@
         static final String defStringVal = "localhost|127.*|[::1]|0.0.0.0|[::0]";
 
         String hostsSource;
-        RegexpPool hostsPool;
+        Pattern pattern;
         final String property;
         final String defaultVal;
         static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null, defStringVal);
         static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null, defStringVal);
+        static NonProxyInfo socksNonProxyInfo = new NonProxyInfo("socksNonProxyHosts", null, null, defStringVal);
+        // Android-changed: Different NonProxyInfo flags for https hosts vs. http.
         static NonProxyInfo httpsNonProxyInfo = new NonProxyInfo("https.nonProxyHosts", null, null, defStringVal);
 
-        NonProxyInfo(String p, String s, RegexpPool pool, String d) {
+        NonProxyInfo(String p, String s, Pattern pattern, String d) {
             property = p;
             hostsSource = s;
-            hostsPool = pool;
+            this.pattern = pattern;
             defaultVal = d;
         }
     }
@@ -166,11 +191,13 @@
         } else if ("https".equalsIgnoreCase(protocol)) {
             // HTTPS uses the same property as HTTP, for backward
             // compatibility
-            //
-            // Android-changed: Allow a different set of flags for https hosts.
+            // Android-changed: Different NonProxyInfo flags for https hosts vs. http.
+            // pinfo = NonProxyInfo.httpNonProxyInfo;
             pinfo = NonProxyInfo.httpsNonProxyInfo;
         } else if ("ftp".equalsIgnoreCase(protocol)) {
             pinfo = NonProxyInfo.ftpNonProxyInfo;
+        } else if ("socket".equalsIgnoreCase(protocol)) {
+            pinfo = NonProxyInfo.socksNonProxyInfo;
         }
 
         /**
@@ -214,7 +241,20 @@
                                  * settings (Gnome & Windows) if we were
                                  * instructed to.
                                  */
-                                // Android-changed, hasSystemProxies is always false
+                                // Android-removed: Dead code, hasSystemProxies is always false.
+                                /*
+                                if (hasSystemProxies) {
+                                    String sproto;
+                                    if (proto.equalsIgnoreCase("socket"))
+                                        sproto = "socks";
+                                    else
+                                        sproto = proto;
+                                    Proxy sproxy = getSystemProxy(sproto, urlhost);
+                                    if (sproxy != null) {
+                                        return sproxy;
+                                    }
+                                }
+                                */
                                 return Proxy.NO_PROXY;
                             }
                             // If a Proxy Host is defined for that protocol
@@ -227,7 +267,7 @@
                                             nphosts = nprop.defaultVal;
                                         } else {
                                             nprop.hostsSource = null;
-                                            nprop.hostsPool = null;
+                                            nprop.pattern = null;
                                         }
                                     } else if (nphosts.length() != 0) {
                                         // add the required default patterns
@@ -238,20 +278,11 @@
                                     }
                                     if (nphosts != null) {
                                         if (!nphosts.equals(nprop.hostsSource)) {
-                                            RegexpPool pool = new RegexpPool();
-                                            StringTokenizer st = new StringTokenizer(nphosts, "|", false);
-                                            try {
-                                                while (st.hasMoreTokens()) {
-                                                    pool.add(st.nextToken().toLowerCase(), Boolean.TRUE);
-                                                }
-                                            } catch (sun.misc.REException ex) {
-                                            }
-                                            nprop.hostsPool = pool;
+                                            nprop.pattern = toPattern(nphosts);
                                             nprop.hostsSource = nphosts;
                                         }
                                     }
-                                    if (nprop.hostsPool != null &&
-                                        nprop.hostsPool.match(urlhost) != null) {
+                                    if (shouldNotUseProxyFor(nprop.pattern, urlhost)) {
                                         return Proxy.NO_PROXY;
                                     }
                                 }
@@ -324,4 +355,55 @@
             return -1;
         }
     }
+
+    // Android-removed: Native logic not available/used on Android.
+    /*
+    private native static boolean init();
+    private synchronized native Proxy getSystemProxy(String protocol, String host);
+    */
+
+    /**
+     * @return {@code true} if given this pattern for non-proxy hosts and this
+     *         urlhost the proxy should NOT be used to access this urlhost
+     */
+    static boolean shouldNotUseProxyFor(Pattern pattern, String urlhost) {
+        if (pattern == null || urlhost.isEmpty())
+            return false;
+        boolean matches = pattern.matcher(urlhost).matches();
+        return matches;
+    }
+
+    /**
+     * @param mask non-null mask
+     * @return {@link java.util.regex.Pattern} corresponding to this mask
+     *         or {@code null} in case mask should not match anything
+     */
+    static Pattern toPattern(String mask) {
+        boolean disjunctionEmpty = true;
+        StringJoiner joiner = new StringJoiner("|");
+        for (String disjunct : mask.split("\\|")) {
+            if (disjunct.isEmpty())
+                continue;
+            disjunctionEmpty = false;
+            String regex = disjunctToRegex(disjunct.toLowerCase());
+            joiner.add(regex);
+        }
+        return disjunctionEmpty ? null : Pattern.compile(joiner.toString());
+    }
+
+    /**
+     * @param disjunct non-null mask disjunct
+     * @return java regex string corresponding to this mask
+     */
+    static String disjunctToRegex(String disjunct) {
+        String regex;
+        if (disjunct.startsWith("*")) {
+            regex = ".*" + quote(disjunct.substring(1));
+        } else if (disjunct.endsWith("*")) {
+            regex = quote(disjunct.substring(0, disjunct.length() - 1)) + ".*";
+        } else {
+            regex = quote(disjunct);
+        }
+        return regex;
+    }
 }
diff --git a/ojluni/src/main/java/sun/net/util/IPAddressUtil.java b/ojluni/src/main/java/sun/net/util/IPAddressUtil.java
index 7ca0f12..4a58e5f 100644
--- a/ojluni/src/main/java/sun/net/util/IPAddressUtil.java
+++ b/ojluni/src/main/java/sun/net/util/IPAddressUtil.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,89 +37,84 @@
      * @param src a String representing an IPv4 address in standard format
      * @return a byte array representing the IPv4 numeric address
      */
+    @SuppressWarnings("fallthrough")
     public static byte[] textToNumericFormatV4(String src)
     {
-        if (src.length() == 0) {
+        byte[] res = new byte[INADDR4SZ];
+
+        long tmpValue = 0;
+        int currByte = 0;
+        boolean newOctet = true;
+
+        int len = src.length();
+        if (len == 0 || len > 15) {
             return null;
         }
-
-        byte[] res = new byte[INADDR4SZ];
-        String[] s = src.split("\\.", -1);
-        long val;
-        try {
-            switch(s.length) {
-            // BEGIN Android-removed
-            /*
-            case 1:
-                // When only one part is given, the value is stored directly in
-                // the network address without any byte rearrangement.
-
-                val = Long.parseLong(s[0]);
-                if (val < 0 || val > 0xffffffffL)
+        /*
+         * When only one part is given, the value is stored directly in
+         * the network address without any byte rearrangement.
+         *
+         * When a two part address is supplied, the last part is
+         * interpreted as a 24-bit quantity and placed in the right
+         * most three bytes of the network address. This makes the
+         * two part address format convenient for specifying Class A
+         * network addresses as net.host.
+         *
+         * When a three part address is specified, the last part is
+         * interpreted as a 16-bit quantity and placed in the right
+         * most two bytes of the network address. This makes the
+         * three part address format convenient for specifying
+         * Class B net- work addresses as 128.net.host.
+         *
+         * When four parts are specified, each is interpreted as a
+         * byte of data and assigned, from left to right, to the
+         * four bytes of an IPv4 address.
+         *
+         * We determine and parse the leading parts, if any, as single
+         * byte values in one pass directly into the resulting byte[],
+         * then the remainder is treated as a 8-to-32-bit entity and
+         * translated into the remaining bytes in the array.
+         */
+        for (int i = 0; i < len; i++) {
+            char c = src.charAt(i);
+            if (c == '.') {
+                if (newOctet || tmpValue < 0 || tmpValue > 0xff || currByte == 3) {
                     return null;
-                res[0] = (byte) ((val >> 24) & 0xff);
-                res[1] = (byte) (((val & 0xffffff) >> 16) & 0xff);
-                res[2] = (byte) (((val & 0xffff) >> 8) & 0xff);
-                res[3] = (byte) (val & 0xff);
-                break;
-            case 2:
-                // When a two part address is supplied, the last part is
-                // interpreted as a 24-bit quantity and placed in the right
-                // most three bytes of the network address. This makes the
-                // two part address format convenient for specifying Class A
-                // network addresses as net.host.
-
-                val = Integer.parseInt(s[0]);
-                if (val < 0 || val > 0xff)
-                    return null;
-                res[0] = (byte) (val & 0xff);
-                val = Integer.parseInt(s[1]);
-                if (val < 0 || val > 0xffffff)
-                    return null;
-                res[1] = (byte) ((val >> 16) & 0xff);
-                res[2] = (byte) (((val & 0xffff) >> 8) &0xff);
-                res[3] = (byte) (val & 0xff);
-                break;
-            case 3:
-                //
-                // When a three part address is specified, the last part is
-                // interpreted as a 16-bit quantity and placed in the right
-                // most two bytes of the network address. This makes the
-                // three part address format convenient for specifying
-                // Class B net- work addresses as 128.net.host.
-                for (int i = 0; i < 2; i++) {
-                    val = Integer.parseInt(s[i]);
-                    if (val < 0 || val > 0xff)
-                        return null;
-                    res[i] = (byte) (val & 0xff);
                 }
-                val = Integer.parseInt(s[2]);
-                if (val < 0 || val > 0xffff)
+                res[currByte++] = (byte) (tmpValue & 0xff);
+                tmpValue = 0;
+                newOctet = true;
+            } else {
+                int digit = Character.digit(c, 10);
+                if (digit < 0) {
                     return null;
-                res[2] = (byte) ((val >> 8) & 0xff);
-                res[3] = (byte) (val & 0xff);
-                break;
-            */
-            // END Android-removed
-            case 4:
-                /*
-                 * When four parts are specified, each is interpreted as a
-                 * byte of data and assigned, from left to right, to the
-                 * four bytes of an IPv4 address.
-                 */
-                for (int i = 0; i < 4; i++) {
-                    val = Integer.parseInt(s[i]);
-                    if (val < 0 || val > 0xff)
-                        return null;
-                    res[i] = (byte) (val & 0xff);
                 }
-                break;
-            default:
-                return null;
+                tmpValue *= 10;
+                tmpValue += digit;
+                newOctet = false;
             }
-        } catch(NumberFormatException e) {
+        }
+        if (newOctet || tmpValue < 0 || tmpValue >= (1L << ((4 - currByte) * 8))) {
             return null;
         }
+        switch (currByte) {
+            // BEGIN Android-changed: Require all four parts to be given for an IPv4 address.
+            /*
+            case 0:
+                res[0] = (byte) ((tmpValue >> 24) & 0xff);
+            case 1:
+                res[1] = (byte) ((tmpValue >> 16) & 0xff);
+            case 2:
+                res[2] = (byte) ((tmpValue >>  8) & 0xff);
+            */
+            case 0:
+            case 1:
+            case 2:
+                return null;
+            // END Android-changed: Require all four parts to be given for an IPv4 address.
+            case 3:
+                res[3] = (byte) ((tmpValue >>  0) & 0xff);
+        }
         return res;
     }
 
diff --git a/ojluni/src/main/java/sun/net/util/URLUtil.java b/ojluni/src/main/java/sun/net/util/URLUtil.java
index 08c1e43..c25defb 100644
--- a/ojluni/src/main/java/sun/net/util/URLUtil.java
+++ b/ojluni/src/main/java/sun/net/util/URLUtil.java
@@ -76,5 +76,29 @@
 
         return strForm.toString();
     }
+
+    // Android-removed: Android doesn't support SecurityManager, so Permissions logic is dead code.
+    /*
+    public static Permission getConnectPermission(URL url) throws IOException {
+        String urlStringLowerCase = url.toString().toLowerCase();
+        if (urlStringLowerCase.startsWith("http:") || urlStringLowerCase.startsWith("https:")) {
+            return getURLConnectPermission(url);
+        } else if (urlStringLowerCase.startsWith("jar:http:") || urlStringLowerCase.startsWith("jar:https:")) {
+            String urlString = url.toString();
+            int bangPos = urlString.indexOf("!/");
+            urlString = urlString.substring(4, bangPos > -1 ? bangPos : urlString.length());
+            URL u = new URL(urlString);
+            return getURLConnectPermission(u);
+            // If protocol is HTTP or HTTPS than use URLPermission object
+        } else {
+            return url.openConnection().getPermission();
+        }
+    }
+
+    private static Permission getURLConnectPermission(URL url) {
+        String urlString = url.getProtocol() + "://" + url.getAuthority() + url.getPath();
+        return new URLPermission(urlString);
+    }
+    */
 }
 
diff --git a/ojluni/src/main/java/sun/net/www/MessageHeader.java b/ojluni/src/main/java/sun/net/www/MessageHeader.java
index 0237a85..34b6307 100644
--- a/ojluni/src/main/java/sun/net/www/MessageHeader.java
+++ b/ojluni/src/main/java/sun/net/www/MessageHeader.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,13 +31,7 @@
 
 import java.io.*;
 import java.util.Collections;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Set;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
+import java.util.*;
 
 /** An RFC 844 or MIME message header.  Includes methods
     for parsing headers from incoming streams, fetching
@@ -61,6 +55,17 @@
     }
 
     /**
+     * Returns list of header names in a comma separated list
+     */
+    public synchronized String getHeaderNamesInList() {
+        StringJoiner joiner = new StringJoiner(",");
+        for (int i=0; i<nkeys; i++) {
+            joiner.add(keys[i]);
+        }
+        return joiner.toString();
+    }
+
+    /**
      * Reset a message header (all key/values removed)
      */
     public synchronized void reset() {
@@ -148,7 +153,7 @@
         for (int i=0; i<nkeys; i++) {
             if (k.equalsIgnoreCase(keys[i])
                     && values[i] != null && values[i].length() > 5
-                    && values[i].regionMatches(true, 0, "NTLM ", 0, 5)) {
+                    && values[i].substring(0, 5).equalsIgnoreCase("NTLM ")) {
                 found = true;
                 break;
             }
@@ -236,7 +241,8 @@
         return filterAndAddHeaders(excludeList, null);
     }
 
-    public synchronized Map<String, List<String>> filterAndAddHeaders(String[] excludeList, Map<String, List<String>>  include) {
+    public synchronized Map<String, List<String>> filterAndAddHeaders(
+            String[] excludeList, Map<String, List<String>>  include) {
         boolean skipIt = false;
         Map<String, List<String>> m = new HashMap<String, List<String>>();
         for (int i = nkeys; --i >= 0;) {
@@ -265,15 +271,13 @@
         }
 
         if (include != null) {
-            Iterator entries = include.entrySet().iterator();
-            while (entries.hasNext()) {
-                Map.Entry entry = (Map.Entry)entries.next();
-                List l = (List)m.get(entry.getKey());
+                for (Map.Entry<String,List<String>> entry: include.entrySet()) {
+                List<String> l = m.get(entry.getKey());
                 if (l == null) {
-                    l = new ArrayList();
-                    m.put((String)entry.getKey(), l);
+                    l = new ArrayList<String>();
+                    m.put(entry.getKey(), l);
                 }
-                l.add(entry.getValue());
+                l.addAll(entry.getValue());
             }
         }
 
@@ -437,6 +441,7 @@
     }
 
     /** Parse and merge a MIME header from an input stream. */
+    @SuppressWarnings("fallthrough")
     public void mergeHeader(InputStream is) throws java.io.IOException {
         if (is == null)
             return;
@@ -458,6 +463,7 @@
                         break;
                       case '\t':
                         c = ' ';
+                      /*fall through*/
                       case ' ':
                         inKey = false;
                         break;
diff --git a/ojluni/src/main/java/sun/net/www/MeteredStream.java b/ojluni/src/main/java/sun/net/www/MeteredStream.java
index 17c8b83..26fe85d 100644
--- a/ojluni/src/main/java/sun/net/www/MeteredStream.java
+++ b/ojluni/src/main/java/sun/net/www/MeteredStream.java
@@ -142,15 +142,17 @@
             return 0;
         }
 
-// Android-changed: Remove support for Android-removed class ChunkedInputSTream
-//        if (in instanceof ChunkedInputStream) {
-//            n = in.skip(n);
-//        }
-//        else {
+        // Android-removed: Removed support for Android-removed class ChunkedInputStream.
+        /*
+        if (in instanceof ChunkedInputStream) {
+            n = in.skip(n);
+        }
+        else {
+        */
             // just skip min(n, num_bytes_left)
             long min = (n > expected - count) ? expected - count: n;
             n = in.skip(min);
-//        }
+        // }
         justRead(n);
         return n;
     }
diff --git a/ojluni/src/main/java/sun/net/www/URLConnection.java b/ojluni/src/main/java/sun/net/www/URLConnection.java
index 2760acc..c495928 100644
--- a/ojluni/src/main/java/sun/net/www/URLConnection.java
+++ b/ojluni/src/main/java/sun/net/www/URLConnection.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,12 +26,7 @@
 package sun.net.www;
 
 import java.net.URL;
-import java.net.ContentHandler;
 import java.util.*;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.BufferedInputStream;
-import java.net.UnknownServiceException;
 
 /**
  * A class to represent an active connection to an object
@@ -99,7 +94,7 @@
     public Map<String,List<String>> getRequestProperties() {
         if (connected)
             throw new IllegalStateException("Already connected");
-        return Collections.EMPTY_MAP;
+        return Collections.emptyMap();
     }
 
     public String getHeaderField(String name) {
diff --git a/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java b/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java
index 24f2f3b..e9f3d78 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java
@@ -81,10 +81,12 @@
  */
 public class FtpURLConnection extends URLConnection {
 
-// Android-changed: Removed support for proxying FTP over HTTP since it
-// relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
-//    // In case we have to use proxies, we use HttpURLConnection
-//    HttpURLConnection http = null;
+    // Android-changed: Removed support for proxying FTP over HTTP.
+    // It relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+    /*
+    // In case we have to use proxies, we use HttpURLConnection
+    HttpURLConnection http = null;
+    */
     private Proxy instProxy;
 
     InputStream is = null;
@@ -163,6 +165,8 @@
      *
      * @param   url     The <code>URL</code> to retrieve or store.
      */
+    // Android-changed: Ctors can throw IOException for NetworkSecurityPolicy enforcement.
+    // public FtpURLConnection(URL url) {
     public FtpURLConnection(URL url) throws IOException {
         this(url, null);
     }
@@ -170,19 +174,22 @@
     /**
      * Same as FtpURLconnection(URL) with a per connection proxy specified
      */
+    // Android-changed: Ctors can throw IOException for NetworkSecurityPolicy enforcement.
+    // FtpURLConnection(URL url, Proxy p) {
     FtpURLConnection(URL url, Proxy p) throws IOException {
         super(url);
         instProxy = p;
         host = url.getHost();
         port = url.getPort();
         String userInfo = url.getUserInfo();
-
+        // BEGIN Android-added: Enforce NetworkSecurityPolicy.isClearTextTrafficPermitted().
         if (!NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()) {
             // Cleartext network traffic is not permitted -- refuse this connection.
             throw new IOException("Cleartext traffic not permitted: "
                     + url.getProtocol() + "://" + host
                     + ((url.getPort() >= 0) ? (":" + url.getPort()) : ""));
         }
+        // END Android-added: Enforce NetworkSecurityPolicy.isClearTextTrafficPermitted().
 
         if (userInfo != null) { // get the user and password
             int delimiter = userInfo.indexOf(':');
@@ -246,50 +253,56 @@
                         continue;
                     }
                     // OK, we have an http proxy
-                    // Android-changed: Removed support for proxying FTP over HTTP since it
-                    // relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+                    // BEGIN Android-changed: Removed support for proxying FTP over HTTP.
+                    // It relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+                    /*
+                    InetSocketAddress paddr = (InetSocketAddress) p.address();
+                    try {
+                        http = new HttpURLConnection(url, p);
+                        http.setDoInput(getDoInput());
+                        http.setDoOutput(getDoOutput());
+                        if (connectTimeout >= 0) {
+                            http.setConnectTimeout(connectTimeout);
+                        }
+                        if (readTimeout >= 0) {
+                            http.setReadTimeout(readTimeout);
+                        }
+                        http.connect();
+                        connected = true;
+                        return;
+                    } catch (IOException ioe) {
+                        sel.connectFailed(uri, paddr, ioe);
+                        http = null;
+                    }
+                    */
                     sel.connectFailed(uri, p.address(), new IOException("FTP connections over HTTP proxy not supported"));
                     continue;
-//                    InetSocketAddress paddr = (InetSocketAddress) p.address();
-//                    try {
-//                        http = new HttpURLConnection(url, p);
-//                        http.setDoInput(getDoInput());
-//                        http.setDoOutput(getDoOutput());
-//                        if (connectTimeout >= 0) {
-//                            http.setConnectTimeout(connectTimeout);
-//                        }
-//                        if (readTimeout >= 0) {
-//                            http.setReadTimeout(readTimeout);
-//                        }
-//                        http.connect();
-//                        connected = true;
-//                        return;
-//                    } catch (IOException ioe) {
-//                        sel.connectFailed(uri, paddr, ioe);
-//                        http = null;
-//                    }
+                    // END Android-changed: Removed support for proxying FTP over HTTP.
                 }
             }
         } else { // per connection proxy specified
             p = instProxy;
-// Android-changed: Removed support for proxying FTP over HTTP since it
-// relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
-// As specified in the documentation for URL.openConnection(Proxy), we
-// ignore the unsupported proxy and attempt a normal (direct) connection
-//            if (p.type() == Proxy.Type.HTTP) {
-//                http = new HttpURLConnection(url, instProxy);
-//                http.setDoInput(getDoInput());
-//                http.setDoOutput(getDoOutput());
-//                if (connectTimeout >= 0) {
-//                    http.setConnectTimeout(connectTimeout);
-//                }
-//                if (readTimeout >= 0) {
-//                    http.setReadTimeout(readTimeout);
-//                }
-//                http.connect();
-//                connected = true;
-//                return;
-//            }
+            // BEGIN Android-changed: Removed support for proxying FTP over HTTP.
+            // It relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+            // As specified in the documentation for URL.openConnection(Proxy), we
+            // ignore the unsupported proxy and attempt a normal (direct) connection
+            /*
+            if (p.type() == Proxy.Type.HTTP) {
+                http = new HttpURLConnection(url, instProxy);
+                http.setDoInput(getDoInput());
+                http.setDoOutput(getDoOutput());
+                if (connectTimeout >= 0) {
+                    http.setConnectTimeout(connectTimeout);
+                }
+                if (readTimeout >= 0) {
+                    http.setReadTimeout(readTimeout);
+                }
+                http.connect();
+                connected = true;
+                return;
+            }
+            */
+            // END Android-changed: Removed support for proxying FTP over HTTP.
         }
 
         if (user == null) {
@@ -319,7 +332,7 @@
             throw new IOException(fe);
         }
         try {
-            ftp.login(user, password.toCharArray());
+            ftp.login(user, password == null ? null : password.toCharArray());
         } catch (sun.net.ftp.FtpProtocolException e) {
             ftp.close();
             // Backward compatibility
@@ -410,11 +423,14 @@
         if (!connected) {
             connect();
         }
-        // Android-changed: Removed support for proxying FTP over HTTP since it
-        // relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
-//        if (http != null) {
-//            return http.getInputStream();
-//        }
+
+        // Android-changed: Removed support for proxying FTP over HTTP.
+        // It relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+        /*
+        if (http != null) {
+            return http.getInputStream();
+        }
+        */
 
         if (os != null) {
             throw new IOException("Already opened for output");
@@ -525,15 +541,18 @@
         if (!connected) {
             connect();
         }
-// Android-changed: Removed support for proxying FTP over HTTP since it
-// relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
-//        if (http != null) {
-//            OutputStream out = http.getOutputStream();
-//            // getInputStream() is neccessary to force a writeRequests()
-//            // on the http client.
-//            http.getInputStream();
-//            return out;
-//        }
+
+        // Android-changed: Removed support for proxying FTP over HTTP.
+        // It relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+        /*
+        if (http != null) {
+            OutputStream out = http.getOutputStream();
+            // getInputStream() is neccessary to force a writeRequests()
+            // on the http client.
+            http.getInputStream();
+            return out;
+        }
+        */
 
         if (is != null) {
             throw new IOException("Already opened for input");
diff --git a/ojluni/src/main/java/sun/net/www/protocol/jar/Handler.java b/ojluni/src/main/java/sun/net/www/protocol/jar/Handler.java
index 62686c6..8e9f8e3 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/jar/Handler.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/jar/Handler.java
@@ -123,6 +123,7 @@
 
 
     @Override
+    @SuppressWarnings("deprecation")
     protected void parseURL(URL url, String spec,
                             int start, int limit) {
         String file = null;
diff --git a/ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java b/ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java
index ae86964..edd99ff 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java b/ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java
index 4c5dc87..d7c4424 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -125,7 +125,9 @@
              * to get the jarFile, and set it as our permission.
              */
             if (getUseCaches()) {
+                boolean oldUseCaches = jarFileURLConnection.getUseCaches();
                 jarFileURLConnection = factory.getConnection(jarFile);
+                jarFileURLConnection.setUseCaches(oldUseCaches);
             }
 
             if ((entryName != null)) {