View Javadoc
1   /*
2    * $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 $
3    * $Revision: 480424 $
4    * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
5    *
6    * ====================================================================
7    *
8    *  Licensed to the Apache Software Foundation (ASF) under one or more
9    *  contributor license agreements.  See the NOTICE file distributed with
10   *  this work for additional information regarding copyright ownership.
11   *  The ASF licenses this file to You under the Apache License, Version 2.0
12   *  (the "License"); you may not use this file except in compliance with
13   *  the License.  You may obtain a copy of the License at
14   *
15   *      http://www.apache.org/licenses/LICENSE-2.0
16   *
17   *  Unless required by applicable law or agreed to in writing, software
18   *  distributed under the License is distributed on an "AS IS" BASIS,
19   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   *  See the License for the specific language governing permissions and
21   *  limitations under the License.
22   * ====================================================================
23   *
24   * This software consists of voluntary contributions made by many
25   * individuals on behalf of the Apache Software Foundation.  For more
26   * information on the Apache Software Foundation, please see
27   * <http://www.apache.org/>.
28   *
29   */
30  package edu.internet2.middleware.grouperClientExt.org.apache.commons.httpclient.contrib.proxy;
31  
32  import java.lang.reflect.Array;
33  import java.lang.reflect.Method;
34  import java.net.URL;
35  import java.util.Properties;
36  
37  import edu.internet2.middleware.grouperClientExt.org.apache.commons.httpclient.ProxyHost;
38  import edu.internet2.middleware.grouperClientExt.org.apache.commons.logging.Log;
39  import edu.internet2.middleware.grouperClientExt.org.apache.commons.logging.LogFactory;
40  
41  /**
42   * A utility class that gives applets the ability to detect proxy host settings.
43   * This was adapted from a post from Chris Forster on 20030227 to a Sun Java 
44   * forum here:
45   * http://forum.java.sun.com/thread.jspa?threadID=364342&tstart=120
46   * 
47   * The algorithm - which relies on Sun java plugin internal classes in some 
48   * cases - was maintained, but the following changes were made:
49   * 
50   * 1. Logging was used to allow control of debug type messages.
51   * 2. Reflection is used instead of direct references to Sun internal classes
52   *    to avoid the need to have these classes in the CLASSPATH to compile.
53   * 3. Removed the use of global variables to allow this class to be used in 
54   *    a multi-threaded environment.
55   * 4. Add the use of exception to indicate to the caller when proxy detection
56   *    failed as opposed to when no proxy is configured.
57   *    
58   * <p>
59   * DISCLAIMER: HttpClient developers DO NOT actively support this component.
60   * The component is provided as a reference material, which may be inappropriate
61   * for use without additional customization.
62   * </p>
63   */
64  public class PluginProxyUtil {
65      
66      /** Log object for this class */
67      private static final Log LOG = LogFactory.getLog(PluginProxyUtil.class);  
68      
69      /** 
70       * This is used internally to indicate that no proxy detection succeeded 
71       * and no proxy setting is to be used - failover is unnecessary
72       */
73      private static final ProxyHostware/grouperClientExt/org/apache/commons/httpclient/ProxyHost.html#ProxyHost">ProxyHost NO_PROXY_HOST = new ProxyHost("",80);
74      
75      /**
76       * The system property that is used to convey proxy information in some VM's 
77       */
78      private static final String PLUGIN_PROXY_CONFIG_PROP = 
79                                                  "javaplugin.proxy.config.list";
80      
81      /**
82       * Returns the Proxy Host information using settings from the java plugin.
83       * 
84       * @param sampleURL the url target for which proxy host information is
85       *                  required 
86       * @return the proxy host info (name and port) or null if a direct 
87       *         connection is allowed to the target url.  
88       * @throws ProxyDetectionException if detection failed
89       */
90      public static ProxyHost detectProxy(URL sampleURL) 
91          throws ProxyDetectionException
92      {
93          
94          ProxyHost result = null;
95          String javaVers = System.getProperty("java.runtime.version");
96          
97          if (LOG.isDebugEnabled()) {
98              LOG.debug("About to attempt auto proxy detection under Java " +
99                        "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") || (javaVers.startsWith("1.5") || javaVers.startsWith("1.6")))  {
112             result = detectProxySettingsJDK14_JDK15_JDK16(sampleURL);
113             if (result == null) {
114                 invokeFailover = true;
115             }
116         } else {
117             if (LOG.isDebugEnabled()) {
118                 LOG.debug("Sun Plugin reported java version not 1.3.X, " +
119                           "1.4.X, 1.5.X or 1.6.X - trying failover detection...");
120             }
121             invokeFailover = true;
122         }
123         if (invokeFailover) {
124             if (LOG.isDebugEnabled()) {
125                 LOG.debug("Using failover proxy detection...");
126             }
127             result = getPluginProxyConfigSettings();
128         }
129         if (NO_PROXY_HOST.equals(result)) {
130             result = null;
131         }
132         return result;
133     }
134 
135     /**
136      * Use Sun-specific internal plugin proxy classes for 1.3.X
137      * Look around for the 1.3.X plugin proxy detection class. Without it, 
138      * cannot autodetect...
139      * 
140      * @param sampleURL the URL to check proxy settings for
141      * @return ProxyHost the host and port of the proxy that should be used
142      * @throws ProxyDetectionException if detection failed
143      */
144     private static ProxyHost detectProxySettingsJDK13(URL sampleURL) 
145         throws ProxyDetectionException
146     {
147         ProxyHost result = null;
148         try {
149             // Attempt to discover proxy info by asking internal plugin 
150             // code to locate proxy path to server sampleURL...
151             Class pluginProxyHandler = 
152                 Class.forName("sun.plugin.protocol.PluginProxyHandler");
153             Method getDefaultProxyHandlerMethod = 
154                 pluginProxyHandler.getDeclaredMethod("getDefaultProxyHandler",
155                                                      null);
156             Object proxyHandlerObj = 
157                 getDefaultProxyHandlerMethod.invoke(null, null);
158             if (proxyHandlerObj != null) {
159                 Class proxyHandlerClass = proxyHandlerObj.getClass();
160                 Method getProxyInfoMethod = 
161                     proxyHandlerClass.getDeclaredMethod("getProxyInfo",
162                                                         new Class[]{URL.class});
163                 Object proxyInfoObject = 
164                     getProxyInfoMethod.invoke(proxyHandlerObj, 
165                                               new Object[] { sampleURL });
166                 if (proxyInfoObject != null) {
167                     Class proxyInfoClass = proxyInfoObject.getClass();
168                     Method getProxyMethod = 
169                         proxyInfoClass.getDeclaredMethod("getProxy", null);
170                     boolean useProxy = 
171                         (getProxyMethod.invoke(proxyInfoObject, null) != null);
172                     if (useProxy) {
173                         String proxyIP = 
174                             (String)getProxyMethod.invoke(proxyInfoObject, null);
175                         Method getProxyPortMethod = 
176                             proxyInfoClass.getDeclaredMethod("getPort", null);
177                         Integer portInteger = 
178                             (Integer)getProxyPortMethod.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.debug("1.3.X reported NULL for " +
188                                       "proxyInfo.getProxy (no proxy assumed)");
189                         }
190                         result = NO_PROXY_HOST;                                            
191                     }
192                 } else {
193                     if (LOG.isDebugEnabled()) {
194                         LOG.debug("NULL proxyInfo in 1.3.X auto proxy " +
195                                        "detection, (no proxy assumed)");
196                     }
197                     result = NO_PROXY_HOST;
198                 }
199             } else {
200                 throw new ProxyDetectionException(
201                   "Sun Plugin 1.3.X failed to provide a default proxy handler");
202             }
203         } catch (Exception e) {
204             LOG.warn("Sun Plugin 1.3.X proxy detection class not " +
205                      "found, will try failover detection, e:"+e);
206         }        
207         return result;
208     }
209     
210     /**
211      * Returns the proxy information for the specified sampleURL using JRE 1.4
212      * specific plugin classes.
213      * 
214      * Notes:
215      *     Plugin 1.4 Final added 
216      *     com.sun.java.browser.net.* classes ProxyInfo & ProxyService... 
217      *     Use those with JREs => 1.4
218      *
219      * @param sampleURL the URL to check proxy settings for
220      * @return ProxyHost the host and port of the proxy that should be used
221      */
222     private static ProxyHost detectProxySettingsJDK14_JDK15_JDK16(URL sampleURL) {
223         ProxyHost result = null;
224         try {
225             // Look around for the 1.4.X plugin proxy detection class... 
226             // Without it, cannot autodetect...
227             Class ProxyServiceClass = 
228                 Class.forName("com.sun.java.browser.net.ProxyService");
229             Method getProxyInfoMethod = 
230                 ProxyServiceClass.getDeclaredMethod("getProxyInfo", 
231                                                     new Class[] {URL.class});
232             Object proxyInfoArrayObj = 
233                 getProxyInfoMethod.invoke(null, new Object[] {sampleURL});
234             
235             if (proxyInfoArrayObj == null  
236                     || Array.getLength(proxyInfoArrayObj) == 0) {
237                 if (LOG.isDebugEnabled()) {
238                     LOG.debug("1.4.X reported NULL proxy (no proxy assumed)");
239                 }
240                 result = NO_PROXY_HOST;                    
241             } else {
242                 Object proxyInfoObject = Array.get(proxyInfoArrayObj, 0);
243                 Class proxyInfoClass = proxyInfoObject.getClass();
244                 Method getHostMethod = 
245                     proxyInfoClass.getDeclaredMethod("getHost",null);
246                 String proxyIP = 
247                     (String)getHostMethod.invoke(proxyInfoObject, null);
248                 Method getPortMethod = 
249                     proxyInfoClass.getDeclaredMethod("getPort",null);
250                 Integer portInteger = 
251                     (Integer)getPortMethod.invoke(proxyInfoObject, null);
252                 int proxyPort = portInteger.intValue(); 
253                 if (LOG.isDebugEnabled()) {
254                     LOG.debug("1.4.X Proxy info geProxy:"+proxyIP+ 
255                               " get Port:"+proxyPort);
256                 }
257                 result = new ProxyHost(proxyIP, proxyPort);
258             }
259         } catch (Exception e) { 
260             e.printStackTrace();
261             LOG.warn("Sun Plugin 1.4.X proxy detection class not found, " +
262                      "will try failover detection, e:"+e);
263         }        
264         return result;
265     }
266     
267     /**
268      * Returns the proxy host information found by inspecting the system 
269      * property "javaplugin.proxy.config.list".
270      * 
271      * @return ProxyHost the host and port of the proxy that should be used
272      * @throws ProxyDetectionException if an exception is encountered while
273      *                                 parsing the value of 
274      *                                 PLUGIN_PROXY_CONFIG_PROP
275      */
276     private static ProxyHost getPluginProxyConfigSettings() 
277         throws ProxyDetectionException
278     {
279         ProxyHost result = null;
280         try {
281             Properties properties = System.getProperties();
282             String proxyList = 
283                 properties.getProperty("javaplugin.proxy.config.list");
284             if (LOG.isDebugEnabled()) {
285                 LOG.debug("Plugin Proxy Config List Property:"+proxyList);
286             }
287             boolean useProxy = (proxyList != null);
288             if (useProxy) {
289                 proxyList = proxyList.toUpperCase();
290                 //  Using HTTP proxy as proxy for HTTP proxy tunnelled SSL 
291                 //  socket (should be listed FIRST)....
292                 //  1/14/03 1.3.1_06 appears to omit HTTP portion of 
293                 //  reported proxy list... Mod to accomodate this...
294                 //  Expecting proxyList of "HTTP=XXX.XXX.XXX.XXX:Port" OR 
295                 //  "XXX.XXX.XXX.XXX:Port" & assuming HTTP...
296                 String proxyIP="";
297                 if (proxyList.indexOf("HTTP=") > -1) {
298                     proxyIP = 
299                         proxyList.substring(proxyList.indexOf("HTTP=")+5, 
300                                             proxyList.indexOf(":"));
301                 } else {
302                     proxyIP = proxyList.substring(0, proxyList.indexOf(":"));
303                 }
304                 int endOfPort = proxyList.indexOf(",");
305                 if (endOfPort < 1) endOfPort = proxyList.length();
306                 String portString = 
307                     proxyList.substring(proxyList.indexOf(":")+1,endOfPort);
308                 int proxyPort = Integer.parseInt(portString);
309                 if (LOG.isDebugEnabled()) {
310                     LOG.debug("proxy " + proxyIP+" port " + proxyPort);
311                 }
312                 result = new ProxyHost(proxyIP, proxyPort);
313             } else {
314                 LOG.debug("No configured plugin proxy list");
315                 result = NO_PROXY_HOST;
316             }
317         } catch (Exception e) {
318             if (LOG.isDebugEnabled()) {
319                 LOG.debug("Exception during failover auto proxy detection, " +
320                           ", e:"+e);
321                 throw new ProxyDetectionException(
322                         "Encountered unexpected exception while attempting " +
323                         "to parse proxy information stored in "+
324                         PLUGIN_PROXY_CONFIG_PROP, e);
325             }
326         }
327         return result;
328     }    
329 }