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

Last change on this file since 13649 was 13647, checked in by Don-vip, 6 years ago

see #16204 - Allow to start and close JOSM in WebStart sandbox mode (where every external access is denied). This was very useful to reproduce some very tricky bugs that occured in real life but were almost impossible to diagnose.

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