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