1/*
2 * Copyright (c) 2014, 2016, 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 8145732
27 * @run main/othervm B8035158
28 */
29
30import java.net.Proxy;
31import java.net.ProxySelector;
32import java.net.URI;
33import java.util.*;
34import java.util.concurrent.Callable;
35
36public 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        t.add(new TestCase("google.com|google.com|google.ie",
99                "http://google.ie", false));
100
101        t.add(new TestCase("google.com|bing.com|yahoo.com",
102                "http://127.0.0.1", false));
103        t.add(new TestCase("google.com|bing.com|yahoo.com",
104                "http://google.com", false));
105        t.add(new TestCase("google.com|bing.com|yahoo.com",
106                "http://bing.com", false));
107        t.add(new TestCase("google.com|bing.com|yahoo.com",
108                "http://yahoo.com", false));
109
110        t.add(new TestCase("google.com|bing.com", "http://google.com", false));
111        t.add(new TestCase("google.com|bing.com", "http://bing.com", false));
112        t.add(new TestCase("google.com|bing.com", "http://yahoo.com",
113                true));
114        t.add(new TestCase("google.com|bing.co*", "http://google.com", false));
115        t.add(new TestCase("google.com|bing.co*", "http://bing.com", false));
116        t.add(new TestCase("google.com|bing.co*", "http://yahoo.com",
117                true));
118        t.add(new TestCase("google.com|*ing.com", "http://google.com", false));
119        t.add(new TestCase("google.com|*ing.com", "http://bing.com", false));
120        t.add(new TestCase("google.com|*ing.com", "http://yahoo.com",
121                true));
122        t.add(new TestCase("google.co*|bing.com", "http://google.com", false));
123        t.add(new TestCase("google.co*|bing.com", "http://bing.com", false));
124        t.add(new TestCase("google.co*|bing.com", "http://yahoo.com",
125                true));
126        t.add(new TestCase("google.co*|bing.co*", "http://google.com", false));
127        t.add(new TestCase("google.co*|bing.co*", "http://bing.com", false));
128        t.add(new TestCase("google.co*|bing.co*", "http://yahoo.com",
129                true));
130        t.add(new TestCase("google.co*|*ing.com", "http://google.com", false));
131        t.add(new TestCase("google.co*|*ing.com", "http://bing.com", false));
132        t.add(new TestCase("google.co*|*ing.com", "http://yahoo.com",
133                true));
134        t.add(new TestCase("*oogle.com|bing.com", "http://google.com", false));
135        t.add(new TestCase("*oogle.com|bing.com", "http://bing.com", false));
136        t.add(new TestCase("*oogle.com|bing.com", "http://yahoo.com",
137                true));
138        t.add(new TestCase("*oogle.com|bing.co*", "http://google.com", false));
139        t.add(new TestCase("*oogle.com|bing.co*", "http://bing.com", false));
140        t.add(new TestCase("*oogle.com|bing.co*", "http://yahoo.com",
141                true));
142        t.add(new TestCase("*oogle.com|*ing.com", "http://google.com", false));
143        t.add(new TestCase("*oogle.com|*ing.com", "http://bing.com", false));
144        t.add(new TestCase("*oogle.com|*ing.com", "http://yahoo.com",
145                true));
146
147        t.add(new TestCase("google.com|bing.com|yahoo.com", "http://google.com", false));
148        t.add(new TestCase("google.com|bing.com|yahoo.com", "http://bing.com", false));
149        t.add(new TestCase("google.com|bing.com|yahoo.com", "http://yahoo.com", false));
150        t.add(new TestCase("google.com|bing.com|yahoo.com",
151                "http://duckduckgo.com", true));
152
153        t.add(new TestCase("p-proxy.com", "http://p-proxy.com", false));
154        t.add(new TestCase("google.co*|google.ie", "http://google.co.uk",
155                false));
156
157        t.add(new TestCase("*oracle.com", "http://my.oracle.com", false));
158        t.add(new TestCase("google.com|bing.com|yahoo.com", "http://127.0.0.1", false));
159        t.add(new TestCase("google.com|bing.com|yahoo.com", "http://yahoo.com", false));
160
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}
262