1 /*
2 * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpClient.java,v 1.76 2003/05/12 02:42:42 mbecke Exp $
3 * $Revision: 1.76 $
4 * $Date: 2003/05/12 02:42:42 $
5 *
6 * ====================================================================
7 *
8 * The Apache Software License, Version 1.1
9 *
10 * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
11 * reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in
22 * the documentation and/or other materials provided with the
23 * distribution.
24 *
25 * 3. The end-user documentation included with the redistribution, if
26 * any, must include the following acknowlegement:
27 * "This product includes software developed by the
28 * Apache Software Foundation (http://www.apache.org/)."
29 * Alternately, this acknowlegement may appear in the software itself,
30 * if and wherever such third-party acknowlegements normally appear.
31 *
32 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
33 * Foundation" must not be used to endorse or promote products derived
34 * from this software without prior written permission. For written
35 * permission, please contact apache@apache.org.
36 *
37 * 5. Products derived from this software may not be called "Apache"
38 * nor may "Apache" appear in their names without prior written
39 * permission of the Apache Group.
40 *
41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 * ====================================================================
54 *
55 * This software consists of voluntary contributions made by many
56 * individuals on behalf of the Apache Software Foundation. For more
57 * information on the Apache Software Foundation, please see
58 * <http://www.apache.org/>.
59 *
60 * [Additional notices, if required by prior licensing conditions]
61 *
62 */
63
64 package org.apache.commons.httpclient;
65
66 import java.io.IOException;
67 import java.net.URL;
68 import java.security.Security;
69 import java.security.Provider;
70
71 import org.apache.commons.httpclient.protocol.Protocol;
72 import org.apache.commons.logging.Log;
73 import org.apache.commons.logging.LogFactory;
74
75
76 /***
77 * <p>
78 * An HTTP "user-agent", containing an {@link HttpState} and
79 * one or more {@link HttpConnection}s, to which
80 * {@link HttpMethod}s can be applied.
81 * </p>
82 * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
83 * @author <a href="mailto:rwaldhoff@apache.org">Rodney Waldhoff</a>
84 * @author Sean C. Sullivan
85 * @author <a href="mailto:dion@apache.org">dIon Gillard</a>
86 * @author Ortwin Gl�ck
87 * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
88 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
89 * @author Sam Maloney
90 * @author Laura Werner
91 *
92 * @version $Revision: 1.76 $ $Date: 2003/05/12 02:42:42 $
93 */
94 public class HttpClient {
95
96
97 // -------------------------------------------------------------- Constants
98
99 /*** Log object for this class. */
100 private static final Log LOG = LogFactory.getLog(HttpClient.class);
101
102 static {
103 if (LOG.isDebugEnabled()) {
104 LOG.debug("Java version: " + System.getProperty("java.version"));
105 LOG.debug("Java vendor: " + System.getProperty("java.vendor"));
106 LOG.debug("Java class path: " + System.getProperty("java.class.path"));
107 LOG.debug("Operating system name: " + System.getProperty("os.name"));
108 LOG.debug("Operating system architecture: " + System.getProperty("os.arch"));
109 LOG.debug("Operating system version: " + System.getProperty("os.version"));
110
111 Provider[] providers = Security.getProviders();
112 for (int i = 0; i < providers.length; i++) {
113 Provider provider = providers[i];
114 LOG.debug(provider.getName() + " " + provider.getVersion()
115 + ": " + provider.getInfo());
116 }
117
118 }
119 }
120 // ----------------------------------------------------------- Constructors
121
122 /***
123 * Creates an HttpClient using <code>SimpleHttpConnectionManager</code>.
124 *
125 * @see SimpleHttpConnectionManager
126 */
127 public HttpClient() {
128 this(new SimpleHttpConnectionManager());
129 }
130
131 /***
132 * Creates an HttpClient with a user specified connection manager.
133 * @param httpConnectionManager The connection manager to use.
134 *
135 * @since 2.0
136 */
137 public HttpClient(HttpConnectionManager httpConnectionManager) {
138
139 if (httpConnectionManager == null) {
140 throw new IllegalArgumentException("httpConnectionManager cannot be null");
141 }
142
143 this.state = new HttpState();
144 this.httpConnectionManager = httpConnectionManager;
145
146 this.hostConfiguration = new HostConfiguration();
147
148 }
149
150 // ----------------------------------------------------- Instance Variables
151
152 /*** The current connection manager */
153 private HttpConnectionManager httpConnectionManager;
154
155 /***
156 * My {@link HttpState state}.
157 */
158 private HttpState state;
159
160 /*** the timout when waiting for a connection from the connectionManager */
161 private long httpConnectionTimeout = 0;
162
163 /*** The timeout in milliseconds*/
164 private int timeoutInMilliseconds = 0;
165
166 /*** The connection timeout. */
167 private int connectionTimeout = 0;
168
169 /*** The host configuration to use */
170 private HostConfiguration hostConfiguration;
171
172 /*** True if strict mode is enabled. */
173 private boolean strictMode = false;
174
175 // ------------------------------------------------------------- Properties
176
177 /***
178 * Get my {@link HttpState state}.
179 *
180 * @see #setState(HttpState)
181 * @return the shared client state
182 */
183 public synchronized HttpState getState() {
184 return state;
185 }
186
187 /***
188 * Set my {@link HttpState state}.
189 *
190 * @see #getState()
191 * @param state the new state for the client
192 */
193 public synchronized void setState(HttpState state) {
194 this.state = state;
195 }
196
197 /***
198 *
199 * @param strictMode <code>true</code> if strict mode should be used
200 *
201 * @see #isStrictMode()
202 *
203 */
204 public synchronized void setStrictMode(boolean strictMode) {
205 this.strictMode = strictMode;
206 }
207
208 /***
209 *
210 * @return <code>true</code> if strict mode being used
211 *
212 * @see #setStrictMode(boolean)
213 *
214 */
215 public synchronized boolean isStrictMode() {
216 return strictMode;
217 }
218
219 /***
220 * Sets the SO_TIMEOUT which is the timeout for waiting for data.
221 *
222 * A timeout value of zero is interpreted as an infinite timeout.
223 *
224 * @param newTimeoutInMilliseconds Timeout in milliseconds
225 *
226 */
227 public synchronized void setTimeout(int newTimeoutInMilliseconds) {
228 this.timeoutInMilliseconds = newTimeoutInMilliseconds;
229 }
230
231 /***
232 * Sets the timeout used when retrieving an HttpConnection from the
233 * HttpConnectionManager.
234 *
235 * @param timeout the timeout in milliseconds
236 *
237 * @see HttpConnectionManager#getConnection(HostConfiguration, long)
238 */
239 public synchronized void setHttpConnectionFactoryTimeout(long timeout) {
240 this.httpConnectionTimeout = timeout;
241 }
242
243 /***
244 * Sets the timeout until a connection is etablished. A value of 0 means
245 * the timeout is not used. The default value is 0.
246 * @see HttpConnection#setConnectionTimeout(int)
247 * @param newTimeoutInMilliseconds Timeout in milliseconds.
248 */
249 public synchronized void setConnectionTimeout(int newTimeoutInMilliseconds) {
250 this.connectionTimeout = newTimeoutInMilliseconds;
251 }
252
253 // --------------------------------------------------------- Public Methods
254
255 /***
256 * @deprecated use hostConfiguration
257 *
258 * Sets the host, port and protocol(http) to be used when executing a
259 * method.
260 *
261 * @param host the host to connect to
262 * @param port the port to connect to
263 *
264 * @see #getHostConfiguration()
265 */
266 public void startSession(String host, int port) {
267 LOG.trace("enter HttpClient.startSession(String, int)");
268 startSession(host, port, false);
269 }
270
271 /***
272 * @deprecated use hostConfiguration
273 *
274 * Sets the host, port and protocol to be used when executing a method.
275 *
276 * @param host the host to connect to
277 * @param port the port to connect to
278 * @param https when <code>true</code>, create an HTTPS session
279 *
280 * @see #getHostConfiguration()
281 */
282 public void startSession(String host, int port, boolean https) {
283 LOG.trace("enter HttpClient.startSession(String, int, boolean)");
284
285 if (LOG.isDebugEnabled()) {
286 LOG.debug("HttpClient.startSession(String,int,boolean): Host:"
287 + host + " Port:" + port + " HTTPS:" + https);
288 }
289
290 this.hostConfiguration.setHost(host, port, https ? "https" : "http");
291 }
292
293 /***
294 * @deprecated use hostConfiguration and httpState
295 *
296 * Sets the host, port, protocol(http) and credentials to be used when
297 * executing a method.
298 *
299 * @param host the host to connect to
300 * @param port the port to connect to
301 * @param creds the default credentials to use
302 *
303 * @see #getHostConfiguration()
304 * @see #getState()
305 * @see #startSession(String, int, Credentials, boolean)
306 */
307 public void startSession(String host, int port, Credentials creds) {
308 LOG.trace("enter HttpClient.startSession(String, int, Credentials)");
309 startSession(host, port, creds, false);
310 }
311
312 /***
313 * @deprecated use hostConfiguration and httpState
314 *
315 * Sets the host, port, protocol and credentials to be used when executing a
316 * method.
317 *
318 * @param host the host to connect to
319 * @param port the port to connect to
320 * @param creds the default credentials to use
321 * @param https when <code>true</code>, create an HTTPS session
322 *
323 * @see #getHostConfiguration()
324 * @see #getState()
325 */
326 public void startSession(String host, int port, Credentials creds, boolean https) {
327 LOG.trace("enter HttpClient.startSession(String, int, Credentials, boolean)");
328
329 if (LOG.isDebugEnabled()) {
330 LOG.debug(
331 "Starting HttpClient session"
332 + " Host:" + host
333 + " Port:" + port + " Credentials:" + creds
334 + " HTTPS:" + https);
335 }
336 getState().setCredentials(null, creds);
337 this.hostConfiguration.setHost(
338 host,
339 port,
340 https ? "https" : "http"
341 );
342 }
343
344 /***
345 * @deprecated use hostConfiguration and httpState
346 *
347 * Sets the host, port, protocol and credentials to be used when executing a
348 * method using the server specified by the scheme, userinfo, host and port
349 * of the given <i>uri</i>.
350 * <p>
351 * Note that the path component is not utilized.
352 * <p>
353 * @param uri an <code>HttpURL</code> or <code>HttpsURL</code> instance; the
354 * {@link URI URI} from which the scheme, userinfo, host and port of the
355 * session are determined
356 *
357 * @throws IllegalStateException not enough information to process
358 * @throws URIException If the URI is bad.
359 *
360 * @see #getHostConfiguration()
361 * @see #getState()
362 */
363 public void startSession(URI uri)
364 throws URIException, IllegalStateException {
365
366 LOG.trace("enter HttpClient.startSession(URI)");
367
368 String scheme = uri.getScheme();
369 if (scheme == null) { // it may a URI instance or abs_path
370 LOG.error("no scheme to start a session");
371 throw new IllegalStateException("no scheme to start a session");
372 }
373
374 Protocol protocol = Protocol.getProtocol(scheme);
375
376 String userinfo = uri.getUserinfo();
377 if (userinfo != null) {
378 getState().setCredentials(null,
379 new UsernamePasswordCredentials(userinfo));
380 }
381 String host = uri.getHost();
382 if (host == null || host.length() == 0) {
383 LOG.error("no host to start a session");
384 throw new IllegalStateException("no host to start a session");
385 }
386 int port = uri.getPort();
387 if (port == -1) { // neither HttpURL or HttpsURL instance
388 LOG.error("HttpURL or HttpsURL instance required");
389 throw new IllegalStateException
390 ("HttpURL or HttpsURL instance required");
391 }
392 this.hostConfiguration.setHost(host, null, port, protocol);
393 }
394
395 /***
396 * @deprecated use hostConfiguration
397 *
398 * Sets the host, port and protocol to be used when executing a method.
399 * <p>
400 * Note that everything but the protocol, host and port of the
401 * given <i>url</i> is ignored.
402 * </p>
403 * @param url the {@link URL URL} from which the protocol, host, and port of
404 * the session are determined
405 *
406 * @exception IllegalArgumentException if the protocol is not http or https
407 *
408 * @see #getHostConfiguration()
409 */
410 public void startSession(URL url) throws IllegalArgumentException {
411 LOG.trace("enter HttpClient.startSession(String, int, Credentials, boolean)");
412
413 int port = url.getPort();
414 Protocol protocol = Protocol.getProtocol(url.getProtocol());
415
416 hostConfiguration.setHost(url.getHost(), null, port, protocol);
417 }
418
419 /***
420 * @deprecated use hostConfiguration and httpState
421 *
422 * Sets the host, port, protocol and credentials to be used when executing a
423 * method.
424 * <p>
425 * Note that everything but the protocol, host and port of the
426 * given <i>url</i> is ignored.
427 * </p>
428 * @param url the {@link URL URL} from which the protocol, host, and port of
429 * the session are determined
430 * @param creds the default credentials to use
431 *
432 * @exception IllegalArgumentException if the protocol is not http or https
433 *
434 * @see #getHostConfiguration()
435 * @see #getState()
436 */
437 public void startSession(URL url, Credentials creds)
438 throws IllegalArgumentException {
439
440 LOG.trace("enter HttpClient.startSession(URL, Credentials)");
441 getState().setCredentials(null, creds);
442 startSession(url);
443 }
444
445 /***
446 * @deprecated use hostConfiguration
447 *
448 * Sets the host, port, protocol(http) and proxy to be used when executing a
449 * method.
450 *
451 * @param host the host to connect to
452 * @param port the port to connect to
453 * @param proxyhost the proxy host to connect via
454 * @param proxyport the proxy port to connect via
455 *
456 * @see #getHostConfiguration()
457 */
458 public void startSession(String host, int port, String proxyhost, int proxyport) {
459 LOG.trace("enter HttpClient.startSession(String, int, String, int)");
460 startSession(host, port, proxyhost, proxyport, false);
461 }
462
463 /***
464 * @deprecated use hostConfiguration
465 *
466 * Sets the host, port, protocol and proxy to be used when executing a
467 * method.
468 *
469 * @param host the host to connect to
470 * @param port the port to connect to
471 * @param proxyhost the proxy host to connect via
472 * @param proxyport the proxy port to connect via
473 * @param secure whether or not to connect using HTTPS
474 *
475 * @see #getHostConfiguration()
476 */
477 public void startSession(String host, int port,
478 String proxyhost, int proxyport, boolean secure) {
479
480 LOG.trace("enter HttpClient.startSession("
481 + "String, int, String, int, boolean)");
482 this.hostConfiguration.setHost (host, port, secure ? "https" : "http");
483 this.hostConfiguration.setProxy(proxyhost, proxyport);
484 }
485
486 /***
487 * Executes the given method.
488 *
489 * @param method the {@link HttpMethod} to execute.
490 * @return the method's response code
491 *
492 * @throws IOException if an I/O error occurs
493 * @throws HttpException if a protocol exception occurs
494 */
495 public int executeMethod(HttpMethod method)
496 throws IOException, HttpException {
497
498 LOG.trace("enter HttpClient.executeMethod(HttpMethod)");
499 // execute this method and use its host configuration, if it has one
500 return executeMethod(
501 method.getHostConfiguration() != null
502 ? method.getHostConfiguration()
503 : getHostConfiguration(),
504 method,
505 null
506 );
507
508 }
509
510 /***
511 * Executes the given method.
512 *
513 * @param hostConfiguration The configuration to use.
514 * @param method the {@link HttpMethod} to execute.
515 * @return the method's response code
516 *
517 * @throws IOException if an I/O error occurs
518 * @throws HttpException if a protocol exception occurs
519 * @since 2.0
520 */
521 public int executeMethod(HostConfiguration hostConfiguration, HttpMethod method)
522 throws IOException, HttpException {
523
524 LOG.trace("enter HttpClient.executeMethod(HostConfiguration,HttpMethod)");
525
526 return executeMethod(hostConfiguration, method, null);
527 }
528
529
530
531 /***
532 * Executes the given method.
533 *
534 * @param hostConfiguration The configuration to use.
535 * @param method the {@link HttpMethod} to execute.
536 * @param state the {@link HttpState} to use when executing the method.
537 * If <code>null</code>, the state returned by {@link #getState} will be used instead.
538 *
539 * @return the method's response code
540 *
541 * @throws IOException if an I/O error occurs
542 * @throws HttpException if a protocol exception occurs
543 * @since 2.0
544 */
545 public int executeMethod(HostConfiguration hostConfiguration,
546 HttpMethod method, HttpState state)
547 throws IOException, HttpException {
548
549 LOG.trace("enter HttpClient.executeMethod(HostConfiguration,HttpMethod,HttpState)");
550
551 if (method == null) {
552 throw new IllegalArgumentException("HttpMethod parameter may not be null");
553 }
554
555 int soTimeout = 0;
556 boolean strictMode = false;
557 int connectionTimeout = 0;
558 long httpConnectionTimeout = 0;
559 HostConfiguration defaultHostConfiguration = null;
560
561 /* access all synchronized data in a single block, this will keeps us
562 * from accessing data asynchronously as well having to regain the lock
563 * for each item.
564 */
565 synchronized (this) {
566 soTimeout = this.timeoutInMilliseconds;
567 strictMode = this.strictMode;
568 connectionTimeout = this.connectionTimeout;
569 httpConnectionTimeout = this.httpConnectionTimeout;
570 if (state == null) {
571 state = getState();
572 }
573 defaultHostConfiguration = getHostConfiguration();
574 }
575
576 HostConfiguration methodConfiguration
577 = new HostConfiguration(hostConfiguration);
578
579 if (hostConfiguration != defaultHostConfiguration) {
580 // we may need to apply some defaults
581 if (!methodConfiguration.isHostSet()) {
582 methodConfiguration.setHost(
583 defaultHostConfiguration.getHost(),
584 defaultHostConfiguration.getVirtualHost(),
585 defaultHostConfiguration.getPort(),
586 defaultHostConfiguration.getProtocol()
587 );
588 }
589 if (!methodConfiguration.isProxySet()
590 && defaultHostConfiguration.isProxySet()) {
591
592 methodConfiguration.setProxy(
593 defaultHostConfiguration.getProxyHost(),
594 defaultHostConfiguration.getProxyPort()
595 );
596 }
597 if (methodConfiguration.getLocalAddress() == null
598 && defaultHostConfiguration.getLocalAddress() != null) {
599
600 methodConfiguration.setLocalAddress(defaultHostConfiguration.getLocalAddress());
601 }
602 }
603
604 HttpConnectionManager connmanager = this.httpConnectionManager;
605 if (state.getHttpConnectionManager() != null) {
606 connmanager = state.getHttpConnectionManager();
607 }
608
609 HttpConnection connection = connmanager.getConnection(
610 methodConfiguration,
611 httpConnectionTimeout
612 );
613
614 try {
615 // Catch all possible exceptions to make sure to release the
616 // connection, as although the user may call
617 // Method->releaseConnection(), the method doesn't know about the
618 // connection until HttpMethod.execute() is called.
619
620 method.setStrictMode(strictMode);
621
622 if (!connection.isOpen()) {
623 connection.setSoTimeout(soTimeout);
624 connection.setConnectionTimeout(connectionTimeout);
625 connection.open();
626 if (connection.isProxied() && connection.isSecure()) {
627 method = new ConnectMethod(method);
628 }
629 }
630 } catch (IOException e) {
631 connection.releaseConnection();
632 throw e;
633 } catch (RuntimeException e) {
634 connection.releaseConnection();
635 throw e;
636 }
637
638 return method.execute(state, connection);
639 }
640
641 /***
642 * @deprecated this method has no effect. HttpMethod.releaseConnection()
643 * should be used to release resources after a HttpMethod has been executed.
644 *
645 * @see HttpMethod#releaseConnection()
646 */
647 public void endSession() throws IOException {
648 }
649
650 /***
651 * Return the host that the client is accessing.
652 *
653 * @return The host that the client is accessing, or <code>null</code> if
654 * the session has not been started via startSession.
655 */
656 public String getHost() {
657 return hostConfiguration.getHost();
658 }
659
660 /***
661 * Return the port that the client is accessing.
662 *
663 * @return The port that the client is accessing, or -1 if the session
664 * has not been started via startSession().
665 */
666 public int getPort() {
667 return hostConfiguration.getPort();
668 }
669
670 /***
671 * Returns the hostConfiguration.
672 * @return HostConfiguration
673 *
674 * @since 2.0
675 */
676 public synchronized HostConfiguration getHostConfiguration() {
677 return hostConfiguration;
678 }
679
680 /***
681 * Sets the hostConfiguration.
682 * @param hostConfiguration The hostConfiguration to set
683 *
684 * @since 2.0
685 */
686 public synchronized void setHostConfiguration(HostConfiguration hostConfiguration) {
687 this.hostConfiguration = hostConfiguration;
688 }
689
690 /***
691 * Returns the httpConnectionManager.
692 * @return HttpConnectionManager
693 *
694 * @since 2.0
695 */
696 public synchronized HttpConnectionManager getHttpConnectionManager() {
697 return httpConnectionManager;
698 }
699
700 /***
701 * Sets the httpConnectionManager.
702 * @param httpConnectionManager The httpConnectionManager to set
703 *
704 * @since 2.0
705 */
706 public synchronized void setHttpConnectionManager(
707 HttpConnectionManager httpConnectionManager
708 ) {
709 this.httpConnectionManager = httpConnectionManager;
710 }
711
712 }
This page was automatically generated by Maven