6737819: sun.misc.net.DefaultProxySelector doesn't use proxy setting to localhost
authorjccollet
Fri, 18 Sep 2009 10:51:44 +0200
changeset 3855 653df3a7256d
parent 3854 b2a90c48e69f
child 3856 47b5ce137a2b
6737819: sun.misc.net.DefaultProxySelector doesn't use proxy setting to localhost Summary: Move default nonProxyHosts from hardcoded to property default value Reviewed-by: chegar
jdk/src/share/classes/java/net/doc-files/net-properties.html
jdk/src/share/classes/sun/net/spi/DefaultProxySelector.java
jdk/src/share/lib/net.properties
jdk/test/java/net/ProxySelector/B6737819.java
--- a/jdk/src/share/classes/java/net/doc-files/net-properties.html	Wed Sep 16 09:23:50 2009 -0700
+++ b/jdk/src/share/classes/java/net/doc-files/net-properties.html	Fri Sep 18 10:51:44 2009 +0200
@@ -71,12 +71,12 @@
 	<LI><P>HTTP</P>
 	<P>The following proxy settings are used by the HTTP protocol handler.</P>
 	<UL>
-		<LI><P><B>http.proxyHost</FONT></B> (default: &lt;none&gt;)<BR>
+		<LI><P><B>http.proxyHost</B> (default: &lt;none&gt;)<BR>
 	        The hostname, or address, of the proxy server 
 		</P>
 		<LI><P><B>http.proxyPort</B> (default: 80)<BR>
 	        The port number of the proxy server.</P>
-		<LI><P><B>http.nonProxyHosts</B> (default: &lt;none&gt;)<BR>
+		<LI><P><B>http.nonProxyHosts</B> (default:  localhost|127.*|[::1])<BR>
 	        Indicates the hosts that should be accessed without going
 	        through the proxy. Typically this defines internal hosts.
 	        The value of this property is a list of hosts,
@@ -86,7 +86,8 @@
 		will indicate that every hosts in the foo.com domain and the
 		localhost should be accessed directly even if a proxy server is
 		specified.</P>
-	</UL>
+                <P>The default value excludes all common variations of the loopback address.</P>
+        </UL>
 	<LI><P>HTTPS<BR>This is HTTP over SSL, a secure version of HTTP
 	mainly used when confidentiality (like on payment sites) is needed.</P>
 	<P>The following proxy settings are used by the HTTPS protocol handler.</P>
@@ -107,7 +108,7 @@
 		</P>
 		<LI><P><B>ftp.proxyPort</B> (default: 80)<BR>
 	        The port number of the proxy server.</P>
-		<LI><P><B>ftp.nonProxyHosts</B> (default: &lt;none&gt;)<BR>
+		<LI><P><B>ftp.nonProxyHosts</B> (default: localhost|127.*|[::1])<BR>
 	        Indicates the hosts that should be accessed without going
 	        through the proxy. Typically this defines internal hosts.
 	        The value of this property is a list of hosts, separated by
@@ -117,6 +118,7 @@
 		will indicate that every hosts in the foo.com domain and the
 		localhost should be accessed directly even if a proxy server is
 		specified.</P>
+                <P>The default value excludes all common variations of the loopback address.</P>
 	</UL>
 	<LI><P>SOCKS<BR>This is another type of proxy. It allows for lower
 	level type of tunneling since it works at the TCP level. In effect,
--- a/jdk/src/share/classes/sun/net/spi/DefaultProxySelector.java	Wed Sep 16 09:23:50 2009 -0700
+++ b/jdk/src/share/classes/sun/net/spi/DefaultProxySelector.java	Fri Sep 18 10:51:44 2009 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc.  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
@@ -25,11 +25,9 @@
 
 package sun.net.spi;
 
-import sun.net.www.http.*;
 import sun.net.NetProperties;
 import java.net.*;
 import java.util.*;
-import java.util.regex.*;
 import java.io.*;
 import sun.misc.RegexpPool;
 import java.security.AccessController;
@@ -102,17 +100,22 @@
      */
 
     static class NonProxyInfo {
+        // Default value for nonProxyHosts, this provides backward compatibility
+        // by excluding localhost and its litteral notations.
+        static final String defStringVal = "localhost|127.*|[::1]";
+
         String hostsSource;
         RegexpPool hostsPool;
-        String property;
+        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 ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null);
-        static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null);
-
-        NonProxyInfo(String p, String s, RegexpPool pool) {
+        NonProxyInfo(String p, String s, RegexpPool pool, String d) {
             property = p;
             hostsSource = s;
             hostsPool = pool;
+            defaultVal = d;
         }
     }
 
@@ -130,7 +133,6 @@
         }
         String protocol = uri.getScheme();
         String host = uri.getHost();
-        int port = uri.getPort();
 
         if (host == null) {
             // This is a hack to ensure backward compatibility in two
@@ -149,11 +151,6 @@
                 }
                 i = auth.lastIndexOf(':');
                 if (i >= 0) {
-                    try {
-                        port = Integer.parseInt(auth.substring(i+1));
-                    } catch (NumberFormatException e) {
-                        port = -1;
-                    }
                     auth = auth.substring(0,i);
                 }
                 host = auth;
@@ -165,13 +162,6 @@
         }
         List<Proxy> proxyl = new ArrayList<Proxy>(1);
 
-        // special case localhost and loopback addresses to
-        // not go through proxy
-        if (isLoopback(host)) {
-            proxyl.add(Proxy.NO_PROXY);
-            return proxyl;
-        }
-
         NonProxyInfo pinfo = null;
 
         if ("http".equalsIgnoreCase(protocol)) {
@@ -244,9 +234,14 @@
                                 nphosts = NetProperties.get(nprop.property);
                                 synchronized (nprop) {
                                     if (nphosts == null) {
-                                        nprop.hostsSource = null;
-                                        nprop.hostsPool = null;
-                                    } else {
+                                        if (nprop.defaultVal != null) {
+                                            nphosts = nprop.defaultVal;
+                                        } else {
+                                            nprop.hostsSource = null;
+                                            nprop.hostsPool = null;
+                                        }
+                                    }
+                                    if (nphosts != null) {
                                         if (!nphosts.equals(nprop.hostsSource)) {
                                             RegexpPool pool = new RegexpPool();
                                             StringTokenizer st = new StringTokenizer(nphosts, "|", false);
@@ -334,107 +329,6 @@
         }
     }
 
-    private boolean isLoopback(String host) {
-        if (host == null || host.length() == 0)
-            return false;
-
-        if (host.equalsIgnoreCase("localhost"))
-            return true;
-
-        /* The string could represent a numerical IP address.
-         * For IPv4 addresses, check whether it starts with 127.
-         * For IPv6 addresses, check whether it is ::1 or its equivalent.
-         * Don't check IPv4-mapped or IPv4-compatible addresses
-         */
-
-        if (host.startsWith("127.")) {
-            // possible IPv4 loopback address
-            int p = 4;
-            int q;
-            int n = host.length();
-            // Per RFC2732: At most three digits per byte
-            // Further constraint: Each element fits in a byte
-            if ((q = scanByte(host, p, n)) <= p) return false;   p = q;
-            if ((q = scan(host, p, n, '.')) <= p) return q == n && number > 0;  p = q;
-            if ((q = scanByte(host, p, n)) <= p) return false;   p = q;
-            if ((q = scan(host, p, n, '.')) <= p) return q == n && number > 0;  p = q;
-            if ((q = scanByte(host, p, n)) <= p) return false;
-            return q == n && number > 0;
-        }
-
-        if (host.endsWith(":1")) {
-            final Pattern p6 = Pattern.compile("::1|(0:){7}1|(0:){1,6}:1");
-            return p6.matcher(host).matches();
-        }
-        return false;
-    }
-
-    // Character-class masks, in reverse order from RFC2396 because
-    // initializers for static fields cannot make forward references.
-
-    // Compute a low-order mask for the characters
-    // between first and last, inclusive
-    private static long lowMask(char first, char last) {
-        long m = 0;
-        int f = Math.max(Math.min(first, 63), 0);
-        int l = Math.max(Math.min(last, 63), 0);
-        for (int i = f; i <= l; i++)
-            m |= 1L << i;
-        return m;
-    }
-    // digit    = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
-    //            "8" | "9"
-    private static final long L_DIGIT = lowMask('0', '9');
-    private static final long H_DIGIT = 0L;
-
-    // Scan a string of decimal digits whose value fits in a byte
-    //
-    private int number;
-    private int scanByte(String input, int start, int n)
-    {
-        int p = start;
-        int q = scan(input, p, n, L_DIGIT, H_DIGIT);
-        if (q <= p) return q;
-        number = Integer.parseInt(input.substring(p, q));
-        if (number > 255) return p;
-        return q;
-    }
-
-    // Scan a specific char: If the char at the given start position is
-    // equal to c, return the index of the next char; otherwise, return the
-    // start position.
-    //
-    private int scan(String input, int start, int end, char c) {
-        if ((start < end) && (input.charAt(start) == c))
-            return start + 1;
-        return start;
-    }
-
-    // Scan chars that match the given mask pair
-    //
-    private int scan(String input, int start, int n, long lowMask, long highMask)
-    {
-        int p = start;
-        while (p < n) {
-            char c = input.charAt(p);
-            if (match(c, lowMask, highMask)) {
-                p++;
-                continue;
-            }
-            break;
-        }
-        return p;
-    }
-
-    // Tell whether the given character is permitted by the given mask pair
-    private boolean match(char c, long lowMask, long highMask) {
-        if (c < 64)
-            return ((1L << c) & lowMask) != 0;
-        if (c < 128)
-            return ((1L << (c - 64)) & highMask) != 0;
-        return false;
-    }
-
     private native static boolean init();
     private native Proxy getSystemProxy(String protocol, String host);
 }
--- a/jdk/src/share/lib/net.properties	Wed Sep 16 09:23:50 2009 -0700
+++ b/jdk/src/share/lib/net.properties	Fri Sep 18 10:51:44 2009 +0200
@@ -32,7 +32,7 @@
 #
 # http.proxyHost=
 # http.proxyPort=80
-# http.nonProxyHosts=localhost|127.0.0.1
+http.nonProxyHosts=localhost|127.*|[::1]
 #
 # HTTPS Proxy Settings. proxyHost is the name of the proxy server
 # (e.g. proxy.mydomain.com), proxyPort is the port number to use (default
@@ -49,7 +49,7 @@
 #
 # ftp.proxyHost=
 # ftp.proxyPort=80
-# ftp.nonProxyHosts=localhost|127.0.0.1
+ftp.nonProxyHosts=localhost|127.*|[::1]
 #
 # Gopher Proxy settings. proxyHost is the name of the proxy server
 # (e.g. proxy.mydomain.com), proxyPort is the port number to use (default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/ProxySelector/B6737819.java	Fri Sep 18 10:51:44 2009 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+/*
+ * @test
+ * @bug 6737819
+ * @summary sun.misc.net.DefaultProxySelector doesn't use proxy setting to localhost
+ */
+
+import java.net.ProxySelector;
+import java.net.Proxy;
+import java.net.URI;
+
+public class B6737819 {
+    private static String[] uris = {
+        "http://localhost/index.html",
+        "http://127.0.0.1/index.html",
+        "http://127.2/index.html",
+        "http://[::1]/index.html"
+    };
+    public static void main(String[] args) throws Exception {
+        System.setProperty("http.proxyHost", "myproxy");
+        System.setProperty("http.proxyPort", "8080");
+        ProxySelector sel = ProxySelector.getDefault();
+        java.util.List<Proxy> l;
+        // Default value for http.nonProxyHots should exclude all this uris
+        // from going through the HTTP proxy
+        for (String s : uris) {
+            l = sel.select(new URI(s));
+            if (l.size() == 1 && l.get(0).type() != Proxy.Type.DIRECT) {
+                throw new RuntimeException("ProxySelector returned the wrong proxy for " + s);
+            }
+        }
+        // Let's override the default nonProxyHosts and make sure we now get a
+        // HTTP proxy
+        System.setProperty("http.nonProxyHosts", "");
+        for (String s : uris) {
+            l = sel.select(new URI(s));
+            if (l.size() == 1 && l.get(0).type() != Proxy.Type.HTTP) {
+                throw new RuntimeException("ProxySelector returned the wrong proxy for " + s);
+            }
+        }
+    }
+}