001: /*
002: * $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 $
003: * $Revision: 480424 $
004: * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
005: *
006: * ====================================================================
007: *
008: * Licensed to the Apache Software Foundation (ASF) under one or more
009: * contributor license agreements. See the NOTICE file distributed with
010: * this work for additional information regarding copyright ownership.
011: * The ASF licenses this file to You under the Apache License, Version 2.0
012: * (the "License"); you may not use this file except in compliance with
013: * the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing, software
018: * distributed under the License is distributed on an "AS IS" BASIS,
019: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020: * See the License for the specific language governing permissions and
021: * limitations under the License.
022: * ====================================================================
023: *
024: * This software consists of voluntary contributions made by many
025: * individuals on behalf of the Apache Software Foundation. For more
026: * information on the Apache Software Foundation, please see
027: * <http://www.apache.org/>.
028: *
029: */
030:
031: package org.apache.commons.httpclient;
032:
033: import java.io.IOException;
034: import java.net.Socket;
035:
036: import org.apache.commons.httpclient.params.HttpClientParams;
037: import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
038: import org.apache.commons.httpclient.params.HttpParams;
039:
040: /**
041: * A client that provides {@link java.net.Socket sockets} for communicating through HTTP proxies
042: * via the HTTP CONNECT method. This is primarily needed for non-HTTP protocols that wish to
043: * communicate via an HTTP proxy.
044: *
045: * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
046: * @author Michael Becke
047: *
048: * @since 3.0
049: *
050: * @version $Revision: 480424 $
051: */
052: public class ProxyClient {
053:
054: // ----------------------------------------------------- Instance Variables
055:
056: /**
057: * The {@link HttpState HTTP state} associated with this ProxyClient.
058: */
059: private HttpState state = new HttpState();
060:
061: /**
062: * The {@link HttpClientParams collection of parameters} associated with this ProxyClient.
063: */
064: private HttpClientParams params = null;
065:
066: /**
067: * The {@link HostConfiguration host configuration} associated with
068: * the ProxyClient
069: */
070: private HostConfiguration hostConfiguration = new HostConfiguration();
071:
072: /**
073: * Creates an instance of ProxyClient using default {@link HttpClientParams parameter set}.
074: *
075: * @see HttpClientParams
076: */
077: public ProxyClient() {
078: this (new HttpClientParams());
079: }
080:
081: /**
082: * Creates an instance of ProxyClient using the given
083: * {@link HttpClientParams parameter set}.
084: *
085: * @param params The {@link HttpClientParams parameters} to use.
086: *
087: * @see HttpClientParams
088: */
089: public ProxyClient(HttpClientParams params) {
090: super ();
091: if (params == null) {
092: throw new IllegalArgumentException("Params may not be null");
093: }
094: this .params = params;
095: }
096:
097: // ------------------------------------------------------------- Properties
098:
099: /**
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(
136: HostConfiguration hostConfiguration) {
137: this .hostConfiguration = hostConfiguration;
138: }
139:
140: /**
141: * Returns {@link HttpClientParams HTTP protocol parameters} associated with this ProxyClient.
142: *
143: * @see HttpClientParams
144: */
145: public synchronized HttpClientParams getParams() {
146: return this .params;
147: }
148:
149: /**
150: * Assigns {@link HttpClientParams HTTP protocol parameters} for this ProxyClient.
151: *
152: * @see HttpClientParams
153: */
154: public synchronized void setParams(final HttpClientParams params) {
155: if (params == null) {
156: throw new IllegalArgumentException(
157: "Parameters may not be null");
158: }
159: this .params = params;
160: }
161:
162: /**
163: * Creates a socket that is connected, via the HTTP CONNECT method, to a proxy.
164: *
165: * <p>
166: * Even though HTTP CONNECT proxying is generally used for HTTPS tunneling, the returned
167: * socket will not have been wrapped in an SSL socket.
168: * </p>
169: *
170: * <p>
171: * Both the proxy and destination hosts must be set via the
172: * {@link #getHostConfiguration() host configuration} prior to calling this method.
173: * </p>
174: *
175: * @return the connect response
176: *
177: * @throws IOException
178: * @throws HttpException
179: *
180: * @see #getHostConfiguration()
181: */
182: public ConnectResponse connect() throws IOException, HttpException {
183:
184: HostConfiguration hostconf = getHostConfiguration();
185: if (hostconf.getProxyHost() == null) {
186: throw new IllegalStateException(
187: "proxy host must be configured");
188: }
189: if (hostconf.getHost() == null) {
190: throw new IllegalStateException(
191: "destination host must be configured");
192: }
193: if (hostconf.getProtocol().isSecure()) {
194: throw new IllegalStateException(
195: "secure protocol socket factory may not be used");
196: }
197:
198: ConnectMethod method = new ConnectMethod(getHostConfiguration());
199: method.getParams().setDefaults(getParams());
200:
201: DummyConnectionManager connectionManager = new DummyConnectionManager();
202: connectionManager.setConnectionParams(getParams());
203:
204: HttpMethodDirector director = new HttpMethodDirector(
205: connectionManager, hostconf, getParams(), getState());
206:
207: director.executeMethod(method);
208:
209: ConnectResponse response = new ConnectResponse();
210: response.setConnectMethod(method);
211:
212: // only set the socket if the connect was successful
213: if (method.getStatusCode() == HttpStatus.SC_OK) {
214: response.setSocket(connectionManager.getConnection()
215: .getSocket());
216: } else {
217: connectionManager.getConnection().close();
218: }
219:
220: return response;
221: }
222:
223: /**
224: * Contains the method used to execute the connect along with the created socket.
225: */
226: public static class ConnectResponse {
227:
228: private ConnectMethod connectMethod;
229:
230: private Socket socket;
231:
232: private ConnectResponse() {
233: }
234:
235: /**
236: * Gets the method that was used to execute the connect. This method is useful for
237: * analyzing the proxy's response when a connect fails.
238: *
239: * @return the connectMethod.
240: */
241: public ConnectMethod getConnectMethod() {
242: return connectMethod;
243: }
244:
245: /**
246: * @param connectMethod The connectMethod to set.
247: */
248: private void setConnectMethod(ConnectMethod connectMethod) {
249: this .connectMethod = connectMethod;
250: }
251:
252: /**
253: * Gets the socket connected and authenticated (if appropriate) to the configured
254: * HTTP proxy, or <code>null</code> if a connection could not be made. It is the
255: * responsibility of the user to close this socket when it is no longer needed.
256: *
257: * @return the socket.
258: */
259: public Socket getSocket() {
260: return socket;
261: }
262:
263: /**
264: * @param socket The socket to set.
265: */
266: private void setSocket(Socket socket) {
267: this .socket = socket;
268: }
269: }
270:
271: /**
272: * A connection manager that creates a single connection. Meant to be used only once.
273: */
274: static class DummyConnectionManager implements
275: HttpConnectionManager {
276:
277: private HttpConnection httpConnection;
278:
279: private HttpParams connectionParams;
280:
281: public void closeIdleConnections(long idleTimeout) {
282: }
283:
284: public HttpConnection getConnection() {
285: return httpConnection;
286: }
287:
288: public void setConnectionParams(HttpParams httpParams) {
289: this .connectionParams = httpParams;
290: }
291:
292: public HttpConnection getConnectionWithTimeout(
293: HostConfiguration hostConfiguration, long timeout) {
294:
295: httpConnection = new HttpConnection(hostConfiguration);
296: httpConnection.setHttpConnectionManager(this );
297: httpConnection.getParams().setDefaults(connectionParams);
298: return httpConnection;
299: }
300:
301: /**
302: * @deprecated
303: */
304: public HttpConnection getConnection(
305: HostConfiguration hostConfiguration, long timeout)
306: throws HttpException {
307: return getConnectionWithTimeout(hostConfiguration, timeout);
308: }
309:
310: public HttpConnection getConnection(
311: HostConfiguration hostConfiguration) {
312: return getConnectionWithTimeout(hostConfiguration, -1);
313: }
314:
315: public void releaseConnection(HttpConnection conn) {
316: }
317:
318: public HttpConnectionManagerParams getParams() {
319: return null;
320: }
321:
322: public void setParams(HttpConnectionManagerParams params) {
323: }
324: }
325: }
|