source: josm/trunk/src/org/openstreetmap/josm/io/DefaultProxySelector.java @ 12805

Last change on this file since 12805 was 12805, checked in by Don-vip, 6 weeks ago

see #15229 - see #15182 - remove GUI references from DefaultProxySelector

  • Property svn:eol-style set to native
File size: 9.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.IOException;
7import java.net.InetSocketAddress;
8import java.net.Proxy;
9import java.net.Proxy.Type;
10import java.net.ProxySelector;
11import java.net.SocketAddress;
12import java.net.URI;
13import java.util.Arrays;
14import java.util.Collections;
15import java.util.HashSet;
16import java.util.List;
17import java.util.Set;
18import java.util.TreeSet;
19
20import org.openstreetmap.josm.Main;
21import org.openstreetmap.josm.tools.Logging;
22
23/**
24 * This is the default proxy selector used in JOSM.
25 * @since 2641
26 */
27public class DefaultProxySelector extends ProxySelector {
28
29    /** Property key for proxy policy */
30    public static final String PROXY_POLICY = "proxy.policy";
31    /** Property key for HTTP proxy host */
32    public static final String PROXY_HTTP_HOST = "proxy.http.host";
33    /** Property key for HTTP proxy port */
34    public static final String PROXY_HTTP_PORT = "proxy.http.port";
35    /** Property key for SOCKS proxy host */
36    public static final String PROXY_SOCKS_HOST = "proxy.socks.host";
37    /** Property key for SOCKS proxy port */
38    public static final String PROXY_SOCKS_PORT = "proxy.socks.port";
39    /** Property key for proxy username */
40    public static final String PROXY_USER = "proxy.user";
41    /** Property key for proxy password */
42    public static final String PROXY_PASS = "proxy.pass";
43    /** Property key for proxy exceptions list */
44    public static final String PROXY_EXCEPTIONS = "proxy.exceptions";
45
46    private static final List<Proxy> NO_PROXY_LIST = Collections.singletonList(Proxy.NO_PROXY);
47
48    private static final String IPV4_LOOPBACK = "127.0.0.1";
49    private static final String IPV6_LOOPBACK = "::1";
50
51    /**
52     * The {@link ProxySelector} provided by the JDK will retrieve proxy information
53     * from the system settings, if the system property <tt>java.net.useSystemProxies</tt>
54     * is defined <strong>at startup</strong>. It has no effect if the property is set
55     * later by the application.
56     *
57     * We therefore read the property at class loading time and remember it's value.
58     */
59    private static boolean jvmWillUseSystemProxies;
60    static {
61        String v = System.getProperty("java.net.useSystemProxies");
62        if (v != null && v.equals(Boolean.TRUE.toString())) {
63            jvmWillUseSystemProxies = true;
64        }
65    }
66
67    /**
68     * The {@link ProxySelector} provided by the JDK will retrieve proxy information
69     * from the system settings, if the system property <tt>java.net.useSystemProxies</tt>
70     * is defined <strong>at startup</strong>. If the property is set later by the application,
71     * this has no effect.
72     *
73     * @return true, if <tt>java.net.useSystemProxies</tt> was set to true at class initialization time
74     *
75     */
76    public static boolean willJvmRetrieveSystemProxies() {
77        return jvmWillUseSystemProxies;
78    }
79
80    private ProxyPolicy proxyPolicy;
81    private InetSocketAddress httpProxySocketAddress;
82    private InetSocketAddress socksProxySocketAddress;
83    private final ProxySelector delegate;
84
85    private final Set<String> errorResources = new HashSet<>();
86    private final Set<String> errorMessages = new HashSet<>();
87    private Set<String> proxyExceptions;
88
89    /**
90     * A typical example is:
91     * <pre>
92     *    PropertySelector delegate = PropertySelector.getDefault();
93     *    PropertySelector.setDefault(new DefaultPropertySelector(delegate));
94     * </pre>
95     *
96     * @param delegate the proxy selector to delegate to if system settings are used. Usually
97     * this is the proxy selector found by ProxySelector.getDefault() before this proxy
98     * selector is installed
99     */
100    public DefaultProxySelector(ProxySelector delegate) {
101        this.delegate = delegate;
102        initFromPreferences();
103    }
104
105    protected int parseProxyPortValue(String property, String value) {
106        if (value == null) return 0;
107        int port = 0;
108        try {
109            port = Integer.parseInt(value);
110        } catch (NumberFormatException e) {
111            Logging.error(tr("Unexpected format for port number in preference ''{0}''. Got ''{1}''.", property, value));
112            Logging.error(tr("The proxy will not be used."));
113            return 0;
114        }
115        if (port <= 0 || port > 65_535) {
116            Logging.error(tr("Illegal port number in preference ''{0}''. Got {1}.", property, port));
117            Logging.error(tr("The proxy will not be used."));
118            return 0;
119        }
120        return port;
121    }
122
123    /**
124     * Initializes the proxy selector from the setting in the preferences.
125     *
126     */
127    public final void initFromPreferences() {
128        String value = Main.pref.get(PROXY_POLICY);
129        if (value.isEmpty()) {
130            proxyPolicy = ProxyPolicy.NO_PROXY;
131        } else {
132            proxyPolicy = ProxyPolicy.fromName(value);
133            if (proxyPolicy == null) {
134                Logging.warn(tr("Unexpected value for preference ''{0}'' found. Got ''{1}''. Will use no proxy.",
135                        PROXY_POLICY, value));
136                proxyPolicy = ProxyPolicy.NO_PROXY;
137            }
138        }
139        String host = Main.pref.get(PROXY_HTTP_HOST, null);
140        int port = parseProxyPortValue(PROXY_HTTP_PORT, Main.pref.get(PROXY_HTTP_PORT, null));
141        httpProxySocketAddress = null;
142        if (proxyPolicy.equals(ProxyPolicy.USE_HTTP_PROXY)) {
143            if (host != null && !host.trim().isEmpty() && port > 0) {
144                httpProxySocketAddress = new InetSocketAddress(host, port);
145            } else {
146                Logging.warn(tr("Unexpected parameters for HTTP proxy. Got host ''{0}'' and port ''{1}''.", host, port));
147                Logging.warn(tr("The proxy will not be used."));
148            }
149        }
150
151        host = Main.pref.get(PROXY_SOCKS_HOST, null);
152        port = parseProxyPortValue(PROXY_SOCKS_PORT, Main.pref.get(PROXY_SOCKS_PORT, null));
153        socksProxySocketAddress = null;
154        if (proxyPolicy.equals(ProxyPolicy.USE_SOCKS_PROXY)) {
155            if (host != null && !host.trim().isEmpty() && port > 0) {
156                socksProxySocketAddress = new InetSocketAddress(host, port);
157            } else {
158                Logging.warn(tr("Unexpected parameters for SOCKS proxy. Got host ''{0}'' and port ''{1}''.", host, port));
159                Logging.warn(tr("The proxy will not be used."));
160            }
161        }
162        proxyExceptions = new HashSet<>(
163            Main.pref.getCollection(PROXY_EXCEPTIONS,
164                    Arrays.asList("localhost", IPV4_LOOPBACK, IPV6_LOOPBACK))
165        );
166    }
167
168    @Override
169    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
170        // Just log something. The network stack will also throw an exception which will be caught somewhere else
171        Logging.error(tr("Connection to proxy ''{0}'' for URI ''{1}'' failed. Exception was: {2}",
172                sa.toString(), uri.toString(), ioe.toString()));
173        // Remember errors to give a friendly user message asking to review proxy configuration
174        errorResources.add(uri.toString());
175        errorMessages.add(ioe.toString());
176    }
177
178    /**
179     * Returns the set of current proxy resources that failed to be retrieved.
180     * @return the set of current proxy resources that failed to be retrieved
181     * @since 6523
182     */
183    public final Set<String> getErrorResources() {
184        return new TreeSet<>(errorResources);
185    }
186
187    /**
188     * Returns the set of current proxy error messages.
189     * @return the set of current proxy error messages
190     * @since 6523
191     */
192    public final Set<String> getErrorMessages() {
193        return new TreeSet<>(errorMessages);
194    }
195
196    /**
197     * Clear the sets of failed resources and error messages.
198     * @since 6523
199     */
200    public final void clearErrors() {
201        errorResources.clear();
202        errorMessages.clear();
203    }
204
205    /**
206     * Determines if proxy errors have occured.
207     * @return {@code true} if errors have occured, {@code false} otherwise.
208     * @since 6523
209     */
210    public final boolean hasErrors() {
211        return !errorResources.isEmpty();
212    }
213
214    @Override
215    public List<Proxy> select(URI uri) {
216        if (uri != null && proxyExceptions.contains(uri.getHost())) {
217            return NO_PROXY_LIST;
218        }
219        switch(proxyPolicy) {
220        case USE_SYSTEM_SETTINGS:
221            if (!jvmWillUseSystemProxies) {
222                Logging.warn(tr("The JVM is not configured to lookup proxies from the system settings. "+
223                        "The property ''java.net.useSystemProxies'' was missing at startup time.  Will not use a proxy."));
224                return NO_PROXY_LIST;
225            }
226            // delegate to the former proxy selector
227            return delegate.select(uri);
228        case NO_PROXY:
229            return NO_PROXY_LIST;
230        case USE_HTTP_PROXY:
231            if (httpProxySocketAddress == null)
232                return NO_PROXY_LIST;
233            return Collections.singletonList(new Proxy(Type.HTTP, httpProxySocketAddress));
234        case USE_SOCKS_PROXY:
235            if (socksProxySocketAddress == null)
236                return NO_PROXY_LIST;
237            return Collections.singletonList(new Proxy(Type.SOCKS, socksProxySocketAddress));
238        }
239        // should not happen
240        return null;
241    }
242}
Note: See TracBrowser for help on using the repository browser.