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
31 package org.apache.commons.httpclient;
32
33 import java.io.IOException;
34 import java.net.Socket;
35
36 import org.apache.commons.httpclient.params.HttpClientParams;
37 import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
38 import org.apache.commons.httpclient.params.HttpParams;
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$
51 */
52 public class ProxyClient {
53
54
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
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 HostConfiguration hostconf = getHostConfiguration();
183 if (hostconf.getProxyHost() == null) {
184 throw new IllegalStateException("proxy host must be configured");
185 }
186 if (hostconf.getHost() == null) {
187 throw new IllegalStateException("destination host must be configured");
188 }
189 if (hostconf.getProtocol().isSecure()) {
190 throw new IllegalStateException("secure protocol socket factory may not be used");
191 }
192
193 ConnectMethod method = new ConnectMethod(getHostConfiguration());
194 method.getParams().setDefaults(getParams());
195
196 DummyConnectionManager connectionManager = new DummyConnectionManager();
197 connectionManager.setConnectionParams(getParams());
198
199 HttpMethodDirector director = new HttpMethodDirector(
200 connectionManager,
201 hostconf,
202 getParams(),
203 getState()
204 );
205
206 director.executeMethod(method);
207
208 ConnectResponse response = new ConnectResponse();
209 response.setConnectMethod(method);
210
211
212 if (method.getStatusCode() == HttpStatus.SC_OK) {
213 response.setSocket(connectionManager.getConnection().getSocket());
214 } else {
215 connectionManager.getConnection().close();
216 }
217
218 return response;
219 }
220
221 /***
222 * Contains the method used to execute the connect along with the created socket.
223 */
224 public static class ConnectResponse {
225
226 private ConnectMethod connectMethod;
227
228 private Socket socket;
229
230 private ConnectResponse() {}
231
232 /***
233 * Gets the method that was used to execute the connect. This method is useful for
234 * analyzing the proxy's response when a connect fails.
235 *
236 * @return the connectMethod.
237 */
238 public ConnectMethod getConnectMethod() {
239 return connectMethod;
240 }
241 /***
242 * @param connectMethod The connectMethod to set.
243 */
244 private void setConnectMethod(ConnectMethod connectMethod) {
245 this.connectMethod = connectMethod;
246 }
247 /***
248 * Gets the socket connected and authenticated (if appropriate) to the configured
249 * HTTP proxy, or <code>null</code> if a connection could not be made. It is the
250 * responsibility of the user to close this socket when it is no longer needed.
251 *
252 * @return the socket.
253 */
254 public Socket getSocket() {
255 return socket;
256 }
257 /***
258 * @param socket The socket to set.
259 */
260 private void setSocket(Socket socket) {
261 this.socket = socket;
262 }
263 }
264
265 /***
266 * A connection manager that creates a single connection. Meant to be used only once.
267 */
268 static class DummyConnectionManager implements HttpConnectionManager {
269
270 private HttpConnection httpConnection;
271
272 private HttpParams connectionParams;
273
274 public void closeIdleConnections(long idleTimeout) {
275 }
276
277 public HttpConnection getConnection() {
278 return httpConnection;
279 }
280
281 public void setConnectionParams(HttpParams httpParams) {
282 this.connectionParams = httpParams;
283 }
284
285 public HttpConnection getConnectionWithTimeout(
286 HostConfiguration hostConfiguration, long timeout) {
287
288 httpConnection = new HttpConnection(hostConfiguration);
289 httpConnection.setHttpConnectionManager(this);
290 httpConnection.getParams().setDefaults(connectionParams);
291 return httpConnection;
292 }
293
294 /***
295 * @deprecated
296 */
297 public HttpConnection getConnection(HostConfiguration hostConfiguration, long timeout)
298 throws HttpException {
299 return getConnectionWithTimeout(hostConfiguration, timeout);
300 }
301
302 public HttpConnection getConnection(HostConfiguration hostConfiguration) {
303 return getConnectionWithTimeout(hostConfiguration, -1);
304 }
305
306 public void releaseConnection(HttpConnection conn) {
307 }
308
309 public HttpConnectionManagerParams getParams() {
310 return null;
311 }
312
313 public void setParams(HttpConnectionManagerParams params) {
314 }
315 }
316 }