1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 8035158
  27  * @run main/othervm B8035158
  28  */
  29 
  30 import java.net.Proxy;
  31 import java.net.ProxySelector;
  32 import java.net.URI;
  33 import java.util.*;
  34 import java.util.concurrent.Callable;
  35 
  36 public class B8035158 {
  37 
  38     public static void main(String[] args) {
  39         for (TestCase t : emptyNonProxiesHosts()) t.run();
  40         for (TestCase t : nonEmptyNonProxiesHosts()) t.run();
  41         for (TestCase t : misc()) t.run();
  42     }
  43 
  44     // Setting http.nonProxyHosts to an empty string has an effect of
  45     // not including default hosts to the list of exceptions
  46     // (i.e. if you want everything to be connected directly rather than
  47     // through proxy, you should set this property to an empty string)
  48     private static Collection<TestCase> emptyNonProxiesHosts() {
  49         List<TestCase> tests = new LinkedList<>();
  50         String[] loopbacks = {"localhost", "[::1]", "[::0]", "0.0.0.0",
  51                 "127.0.0.0", "127.0.0.1", "127.0.1.0", "127.0.1.1",
  52                 "127.1.0.0", "127.1.0.1", "127.1.1.0", "127.1.1.1"};
  53         Map<String, String> properties = new HashMap<>();
  54         properties.put("http.proxyHost", "http://proxy.example.com");
  55         properties.put("http.nonProxyHosts", "");
  56         for (String s : loopbacks) {
  57             tests.add(new TestCase(properties, "http://" + s, true));
  58         }
  59         return tests;
  60     }
  61 
  62     // No matter what is set into the http.nonProxyHosts (as far as it is not
  63     // an empty string) loopback address aliases must be always connected
  64     // directly
  65     private static Collection<TestCase> nonEmptyNonProxiesHosts() {
  66         List<TestCase> tests = new LinkedList<>();
  67         String[] nonProxyHosts = {
  68                 "google.com",
  69                 "localhost", "[::1]", "[::0]", "0.0.0.0",
  70                 "127.0.0.0", "127.0.0.1", "127.0.1.0", "127.0.1.1",
  71                 "127.1.0.0", "127.1.0.1", "127.1.1.0", "127.1.1.1"};
  72         String[] loopbacks = {"localhost", "[::1]", "[::0]", "0.0.0.0",
  73                 "127.0.0.0", "127.0.0.1", "127.0.1.0", "127.0.1.1",
  74                 "127.1.0.0", "127.1.0.1", "127.1.1.0", "127.1.1.1"};
  75         for (String h : nonProxyHosts) {
  76             for (String s : loopbacks) {
  77                 Map<String, String> properties = new HashMap<>();
  78                 properties.put("http.proxyHost", "http://proxy.example.com");
  79                 properties.put("http.nonProxyHosts", h);
  80                 tests.add(new TestCase(properties, "http://" + s, false));
  81             }
  82         }
  83         return tests;
  84     }
  85 
  86     // unsorted tests
  87     private static Collection<TestCase> misc() {
  88         List<TestCase> t = new LinkedList<>();
  89         t.add(new TestCase("oracle.com", "http://137.254.16.101", true));
  90         t.add(new TestCase("google.com", "http://74.125.200.101", true));
  91 
  92         t.add(new TestCase("google.com|google.ie", "http://google.co.uk",
  93                 true));
  94         t.add(new TestCase("google.com|google.ie", "http://google.com",
  95                 false));
  96         t.add(new TestCase("google.com|google.ie", "http://google.ie",
  97                 false));
  98 
  99         t.add(new TestCase("google.com|bing.com|yahoo.com",
 100                 "http://127.0.0.1", false));
 101         t.add(new TestCase("google.com|bing.com|yahoo.com",
 102                 "http://google.com", false));
 103         t.add(new TestCase("google.com|bing.com|yahoo.com",
 104                 "http://bing.com", false));
 105         t.add(new TestCase("google.com|bing.com|yahoo.com",
 106                 "http://yahoo.com", false));
 107 
 108         t.add(new TestCase("google.com|bing.com", "http://google.com", false));
 109         t.add(new TestCase("google.com|bing.com", "http://bing.com", false));
 110         t.add(new TestCase("google.com|bing.com", "http://yahoo.com",
 111                 true));
 112         t.add(new TestCase("google.com|bing.co*", "http://google.com", false));
 113         t.add(new TestCase("google.com|bing.co*", "http://bing.com", false));
 114         t.add(new TestCase("google.com|bing.co*", "http://yahoo.com",
 115                 true));
 116         t.add(new TestCase("google.com|*ing.com", "http://google.com", false));
 117         t.add(new TestCase("google.com|*ing.com", "http://bing.com", false));
 118         t.add(new TestCase("google.com|*ing.com", "http://yahoo.com",
 119                 true));
 120         t.add(new TestCase("google.co*|bing.com", "http://google.com", false));
 121         t.add(new TestCase("google.co*|bing.com", "http://bing.com", false));
 122         t.add(new TestCase("google.co*|bing.com", "http://yahoo.com",
 123                 true));
 124         t.add(new TestCase("google.co*|bing.co*", "http://google.com", false));
 125         t.add(new TestCase("google.co*|bing.co*", "http://bing.com", false));
 126         t.add(new TestCase("google.co*|bing.co*", "http://yahoo.com",
 127                 true));
 128         t.add(new TestCase("google.co*|*ing.com", "http://google.com", false));
 129         t.add(new TestCase("google.co*|*ing.com", "http://bing.com", false));
 130         t.add(new TestCase("google.co*|*ing.com", "http://yahoo.com",
 131                 true));
 132         t.add(new TestCase("*oogle.com|bing.com", "http://google.com", false));
 133         t.add(new TestCase("*oogle.com|bing.com", "http://bing.com", false));
 134         t.add(new TestCase("*oogle.com|bing.com", "http://yahoo.com",
 135                 true));
 136         t.add(new TestCase("*oogle.com|bing.co*", "http://google.com", false));
 137         t.add(new TestCase("*oogle.com|bing.co*", "http://bing.com", false));
 138         t.add(new TestCase("*oogle.com|bing.co*", "http://yahoo.com",
 139                 true));
 140         t.add(new TestCase("*oogle.com|*ing.com", "http://google.com", false));
 141         t.add(new TestCase("*oogle.com|*ing.com", "http://bing.com", false));
 142         t.add(new TestCase("*oogle.com|*ing.com", "http://yahoo.com",
 143                 true));
 144 
 145         t.add(new TestCase("google.com|bing.com|yahoo.com", "http://google.com", false));
 146         t.add(new TestCase("google.com|bing.com|yahoo.com", "http://bing.com", false));
 147         t.add(new TestCase("google.com|bing.com|yahoo.com", "http://yahoo.com", false));
 148         t.add(new TestCase("google.com|bing.com|yahoo.com",
 149                 "http://duckduckgo.com", true));
 150 
 151         t.add(new TestCase("p-proxy.com", "http://p-proxy.com", false));
 152         t.add(new TestCase("google.co*|google.ie", "http://google.co.uk",
 153                 false));
 154 
 155         t.add(new TestCase("*oracle.com", "http://my.oracle.com", false));
 156         t.add(new TestCase("google.com|bing.com|yahoo.com", "http://127.0.0.1", false));
 157         t.add(new TestCase("google.com|bing.com|yahoo.com", "http://yahoo.com", false));
 158 
 159         // example from
 160         // http://docs.oracle.com/javase/7/docs/technotes/guides/net/proxies.html
 161         t.add(new TestCase("localhost|host.example.com", "http://localhost",
 162                 false));
 163         t.add(new TestCase("localhost|host.example.com",
 164                 "http://host.example.com", false));
 165         t.add(new TestCase("localhost|host.example.com",
 166                 "http://google.com", true));
 167         return t;
 168     }
 169 
 170 
 171     private static <T> T withSystemPropertiesSet(
 172             Map<String, String> localProperties,
 173             Callable<? extends T> code) {
 174         Map<String, String> backup = new HashMap<>();
 175         try {
 176             backupAndSetProperties(localProperties, backup);
 177             return code.call();
 178         } catch (Exception e) {
 179             throw new RuntimeException(e);
 180         } finally {
 181             restoreProperties(backup);
 182         }
 183     }
 184 
 185     private static void backupAndSetProperties(
 186             Map<String, String> localProperties,
 187             Map<String, String> oldProperties) {
 188         for (Map.Entry<String, String> e : localProperties.entrySet()) {
 189             String oldValue = System.setProperty(e.getKey(), e.getValue());
 190             oldProperties.put(e.getKey(), oldValue);
 191         }
 192     }
 193 
 194     private static void restoreProperties(Map<String, String> oldProperties) {
 195         for (Map.Entry<String, String> e : oldProperties.entrySet()) {
 196             String oldValue = e.getValue();
 197             String key = e.getKey();
 198             if (oldValue == null)
 199                 System.getProperties().remove(key);
 200             else
 201                 System.setProperty(key, oldValue);
 202         }
 203     }
 204 
 205     private static class TestCase {
 206 
 207         final Map<String, String> localProperties;
 208         final String urlhost;
 209         final boolean expectedProxying;
 210 
 211         TestCase(String nonProxyHosts, String urlhost,
 212                  boolean expectedProxying) {
 213             this(nonProxyHosts, "proxy.example.com", urlhost,
 214                     expectedProxying);
 215         }
 216 
 217         TestCase(String nonProxyHosts, String proxyHost, String urlhost,
 218                  boolean expectedProxying) {
 219             this(new HashMap<String, String>() {
 220                 {
 221                     put("http.nonProxyHosts", nonProxyHosts);
 222                     put("http.proxyHost", proxyHost);
 223                 }
 224             }, urlhost, expectedProxying);
 225         }
 226 
 227         TestCase(Map<String, String> localProperties, String urlhost,
 228                  boolean expectedProxying) {
 229             this.localProperties = localProperties;
 230             this.urlhost = urlhost;
 231             this.expectedProxying = expectedProxying;
 232         }
 233 
 234         void run() {
 235             System.out.printf("urlhost=%s properties=%s: proxied? %s%n",
 236                     urlhost, localProperties, expectedProxying);
 237 
 238             List<Proxy> proxies = withSystemPropertiesSet(localProperties,
 239                     () -> ProxySelector.getDefault().select(
 240                             URI.create(urlhost))
 241             );
 242 
 243             verify(proxies);
 244         }
 245 
 246         void verify(List<? extends Proxy> proxies) {
 247 
 248             boolean actualProxying = !(proxies.size() == 1 &&
 249                     proxies.get(0).type() == Proxy.Type.DIRECT);
 250 
 251             if (actualProxying != expectedProxying)
 252                 throw new AssertionError(String.format(
 253                         "Expected %s connection for %s (given " +
 254                                 "properties=%s). Here's the list of proxies " +
 255                                 "returned: %s",
 256                         expectedProxying ? "proxied" : "direct", urlhost,
 257                         localProperties, proxies
 258                 ));
 259         }
 260     }
 261 }