001: /*
002: * $HeadURL: https://svn.apache.org/repos/asf/jakarta/httpcomponents/oac.hc3x/tags/HTTPCLIENT_3_1/src/contrib/org/apache/commons/httpclient/contrib/proxy/PluginProxyUtil.java $
003: * $Revision: 480424 $
004: * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
005: *
006: * ====================================================================
007: *
008: * Licensed to the Apache Software Foundation (ASF) under one or more
009: * contributor license agreements. See the NOTICE file distributed with
010: * this work for additional information regarding copyright ownership.
011: * The ASF licenses this file to You under the Apache License, Version 2.0
012: * (the "License"); you may not use this file except in compliance with
013: * the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing, software
018: * distributed under the License is distributed on an "AS IS" BASIS,
019: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020: * See the License for the specific language governing permissions and
021: * limitations under the License.
022: * ====================================================================
023: *
024: * This software consists of voluntary contributions made by many
025: * individuals on behalf of the Apache Software Foundation. For more
026: * information on the Apache Software Foundation, please see
027: * <http://www.apache.org/>.
028: *
029: */
030: package org.apache.commons.httpclient.contrib.proxy;
031:
032: import java.lang.reflect.Array;
033: import java.lang.reflect.Method;
034: import java.net.URL;
035: import java.util.Properties;
036:
037: import org.apache.commons.httpclient.ProxyHost;
038: import org.apache.commons.logging.Log;
039: import org.apache.commons.logging.LogFactory;
040:
041: /**
042: * A utility class that gives applets the ability to detect proxy host settings.
043: * This was adapted from a post from Chris Forster on 20030227 to a Sun Java
044: * forum here:
045: * http://forum.java.sun.com/thread.jspa?threadID=364342&tstart=120
046: *
047: * The algorithm - which relies on Sun java plugin internal classes in some
048: * cases - was maintained, but the following changes were made:
049: *
050: * 1. Logging was used to allow control of debug type messages.
051: * 2. Reflection is used instead of direct references to Sun internal classes
052: * to avoid the need to have these classes in the CLASSPATH to compile.
053: * 3. Removed the use of global variables to allow this class to be used in
054: * a multi-threaded environment.
055: * 4. Add the use of exception to indicate to the caller when proxy detection
056: * failed as opposed to when no proxy is configured.
057: *
058: * <p>
059: * DISCLAIMER: HttpClient developers DO NOT actively support this component.
060: * The component is provided as a reference material, which may be inappropriate
061: * for use without additional customization.
062: * </p>
063: */
064: public class PluginProxyUtil {
065:
066: /** Log object for this class */
067: private static final Log LOG = LogFactory
068: .getLog(PluginProxyUtil.class);
069:
070: /**
071: * This is used internally to indicate that no proxy detection succeeded
072: * and no proxy setting is to be used - failover is unnecessary
073: */
074: private static final ProxyHost NO_PROXY_HOST = new ProxyHost("", 80);
075:
076: /**
077: * The system property that is used to convey proxy information in some VM's
078: */
079: private static final String PLUGIN_PROXY_CONFIG_PROP = "javaplugin.proxy.config.list";
080:
081: /**
082: * Returns the Proxy Host information using settings from the java plugin.
083: *
084: * @param sampleURL the url target for which proxy host information is
085: * required
086: * @return the proxy host info (name and port) or null if a direct
087: * connection is allowed to the target url.
088: * @throws ProxyDetectionException if detection failed
089: */
090: public static ProxyHost detectProxy(URL sampleURL)
091: throws ProxyDetectionException {
092:
093: ProxyHost result = null;
094: String javaVers = System.getProperty("java.runtime.version");
095:
096: if (LOG.isDebugEnabled()) {
097: LOG
098: .debug("About to attempt auto proxy detection under Java "
099: + "version:" + javaVers);
100: }
101:
102: // If specific, known detection methods fail may try fallback
103: // detection method
104: boolean invokeFailover = false;
105:
106: if (javaVers.startsWith("1.3")) {
107: result = detectProxySettingsJDK13(sampleURL);
108: if (result == null) {
109: invokeFailover = true;
110: }
111: } else if (javaVers.startsWith("1.4")
112: || (javaVers.startsWith("1.5") || javaVers
113: .startsWith("1.6"))) {
114: result = detectProxySettingsJDK14_JDK15_JDK16(sampleURL);
115: if (result == null) {
116: invokeFailover = true;
117: }
118: } else {
119: if (LOG.isDebugEnabled()) {
120: LOG
121: .debug("Sun Plugin reported java version not 1.3.X, "
122: + "1.4.X, 1.5.X or 1.6.X - trying failover detection...");
123: }
124: invokeFailover = true;
125: }
126: if (invokeFailover) {
127: if (LOG.isDebugEnabled()) {
128: LOG.debug("Using failover proxy detection...");
129: }
130: result = getPluginProxyConfigSettings();
131: }
132: if (NO_PROXY_HOST.equals(result)) {
133: result = null;
134: }
135: return result;
136: }
137:
138: /**
139: * Use Sun-specific internal plugin proxy classes for 1.3.X
140: * Look around for the 1.3.X plugin proxy detection class. Without it,
141: * cannot autodetect...
142: *
143: * @param sampleURL the URL to check proxy settings for
144: * @return ProxyHost the host and port of the proxy that should be used
145: * @throws ProxyDetectionException if detection failed
146: */
147: private static ProxyHost detectProxySettingsJDK13(URL sampleURL)
148: throws ProxyDetectionException {
149: ProxyHost result = null;
150: try {
151: // Attempt to discover proxy info by asking internal plugin
152: // code to locate proxy path to server sampleURL...
153: Class pluginProxyHandler = Class
154: .forName("sun.plugin.protocol.PluginProxyHandler");
155: Method getDefaultProxyHandlerMethod = pluginProxyHandler
156: .getDeclaredMethod("getDefaultProxyHandler", null);
157: Object proxyHandlerObj = getDefaultProxyHandlerMethod
158: .invoke(null, null);
159: if (proxyHandlerObj != null) {
160: Class proxyHandlerClass = proxyHandlerObj.getClass();
161: Method getProxyInfoMethod = proxyHandlerClass
162: .getDeclaredMethod("getProxyInfo",
163: new Class[] { URL.class });
164: Object proxyInfoObject = getProxyInfoMethod.invoke(
165: proxyHandlerObj, new Object[] { sampleURL });
166: if (proxyInfoObject != null) {
167: Class proxyInfoClass = proxyInfoObject.getClass();
168: Method getProxyMethod = proxyInfoClass
169: .getDeclaredMethod("getProxy", null);
170: boolean useProxy = (getProxyMethod.invoke(
171: proxyInfoObject, null) != null);
172: if (useProxy) {
173: String proxyIP = (String) getProxyMethod
174: .invoke(proxyInfoObject, null);
175: Method getProxyPortMethod = proxyInfoClass
176: .getDeclaredMethod("getPort", null);
177: Integer portInteger = (Integer) getProxyPortMethod
178: .invoke(proxyInfoObject, null);
179: int proxyPort = portInteger.intValue();
180: if (LOG.isDebugEnabled()) {
181: LOG.debug("1.3.X: proxy=" + proxyIP
182: + " port=" + proxyPort);
183: }
184: result = new ProxyHost(proxyIP, proxyPort);
185: } else {
186: if (LOG.isDebugEnabled()) {
187: LOG
188: .debug("1.3.X reported NULL for "
189: + "proxyInfo.getProxy (no proxy assumed)");
190: }
191: result = NO_PROXY_HOST;
192: }
193: } else {
194: if (LOG.isDebugEnabled()) {
195: LOG.debug("NULL proxyInfo in 1.3.X auto proxy "
196: + "detection, (no proxy assumed)");
197: }
198: result = NO_PROXY_HOST;
199: }
200: } else {
201: throw new ProxyDetectionException(
202: "Sun Plugin 1.3.X failed to provide a default proxy handler");
203: }
204: } catch (Exception e) {
205: LOG.warn("Sun Plugin 1.3.X proxy detection class not "
206: + "found, will try failover detection, e:" + e);
207: }
208: return result;
209: }
210:
211: /**
212: * Returns the proxy information for the specified sampleURL using JRE 1.4
213: * specific plugin classes.
214: *
215: * Notes:
216: * Plugin 1.4 Final added
217: * com.sun.java.browser.net.* classes ProxyInfo & ProxyService...
218: * Use those with JREs => 1.4
219: *
220: * @param sampleURL the URL to check proxy settings for
221: * @return ProxyHost the host and port of the proxy that should be used
222: */
223: private static ProxyHost detectProxySettingsJDK14_JDK15_JDK16(
224: URL sampleURL) {
225: ProxyHost result = null;
226: try {
227: // Look around for the 1.4.X plugin proxy detection class...
228: // Without it, cannot autodetect...
229: Class ProxyServiceClass = Class
230: .forName("com.sun.java.browser.net.ProxyService");
231: Method getProxyInfoMethod = ProxyServiceClass
232: .getDeclaredMethod("getProxyInfo",
233: new Class[] { URL.class });
234: Object proxyInfoArrayObj = getProxyInfoMethod.invoke(null,
235: new Object[] { sampleURL });
236:
237: if (proxyInfoArrayObj == null
238: || Array.getLength(proxyInfoArrayObj) == 0) {
239: if (LOG.isDebugEnabled()) {
240: LOG
241: .debug("1.4.X reported NULL proxy (no proxy assumed)");
242: }
243: result = NO_PROXY_HOST;
244: } else {
245: Object proxyInfoObject = Array
246: .get(proxyInfoArrayObj, 0);
247: Class proxyInfoClass = proxyInfoObject.getClass();
248: Method getHostMethod = proxyInfoClass
249: .getDeclaredMethod("getHost", null);
250: String proxyIP = (String) getHostMethod.invoke(
251: proxyInfoObject, null);
252: Method getPortMethod = proxyInfoClass
253: .getDeclaredMethod("getPort", null);
254: Integer portInteger = (Integer) getPortMethod.invoke(
255: proxyInfoObject, null);
256: int proxyPort = portInteger.intValue();
257: if (LOG.isDebugEnabled()) {
258: LOG.debug("1.4.X Proxy info geProxy:" + proxyIP
259: + " get Port:" + proxyPort);
260: }
261: result = new ProxyHost(proxyIP, proxyPort);
262: }
263: } catch (Exception e) {
264: e.printStackTrace();
265: LOG
266: .warn("Sun Plugin 1.4.X proxy detection class not found, "
267: + "will try failover detection, e:" + e);
268: }
269: return result;
270: }
271:
272: /**
273: * Returns the proxy host information found by inspecting the system
274: * property "javaplugin.proxy.config.list".
275: *
276: * @return ProxyHost the host and port of the proxy that should be used
277: * @throws ProxyDetectionException if an exception is encountered while
278: * parsing the value of
279: * PLUGIN_PROXY_CONFIG_PROP
280: */
281: private static ProxyHost getPluginProxyConfigSettings()
282: throws ProxyDetectionException {
283: ProxyHost result = null;
284: try {
285: Properties properties = System.getProperties();
286: String proxyList = properties
287: .getProperty("javaplugin.proxy.config.list");
288: if (LOG.isDebugEnabled()) {
289: LOG.debug("Plugin Proxy Config List Property:"
290: + proxyList);
291: }
292: boolean useProxy = (proxyList != null);
293: if (useProxy) {
294: proxyList = proxyList.toUpperCase();
295: // Using HTTP proxy as proxy for HTTP proxy tunnelled SSL
296: // socket (should be listed FIRST)....
297: // 1/14/03 1.3.1_06 appears to omit HTTP portion of
298: // reported proxy list... Mod to accomodate this...
299: // Expecting proxyList of "HTTP=XXX.XXX.XXX.XXX:Port" OR
300: // "XXX.XXX.XXX.XXX:Port" & assuming HTTP...
301: String proxyIP = "";
302: if (proxyList.indexOf("HTTP=") > -1) {
303: proxyIP = proxyList.substring(proxyList
304: .indexOf("HTTP=") + 5, proxyList
305: .indexOf(":"));
306: } else {
307: proxyIP = proxyList.substring(0, proxyList
308: .indexOf(":"));
309: }
310: int endOfPort = proxyList.indexOf(",");
311: if (endOfPort < 1)
312: endOfPort = proxyList.length();
313: String portString = proxyList.substring(proxyList
314: .indexOf(":") + 1, endOfPort);
315: int proxyPort = Integer.parseInt(portString);
316: if (LOG.isDebugEnabled()) {
317: LOG
318: .debug("proxy " + proxyIP + " port "
319: + proxyPort);
320: }
321: result = new ProxyHost(proxyIP, proxyPort);
322: } else {
323: LOG.debug("No configured plugin proxy list");
324: result = NO_PROXY_HOST;
325: }
326: } catch (Exception e) {
327: if (LOG.isDebugEnabled()) {
328: LOG
329: .debug("Exception during failover auto proxy detection, "
330: + ", e:" + e);
331: throw new ProxyDetectionException(
332: "Encountered unexpected exception while attempting "
333: + "to parse proxy information stored in "
334: + PLUGIN_PROXY_CONFIG_PROP, e);
335: }
336: }
337: return result;
338: }
339: }
|