View Javadoc

1   /*
2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/ProxyClient.java,v 1.5 2004/12/20 11:39:04 olegk Exp $
3    * $Revision: 354155 $
4    * $Date: 2005-12-05 15:18:10 -0500 (Mon, 05 Dec 2005) $
5    *
6    * ====================================================================
7    *
8    *  Copyright 1999-2004 The Apache Software Foundation
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   * ====================================================================
22   *
23   * This software consists of voluntary contributions made by many
24   * individuals on behalf of the Apache Software Foundation.  For more
25   * information on the Apache Software Foundation, please see
26   * <http://www.apache.org/>.
27   *
28   */
29  
30  package org.apache.commons.httpclient;
31  
32  import java.io.IOException;
33  import java.net.Socket;
34  
35  import org.apache.commons.httpclient.params.HttpClientParams;
36  import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
37  import org.apache.commons.httpclient.params.HttpParams;
38  
39  
40  /***
41   * A client that provides {@link java.net.Socket sockets} for communicating through HTTP proxies
42   * via the HTTP CONNECT method.  This is primarily needed for non-HTTP protocols that wish to 
43   * communicate via an HTTP proxy.
44   * 
45   * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
46   * @author Michael Becke
47   * 
48   * @since 3.0
49   * 
50   * @version $Revision: 354155 $
51   */
52  public class ProxyClient {
53  
54      // ----------------------------------------------------- Instance Variables
55  
56      /***
57       * The {@link HttpState HTTP state} associated with this ProxyClient.
58       */
59      private HttpState state = new HttpState();
60      
61      /***
62       * The {@link HttpClientParams collection of parameters} associated with this ProxyClient.
63       */
64      private HttpClientParams params = null; 
65  
66      /*** 
67       * The {@link HostConfiguration host configuration} associated with
68       * the ProxyClient
69       */
70      private HostConfiguration hostConfiguration = new HostConfiguration();
71      
72      /***
73       * Creates an instance of ProxyClient using default {@link HttpClientParams parameter set}.
74       * 
75       * @see HttpClientParams
76       */
77      public ProxyClient() {
78          this(new HttpClientParams());
79      }
80  
81      /***
82       * Creates an instance of ProxyClient using the given 
83       * {@link HttpClientParams parameter set}.
84       * 
85       * @param params The {@link HttpClientParams parameters} to use.
86       * 
87       * @see HttpClientParams
88       */
89      public ProxyClient(HttpClientParams params) {
90          super();
91          if (params == null) {
92              throw new IllegalArgumentException("Params may not be null");  
93          }
94          this.params = params;
95      }
96  
97      // ------------------------------------------------------------- Properties
98  
99      /***
100      * Returns {@link HttpState HTTP state} associated with the ProxyClient.
101      *
102      * @see #setState(HttpState)
103      * @return the shared client state
104      */
105     public synchronized HttpState getState() {
106         return state;
107     }
108 
109     /***
110      * Assigns {@link HttpState HTTP state} for the ProxyClient.
111      *
112      * @see #getState()
113      * @param state the new {@link HttpState HTTP state} for the client
114      */
115     public synchronized void setState(HttpState state) {
116         this.state = state;
117     }
118 
119     /***
120      * Returns the {@link HostConfiguration host configuration} associated with the 
121      * ProxyClient.
122      * 
123      * @return {@link HostConfiguration host configuration}
124      */
125     public synchronized HostConfiguration getHostConfiguration() {
126         return hostConfiguration;
127     }
128 
129     /***
130      * Assigns the {@link HostConfiguration host configuration} to use with the
131      * ProxyClient.
132      * 
133      * @param hostConfiguration The {@link HostConfiguration host configuration} to set
134      */
135     public synchronized void setHostConfiguration(HostConfiguration hostConfiguration) {
136         this.hostConfiguration = hostConfiguration;
137     }
138 
139     /***
140      * Returns {@link HttpClientParams HTTP protocol parameters} associated with this ProxyClient.
141      * 
142      * @see HttpClientParams
143      */
144     public synchronized HttpClientParams getParams() {
145         return this.params;
146     }
147 
148     /***
149      * Assigns {@link HttpClientParams HTTP protocol parameters} for this ProxyClient.
150      * 
151      * @see HttpClientParams
152      */
153     public synchronized void setParams(final HttpClientParams params) {
154         if (params == null) {
155             throw new IllegalArgumentException("Parameters may not be null");
156         }
157         this.params = params;
158     }
159 
160     /***
161      * Creates a socket that is connected, via the HTTP CONNECT method, to a proxy.
162      * 
163      * <p>
164      * Even though HTTP CONNECT proxying is generally used for HTTPS tunneling, the returned
165      * socket will not have been wrapped in an SSL socket.
166      * </p>
167      * 
168      * <p>
169      * Both the proxy and destination hosts must be set via the 
170      * {@link #getHostConfiguration() host configuration} prior to calling this method.
171      * </p>
172      * 
173      * @return the connect response
174      * 
175      * @throws IOException
176      * @throws HttpException
177      * 
178      * @see #getHostConfiguration()
179      */
180     public ConnectResponse connect() throws IOException, HttpException {
181         
182         if (getHostConfiguration().getProxyHost() == null) {
183             throw new IllegalStateException("proxy host must be configured");
184         }
185         if (getHostConfiguration().getHost() == null) {
186             throw new IllegalStateException("destination host must be configured");
187         }
188         
189         ConnectMethod method = new ConnectMethod();
190         method.getParams().setDefaults(getParams());
191         
192         DummyConnectionManager connectionManager = new DummyConnectionManager();
193         connectionManager.setConnectionParams(getParams());
194         
195         HttpMethodDirector director = new HttpMethodDirector(
196             connectionManager,
197             getHostConfiguration(),
198             getParams(),
199             getState()
200         );
201         
202         director.executeMethod(method);
203         
204         ConnectResponse response = new ConnectResponse();
205         response.setConnectMethod(method);
206         
207         // only set the socket if the connect was successful
208         if (method.getStatusCode() == HttpStatus.SC_OK) {
209             response.setSocket(connectionManager.getConnection().getSocket());
210         } else {
211             connectionManager.getConnection().close();
212         }
213         
214         return response;
215     }
216 
217     /***
218      * Contains the method used to execute the connect along with the created socket.
219      */
220     public static class ConnectResponse {
221         
222         private ConnectMethod connectMethod;
223         
224         private Socket socket;
225         
226         private ConnectResponse() {}
227         
228         /***
229          * Gets the method that was used to execute the connect.  This method is useful for 
230          * analyzing the proxy's response when a connect fails.
231          * 
232          * @return the connectMethod.
233          */
234         public ConnectMethod getConnectMethod() {
235             return connectMethod;
236         }
237         /***
238          * @param connectMethod The connectMethod to set.
239          */
240         private void setConnectMethod(ConnectMethod connectMethod) {
241             this.connectMethod = connectMethod;
242         }
243         /***
244          * Gets the socket connected and authenticated (if appropriate) to the configured
245          * HTTP proxy, or <code>null</code> if a connection could not be made.  It is the
246          * responsibility of the user to close this socket when it is no longer needed.
247          * 
248          * @return the socket.
249          */
250         public Socket getSocket() {
251             return socket;
252         }
253         /***
254          * @param socket The socket to set.
255          */
256         private void setSocket(Socket socket) {
257             this.socket = socket;
258         }
259     }
260     
261     /***
262      * A connection manager that creates a single connection.  Meant to be used only once.
263      */
264     static class DummyConnectionManager implements HttpConnectionManager {
265 
266         private HttpConnection httpConnection;
267         
268         private HttpParams connectionParams;
269         
270         public void closeIdleConnections(long idleTimeout) {
271         }
272 
273         public HttpConnection getConnection() {
274             return httpConnection;
275         }
276 
277         public void setConnectionParams(HttpParams httpParams) {
278             this.connectionParams = httpParams;
279         }
280 
281         public HttpConnection getConnectionWithTimeout(
282             HostConfiguration hostConfiguration, long timeout) {
283 
284             httpConnection = new HttpConnection(hostConfiguration);
285             httpConnection.setHttpConnectionManager(this);
286             httpConnection.getParams().setDefaults(connectionParams);
287             return httpConnection;
288         }        
289         
290         /***
291          * @deprecated
292          */
293         public HttpConnection getConnection(HostConfiguration hostConfiguration, long timeout)
294             throws HttpException {
295             return getConnectionWithTimeout(hostConfiguration, timeout);
296         }
297         
298         public HttpConnection getConnection(HostConfiguration hostConfiguration) {
299             return getConnectionWithTimeout(hostConfiguration, -1);
300         }
301     
302         public void releaseConnection(HttpConnection conn) {
303         }
304 
305         public HttpConnectionManagerParams getParams() {
306             return null;
307         }
308 
309         public void setParams(HttpConnectionManagerParams params) {
310         }
311     }
312 }