Index: examples/CustomHttpConnection.java =================================================================== RCS file: examples/CustomHttpConnection.java diff -N examples/CustomHttpConnection.java --- examples/CustomHttpConnection.java 19 Jul 2003 09:41:37 -0000 1.4 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,132 +0,0 @@ -/* - * $Header: /home/cvspublic/jakarta-commons/httpclient/src/examples/CustomHttpConnection.java,v 1.4 2003/07/19 09:41:37 olegk Exp $ - * $Revision: 1.4 $ - * $Date: 2003/07/19 09:41:37 $ - * ==================================================================== - * - * The Apache Software License, Version 1.1 - * - * Copyright (c) 1999-2003 The Apache Software Foundation. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowlegement may appear in the software itself, - * if and wherever such third-party acknowlegements normally appear. - * - * 4. The names "The Jakarta Project", "HttpClient", and "Apache Software - * Foundation" must not be used to endorse or promote products derived - * from this software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache" - * nor may "Apache" appear in their names without prior written - * permission of the Apache Group. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - * [Additional notices, if required by prior licensing conditions] - * - */ - -import org.apache.commons.httpclient.HttpConnection; -import org.apache.commons.httpclient.HttpState; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.URI; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.protocol.Protocol; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.ConnectMethod; - -/** - * This example demonstrates how to establishing connection to an HTTP server - * when higher level of control is desired - * - * @author Armando Anton - * @author Oleg Kalnichevski - */ - -public class CustomHttpConnection -{ - public static void main(String[] args) throws Exception - { - if (args.length != 1) - { - System.err.println("Usage: java CustomHttpConnection "); - System.err.println(" The url of a webpage"); - System.exit(1); - } - - URI uri = new URI(args[0], true); - - String schema = uri.getScheme(); - if ((schema == null) || (schema.equals(""))) - { - schema = "http"; - } - Protocol protocol = Protocol.getProtocol(schema); - - HttpState state = new HttpState(); - - HttpMethod method = new GetMethod(uri.toString()); - String host = uri.getHost(); - int port = uri.getPort(); - - HttpConnection connection = new HttpConnection(host, port, protocol); - - connection.setProxyHost(System.getProperty("http.proxyHost")); - connection.setProxyPort( Integer.parseInt(System.getProperty("http.proxyPort","80"))); - - if (System.getProperty("http.proxyUserName") != null) - { - state.setProxyCredentials(null, null, - new UsernamePasswordCredentials( - System.getProperty("http.proxyUserName"), - System.getProperty("http.proxyPassword"))); - } - - if (connection.isProxied() && connection.isSecure()) { - method = new ConnectMethod(method); - } - method.execute(state, connection); - - if (method.getStatusCode() == HttpStatus.SC_OK) { - System.out.println(method.getResponseBodyAsString()); - } else { - System.out.println("Unexpected failure: " + method.getStatusLine().toString()); - } - method.releaseConnection(); - } -} Index: java/httpclient.properties =================================================================== RCS file: java/httpclient.properties diff -N java/httpclient.properties --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ java/httpclient.properties 3 Sep 2003 20:54:14 -0000 @@ -0,0 +1,8 @@ +# Apache Jakarta HTTP client properties + +http.protocol.version = HTTP/1.1 +http.socket.timeout = 0 +http.connection.timeout = 0 +http.connection-manager.timeout = 0 + +http.useragent = Jakarta Commons-HttpClient/2.1m1 \ No newline at end of file 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.80 diff -u -r1.80 HttpClient.java --- java/org/apache/commons/httpclient/HttpClient.java 12 Aug 2003 02:35:17 -0000 1.80 +++ java/org/apache/commons/httpclient/HttpClient.java 3 Sep 2003 20:54:16 -0000 @@ -143,6 +143,7 @@ this.httpConnectionManager = httpConnectionManager; this.hostConfiguration = new HostConfiguration(); + this.params = new HttpParams(); } @@ -155,22 +156,12 @@ * My {@link HttpState state}. */ private HttpState state; - - /** the timout when waiting for a connection from the connectionManager */ - private long httpConnectionTimeout = 0; - - /** The timeout in milliseconds*/ - private int timeoutInMilliseconds = 0; - - /** The connection timeout. */ - private int connectionTimeout = 0; + + private HttpParams params; /** The host configuration to use */ private HostConfiguration hostConfiguration; - /** True if strict mode is enabled. */ - private boolean strictMode = false; - // ------------------------------------------------------------- Properties /** @@ -199,20 +190,30 @@ * * @see #isStrictMode() * + * @deprecated Use {@link HttpParams#setParameter(String, String)}, + * {@link HttpMethod#getParams()}, {@link HttpClient#getParams()} + * to exercise a more granular control over HTTP protocol strictness. */ public synchronized void setStrictMode(boolean strictMode) { - this.strictMode = strictMode; + if (strictMode) { + this.params.makeStrict(); + } else { + this.params.makeLenient(); + } } /** * - * @return true if strict mode being used + * @return false * * @see #setStrictMode(boolean) * + * @deprecated Use {@link HttpParams#getParameter(String)}, + * {@link HttpMethod#getParams()}, {@link HttpClient#getParams()} + * to exercise a more granular control over HTTP protocol strictness. */ public synchronized boolean isStrictMode() { - return strictMode; + return false; } /** @@ -221,10 +222,13 @@ * A timeout value of zero is interpreted as an infinite timeout. * * @param newTimeoutInMilliseconds Timeout in milliseconds + * + * @deprecated Use {@link HttpParams#setSoTimeout(int)}, + * {@link HttpClient#getParams()}. * */ public synchronized void setTimeout(int newTimeoutInMilliseconds) { - this.timeoutInMilliseconds = newTimeoutInMilliseconds; + this.params.setSoTimeout(newTimeoutInMilliseconds); } /** @@ -234,9 +238,12 @@ * @param timeout the timeout in milliseconds * * @see HttpConnectionManager#getConnection(HostConfiguration, long) + * + * @deprecated Use {@link HttpParams#setConnectionManagerTimeout(long)}, + * {@link HttpClient#getParams()} */ public synchronized void setHttpConnectionFactoryTimeout(long timeout) { - this.httpConnectionTimeout = timeout; + this.params.setConnectionManagerTimeout(timeout); } /** @@ -244,9 +251,12 @@ * the timeout is not used. The default value is 0. * @see HttpConnection#setConnectionTimeout(int) * @param newTimeoutInMilliseconds Timeout in milliseconds. + * + * @deprecated Use {@link HttpParams#setConnectionTimeout(int)}, + * {@link HttpClient#getParams()}. */ public synchronized void setConnectionTimeout(int newTimeoutInMilliseconds) { - this.connectionTimeout = newTimeoutInMilliseconds; + this.params.setConnectionTimeout(newTimeoutInMilliseconds); } // --------------------------------------------------------- Public Methods @@ -336,10 +346,7 @@ * for each item. */ synchronized (this) { - methodDirector.setSoTimeout(this.timeoutInMilliseconds); - methodDirector.setStrictMode(this.strictMode); - methodDirector.setConnectionTimeout(this.connectionTimeout); - methodDirector.setHttpConnectionFactoryTimeout(this.httpConnectionTimeout); + methodDirector.setParams(this.params); methodDirector.setState(state == null ? getState() : state); methodDirector.setConnectionManager(this.httpConnectionManager); defaultHostConfiguration = getHostConfiguration(); @@ -440,6 +447,10 @@ HttpConnectionManager httpConnectionManager ) { this.httpConnectionManager = httpConnectionManager; + } + + public HttpParams getParams() { + return this.params; } } 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.28 diff -u -r1.28 HttpMethod.java --- java/org/apache/commons/httpclient/HttpMethod.java 12 Aug 2003 02:55:22 -0000 1.28 +++ java/org/apache/commons/httpclient/HttpMethod.java 3 Sep 2003 20:54:20 -0000 @@ -518,4 +518,6 @@ */ void setDoAuthentication(boolean doAuthentication); + public HttpParams getParams(); + } 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.178 diff -u -r1.178 HttpMethodBase.java --- java/org/apache/commons/httpclient/HttpMethodBase.java 3 Sep 2003 02:17:49 -0000 1.178 +++ java/org/apache/commons/httpclient/HttpMethodBase.java 3 Sep 2003 20:54:32 -0000 @@ -142,16 +142,6 @@ /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(HttpMethodBase.class); - /** The User-Agent header sent on every request. */ - protected static final Header USER_AGENT; - - static { - String agent = System.getProperties() - .getProperty("httpclient.useragent", - "Jakarta Commons-HttpClient/2.1m1"); - USER_AGENT = new Header("User-Agent", agent); - } - // ----------------------------------------------------- Instance variables /** Request headers, if any. */ @@ -195,12 +185,8 @@ * HTTP authentication challenges. */ private boolean doAuthentication = true; - /** Version of the HTTP protocol to be used. */ - private HttpVersion version = HttpVersion.HTTP_1_1; - - /** True if this HTTP method should strictly follow the HTTP protocol - * specification. */ - private boolean strictMode = false; + /** HTTP protocol parameters. */ + private HttpParams params = new HttpParams(); /** True if this method has already been executed. */ private boolean used = false; @@ -363,13 +349,13 @@ * * @param http11 true to use HTTP/1.1, false to use 1.0 * - * @deprecated Use {@link #setHttpVersion(HttpVersion)} + * @deprecated Use {@link HttpParams#setVersion(HttpVersion)} */ public void setHttp11(boolean http11) { if (http11) { - this.version = HttpVersion.HTTP_1_1; + this.params.setVersion(HttpVersion.HTTP_1_1); } else { - this.version = HttpVersion.HTTP_1_0; + this.params.setVersion(HttpVersion.HTTP_1_0); } } @@ -407,10 +393,10 @@ * * @return true to use HTTP/1.1, false to use 1.0 * - * @deprecated Use {@link #getHttpVersion()} + * @deprecated Use {@link HttpParams#getVersion()} */ public boolean isHttp11() { - return this.version.equals(HttpVersion.HTTP_1_1); + return getHttpVersion().equals(HttpVersion.HTTP_1_1); } /** @@ -837,18 +823,26 @@ * which many HTTP servers expect. * * @param strictMode true for strict mode, false otherwise + * + * @deprecated Use {@link HttpParams#setParameter(String, String)} to exercise + * a more granular control over HTTP protocol strictness. */ public void setStrictMode(boolean strictMode) { - this.strictMode = strictMode; + if (strictMode) { + this.params.makeStrict(); + } else { + this.params.makeLenient(); + } } /** - * Returns the value of the strict mode flag. + * @deprecated Use {@link HttpParams#setParameter(String, String)} to exercise + * a more granular control over HTTP protocol strictness. * - * @return true if strict mode is enabled, false otherwise + * @return false */ public boolean isStrictMode() { - return strictMode; + return false; } /** @@ -933,16 +927,17 @@ } LOG.debug("Resorting to protocol version default close connection policy"); // missing or invalid connection header, do the default - if (this.version.greaterEquals(HttpVersion.HTTP_1_1)) { + HttpVersion version = getHttpVersion(); + if (version.greaterEquals(HttpVersion.HTTP_1_1)) { if (LOG.isDebugEnabled()) { - LOG.debug("Should NOT close connection, using " + this.version.toString()); + LOG.debug("Should NOT close connection, using " + version.toString()); } } else { if (LOG.isDebugEnabled()) { - LOG.debug("Should close connection, using " + this.version.toString()); + LOG.debug("Should close connection, using " + version.toString()); } } - return this.version.lessEquals(HttpVersion.HTTP_1_0); + return version.lessEquals(HttpVersion.HTTP_1_0); } /** @@ -971,21 +966,13 @@ } /** - * Execute this HTTP method. Note that we cannot currently support redirects - * that change the connection parameters (host, port, protocol) because - * we don't yet have a good way to get the new connection. For the time - * being, we just return the redirect response code, and allow the user - * agent to resubmit if desired. + * Executes this method using the specified HttpConnection and + * HttpState. * * @param state {@link HttpState state} information to associate with this * request. Must be non-null. * @param conn the {@link HttpConnection connection} to used to execute * this HTTP method. Must be non-null. - * Note that we cannot currently support redirects that - * change the HttpConnection parameters (host, port, protocol) - * because we don't yet have a good way to get the new connection. - * For the time being, we just return the 302 response, and allow - * the user agent to resubmit if desired. * * @return the integer status code if one was obtained, or -1 * @@ -1054,7 +1041,7 @@ getResponseTrailerHeaderGroup().clear(); statusLine = null; used = false; - version = HttpVersion.HTTP_1_1; + params = new HttpParams(); responseBody = null; recoverableExceptionCount = 0; connectionCloseForced = false; @@ -1179,7 +1166,7 @@ Cookie[] cookies = matcher.match(conn.getHost(), conn.getPort(), getPath(), conn.isSecure(), state.getCookies()); if ((cookies != null) && (cookies.length > 0)) { - if (this.isStrictMode()) { + if (getParams().isParameterOn(HttpParams.SINGLE_COOKIE_HEADER)) { // In strict mode put all cookies on the same header getRequestHeaderGroup().addHeader( matcher.formatCookieHeader(cookies)); @@ -1368,8 +1355,12 @@ LOG.trace("enter HttpMethodBase.addUserAgentRequestHeaders(HttpState, " + "HttpConnection)"); - if (getRequestHeader("user-agent") == null) { - setRequestHeader(HttpMethodBase.USER_AGENT); + if (getRequestHeader("User-Agent") == null) { + String agent = getParams().getParameter(HttpParams.USER_AGENT); + if (agent == null) { + agent = "Jakarta Commons-HttpClient"; + } + setRequestHeader("User-Agent", agent); } } @@ -1732,14 +1723,14 @@ if (conn.isResponseAvailable(conn.getSoTimeout())) { result = new ChunkedInputStream(is, this); } else { - if (isStrictMode()) { + if (getParams().isParameterOn(HttpParams.STRICT_TRANSFER_ENCODING)) { throw new ProtocolException("Chunk-encoded body declared but not sent"); } else { LOG.warn("Chunk-encoded body missing"); } } } else { - if (isStrictMode() && LOG.isWarnEnabled()) { + if (LOG.isWarnEnabled()) { LOG.warn("Transfer-Encoding is set but does not contain \"chunked\": " + transferEncoding); } @@ -1867,14 +1858,15 @@ //check for a valid HTTP-Version String versionStr = statusLine.getHttpVersion(); - if (!this.strictMode && versionStr.equals("HTTP")) { - this.version = HttpVersion.HTTP_1_0; + if (getParams().isParameterOff(HttpParams.UNAMBIGUOUS_STATUS_LINE) + && versionStr.equals("HTTP")) { + getParams().setVersion(HttpVersion.HTTP_1_0); if (LOG.isWarnEnabled()) { LOG.warn("Ambiguous status line (HTTP protocol version missing):" + statusLine.toString()); } } else { - this.version = HttpVersion.parse(versionStr); + getParams().setVersion(HttpVersion.parse(versionStr)); } } @@ -1936,6 +1928,7 @@ Wire.output("\r\n"); } + HttpVersion ver = getParams().getVersion(); Header expectheader = getRequestHeader("Expect"); String expectvalue = null; if (expectheader != null) { @@ -1943,7 +1936,7 @@ } if ((expectvalue != null) && (expectvalue.compareToIgnoreCase("100-continue") == 0)) { - if (this.isHttp11()) { + if (ver.greaterEquals(HttpVersion.HTTP_1_1)) { int readTimeout = conn.getSoTimeout(); try { conn.setSoTimeout(RESPONSE_WAIT_TIME_MS); @@ -2095,28 +2088,26 @@ } /** - * Get the HTTP version to be used with this method. + * Returns {@link HttpParams HTTP protocol parameters}. * - * @return HTTP version. + * @return HTTP parameters. * * @since 2.1 */ - public HttpVersion getHttpVersion() { - return this.version; + public HttpParams getParams() { + return this.params; } /** - * Set the HTTP version to be used with this method. + * Returns the HTTP version to be used with this method. + * + * @return HTTP version. * * @since 2.1 */ - public void setHttpVersion(HttpVersion version) { - if (version == null) { - this.version = HttpVersion.HTTP_1_1; - } else { - this.version = version; - } - } + protected HttpVersion getHttpVersion() { + return this.params.getVersion(); + } /** * Per RFC 2616 section 4.3, some response can never contain a message Index: java/org/apache/commons/httpclient/HttpMethodDirector.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodDirector.java,v retrieving revision 1.2 diff -u -r1.2 HttpMethodDirector.java --- java/org/apache/commons/httpclient/HttpMethodDirector.java 12 Aug 2003 18:46:47 -0000 1.2 +++ java/org/apache/commons/httpclient/HttpMethodDirector.java 3 Sep 2003 20:54:36 -0000 @@ -95,13 +95,7 @@ private HttpConnection connection; - private int soTimeout; - - private int connectionTimeout; - - private boolean strictMode; - - private long httpConnectionFactoryTimeout; + private HttpParams params; /** A flag to indicate if the connection should be released after the method is executed. */ private boolean releaseConnection = false; @@ -129,7 +123,7 @@ */ public void executeMethod() throws IOException, HttpException { - method.setStrictMode(strictMode); + method.getParams().setDefaults(this.params); try { int forwardCount = 0; //protect from an infinite loop @@ -230,7 +224,7 @@ if (connection == null) { connection = connectionManager.getConnectionWithTimeout( hostConfiguration, - httpConnectionFactoryTimeout + this.params.getConnectionManagerTimeout() ); connection.setLocked(true); @@ -248,8 +242,8 @@ if (!connection.isOpen()) { // this connection must be opened before it can be used - connection.setSoTimeout(soTimeout); - connection.setConnectionTimeout(connectionTimeout); + connection.setSoTimeout(this.params.getSoTimeout()); + connection.setConnectionTimeout(this.params.getConnectionTimeout()); connection.open(); if (connection.isProxied() && connection.isSecure()) { // we need to create a secure tunnel before we can execute the real method @@ -708,57 +702,15 @@ /** * @return */ - public int getConnectionTimeout() { - return connectionTimeout; - } - - /** - * @param connectionTimeout - */ - public void setConnectionTimeout(int connectionTimeout) { - this.connectionTimeout = connectionTimeout; - } - - /** - * @return - */ - public long getHttpConnectionFactoryTimeout() { - return httpConnectionFactoryTimeout; - } - - /** - * @param httpConnectionFactoryTimeout - */ - public void setHttpConnectionFactoryTimeout(long httpConnectionTimeout) { - this.httpConnectionFactoryTimeout = httpConnectionTimeout; - } - - /** - * @return - */ - public int getSoTimeout() { - return soTimeout; - } - - /** - * @param soTimeout - */ - public void setSoTimeout(int soTimeout) { - this.soTimeout = soTimeout; - } - - /** - * @return - */ - public boolean isStrictMode() { - return strictMode; + public HttpParams getParams() { + return this.params; } /** - * @param strictMode + * @param params */ - public void setStrictMode(boolean strictMode) { - this.strictMode = strictMode; + public void setParams(final HttpParams params) { + this.params = params; } } Index: java/org/apache/commons/httpclient/HttpParams.java =================================================================== RCS file: java/org/apache/commons/httpclient/HttpParams.java diff -N java/org/apache/commons/httpclient/HttpParams.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ java/org/apache/commons/httpclient/HttpParams.java 3 Sep 2003 20:54:38 -0000 @@ -0,0 +1,429 @@ +/* + * $Header$ + * $Revision$ + * $Date$ + * + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.apache.commons.httpclient; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.HashMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This class represents a collection of HTTP protocol parameters. Protocol parameters + * may be linked together to form a hierarchy. A parameter may be off, on + * or not explicitly defined. If a parameter value has not been explicitly defined, + * its default value will be drawn from the upper level collection of parameters. + * + * @author Oleg Kalnichevski + * + * @version $Revision$ + * + */ + +public class HttpParams { + + /** Log object for this class. */ + private static final Log LOG = LogFactory.getLog(HttpParams.class); + + public static final String USER_AGENT = "http.useragent"; + public static final String PROTOCOL_VERSION = "http.protocol.version"; + public static final String SO_TIMEOUT = "http.socket.timeout"; + public static final String CONNECTION_TIMEOUT = "http.connection.timeout"; + public static final String CONNECTION_MANAGER_TIMEOUT = "http.connection-manager.timeout"; + public static final String PREEMPTIVE_AUTHENTICATION = "http.authentication.preemptive"; + + public static final String UNAMBIGUOUS_STATUS_LINE = "http.protocol.unambiguous-statusline"; + public static final String SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header"; + public static final String STRICT_TRANSFER_ENCODING = "http.protocol.strict-transfer-encoding"; + public static final String REJECT_HEAD_BODY = "http.protocol.reject-head-body"; + public static final String REJECT_RELATIVE_REDIRECT = "http.protocol.reject-relative-redirect"; + + private static final String[] PROTOCOL_STRICTNESS_PARAMETERS = { + UNAMBIGUOUS_STATUS_LINE, + SINGLE_COOKIE_HEADER, + STRICT_TRANSFER_ENCODING, + REJECT_HEAD_BODY, + REJECT_RELATIVE_REDIRECT + }; + + public static final HttpParams GLOBAL_DEFAULTS = new HttpParams(null); + + static { + String resource = System.getProperty("org.apache.commons.httpclient.properties"); + if (resource == null) { + if (LOG.isInfoEnabled()) { + LOG.info("HttpClient properties file URL not specified. Assuming default."); + } + resource = "httpclient.properties"; + } + URL url = HttpParams.class.getClassLoader().getResource(resource); + if (LOG.isDebugEnabled()) { + LOG.debug("Reading HttpClient properties from URL: " + url.toExternalForm()); + } + + if (url != null) { + try { + GLOBAL_DEFAULTS.load(url.openStream()); + } catch(IOException e) { + LOG.error("Error reading global properties", e); + } + } + + // TODO: To be removed. Provided for backward compatibility + String preemptiveDefault = System.getProperties() + .getProperty("httpclient.authentication.preemptive"); + if (preemptiveDefault != null) { + LOG.warn("'httpclient.authentication.preemptive' system property has been deprecated" + + " and should not be used"); + preemptiveDefault = preemptiveDefault.trim().toLowerCase(); + if (preemptiveDefault.equals("true")) { + GLOBAL_DEFAULTS.setParameter(PREEMPTIVE_AUTHENTICATION, "on"); + } else if (preemptiveDefault.equals("false")) { + GLOBAL_DEFAULTS.setParameter(PREEMPTIVE_AUTHENTICATION, "off"); + } + } + // TODO: To be removed. Provided for backward compatibility + String agent = System.getProperties() + .getProperty("httpclient.useragent"); + if (agent != null) { + LOG.warn("'httpclient.useragent' system property has been deprecated" + + " and should not be used"); + GLOBAL_DEFAULTS.setParameter(USER_AGENT, agent); + } + } + + private HttpParams defaults = null; + + /** Hash map of HTTP parameters that this object contains */ + private HashMap parameters = null; + + private HttpVersion version = null; + + private Integer soTimeout = null; + + private Integer connectionTimeout = null; + + private Long connectionManagerTimeout = null; + + public HttpParams(final HttpParams defaults) { + super(); + this.defaults = defaults; + } + + public HttpParams() { + this(GLOBAL_DEFAULTS); + } + + /** + * Returns reference to + * + */ + public synchronized HttpParams getDefaults() { + return this.defaults; + } + + public synchronized void setDefaults(final HttpParams params) { + this.defaults = params; + } + + public synchronized String getParameter(final String name) { + // See if the parameter has been explicitly defined + if (this.parameters != null) { + // If so, return + return (String)this.parameters.get(name); + } else { + // If not, see if defaults are available + if (this.defaults != null) { + // Return default parameter value + return this.defaults.getParameter(name); + } else { + // Otherwise, return null + return null; + } + + } + } + + public synchronized void setParameter(final String name, final String value) { + if (this.parameters == null) { + this.parameters = new HashMap(); + } + this.parameters.put(name, value); + if (LOG.isDebugEnabled()) { + LOG.debug("Set parameter " + name + " = " + value); + } + } + + public synchronized void setParameters(final String[] names, final String value) { + for (int i = 0; i < names.length; i++) { + setParameter(names[i], value); + } + } + + public synchronized boolean isParameterOn(final String name) { + boolean isOn = false; + String param = getParameter(name); + if (param != null) { + if (param.equalsIgnoreCase("on") || param.equalsIgnoreCase("true")) { + isOn = true; + } + } + return isOn; + } + + public synchronized boolean isParameterOff(final String name) { + boolean isOff = true; + String param = getParameter(name); + if (param != null) { + if (!param.equalsIgnoreCase("on") && !param.equalsIgnoreCase("true")) { + isOff = false; + } + } + return isOff; + } + + public synchronized HttpVersion getVersion() { + // See if the parameter has been explicitly defined + if (this.version != null) { + // If so, return + return this.version; + } else { + // If not, see if defaults are available + if (this.defaults != null) { + // Return default parameter value + return this.defaults.getVersion(); + } else { + // Otherwise, return a reasonable default value + return HttpVersion.HTTP_1_1; + } + + } + } + + public synchronized void setVersion(HttpVersion version) { + this.version = version; + } + + public synchronized int getSoTimeout() { + // See if the parameter has been explicitly defined + if (this.soTimeout != null) { + // If so, return + return this.soTimeout.intValue(); + } else { + // If not, see if defaults are available + if (this.defaults != null) { + // Return default parameter value + return this.defaults.getSoTimeout(); + } else { + // Otherwise, return a reasonable default value + return 0; + } + + } + } + + public synchronized void setSoTimeout(int timeout) { + this.soTimeout = new Integer(timeout); + } + + public synchronized int getConnectionTimeout() { + // See if the parameter has been explicitly defined + if (this.connectionTimeout != null) { + // If so, return + return this.connectionTimeout.intValue(); + } else { + // If not, see if defaults are available + if (this.defaults != null) { + // Return default parameter value + return this.defaults.getConnectionTimeout(); + } else { + // Otherwise, return a reasonable default value + return 0; + } + + } + } + + public synchronized void setConnectionTimeout(int timeout) { + this.connectionTimeout = new Integer(timeout); + } + + public synchronized long getConnectionManagerTimeout() { + // See if the parameter has been explicitly defined + if (this.connectionManagerTimeout != null) { + // If so, return + return this.connectionManagerTimeout.longValue(); + } else { + // If not, see if defaults are available + if (this.defaults != null) { + // Return default parameter value + return this.defaults.getConnectionManagerTimeout(); + } else { + // Otherwise, return a reasonable default value + return 0; + } + + } + } + + public synchronized void setConnectionManagerTimeout(long timeout) { + this.connectionManagerTimeout = new Long(timeout); + } + + public void makeStrict() { + setParameters(PROTOCOL_STRICTNESS_PARAMETERS, "on"); + } + + public void makeLenient() { + setParameters(PROTOCOL_STRICTNESS_PARAMETERS, "off"); + } + + public void makeDefault() { + setParameters(PROTOCOL_STRICTNESS_PARAMETERS, null); + } + + public void load(final InputStream instream) throws IOException { + if (instream == null) { + throw new IllegalArgumentException("Input stream may not be null"); + } + BufferedReader in = new BufferedReader(new InputStreamReader(instream)); + String line = null; + while ((line = in.readLine()) != null) { + String s = line.trim(); + if ((s.length() > 0) && (s.charAt(0) != '#')) { + String name = null; + String value = null; + int i = s.indexOf('='); + if (i != -1) { + name = s.substring(0, i).trim(); + value = s.substring(i + 1, s.length()).trim(); + } else { + name = s; + } + setParameter(name, value); + } + } + // Process special parameters + String s = null; + s = getParameter(PROTOCOL_VERSION); + if (s != null) { + try { + this.version = HttpVersion.parse(s); + } catch(ProtocolException e) { + if (LOG.isWarnEnabled()) { + LOG.warn("Invalid HTTP protocol version value: " + s); + } + } + } + s = getParameter(SO_TIMEOUT); + if (s != null) { + try { + this.soTimeout = new Integer(s); + } catch(NumberFormatException e) { + if (LOG.isWarnEnabled()) { + LOG.warn("Invalid socket timeout value: " + s); + } + } + } + s = getParameter(CONNECTION_TIMEOUT); + if (s != null) { + try { + this.connectionTimeout = new Integer(s); + } catch(NumberFormatException e) { + if (LOG.isWarnEnabled()) { + LOG.warn("Invalid connection timeout value: " + s); + } + } + } + s = getParameter(CONNECTION_MANAGER_TIMEOUT); + if (s != null) { + try { + this.connectionManagerTimeout = new Long(s); + } catch(NumberFormatException e) { + if (LOG.isWarnEnabled()) { + LOG.warn("Invalid connection manager timeout value: " + s); + } + } + } + } + + public void load(final File file) throws IOException { + if (file == null) { + throw new IllegalArgumentException("File may not be null"); + } + InputStream instream = new FileInputStream(file); + try { + load(instream); + } finally { + instream.close(); + } + } + +} Index: java/org/apache/commons/httpclient/HttpState.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpState.java,v retrieving revision 1.25 diff -u -r1.25 HttpState.java --- java/org/apache/commons/httpclient/HttpState.java 13 Jul 2003 13:54:50 -0000 1.25 +++ java/org/apache/commons/httpclient/HttpState.java 3 Sep 2003 20:54:41 -0000 @@ -104,22 +104,6 @@ // ----------------------------------------------------- Instance Variables /** - * Whether I should attempt to authenticate preemptively. - */ - private boolean preemptive; - - /** - * The boolean property name to turn on preemptive authentication. - */ - public static final String PREEMPTIVE_PROPERTY = - "httpclient.authentication.preemptive"; - - /** - * The default property value for #PREEMPTIVE_PROPERTY. - */ - public static final String PREEMPTIVE_DEFAULT = "false"; - - /** * My {@link Credentials Credentials}s, by realm. */ private HashMap credMap = new HashMap(); @@ -143,8 +127,7 @@ */ private int cookiePolicy = CookiePolicy.RFC2109; - /** The current connection manager */ - private HttpConnectionManager httpConnectionManager; + private boolean preemptive = false; // -------------------------------------------------------- Class Variables @@ -160,21 +143,6 @@ this.cookiePolicy = CookiePolicy.getDefaultPolicy(); - // check the preemptive policy - // TODO: this needs to be a service from some configuration class - String preemptiveDefault = - System.getProperties().getProperty(PREEMPTIVE_PROPERTY, - PREEMPTIVE_DEFAULT); - preemptiveDefault = preemptiveDefault.trim().toLowerCase(); - - if (!(preemptiveDefault.equals("true") - || preemptiveDefault.equals("false"))) { // property problem - LOG.warn("Configuration property " + PREEMPTIVE_PROPERTY - + " must be either true or false. Using default: " - + PREEMPTIVE_DEFAULT); - preemptiveDefault = PREEMPTIVE_DEFAULT; - } - this.preemptive = ("true".equals(preemptiveDefault)); } // ------------------------------------------------------------- Properties @@ -326,6 +294,9 @@ * attempted or not. * * @param value boolean flag + * + * @deprecated Use {@link HttpParams#setParameter(String, String)}, + * {@link HttpParams#PREEMPTIVE_AUTHENTICATION}, {@link HttpClient#getParams()}. */ public void setAuthenticationPreemptive(boolean value) { @@ -338,6 +309,9 @@ * attempted, otherwise return false * * @return boolean flag. + * + * @deprecated Use {@link HttpParams#getParameter(String)}, + * {@link HttpParams#PREEMPTIVE_AUTHENTICATION}, {@link HttpClient#getParams()}. */ public boolean isAuthenticationPreemptive() { Index: java/org/apache/commons/httpclient/methods/HeadMethod.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/HeadMethod.java,v retrieving revision 1.23 diff -u -r1.23 HeadMethod.java --- java/org/apache/commons/httpclient/methods/HeadMethod.java 9 Aug 2003 19:37:58 -0000 1.23 +++ java/org/apache/commons/httpclient/methods/HeadMethod.java 3 Sep 2003 20:54:43 -0000 @@ -68,6 +68,7 @@ import org.apache.commons.httpclient.HttpConnection; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethodBase; +import org.apache.commons.httpclient.HttpParams; import org.apache.commons.httpclient.ProtocolException; import org.apache.commons.httpclient.HttpState; import org.apache.commons.logging.Log; @@ -189,7 +190,7 @@ + this.bodyCheckTimeout + " ms"); } if (conn.isResponseAvailable(this.bodyCheckTimeout)) { - if (isStrictMode()) { + if (getParams().isParameterOn(HttpParams.REJECT_HEAD_BODY)) { throw new ProtocolException( "Body content may not be sent in response to HTTP HEAD request"); } else { Index: test/org/apache/commons/httpclient/SimpleHttpConnection.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/SimpleHttpConnection.java,v retrieving revision 1.15 diff -u -r1.15 SimpleHttpConnection.java --- test/org/apache/commons/httpclient/SimpleHttpConnection.java 8 May 2003 17:33:53 -0000 1.15 +++ test/org/apache/commons/httpclient/SimpleHttpConnection.java 3 Sep 2003 20:54:45 -0000 @@ -225,5 +225,10 @@ public void flushRequestOutputStream() throws IOException { assertOpen(); } + + public void releaseConnection() { + //do nothing, as there's nothing to release + } + } Index: test/org/apache/commons/httpclient/SimpleHttpExecutionContext.java =================================================================== RCS file: test/org/apache/commons/httpclient/SimpleHttpExecutionContext.java diff -N test/org/apache/commons/httpclient/SimpleHttpExecutionContext.java