1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
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
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
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 }