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: 390058 $
4    * $Date: 2006-03-30 12:09:57 +0200 (Thu, 30 Mar 2006) $
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   * A client that provides {@link java.net.Socket sockets} for communicating through HTTP proxies
41   * via the HTTP CONNECT method.  This is primarily needed for non-HTTP protocols that wish to 
42   * communicate via an HTTP proxy.
43   * 
44   * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
45   * @author Michael Becke
46   * 
47   * @since 3.0
48   * 
49   * @version $Revision: 390058 $
50   */
51  public class ProxyClient {
52  
53      // ----------------------------------------------------- Instance Variables
54  
55      /***
56       * The {@link HttpState HTTP state} associated with this ProxyClient.
57       */
58      private HttpState state = new HttpState();
59      
60      /***
61       * The {@link HttpClientParams collection of parameters} associated with this ProxyClient.
62       */
63      private HttpClientParams params = null; 
64  
65      /*** 
66       * The {@link HostConfiguration host configuration} associated with
67       * the ProxyClient
68       */
69      private HostConfiguration hostConfiguration = new HostConfiguration();
70      
71      /***
72       * Creates an instance of ProxyClient using default {@link HttpClientParams parameter set}.
73       * 
74       * @see HttpClientParams
75       */
76      public ProxyClient() {
77          this(new HttpClientParams());
78      }
79  
80      /***
81       * Creates an instance of ProxyClient using the given 
82       * {@link HttpClientParams parameter set}.
83       * 
84       * @param params The {@link HttpClientParams parameters} to use.
85       * 
86       * @see HttpClientParams
87       */
88      public ProxyClient(HttpClientParams params) {
89          super();
90          if (params == null) {
91              throw new IllegalArgumentException("Params may not be null");  
92          }
93          this.params = params;
94      }
95  
96      // ------------------------------------------------------------- Properties
97  
98      /***
99       * Returns {@link HttpState HTTP state} associated with the ProxyClient.
100      *
101      * @see #setState(HttpState)
102      * @return the shared client state
103      */
104     public synchronized HttpState getState() {
105         return state;
106     }
107 
108     /***
109      * Assigns {@link HttpState HTTP state} for the ProxyClient.
110      *
111      * @see #getState()
112      * @param state the new {@link HttpState HTTP state} for the client
113      */
114     public synchronized void setState(HttpState state) {
115         this.state = state;
116     }
117 
118     /***
119      * Returns the {@link HostConfiguration host configuration} associated with the 
120      * ProxyClient.
121      * 
122      * @return {@link HostConfiguration host configuration}
123      */
124     public synchronized HostConfiguration getHostConfiguration() {
125         return hostConfiguration;
126     }
127 
128     /***
129      * Assigns the {@link HostConfiguration host configuration} to use with the
130      * ProxyClient.
131      * 
132      * @param hostConfiguration The {@link HostConfiguration host configuration} to set
133      */
134     public synchronized void setHostConfiguration(HostConfiguration hostConfiguration) {
135         this.hostConfiguration = hostConfiguration;
136     }
137 
138     /***
139      * Returns {@link HttpClientParams HTTP protocol parameters} associated with this ProxyClient.
140      * 
141      * @see HttpClientParams
142      */
143     public synchronized HttpClientParams getParams() {
144         return this.params;
145     }
146 
147     /***
148      * Assigns {@link HttpClientParams HTTP protocol parameters} for this ProxyClient.
149      * 
150      * @see HttpClientParams
151      */
152     public synchronized void setParams(final HttpClientParams params) {
153         if (params == null) {
154             throw new IllegalArgumentException("Parameters may not be null");
155         }
156         this.params = params;
157     }
158 
159     /***
160      * Creates a socket that is connected, via the HTTP CONNECT method, to a proxy.
161      * 
162      * <p>
163      * Even though HTTP CONNECT proxying is generally used for HTTPS tunneling, the returned
164      * socket will not have been wrapped in an SSL socket.
165      * </p>
166      * 
167      * <p>
168      * Both the proxy and destination hosts must be set via the 
169      * {@link #getHostConfiguration() host configuration} prior to calling this method.
170      * </p>
171      * 
172      * @return the connect response
173      * 
174      * @throws IOException
175      * @throws HttpException
176      * 
177      * @see #getHostConfiguration()
178      */
179     public ConnectResponse connect() throws IOException, HttpException {
180         
181         HostConfiguration hostconf = getHostConfiguration();
182         if (hostconf.getProxyHost() == null) {
183             throw new IllegalStateException("proxy host must be configured");
184         }
185         if (hostconf.getHost() == null) {
186             throw new IllegalStateException("destination host must be configured");
187         }
188         if (hostconf.getProtocol().isSecure()) {
189             throw new IllegalStateException("secure protocol socket factory may not be used");
190         }
191         
192         ConnectMethod method = new ConnectMethod(getHostConfiguration());
193         method.getParams().setDefaults(getParams());
194         
195         DummyConnectionManager connectionManager = new DummyConnectionManager();
196         connectionManager.setConnectionParams(getParams());
197         
198         HttpMethodDirector director = new HttpMethodDirector(
199             connectionManager,
200             hostconf,
201             getParams(),
202             getState()
203         );
204         
205         director.executeMethod(method);
206         
207         ConnectResponse response = new ConnectResponse();
208         response.setConnectMethod(method);
209         
210         // only set the socket if the connect was successful
211         if (method.getStatusCode() == HttpStatus.SC_OK) {
212             response.setSocket(connectionManager.getConnection().getSocket());
213         } else {
214             connectionManager.getConnection().close();
215         }
216         
217         return response;
218     }
219 
220     /***
221      * Contains the method used to execute the connect along with the created socket.
222      */
223     public static class ConnectResponse {
224         
225         private ConnectMethod connectMethod;
226         
227         private Socket socket;
228         
229         private ConnectResponse() {}
230         
231         /***
232          * Gets the method that was used to execute the connect.  This method is useful for 
233          * analyzing the proxy's response when a connect fails.
234          * 
235          * @return the connectMethod.
236          */
237         public ConnectMethod getConnectMethod() {
238             return connectMethod;
239         }
240         /***
241          * @param connectMethod The connectMethod to set.
242          */
243         private void setConnectMethod(ConnectMethod connectMethod) {
244             this.connectMethod = connectMethod;
245         }
246         /***
247          * Gets the socket connected and authenticated (if appropriate) to the configured
248          * HTTP proxy, or <code>null</code> if a connection could not be made.  It is the
249          * responsibility of the user to close this socket when it is no longer needed.
250          * 
251          * @return the socket.
252          */
253         public Socket getSocket() {
254             return socket;
255         }
256         /***
257          * @param socket The socket to set.
258          */
259         private void setSocket(Socket socket) {
260             this.socket = socket;
261         }
262     }
263     
264     /***
265      * A connection manager that creates a single connection.  Meant to be used only once.
266      */
267     static class DummyConnectionManager implements HttpConnectionManager {
268 
269         private HttpConnection httpConnection;
270         
271         private HttpParams connectionParams;
272         
273         public void closeIdleConnections(long idleTimeout) {
274         }
275 
276         public HttpConnection getConnection() {
277             return httpConnection;
278         }
279 
280         public void setConnectionParams(HttpParams httpParams) {
281             this.connectionParams = httpParams;
282         }
283 
284         public HttpConnection getConnectionWithTimeout(
285             HostConfiguration hostConfiguration, long timeout) {
286 
287             httpConnection = new HttpConnection(hostConfiguration);
288             httpConnection.setHttpConnectionManager(this);
289             httpConnection.getParams().setDefaults(connectionParams);
290             return httpConnection;
291         }        
292         
293         /***
294          * @deprecated
295          */
296         public HttpConnection getConnection(HostConfiguration hostConfiguration, long timeout)
297             throws HttpException {
298             return getConnectionWithTimeout(hostConfiguration, timeout);
299         }
300         
301         public HttpConnection getConnection(HostConfiguration hostConfiguration) {
302             return getConnectionWithTimeout(hostConfiguration, -1);
303         }
304     
305         public void releaseConnection(HttpConnection conn) {
306         }
307 
308         public HttpConnectionManagerParams getParams() {
309             return null;
310         }
311 
312         public void setParams(HttpConnectionManagerParams params) {
313         }
314     }
315 }