PageRenderTime 54ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/jdk/src/share/classes/sun/net/spi/DefaultProxySelector.java

https://bitbucket.org/nkabir/jdk-6
Java | 440 lines | 262 code | 38 blank | 140 comment | 107 complexity | d96bb425a5f8c6ecde837e02cd103459 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, BSD-3-Clause
  1. /*
  2. * Copyright (c) 2003, 2004, 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. Oracle designates this
  8. * particular file as subject to the "Classpath" exception as provided
  9. * by Oracle in the LICENSE file that accompanied this code.
  10. *
  11. * This code is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * version 2 for more details (a copy is included in the LICENSE file that
  15. * accompanied this code).
  16. *
  17. * You should have received a copy of the GNU General Public License version
  18. * 2 along with this work; if not, write to the Free Software Foundation,
  19. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20. *
  21. * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22. * or visit www.oracle.com if you need additional information or have any
  23. * questions.
  24. */
  25. package sun.net.spi;
  26. import sun.net.www.http.*;
  27. import sun.net.NetProperties;
  28. import java.net.*;
  29. import java.util.*;
  30. import java.util.regex.*;
  31. import java.io.*;
  32. import sun.misc.RegexpPool;
  33. import java.security.AccessController;
  34. import java.security.PrivilegedAction;
  35. /**
  36. * Supports proxy settings using system properties This proxy selector
  37. * provides backward compatibility with the old http protocol handler
  38. * as far as how proxy is set
  39. *
  40. * Most of the implementation copied from the old http protocol handler
  41. *
  42. * Supports http/https/ftp.proxyHost, http/https/ftp.proxyPort,
  43. * proxyHost, proxyPort, and http/https/ftp.nonProxyHost, and socks.
  44. * NOTE: need to do gopher as well
  45. */
  46. public class DefaultProxySelector extends ProxySelector {
  47. /**
  48. * This is where we define all the valid System Properties we have to
  49. * support for each given protocol.
  50. * The format of this 2 dimensional array is :
  51. * - 1 row per protocol (http, ftp, ...)
  52. * - 1st element of each row is the protocol name
  53. * - subsequent elements are prefixes for Host & Port properties
  54. * listed in order of priority.
  55. * Example:
  56. * {"ftp", "ftp.proxy", "ftpProxy", "proxy", "socksProxy"},
  57. * means for FTP we try in that oder:
  58. * + ftp.proxyHost & ftp.proxyPort
  59. * + ftpProxyHost & ftpProxyPort
  60. * + proxyHost & proxyPort
  61. * + socksProxyHost & socksProxyPort
  62. *
  63. * Note that the socksProxy should *always* be the last on the list
  64. */
  65. final static String[][] props = {
  66. /*
  67. * protocol, Property prefix 1, Property prefix 2, ...
  68. */
  69. {"http", "http.proxy", "proxy", "socksProxy"},
  70. {"https", "https.proxy", "proxy", "socksProxy"},
  71. {"ftp", "ftp.proxy", "ftpProxy", "proxy", "socksProxy"},
  72. {"gopher", "gopherProxy", "socksProxy"},
  73. {"socket", "socksProxy"}
  74. };
  75. private static boolean hasSystemProxies = false;
  76. private static Properties defprops = new Properties();
  77. static {
  78. final String key = "java.net.useSystemProxies";
  79. Boolean b = (Boolean) AccessController.doPrivileged(
  80. new PrivilegedAction() {
  81. public Object run() {
  82. return NetProperties.getBoolean(key);
  83. }});
  84. if (b != null && b.booleanValue()) {
  85. java.security.AccessController.doPrivileged(
  86. new sun.security.action.LoadLibraryAction("net"));
  87. hasSystemProxies = init();
  88. }
  89. }
  90. /**
  91. * How to deal with "non proxy hosts":
  92. * since we do have to generate a RegexpPool we don't want to do that if
  93. * it's not necessary. Therefore we do cache the result, on a per-protocol
  94. * basis, and change it only when the "source", i.e. the system property,
  95. * did change.
  96. */
  97. static class NonProxyInfo {
  98. String hostsSource;
  99. RegexpPool hostsPool;
  100. String property;
  101. NonProxyInfo(String p, String s, RegexpPool pool) {
  102. property = p;
  103. hostsSource = s;
  104. hostsPool = pool;
  105. }
  106. }
  107. private static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null);
  108. private static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null);
  109. /**
  110. * select() method. Where all the hard work is done.
  111. * Build a list of proxies depending on URI.
  112. * Since we're only providing compatibility with the system properties
  113. * from previous releases (see list above), that list will always
  114. * contain 1 single proxy, default being NO_PROXY.
  115. */
  116. public java.util.List<Proxy> select(URI uri) {
  117. if (uri == null) {
  118. throw new IllegalArgumentException("URI can't be null.");
  119. }
  120. String protocol = uri.getScheme();
  121. String host = uri.getHost();
  122. int port = uri.getPort();
  123. if (host == null) {
  124. // This is a hack to ensure backward compatibility in two
  125. // cases: 1. hostnames contain non-ascii characters,
  126. // internationalized domain names. in which case, URI will
  127. // return null, see BugID 4957669; 2. Some hostnames can
  128. // contain '_' chars even though it's not supposed to be
  129. // legal, in which case URI will return null for getHost,
  130. // but not for getAuthority() See BugID 4913253
  131. String auth = uri.getAuthority();
  132. if (auth != null) {
  133. int i;
  134. i = auth.indexOf('@');
  135. if (i >= 0) {
  136. auth = auth.substring(i+1);
  137. }
  138. i = auth.lastIndexOf(':');
  139. if (i >= 0) {
  140. try {
  141. port = Integer.parseInt(auth.substring(i+1));
  142. } catch (NumberFormatException e) {
  143. port = -1;
  144. }
  145. auth = auth.substring(0,i);
  146. }
  147. host = auth;
  148. }
  149. }
  150. if (protocol == null || host == null) {
  151. throw new IllegalArgumentException("protocol = "+protocol+" host = "+host);
  152. }
  153. List<Proxy> proxyl = new ArrayList<Proxy>(1);
  154. // special case localhost and loopback addresses to
  155. // not go through proxy
  156. if (isLoopback(host)) {
  157. proxyl.add(Proxy.NO_PROXY);
  158. return proxyl;
  159. }
  160. NonProxyInfo pinfo = null;
  161. if ("http".equalsIgnoreCase(protocol)) {
  162. pinfo = httpNonProxyInfo;
  163. } else if ("https".equalsIgnoreCase(protocol)) {
  164. // HTTPS uses the same property as HTTP, for backward
  165. // compatibility
  166. pinfo = httpNonProxyInfo;
  167. } else if ("ftp".equalsIgnoreCase(protocol)) {
  168. pinfo = ftpNonProxyInfo;
  169. }
  170. /**
  171. * Let's check the System properties for that protocol
  172. */
  173. final String proto = protocol;
  174. final NonProxyInfo nprop = pinfo;
  175. final String urlhost = host.toLowerCase();
  176. /**
  177. * This is one big doPrivileged call, but we're trying to optimize
  178. * the code as much as possible. Since we're checking quite a few
  179. * System properties it does help having only 1 call to doPrivileged.
  180. * Be mindful what you do in here though!
  181. */
  182. Proxy p = (Proxy) AccessController.doPrivileged(
  183. new PrivilegedAction() {
  184. public Object run() {
  185. int i, j;
  186. String phost = null;
  187. int pport = 0;
  188. String nphosts = null;
  189. InetSocketAddress saddr = null;
  190. // Then let's walk the list of protocols in our array
  191. for (i=0; i<props.length; i++) {
  192. if (props[i][0].equalsIgnoreCase(proto)) {
  193. for (j = 1; j < props[i].length; j++) {
  194. /* System.getProp() will give us an empty
  195. * String, "" for a defined but "empty"
  196. * property.
  197. */
  198. phost = NetProperties.get(props[i][j]+"Host");
  199. if (phost != null && phost.length() != 0)
  200. break;
  201. }
  202. if (phost == null || phost.length() == 0) {
  203. /**
  204. * No system property defined for that
  205. * protocol. Let's check System Proxy
  206. * settings (Gnome & Windows) if we were
  207. * instructed to.
  208. */
  209. if (hasSystemProxies) {
  210. String sproto;
  211. if (proto.equalsIgnoreCase("socket"))
  212. sproto = "socks";
  213. else
  214. sproto = proto;
  215. Proxy sproxy = getSystemProxy(sproto, urlhost);
  216. if (sproxy != null) {
  217. return sproxy;
  218. }
  219. }
  220. return Proxy.NO_PROXY;
  221. }
  222. // If a Proxy Host is defined for that protocol
  223. // Let's get the NonProxyHosts property
  224. if (nprop != null) {
  225. nphosts = NetProperties.get(nprop.property);
  226. synchronized (nprop) {
  227. if (nphosts == null) {
  228. nprop.hostsSource = null;
  229. nprop.hostsPool = null;
  230. } else {
  231. if (!nphosts.equals(nprop.hostsSource)) {
  232. RegexpPool pool = new RegexpPool();
  233. StringTokenizer st = new StringTokenizer(nphosts, "|", false);
  234. try {
  235. while (st.hasMoreTokens()) {
  236. pool.add(st.nextToken().toLowerCase(), Boolean.TRUE);
  237. }
  238. } catch (sun.misc.REException ex) {
  239. }
  240. nprop.hostsPool = pool;
  241. nprop.hostsSource = nphosts;
  242. }
  243. }
  244. if (nprop.hostsPool != null &&
  245. nprop.hostsPool.match(urlhost) != null) {
  246. return Proxy.NO_PROXY;
  247. }
  248. }
  249. }
  250. // We got a host, let's check for port
  251. pport = NetProperties.getInteger(props[i][j]+"Port", 0).intValue();
  252. if (pport == 0 && j < (props[i].length - 1)) {
  253. // Can't find a port with same prefix as Host
  254. // AND it's not a SOCKS proxy
  255. // Let's try the other prefixes for that proto
  256. for (int k = 1; k < (props[i].length - 1); k++) {
  257. if ((k != j) && (pport == 0))
  258. pport = NetProperties.getInteger(props[i][k]+"Port", 0).intValue();
  259. }
  260. }
  261. // Still couldn't find a port, let's use default
  262. if (pport == 0) {
  263. if (j == (props[i].length - 1)) // SOCKS
  264. pport = defaultPort("socket");
  265. else
  266. pport = defaultPort(proto);
  267. }
  268. // We did find a proxy definition.
  269. // Let's create the address, but don't resolve it
  270. // as this will be done at connection time
  271. saddr = InetSocketAddress.createUnresolved(phost, pport);
  272. // Socks is *always* the last on the list.
  273. if (j == (props[i].length - 1)) {
  274. return new Proxy(Proxy.Type.SOCKS, saddr);
  275. } else {
  276. return new Proxy(Proxy.Type.HTTP, saddr);
  277. }
  278. }
  279. }
  280. return Proxy.NO_PROXY;
  281. }});
  282. proxyl.add(p);
  283. /*
  284. * If no specific property was set for that URI, we should be
  285. * returning an iterator to an empty List.
  286. */
  287. return proxyl;
  288. }
  289. public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
  290. if (uri == null || sa == null || ioe == null) {
  291. throw new IllegalArgumentException("Arguments can't be null.");
  292. }
  293. // ignored
  294. }
  295. private int defaultPort(String protocol) {
  296. if ("http".equalsIgnoreCase(protocol)) {
  297. return 80;
  298. } else if ("https".equalsIgnoreCase(protocol)) {
  299. return 443;
  300. } else if ("ftp".equalsIgnoreCase(protocol)) {
  301. return 80;
  302. } else if ("socket".equalsIgnoreCase(protocol)) {
  303. return 1080;
  304. } else if ("gopher".equalsIgnoreCase(protocol)) {
  305. return 80;
  306. } else {
  307. return -1;
  308. }
  309. }
  310. private static final Pattern p6 = Pattern.compile("::1|(0:){7}1|(0:){1,6}:1");
  311. private boolean isLoopback(String host) {
  312. if (host == null || host.length() == 0)
  313. return false;
  314. if (host.equalsIgnoreCase("localhost"))
  315. return true;
  316. /* The string could represent a numerical IP address.
  317. * For IPv4 addresses, check whether it starts with 127.
  318. * For IPv6 addresses, check whether it is ::1 or its equivalent.
  319. * Don't check IPv4-mapped or IPv4-compatible addresses
  320. */
  321. if (host.startsWith("127.")) {
  322. // possible IPv4 loopback address
  323. int p = 4;
  324. int q;
  325. int n = host.length();
  326. // Per RFC2732: At most three digits per byte
  327. // Further constraint: Each element fits in a byte
  328. if ((q = scanByte(host, p, n)) <= p) return false; p = q;
  329. if ((q = scan(host, p, n, '.')) <= p) return q == n && number > 0; p = q;
  330. if ((q = scanByte(host, p, n)) <= p) return false; p = q;
  331. if ((q = scan(host, p, n, '.')) <= p) return q == n && number > 0; p = q;
  332. if ((q = scanByte(host, p, n)) <= p) return false;
  333. return q == n && number > 0;
  334. }
  335. if (host.endsWith(":1")) {
  336. return p6.matcher(host).matches();
  337. }
  338. return false;
  339. }
  340. // Character-class masks, in reverse order from RFC2396 because
  341. // initializers for static fields cannot make forward references.
  342. // Compute a low-order mask for the characters
  343. // between first and last, inclusive
  344. private static long lowMask(char first, char last) {
  345. long m = 0;
  346. int f = Math.max(Math.min(first, 63), 0);
  347. int l = Math.max(Math.min(last, 63), 0);
  348. for (int i = f; i <= l; i++)
  349. m |= 1L << i;
  350. return m;
  351. }
  352. // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
  353. // "8" | "9"
  354. private static final long L_DIGIT = lowMask('0', '9');
  355. private static final long H_DIGIT = 0L;
  356. // Scan a string of decimal digits whose value fits in a byte
  357. //
  358. private int number;
  359. private int scanByte(String input, int start, int n)
  360. {
  361. int p = start;
  362. int q = scan(input, p, n, L_DIGIT, H_DIGIT);
  363. if (q <= p) return q;
  364. number = Integer.parseInt(input.substring(p, q));
  365. if (number > 255) return p;
  366. return q;
  367. }
  368. // Scan a specific char: If the char at the given start position is
  369. // equal to c, return the index of the next char; otherwise, return the
  370. // start position.
  371. //
  372. private int scan(String input, int start, int end, char c) {
  373. if ((start < end) && (input.charAt(start) == c))
  374. return start + 1;
  375. return start;
  376. }
  377. // Scan chars that match the given mask pair
  378. //
  379. private int scan(String input, int start, int n, long lowMask, long highMask)
  380. {
  381. int p = start;
  382. while (p < n) {
  383. char c = input.charAt(p);
  384. if (match(c, lowMask, highMask)) {
  385. p++;
  386. continue;
  387. }
  388. break;
  389. }
  390. return p;
  391. }
  392. // Tell whether the given character is permitted by the given mask pair
  393. private boolean match(char c, long lowMask, long highMask) {
  394. if (c < 64)
  395. return ((1L << c) & lowMask) != 0;
  396. if (c < 128)
  397. return ((1L << (c - 64)) & highMask) != 0;
  398. return false;
  399. }
  400. private native static boolean init();
  401. private native Proxy getSystemProxy(String protocol, String host);
  402. }