Index: java/org/apache/commons/httpclient/ConnectMethod.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ConnectMethod.java,v retrieving revision 1.20 diff -u -r1.20 ConnectMethod.java --- java/org/apache/commons/httpclient/ConnectMethod.java 25 Jul 2003 18:29:31 -0000 1.20 +++ java/org/apache/commons/httpclient/ConnectMethod.java 11 Aug 2003 02:05:12 -0000 @@ -69,7 +69,7 @@ import org.apache.commons.logging.LogFactory; /** - *

Wraps another method to tunnel through a proxy.

+ * Establishes a tunneled HTTP connection via the CONNECT method. * * @author Ortwin Gl�ck * @author dIon Gillard @@ -79,10 +79,20 @@ * @version $Revision: 1.20 $ $Date: 2003/07/25 18:29:31 $ */ public class ConnectMethod extends HttpMethodBase { + /** the name of this method */ public static final String NAME = "CONNECT"; /** + * Create a connect method. + */ + public ConnectMethod() { + LOG.trace("enter ConnectMethod()"); + } + + /** + * @deprecated the wrapped method is no longer used + * * Create a connect method wrapping the existing method * * @param method the {@link HttpMethod method} to execute after connecting @@ -90,7 +100,6 @@ */ public ConnectMethod(HttpMethod method) { LOG.trace("enter ConnectMethod(HttpMethod)"); - this.method = method; } /** @@ -102,7 +111,6 @@ return NAME; } - /** * This method does nothing. CONNECT request is not supposed * to contain Authorization request header. @@ -168,54 +176,30 @@ } /** - * Execute this method by tunnelling and then executing the wrapped method. + * Execute this method and create a tunneled HttpConnection. If the method + * is successful (i.e. the status is a 2xx) tunnelCreated() will be called + * on the connection. * * @param state the current http state * @param conn the connection to write to * @return the http status code from execution * @throws HttpException when an error occurs writing the headers * @throws IOException when an error occurs writing the headers + * + * @see HttpConnection#tunnelCreated() */ public int execute(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter ConnectMethod.execute(HttpState, HttpConnection)"); int code = super.execute(state, conn); - LOG.debug("CONNECT status code " + code); + if (LOG.isDebugEnabled()) { + LOG.debug("CONNECT status code " + code); + } if ((code >= 200) && (code < 300)) { conn.tunnelCreated(); - code = method.execute(state, conn); - } else { - // What is to follow is an ugly hack. - // I REALLY hate having to resort to such - // an appalling trick - // TODO: Connect method must be redesigned. - // The only feasible solution is to split monolithic - // HttpMethod into HttpRequest/HttpResponse pair. - // That would allow to execute CONNECT method - // behind the scene and return CONNECT HttpResponse - // object in response to the original request that - // contains the correct status line, headers & - // response body. - - LOG.debug("CONNECT failed, fake the response for the original method"); - if (method instanceof HttpMethodBase) { - // Pass the status, headers and response stream to the wrapped - // method. - // To ensure that the connection is not released more than once - // this method is still responsible for releasing the connection. - // This will happen when the response body is consumed, or when - // the wrapped method closes the response connection in - // releaseConnection(). - ((HttpMethodBase) method).fakeResponse( - getStatusLine(), - getResponseHeaderGroup(), - getResponseStream() - ); - } else { - releaseConnection(); - } } + return code; } @@ -283,8 +267,5 @@ /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(ConnectMethod.class); - - /** The wrapped method */ - private HttpMethod method; } Index: java/org/apache/commons/httpclient/HttpClient.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpClient.java,v retrieving revision 1.79 diff -u -r1.79 HttpClient.java --- java/org/apache/commons/httpclient/HttpClient.java 16 Jul 2003 20:48:27 -0000 1.79 +++ java/org/apache/commons/httpclient/HttpClient.java 11 Aug 2003 02:05:13 -0000 @@ -98,6 +98,7 @@ private static final Log LOG = LogFactory.getLog(HttpClient.class); static { + if (LOG.isDebugEnabled()) { LOG.debug("Java version: " + System.getProperty("java.version")); LOG.debug("Java vendor: " + System.getProperty("java.vendor")); @@ -319,29 +320,32 @@ throw new IllegalArgumentException("HttpMethod parameter may not be null"); } - int soTimeout = 0; - boolean strictMode = false; - int connectionTimeout = 0; - long httpConnectionTimeout = 0; + if (hostConfiguration == null) { + hostConfiguration = ( + method.getHostConfiguration() != null + ? method.getHostConfiguration() + : getHostConfiguration() + ); + } + HostConfiguration defaultHostConfiguration = null; + HttpMethodDirector methodDirector = new HttpMethodDirector(); /* access all synchronized data in a single block, this will keeps us * from accessing data asynchronously as well having to regain the lock * for each item. */ synchronized (this) { - soTimeout = this.timeoutInMilliseconds; - strictMode = this.strictMode; - connectionTimeout = this.connectionTimeout; - httpConnectionTimeout = this.httpConnectionTimeout; - if (state == null) { - state = getState(); - } + methodDirector.setSoTimeout(this.timeoutInMilliseconds); + methodDirector.setStrictMode(this.strictMode); + methodDirector.setConnectionTimeout(this.connectionTimeout); + methodDirector.setHttpConnectionFactoryTimeout(this.httpConnectionTimeout); + methodDirector.setState(state == null ? getState() : state); + methodDirector.setConnectionManager(this.httpConnectionManager); defaultHostConfiguration = getHostConfiguration(); } - HostConfiguration methodConfiguration - = new HostConfiguration(hostConfiguration); + HostConfiguration methodConfiguration = new HostConfiguration(hostConfiguration); if (hostConfiguration != defaultHostConfiguration) { // we may need to apply some defaults @@ -368,41 +372,15 @@ } } - HttpConnectionManager connmanager = this.httpConnectionManager; - - HttpConnection connection = connmanager.getConnectionWithTimeout( - methodConfiguration, - httpConnectionTimeout - ); - - try { - // Catch all possible exceptions to make sure to release the - // connection, as although the user may call - // Method->releaseConnection(), the method doesn't know about the - // connection until HttpMethod.execute() is called. - - method.setStrictMode(strictMode); + methodDirector.setHostConfiguration(methodConfiguration); + methodDirector.setMethod(method); - if (!connection.isOpen()) { - connection.setSoTimeout(soTimeout); - connection.setConnectionTimeout(connectionTimeout); - connection.open(); - if (connection.isProxied() && connection.isSecure()) { - method = new ConnectMethod(method); - } - } - } catch (IOException e) { - connection.releaseConnection(); - throw e; - } catch (RuntimeException e) { - connection.releaseConnection(); - throw e; - } + methodDirector.executeMethod(); - return method.execute(state, connection); + return methodDirector.getMethod().getStatusCode(); } - /** + /** * Return the host that the client is accessing. * * @return The host that the client is accessing, or null if Index: java/org/apache/commons/httpclient/HttpConnection.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java,v retrieving revision 1.72 diff -u -r1.72 HttpConnection.java --- java/org/apache/commons/httpclient/HttpConnection.java 5 Aug 2003 19:29:30 -0000 1.72 +++ java/org/apache/commons/httpclient/HttpConnection.java 11 Aug 2003 02:05:16 -0000 @@ -1017,11 +1017,31 @@ // we are assuming that the connection will only be released once used used = true; - if (httpConnectionManager != null) { + + if (locked) { + LOG.debug("Connection is locked. Call to releaseConnection() ignored."); + } else if (httpConnectionManager != null) { + LOG.debug("Releasing connection back to connection manager."); httpConnectionManager.releaseConnection(this); + } else { + LOG.warn("HttpConnectionManager is null. Connection cannot be released."); } } + /** + * @return + */ + boolean isLocked() { + return locked; + } + + /** + * @param locked + */ + void setLocked(boolean locked) { + this.locked = locked; + } + // ------------------------------------------------------ Protected Methods /** @@ -1314,6 +1334,10 @@ /** TCP_NODELAY socket value */ private boolean soNodelay = true; + /** flag to indicate if this connection can be released, if locked the connection cannot be + * released */ + private boolean locked = false; + /** Whether or not the socket is a secure one. */ private boolean usingSecureSocket = false; @@ -1321,9 +1345,9 @@ private boolean tunnelEstablished = false; /** Whether or not isStale() is used by isOpen() */ - private boolean staleCheckingEnabled = true; - - /** Timeout until connection established (Socket created). 0 means no timeout. */ + private boolean staleCheckingEnabled = true; + + /** Timeout until connection established (Socket created). 0 means no timeout. */ private int connectTimeout = 0; /** the connection manager that created this connection or null */ Index: java/org/apache/commons/httpclient/HttpMethod.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethod.java,v retrieving revision 1.26 diff -u -r1.26 HttpMethod.java --- java/org/apache/commons/httpclient/HttpMethod.java 3 Aug 2003 21:59:13 -0000 1.26 +++ java/org/apache/commons/httpclient/HttpMethod.java 11 Aug 2003 02:05:17 -0000 @@ -254,6 +254,14 @@ */ Header[] getRequestHeaders(); + /** + * Returns the request headers with the given name. Note that header-name matching is + * case insensitive. + * @param headerName the name of the headers to be returned. + * @return an array of zero or more headers + */ + Header[] getRequestHeaders(String headerName); + // ---------------------------------------------------------------- Queries /** @@ -293,6 +301,14 @@ * @return The specified response header. */ Header getResponseHeader(String headerName); + + /** + * Returns the response headers with the given name. Note that header-name matching is + * case insensitive. + * @param headerName the name of the headers to be returned. + * @return an array of zero or more headers + */ + Header[] getResponseHeaders(String headerName); /** * Returns an array of the response footers that the HTTP method currently has Index: java/org/apache/commons/httpclient/HttpMethodBase.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v retrieving revision 1.175 diff -u -r1.175 HttpMethodBase.java --- java/org/apache/commons/httpclient/HttpMethodBase.java 3 Aug 2003 21:59:13 -0000 1.175 +++ java/org/apache/commons/httpclient/HttpMethodBase.java 11 Aug 2003 02:05:22 -0000 @@ -68,14 +68,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; -import java.util.HashSet; -import java.util.Set; import org.apache.commons.httpclient.auth.AuthScheme; -import org.apache.commons.httpclient.auth.AuthenticationException; -import org.apache.commons.httpclient.auth.CredentialsNotAvailableException; import org.apache.commons.httpclient.auth.HttpAuthenticator; -import org.apache.commons.httpclient.auth.MalformedChallengeException; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.cookie.CookieSpec; import org.apache.commons.httpclient.cookie.MalformedCookieException; @@ -94,6 +89,17 @@ * * *

+ * When a method's request may contain a body, subclasses will typically want + * to override: + *

+ *

+ * + *

* When a method requires additional request headers, subclasses will typically * want to override: *