1. /*
  2. * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpClient.java,v 1.96 2004/06/14 21:25:38 olegk Exp $
  3. * $Revision: 1.96 $
  4. * $Date: 2004/06/14 21:25:38 $
  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.security.Provider;
  32. import java.security.Security;
  33. import org.apache.commons.httpclient.params.HttpClientParams;
  34. import org.apache.commons.logging.Log;
  35. import org.apache.commons.logging.LogFactory;
  36. /**
  37. * <p>
  38. * An HTTP "user-agent", containing an {@link HttpState HTTP state} and
  39. * one or more {@link HttpConnection HTTP connections}, to which
  40. * {@link HttpMethod HTTP methods} can be applied.
  41. * </p>
  42. * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
  43. * @author <a href="mailto:rwaldhoff@apache.org">Rodney Waldhoff</a>
  44. * @author Sean C. Sullivan
  45. * @author <a href="mailto:dion@apache.org">dIon Gillard</a>
  46. * @author Ortwin Gl?ck
  47. * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
  48. * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
  49. * @author Sam Maloney
  50. * @author Laura Werner
  51. * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
  52. *
  53. * @version $Revision: 1.96 $ $Date: 2004/06/14 21:25:38 $
  54. */
  55. public class HttpClient {
  56. // -------------------------------------------------------------- Constants
  57. /** Log object for this class. */
  58. private static final Log LOG = LogFactory.getLog(HttpClient.class);
  59. static {
  60. if (LOG.isDebugEnabled()) {
  61. try {
  62. LOG.debug("Java version: " + System.getProperty("java.version"));
  63. LOG.debug("Java vendor: " + System.getProperty("java.vendor"));
  64. LOG.debug("Java class path: " + System.getProperty("java.class.path"));
  65. LOG.debug("Operating system name: " + System.getProperty("os.name"));
  66. LOG.debug("Operating system architecture: " + System.getProperty("os.arch"));
  67. LOG.debug("Operating system version: " + System.getProperty("os.version"));
  68. Provider[] providers = Security.getProviders();
  69. for (int i = 0; i < providers.length; i++) {
  70. Provider provider = providers[i];
  71. LOG.debug(provider.getName() + " " + provider.getVersion()
  72. + ": " + provider.getInfo());
  73. }
  74. } catch (SecurityException ignore) {
  75. }
  76. }
  77. }
  78. // ----------------------------------------------------------- Constructors
  79. /**
  80. * Creates an instance of HttpClient using default {@link HttpClientParams parameter set}.
  81. *
  82. * @see HttpClientParams
  83. */
  84. public HttpClient() {
  85. this(new HttpClientParams());
  86. }
  87. /**
  88. * Creates an instance of HttpClient using the given
  89. * {@link HttpClientParams parameter set}.
  90. *
  91. * @param params The {@link HttpClientParams parameters} to use.
  92. *
  93. * @see HttpClientParams
  94. *
  95. * @since 3.0
  96. */
  97. public HttpClient(HttpClientParams params) {
  98. super();
  99. if (params == null) {
  100. throw new IllegalArgumentException("Params may not be null");
  101. }
  102. this.params = params;
  103. this.httpConnectionManager = null;
  104. Class clazz = params.getConnectionManagerClass();
  105. if (clazz != null) {
  106. try {
  107. this.httpConnectionManager = (HttpConnectionManager) clazz.newInstance();
  108. } catch (Exception e) {
  109. LOG.warn("Error instantiating connection manager class, defaulting to"
  110. + " SimpleHttpConnectionManager",
  111. e);
  112. }
  113. }
  114. if (this.httpConnectionManager == null) {
  115. this.httpConnectionManager = new SimpleHttpConnectionManager();
  116. }
  117. if (this.httpConnectionManager != null) {
  118. this.httpConnectionManager.getParams().setDefaults(this.params);
  119. }
  120. }
  121. /**
  122. * Creates an instance of HttpClient with a user specified
  123. * {@link HttpClientParams parameter set} and
  124. * {@link HttpConnectionManager HTTP connection manager}.
  125. *
  126. * @param params The {@link HttpClientParams parameters} to use.
  127. * @param httpConnectionManager The {@link HttpConnectionManager connection manager}
  128. * to use.
  129. *
  130. * @since 3.0
  131. */
  132. public HttpClient(HttpClientParams params, HttpConnectionManager httpConnectionManager) {
  133. super();
  134. if (httpConnectionManager == null) {
  135. throw new IllegalArgumentException("httpConnectionManager cannot be null");
  136. }
  137. if (params == null) {
  138. throw new IllegalArgumentException("Params may not be null");
  139. }
  140. this.params = params;
  141. this.httpConnectionManager = httpConnectionManager;
  142. if (this.httpConnectionManager != null) {
  143. this.httpConnectionManager.getParams().setDefaults(this.params);
  144. }
  145. }
  146. /**
  147. * Creates an instance of HttpClient with a user specified
  148. * {@link HttpConnectionManager HTTP connection manager}.
  149. *
  150. * @param httpConnectionManager The {@link HttpConnectionManager connection manager}
  151. * to use.
  152. *
  153. * @since 2.0
  154. */
  155. public HttpClient(HttpConnectionManager httpConnectionManager) {
  156. this(new HttpClientParams(), httpConnectionManager);
  157. }
  158. // ----------------------------------------------------- Instance Variables
  159. /**
  160. * The {@link HttpConnectionManager connection manager} being used to manage
  161. * connections for this HttpClient
  162. */
  163. private HttpConnectionManager httpConnectionManager;
  164. /**
  165. * The {@link HttpState HTTP state} associated with this HttpClient.
  166. */
  167. private HttpState state = new HttpState();
  168. /**
  169. * The {@link HttpClientParams collection of parameters} associated with this HttpClient.
  170. */
  171. private HttpClientParams params = null;
  172. /**
  173. * The {@link HostConfiguration host configuration} associated with
  174. * the HttpClient
  175. */
  176. private HostConfiguration hostConfiguration = new HostConfiguration();
  177. // ------------------------------------------------------------- Properties
  178. /**
  179. * Returns {@link HttpState HTTP state} associated with the HttpClient.
  180. *
  181. * @see #setState(HttpState)
  182. * @return the shared client state
  183. */
  184. public synchronized HttpState getState() {
  185. return state;
  186. }
  187. /**
  188. * Assigns {@link HttpState HTTP state} for the HttpClient.
  189. *
  190. * @see #getState()
  191. * @param state the new {@link HttpState HTTP state} for the client
  192. */
  193. public synchronized void setState(HttpState state) {
  194. this.state = state;
  195. }
  196. /**
  197. * Defines how strictly the method follows the HTTP protocol specification
  198. * (see RFC 2616 and other relevant RFCs).
  199. *
  200. * In the strict mode the method precisely
  201. * implements the requirements of the specification, whereas in non-strict mode
  202. * it attempts to mimic the exact behaviour of commonly used HTTP agents,
  203. * which many HTTP servers expect.
  204. *
  205. * @param strictMode <tt>true</tt> for strict mode, <tt>false</tt> otherwise
  206. *
  207. * @see #isStrictMode()
  208. *
  209. * @deprecated Use {@link HttpClientParams#setParameter(String, Object)}
  210. * to exercise a more granular control over HTTP protocol strictness.
  211. */
  212. public synchronized void setStrictMode(boolean strictMode) {
  213. if (strictMode) {
  214. this.params.makeStrict();
  215. } else {
  216. this.params.makeLenient();
  217. }
  218. }
  219. /**
  220. * Returns the value of the strict mode flag.
  221. *
  222. * @return <tt>true</tt> if strict mode is enabled, <tt>false</tt> otherwise
  223. *
  224. * @see #setStrictMode(boolean)
  225. *
  226. * @deprecated Use
  227. * {@link org.apache.commons.httpclient.params.HttpClientParams#getParameter(String)}
  228. * to exercise a more granular control over HTTP protocol strictness.
  229. */
  230. public synchronized boolean isStrictMode() {
  231. return false;
  232. }
  233. /**
  234. * Sets the socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the
  235. * timeout for waiting for data. A timeout value of zero is interpreted as an
  236. * infinite timeout.
  237. *
  238. * @param newTimeoutInMilliseconds Timeout in milliseconds
  239. *
  240. * @deprecated Use
  241. * {@link org.apache.commons.httpclient.params.HttpConnectionManagerParams#setSoTimeout(int)},
  242. * {@link HttpConnectionManager#getParams()}.
  243. *
  244. */
  245. public synchronized void setTimeout(int newTimeoutInMilliseconds) {
  246. this.params.setSoTimeout(newTimeoutInMilliseconds);
  247. }
  248. /**
  249. * Sets the timeout in milliseconds used when retrieving an
  250. * {@link HttpConnection HTTP connection} from the
  251. * {@link HttpConnectionManager HTTP connection manager}.
  252. *
  253. * @param timeout the timeout in milliseconds
  254. *
  255. * @see HttpConnectionManager#getConnection(HostConfiguration, long)
  256. *
  257. * @deprecated Use
  258. * {@link org.apache.commons.httpclient.params.HttpClientParams#setConnectionManagerTimeout(long)},
  259. * {@link HttpClient#getParams()}
  260. */
  261. public synchronized void setHttpConnectionFactoryTimeout(long timeout) {
  262. this.params.setConnectionManagerTimeout(timeout);
  263. }
  264. /**
  265. * Sets the timeout until a connection is etablished. A value of zero
  266. * means the timeout is not used. The default value is zero.
  267. *
  268. * @see HttpConnection#setConnectionTimeout(int)
  269. * @param newTimeoutInMilliseconds Timeout in milliseconds.
  270. *
  271. * @deprecated Use
  272. * {@link org.apache.commons.httpclient.params.HttpConnectionManagerParams#setConnectionTimeout(int)},
  273. * {@link HttpConnectionManager#getParams()}.
  274. */
  275. public synchronized void setConnectionTimeout(int newTimeoutInMilliseconds) {
  276. this.httpConnectionManager.getParams().setConnectionTimeout(newTimeoutInMilliseconds);
  277. }
  278. // --------------------------------------------------------- Public Methods
  279. /**
  280. * Executes the given {@link HttpMethod HTTP method}.
  281. *
  282. * @param method the {@link HttpMethod HTTP method} to execute.
  283. * @return the method's response code
  284. *
  285. * @throws IOException If an I/O (transport) error occurs. Some transport exceptions
  286. * can be recovered from.
  287. * @throws HttpException If a protocol exception occurs. Usually protocol exceptions
  288. * cannot be recovered from.
  289. */
  290. public int executeMethod(HttpMethod method)
  291. throws IOException, HttpException {
  292. LOG.trace("enter HttpClient.executeMethod(HttpMethod)");
  293. // execute this method and use its host configuration, if it has one
  294. return executeMethod(
  295. method.getHostConfiguration() != null
  296. ? method.getHostConfiguration()
  297. : getHostConfiguration(),
  298. method,
  299. null
  300. );
  301. }
  302. /**
  303. * Executes the given {@link HttpMethod HTTP method} using custom
  304. * {@link HostConfiguration host configuration}.
  305. *
  306. * @param hostConfiguration The {@link HostConfiguration host configuration} to use.
  307. * @param method the {@link HttpMethod HTTP method} to execute.
  308. * @return the method's response code
  309. *
  310. * @throws IOException If an I/O (transport) error occurs. Some transport exceptions
  311. * can be recovered from.
  312. * @throws HttpException If a protocol exception occurs. Usually protocol exceptions
  313. * cannot be recovered from.
  314. * @since 2.0
  315. */
  316. public int executeMethod(HostConfiguration hostConfiguration, HttpMethod method)
  317. throws IOException, HttpException {
  318. LOG.trace("enter HttpClient.executeMethod(HostConfiguration,HttpMethod)");
  319. return executeMethod(hostConfiguration, method, null);
  320. }
  321. /**
  322. * Executes the given {@link HttpMethod HTTP method} using the given custom
  323. * {@link HostConfiguration host configuration} with the given custom
  324. * {@link HttpState HTTP state}.
  325. *
  326. * @param hostConfiguration The {@link HostConfiguration host configuration} to use.
  327. * @param method the {@link HttpMethod HTTP method} to execute.
  328. * @param state the {@link HttpState HTTP state} to use when executing the method.
  329. * If <code>null</code>, the state returned by {@link #getState} will be used instead.
  330. *
  331. * @return the method's response code
  332. *
  333. * @throws IOException If an I/O (transport) error occurs. Some transport exceptions
  334. * can be recovered from.
  335. * @throws HttpException If a protocol exception occurs. Usually protocol exceptions
  336. * cannot be recovered from.
  337. * @since 2.0
  338. */
  339. public int executeMethod(HostConfiguration hostConfiguration,
  340. HttpMethod method, HttpState state)
  341. throws IOException, HttpException {
  342. LOG.trace("enter HttpClient.executeMethod(HostConfiguration,HttpMethod,HttpState)");
  343. if (method == null) {
  344. throw new IllegalArgumentException("HttpMethod parameter may not be null");
  345. }
  346. if (hostConfiguration == null) {
  347. hostConfiguration = (
  348. method.getHostConfiguration() != null
  349. ? method.getHostConfiguration()
  350. : getHostConfiguration()
  351. );
  352. }
  353. HostConfiguration defaultHostConfiguration = null;
  354. synchronized (this) {
  355. defaultHostConfiguration = getHostConfiguration();
  356. }
  357. HostConfiguration methodConfiguration = new HostConfiguration(hostConfiguration);
  358. if (hostConfiguration != defaultHostConfiguration) {
  359. // we may need to apply some defaults
  360. if (!methodConfiguration.isHostSet()) {
  361. methodConfiguration.setHost(
  362. defaultHostConfiguration.getHost(),
  363. defaultHostConfiguration.getVirtualHost(),
  364. defaultHostConfiguration.getPort(),
  365. defaultHostConfiguration.getProtocol()
  366. );
  367. }
  368. if (!methodConfiguration.isProxySet()
  369. && defaultHostConfiguration.isProxySet()) {
  370. methodConfiguration.setProxy(
  371. defaultHostConfiguration.getProxyHost(),
  372. defaultHostConfiguration.getProxyPort()
  373. );
  374. }
  375. if (methodConfiguration.getLocalAddress() == null
  376. && defaultHostConfiguration.getLocalAddress() != null) {
  377. methodConfiguration.setLocalAddress(defaultHostConfiguration.getLocalAddress());
  378. }
  379. }
  380. /* access all synchronized data in a single block, this will keeps us
  381. * from accessing data asynchronously as well having to regain the lock
  382. * for each item.
  383. */
  384. HttpMethodDirector methodDirector = null;
  385. synchronized (this) {
  386. methodDirector = new HttpMethodDirector(
  387. this.httpConnectionManager,
  388. methodConfiguration,
  389. this.params,
  390. (state == null ? getState() : state));
  391. defaultHostConfiguration = getHostConfiguration();
  392. }
  393. methodDirector.executeMethod(method);
  394. return method.getStatusCode();
  395. }
  396. /**
  397. * Returns the default host.
  398. *
  399. * @return The default host.
  400. *
  401. * @deprecated use #getHostConfiguration()
  402. */
  403. public String getHost() {
  404. return hostConfiguration.getHost();
  405. }
  406. /**
  407. * Returns the default port.
  408. *
  409. * @return The default port.
  410. *
  411. * @deprecated use #getHostConfiguration()
  412. */
  413. public int getPort() {
  414. return hostConfiguration.getPort();
  415. }
  416. /**
  417. * Returns the {@link HostConfiguration host configuration} associated with the
  418. * HttpClient.
  419. *
  420. * @return {@link HostConfiguration host configuration}
  421. *
  422. * @since 2.0
  423. */
  424. public synchronized HostConfiguration getHostConfiguration() {
  425. return hostConfiguration;
  426. }
  427. /**
  428. * Assigns the {@link HostConfiguration host configuration} to use with the
  429. * HttpClient.
  430. *
  431. * @param hostConfiguration The {@link HostConfiguration host configuration} to set
  432. *
  433. * @since 2.0
  434. */
  435. public synchronized void setHostConfiguration(HostConfiguration hostConfiguration) {
  436. this.hostConfiguration = hostConfiguration;
  437. }
  438. /**
  439. * Returns the {@link HttpConnectionManager HTTP connection manager} associated
  440. * with the HttpClient.
  441. *
  442. * @return {@link HttpConnectionManager HTTP connection manager}
  443. *
  444. * @since 2.0
  445. */
  446. public synchronized HttpConnectionManager getHttpConnectionManager() {
  447. return httpConnectionManager;
  448. }
  449. /**
  450. * Assigns the {@link HttpConnectionManager HTTP connection manager} to use with
  451. * the HttpClient.
  452. *
  453. * @param httpConnectionManager The {@link HttpConnectionManager HTTP connection manager}
  454. * to set
  455. *
  456. * @since 2.0
  457. */
  458. public synchronized void setHttpConnectionManager(
  459. HttpConnectionManager httpConnectionManager
  460. ) {
  461. this.httpConnectionManager = httpConnectionManager;
  462. if (this.httpConnectionManager != null) {
  463. this.httpConnectionManager.getParams().setDefaults(this.params);
  464. }
  465. }
  466. /**
  467. * Returns {@link HttpClientParams HTTP protocol parameters} associated with this HttpClient.
  468. *
  469. * @since 3.0
  470. *
  471. * @see HttpClientParams
  472. */
  473. public HttpClientParams getParams() {
  474. return this.params;
  475. }
  476. /**
  477. * Assigns {@link HttpClientParams HTTP protocol parameters} for this HttpClient.
  478. *
  479. * @since 3.0
  480. *
  481. * @see HttpClientParams
  482. */
  483. public void setParams(final HttpClientParams params) {
  484. if (params == null) {
  485. throw new IllegalArgumentException("Parameters may not be null");
  486. }
  487. this.params = params;
  488. }
  489. }