100 * basis, and change it only when the "source", i.e. the system property, |
98 * basis, and change it only when the "source", i.e. the system property, |
101 * did change. |
99 * did change. |
102 */ |
100 */ |
103 |
101 |
104 static class NonProxyInfo { |
102 static class NonProxyInfo { |
|
103 // Default value for nonProxyHosts, this provides backward compatibility |
|
104 // by excluding localhost and its litteral notations. |
|
105 static final String defStringVal = "localhost|127.*|[::1]"; |
|
106 |
105 String hostsSource; |
107 String hostsSource; |
106 RegexpPool hostsPool; |
108 RegexpPool hostsPool; |
107 String property; |
109 final String property; |
108 |
110 final String defaultVal; |
109 static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null); |
111 static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null, defStringVal); |
110 static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null); |
112 static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null, defStringVal); |
111 |
113 |
112 NonProxyInfo(String p, String s, RegexpPool pool) { |
114 NonProxyInfo(String p, String s, RegexpPool pool, String d) { |
113 property = p; |
115 property = p; |
114 hostsSource = s; |
116 hostsSource = s; |
115 hostsPool = pool; |
117 hostsPool = pool; |
|
118 defaultVal = d; |
116 } |
119 } |
117 } |
120 } |
118 |
121 |
119 |
122 |
120 /** |
123 /** |
128 if (uri == null) { |
131 if (uri == null) { |
129 throw new IllegalArgumentException("URI can't be null."); |
132 throw new IllegalArgumentException("URI can't be null."); |
130 } |
133 } |
131 String protocol = uri.getScheme(); |
134 String protocol = uri.getScheme(); |
132 String host = uri.getHost(); |
135 String host = uri.getHost(); |
133 int port = uri.getPort(); |
|
134 |
136 |
135 if (host == null) { |
137 if (host == null) { |
136 // This is a hack to ensure backward compatibility in two |
138 // This is a hack to ensure backward compatibility in two |
137 // cases: 1. hostnames contain non-ascii characters, |
139 // cases: 1. hostnames contain non-ascii characters, |
138 // internationalized domain names. in which case, URI will |
140 // internationalized domain names. in which case, URI will |
147 if (i >= 0) { |
149 if (i >= 0) { |
148 auth = auth.substring(i+1); |
150 auth = auth.substring(i+1); |
149 } |
151 } |
150 i = auth.lastIndexOf(':'); |
152 i = auth.lastIndexOf(':'); |
151 if (i >= 0) { |
153 if (i >= 0) { |
152 try { |
|
153 port = Integer.parseInt(auth.substring(i+1)); |
|
154 } catch (NumberFormatException e) { |
|
155 port = -1; |
|
156 } |
|
157 auth = auth.substring(0,i); |
154 auth = auth.substring(0,i); |
158 } |
155 } |
159 host = auth; |
156 host = auth; |
160 } |
157 } |
161 } |
158 } |
162 |
159 |
163 if (protocol == null || host == null) { |
160 if (protocol == null || host == null) { |
164 throw new IllegalArgumentException("protocol = "+protocol+" host = "+host); |
161 throw new IllegalArgumentException("protocol = "+protocol+" host = "+host); |
165 } |
162 } |
166 List<Proxy> proxyl = new ArrayList<Proxy>(1); |
163 List<Proxy> proxyl = new ArrayList<Proxy>(1); |
167 |
|
168 // special case localhost and loopback addresses to |
|
169 // not go through proxy |
|
170 if (isLoopback(host)) { |
|
171 proxyl.add(Proxy.NO_PROXY); |
|
172 return proxyl; |
|
173 } |
|
174 |
164 |
175 NonProxyInfo pinfo = null; |
165 NonProxyInfo pinfo = null; |
176 |
166 |
177 if ("http".equalsIgnoreCase(protocol)) { |
167 if ("http".equalsIgnoreCase(protocol)) { |
178 pinfo = NonProxyInfo.httpNonProxyInfo; |
168 pinfo = NonProxyInfo.httpNonProxyInfo; |
242 // Let's get the NonProxyHosts property |
232 // Let's get the NonProxyHosts property |
243 if (nprop != null) { |
233 if (nprop != null) { |
244 nphosts = NetProperties.get(nprop.property); |
234 nphosts = NetProperties.get(nprop.property); |
245 synchronized (nprop) { |
235 synchronized (nprop) { |
246 if (nphosts == null) { |
236 if (nphosts == null) { |
247 nprop.hostsSource = null; |
237 if (nprop.defaultVal != null) { |
248 nprop.hostsPool = null; |
238 nphosts = nprop.defaultVal; |
249 } else { |
239 } else { |
|
240 nprop.hostsSource = null; |
|
241 nprop.hostsPool = null; |
|
242 } |
|
243 } |
|
244 if (nphosts != null) { |
250 if (!nphosts.equals(nprop.hostsSource)) { |
245 if (!nphosts.equals(nprop.hostsSource)) { |
251 RegexpPool pool = new RegexpPool(); |
246 RegexpPool pool = new RegexpPool(); |
252 StringTokenizer st = new StringTokenizer(nphosts, "|", false); |
247 StringTokenizer st = new StringTokenizer(nphosts, "|", false); |
253 try { |
248 try { |
254 while (st.hasMoreTokens()) { |
249 while (st.hasMoreTokens()) { |
332 } else { |
327 } else { |
333 return -1; |
328 return -1; |
334 } |
329 } |
335 } |
330 } |
336 |
331 |
337 private boolean isLoopback(String host) { |
|
338 if (host == null || host.length() == 0) |
|
339 return false; |
|
340 |
|
341 if (host.equalsIgnoreCase("localhost")) |
|
342 return true; |
|
343 |
|
344 /* The string could represent a numerical IP address. |
|
345 * For IPv4 addresses, check whether it starts with 127. |
|
346 * For IPv6 addresses, check whether it is ::1 or its equivalent. |
|
347 * Don't check IPv4-mapped or IPv4-compatible addresses |
|
348 */ |
|
349 |
|
350 if (host.startsWith("127.")) { |
|
351 // possible IPv4 loopback address |
|
352 int p = 4; |
|
353 int q; |
|
354 int n = host.length(); |
|
355 // Per RFC2732: At most three digits per byte |
|
356 // Further constraint: Each element fits in a byte |
|
357 if ((q = scanByte(host, p, n)) <= p) return false; p = q; |
|
358 if ((q = scan(host, p, n, '.')) <= p) return q == n && number > 0; p = q; |
|
359 if ((q = scanByte(host, p, n)) <= p) return false; p = q; |
|
360 if ((q = scan(host, p, n, '.')) <= p) return q == n && number > 0; p = q; |
|
361 if ((q = scanByte(host, p, n)) <= p) return false; |
|
362 return q == n && number > 0; |
|
363 } |
|
364 |
|
365 if (host.endsWith(":1")) { |
|
366 final Pattern p6 = Pattern.compile("::1|(0:){7}1|(0:){1,6}:1"); |
|
367 return p6.matcher(host).matches(); |
|
368 } |
|
369 return false; |
|
370 } |
|
371 |
|
372 // Character-class masks, in reverse order from RFC2396 because |
|
373 // initializers for static fields cannot make forward references. |
|
374 |
|
375 // Compute a low-order mask for the characters |
|
376 // between first and last, inclusive |
|
377 private static long lowMask(char first, char last) { |
|
378 long m = 0; |
|
379 int f = Math.max(Math.min(first, 63), 0); |
|
380 int l = Math.max(Math.min(last, 63), 0); |
|
381 for (int i = f; i <= l; i++) |
|
382 m |= 1L << i; |
|
383 return m; |
|
384 } |
|
385 // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | |
|
386 // "8" | "9" |
|
387 private static final long L_DIGIT = lowMask('0', '9'); |
|
388 private static final long H_DIGIT = 0L; |
|
389 |
|
390 // Scan a string of decimal digits whose value fits in a byte |
|
391 // |
|
392 private int number; |
|
393 private int scanByte(String input, int start, int n) |
|
394 { |
|
395 int p = start; |
|
396 int q = scan(input, p, n, L_DIGIT, H_DIGIT); |
|
397 if (q <= p) return q; |
|
398 number = Integer.parseInt(input.substring(p, q)); |
|
399 if (number > 255) return p; |
|
400 return q; |
|
401 } |
|
402 |
|
403 // Scan a specific char: If the char at the given start position is |
|
404 // equal to c, return the index of the next char; otherwise, return the |
|
405 // start position. |
|
406 // |
|
407 private int scan(String input, int start, int end, char c) { |
|
408 if ((start < end) && (input.charAt(start) == c)) |
|
409 return start + 1; |
|
410 return start; |
|
411 } |
|
412 |
|
413 // Scan chars that match the given mask pair |
|
414 // |
|
415 private int scan(String input, int start, int n, long lowMask, long highMask) |
|
416 { |
|
417 int p = start; |
|
418 while (p < n) { |
|
419 char c = input.charAt(p); |
|
420 if (match(c, lowMask, highMask)) { |
|
421 p++; |
|
422 continue; |
|
423 } |
|
424 break; |
|
425 } |
|
426 return p; |
|
427 } |
|
428 |
|
429 // Tell whether the given character is permitted by the given mask pair |
|
430 private boolean match(char c, long lowMask, long highMask) { |
|
431 if (c < 64) |
|
432 return ((1L << c) & lowMask) != 0; |
|
433 if (c < 128) |
|
434 return ((1L << (c - 64)) & highMask) != 0; |
|
435 return false; |
|
436 } |
|
437 |
|
438 private native static boolean init(); |
332 private native static boolean init(); |
439 private native Proxy getSystemProxy(String protocol, String host); |
333 private native Proxy getSystemProxy(String protocol, String host); |
440 } |
334 } |