/*
 * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v 1.222 2005/01/14 21:16:40 olegk Exp $
 * $Revision: 539441 $
 * $Date: 2007-05-18 14:56:55 +0200 (Fri, 18 May 2007) $
 *
 * ====================================================================
 *
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * ====================================================================
 *
 * 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
 * <http://www.apache.org/>.
 *
 */

package org.apache.commons.httpclient;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.util.Collection;

import org.apache.commons.httpclient.auth.AuthState;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.cookie.CookieSpec;
import org.apache.commons.httpclient.cookie.CookieVersionSupport;
import org.apache.commons.httpclient.cookie.MalformedCookieException;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.util.EncodingUtil;
import org.apache.commons.httpclient.util.ExceptionUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

An abstract base implementation of HttpMethod.

At minimum, subclasses will need to override:

  • getName to return the approriate name for this method

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

When a method expects specific response headers, subclasses may want to override:

Author:Remy Maucherat, Rodney Waldhoff, Sean C. Sullivan, dIon Gillard, Jeff Dever, Davanum Srinivas, Ortwin Glueck, Eric Johnson, Michael Becke, Oleg Kalnichevski, Mike Bowler, Gary Gregory, Christian Kohlschuetter
Version:$Revision: 539441 $ $Date: 2007-05-18 14:56:55 +0200 (Fri, 18 May 2007) $
/** * An abstract base implementation of HttpMethod. * <p> * At minimum, subclasses will need to override: * <ul> * <li>{@link #getName} to return the approriate name for this method * </li> * </ul> * </p> * * <p> * When a method requires additional request headers, subclasses will typically * want to override: * <ul> * <li>{@link #addRequestHeaders addRequestHeaders(HttpState,HttpConnection)} * to write those headers * </li> * </ul> * </p> * * <p> * When a method expects specific response headers, subclasses may want to * override: * <ul> * <li>{@link #processResponseHeaders processResponseHeaders(HttpState,HttpConnection)} * to handle those headers * </li> * </ul> * </p> * * * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> * @author Rodney Waldhoff * @author Sean C. Sullivan * @author <a href="mailto:dion@apache.org">dIon Gillard</a> * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a> * @author <a href="mailto:dims@apache.org">Davanum Srinivas</a> * @author Ortwin Glueck * @author Eric Johnson * @author Michael Becke * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> * @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a> * @author Christian Kohlschuetter * * @version $Revision: 539441 $ $Date: 2007-05-18 14:56:55 +0200 (Fri, 18 May 2007) $ */
public abstract class HttpMethodBase implements HttpMethod { // -------------------------------------------------------------- Constants
Log object for this class.
/** Log object for this class. */
private static final Log LOG = LogFactory.getLog(HttpMethodBase.class); // ----------------------------------------------------- Instance variables
Request headers, if any.
/** Request headers, if any. */
private HeaderGroup requestHeaders = new HeaderGroup();
The Status-Line from the response.
/** The Status-Line from the response. */
protected StatusLine statusLine = null;
Response headers, if any.
/** Response headers, if any. */
private HeaderGroup responseHeaders = new HeaderGroup();
Response trailer headers, if any.
/** Response trailer headers, if any. */
private HeaderGroup responseTrailerHeaders = new HeaderGroup();
Path of the HTTP method.
/** Path of the HTTP method. */
private String path = null;
Query string of the HTTP method, if any.
/** Query string of the HTTP method, if any. */
private String queryString = null;
The response body of the HTTP method, assuming it has not be intercepted by a sub-class.
/** The response body of the HTTP method, assuming it has not be * intercepted by a sub-class. */
private InputStream responseStream = null;
The connection that the response stream was read from.
/** The connection that the response stream was read from. */
private HttpConnection responseConnection = null;
Buffer for the response
/** Buffer for the response */
private byte[] responseBody = null;
True if the HTTP method should automatically follow HTTP redirects.
/** True if the HTTP method should automatically follow HTTP redirects.*/
private boolean followRedirects = false;
True if the HTTP method should automatically handle HTTP authentication challenges.
/** True if the HTTP method should automatically handle * HTTP authentication challenges. */
private boolean doAuthentication = true;
HTTP protocol parameters.
/** HTTP protocol parameters. */
private HttpMethodParams params = new HttpMethodParams();
Host authentication state
/** Host authentication state */
private AuthState hostAuthState = new AuthState();
Proxy authentication state
/** Proxy authentication state */
private AuthState proxyAuthState = new AuthState();
True if this method has already been executed.
/** True if this method has already been executed. */
private boolean used = false;
Count of how many times did this HTTP method transparently handle a recoverable exception.
/** Count of how many times did this HTTP method transparently handle * a recoverable exception. */
private int recoverableExceptionCount = 0;
the host for this HTTP method, can be null
/** the host for this HTTP method, can be null */
private HttpHost httphost = null;
Handles method retries
Deprecated:no loner used
/** * Handles method retries * * @deprecated no loner used */
private MethodRetryHandler methodRetryHandler;
True if the connection must be closed when no longer needed
/** True if the connection must be closed when no longer needed */
private boolean connectionCloseForced = false;
Number of milliseconds to wait for 100-contunue response.
/** Number of milliseconds to wait for 100-contunue response. */
private static final int RESPONSE_WAIT_TIME_MS = 3000;
HTTP protocol version used for execution of this method.
/** HTTP protocol version used for execution of this method. */
protected HttpVersion effectiveVersion = null;
Whether the execution of this method has been aborted
/** Whether the execution of this method has been aborted */
private volatile boolean aborted = false;
Whether the HTTP request has been transmitted to the target server it its entirety
/** Whether the HTTP request has been transmitted to the target * server it its entirety */
private boolean requestSent = false;
Actual cookie policy
/** Actual cookie policy */
private CookieSpec cookiespec = null;
Default initial size of the response buffer if content length is unknown.
/** Default initial size of the response buffer if content length is unknown. */
private static final int DEFAULT_INITIAL_BUFFER_SIZE = 4*1024; // 4 kB // ----------------------------------------------------------- Constructors
No-arg constructor.
/** * No-arg constructor. */
public HttpMethodBase() { }
Constructor specifying a URI. It is responsibility of the caller to ensure that URI elements (path & query parameters) are properly encoded (URL safe).
Params:
  • uri – either an absolute or relative URI. The URI is expected to be URL-encoded
Throws:
/** * Constructor specifying a URI. * It is responsibility of the caller to ensure that URI elements * (path & query parameters) are properly encoded (URL safe). * * @param uri either an absolute or relative URI. The URI is expected * to be URL-encoded * * @throws IllegalArgumentException when URI is invalid * @throws IllegalStateException when protocol of the absolute URI is not recognised */
public HttpMethodBase(String uri) throws IllegalArgumentException, IllegalStateException { try { // create a URI and allow for null/empty uri values if (uri == null || uri.equals("")) { uri = "/"; } String charset = getParams().getUriCharset(); setURI(new URI(uri, true, charset)); } catch (URIException e) { throw new IllegalArgumentException("Invalid uri '" + uri + "': " + e.getMessage() ); } } // ------------------------------------------- Property Setters and Getters
Obtains the name of the HTTP method as used in the HTTP request line, for example "GET" or "POST".
Returns:the name of this method
/** * Obtains the name of the HTTP method as used in the HTTP request line, * for example <tt>"GET"</tt> or <tt>"POST"</tt>. * * @return the name of this method */
public abstract String getName();
Returns the URI of the HTTP method
Throws:
See Also:
Returns:The URI
/** * Returns the URI of the HTTP method * * @return The URI * * @throws URIException If the URI cannot be created. * * @see org.apache.commons.httpclient.HttpMethod#getURI() */
public URI getURI() throws URIException { StringBuffer buffer = new StringBuffer(); if (this.httphost != null) { buffer.append(this.httphost.getProtocol().getScheme()); buffer.append("://"); buffer.append(this.httphost.getHostName()); int port = this.httphost.getPort(); if (port != -1 && port != this.httphost.getProtocol().getDefaultPort()) { buffer.append(":"); buffer.append(port); } } buffer.append(this.path); if (this.queryString != null) { buffer.append('?'); buffer.append(this.queryString); } String charset = getParams().getUriCharset(); return new URI(buffer.toString(), true, charset); }
Sets the URI for this method.
Params:
  • uri – URI to be set
Throws:
Since:3.0
/** * Sets the URI for this method. * * @param uri URI to be set * * @throws URIException if a URI cannot be set * * @since 3.0 */
public void setURI(URI uri) throws URIException { // only set the host if specified by the URI if (uri.isAbsoluteURI()) { this.httphost = new HttpHost(uri); } // set the path, defaulting to root setPath( uri.getPath() == null ? "/" : uri.getEscapedPath() ); setQueryString(uri.getEscapedQuery()); }
Sets whether or not the HTTP method should automatically follow HTTP redirects (status code 302, etc.)
Params:
  • followRedirects – true if the method will automatically follow redirects, false otherwise.
/** * Sets whether or not the HTTP method should automatically follow HTTP redirects * (status code 302, etc.) * * @param followRedirects <tt>true</tt> if the method will automatically follow redirects, * <tt>false</tt> otherwise. */
public void setFollowRedirects(boolean followRedirects) { this.followRedirects = followRedirects; }
Returns true if the HTTP method should automatically follow HTTP redirects (status code 302, etc.), false otherwise.
Returns:true if the method will automatically follow HTTP redirects, false otherwise.
/** * Returns <tt>true</tt> if the HTTP method should automatically follow HTTP redirects * (status code 302, etc.), <tt>false</tt> otherwise. * * @return <tt>true</tt> if the method will automatically follow HTTP redirects, * <tt>false</tt> otherwise. */
public boolean getFollowRedirects() { return this.followRedirects; }
Sets whether version 1.1 of the HTTP protocol should be used per default.
Params:
  • http11 – true to use HTTP/1.1, false to use 1.0
Deprecated:Use HttpMethodParams.setVersion(HttpVersion)
/** Sets whether version 1.1 of the HTTP protocol should be used per default. * * @param http11 <tt>true</tt> to use HTTP/1.1, <tt>false</tt> to use 1.0 * * @deprecated Use {@link HttpMethodParams#setVersion(HttpVersion)} */
public void setHttp11(boolean http11) { if (http11) { this.params.setVersion(HttpVersion.HTTP_1_1); } else { this.params.setVersion(HttpVersion.HTTP_1_0); } }
Returns true if the HTTP method should automatically handle HTTP authentication challenges (status code 401, etc.), false otherwise
Returns:true if authentication challenges will be processed automatically, false otherwise.
Since:2.0
/** * Returns <tt>true</tt> if the HTTP method should automatically handle HTTP * authentication challenges (status code 401, etc.), <tt>false</tt> otherwise * * @return <tt>true</tt> if authentication challenges will be processed * automatically, <tt>false</tt> otherwise. * * @since 2.0 */
public boolean getDoAuthentication() { return doAuthentication; }
Sets whether or not the HTTP method should automatically handle HTTP authentication challenges (status code 401, etc.)
Params:
  • doAuthentication – true to process authentication challenges authomatically, false otherwise.
Since:2.0
/** * Sets whether or not the HTTP method should automatically handle HTTP * authentication challenges (status code 401, etc.) * * @param doAuthentication <tt>true</tt> to process authentication challenges * authomatically, <tt>false</tt> otherwise. * * @since 2.0 */
public void setDoAuthentication(boolean doAuthentication) { this.doAuthentication = doAuthentication; } // ---------------------------------------------- Protected Utility Methods
Returns true if version 1.1 of the HTTP protocol should be used per default, false if version 1.0 should be used.
Returns:true to use HTTP/1.1, false to use 1.0
Deprecated:Use HttpMethodParams.getVersion()
/** * Returns <tt>true</tt> if version 1.1 of the HTTP protocol should be * used per default, <tt>false</tt> if version 1.0 should be used. * * @return <tt>true</tt> to use HTTP/1.1, <tt>false</tt> to use 1.0 * * @deprecated Use {@link HttpMethodParams#getVersion()} */
public boolean isHttp11() { return this.params.getVersion().equals(HttpVersion.HTTP_1_1); }
Sets the path of the HTTP method. It is responsibility of the caller to ensure that the path is properly encoded (URL safe).
Params:
  • path – the path of the HTTP method. The path is expected to be URL-encoded
/** * Sets the path of the HTTP method. * It is responsibility of the caller to ensure that the path is * properly encoded (URL safe). * * @param path the path of the HTTP method. The path is expected * to be URL-encoded */
public void setPath(String path) { this.path = path; }
Adds the specified request header, NOT overwriting any previous value. Note that header-name matching is case insensitive.
Params:
  • header – the header to add to the request
/** * Adds the specified request header, NOT overwriting any previous value. * Note that header-name matching is case insensitive. * * @param header the header to add to the request */
public void addRequestHeader(Header header) { LOG.trace("HttpMethodBase.addRequestHeader(Header)"); if (header == null) { LOG.debug("null header value ignored"); } else { getRequestHeaderGroup().addHeader(header); } }
Use this method internally to add footers.
Params:
  • footer – The footer to add.
/** * Use this method internally to add footers. * * @param footer The footer to add. */
public void addResponseFooter(Header footer) { getResponseTrailerHeaderGroup().addHeader(footer); }
Gets the path of this HTTP method. Calling this method after the request has been executed will return the actual path, following any redirects automatically handled by this HTTP method.
Returns:the path to request or "/" if the path is blank.
/** * Gets the path of this HTTP method. * Calling this method <em>after</em> the request has been executed will * return the <em>actual</em> path, following any redirects automatically * handled by this HTTP method. * * @return the path to request or "/" if the path is blank. */
public String getPath() { return (path == null || path.equals("")) ? "/" : path; }
Sets the query string of this HTTP method. The caller must ensure that the string is properly URL encoded. The query string should not start with the question mark character.
Params:
  • queryString – the query string
See Also:
/** * Sets the query string of this HTTP method. The caller must ensure that the string * is properly URL encoded. The query string should not start with the question * mark character. * * @param queryString the query string * * @see EncodingUtil#formUrlEncode(NameValuePair[], String) */
public void setQueryString(String queryString) { this.queryString = queryString; }
Sets the query string of this HTTP method. The pairs are encoded as UTF-8 characters. To use a different charset the parameters can be encoded manually using EncodingUtil and set as a single String.
Params:
  • params – an array of NameValuePairs to add as query string parameters. The name/value pairs will be automcatically URL encoded
See Also:
/** * Sets the query string of this HTTP method. The pairs are encoded as UTF-8 characters. * To use a different charset the parameters can be encoded manually using EncodingUtil * and set as a single String. * * @param params an array of {@link NameValuePair}s to add as query string * parameters. The name/value pairs will be automcatically * URL encoded * * @see EncodingUtil#formUrlEncode(NameValuePair[], String) * @see #setQueryString(String) */
public void setQueryString(NameValuePair[] params) { LOG.trace("enter HttpMethodBase.setQueryString(NameValuePair[])"); queryString = EncodingUtil.formUrlEncode(params, "UTF-8"); }
Gets the query string of this HTTP method.
Returns:The query string
/** * Gets the query string of this HTTP method. * * @return The query string */
public String getQueryString() { return queryString; }
Set the specified request header, overwriting any previous value. Note that header-name matching is case-insensitive.
Params:
  • headerName – the header's name
  • headerValue – the header's value
/** * Set the specified request header, overwriting any previous value. Note * that header-name matching is case-insensitive. * * @param headerName the header's name * @param headerValue the header's value */
public void setRequestHeader(String headerName, String headerValue) { Header header = new Header(headerName, headerValue); setRequestHeader(header); }
Sets the specified request header, overwriting any previous value. Note that header-name matching is case insensitive.
Params:
  • header – the header
/** * Sets the specified request header, overwriting any previous value. * Note that header-name matching is case insensitive. * * @param header the header */
public void setRequestHeader(Header header) { Header[] headers = getRequestHeaderGroup().getHeaders(header.getName()); for (int i = 0; i < headers.length; i++) { getRequestHeaderGroup().removeHeader(headers[i]); } getRequestHeaderGroup().addHeader(header); }
Returns the specified request header. Note that header-name matching is case insensitive. null will be returned if either headerName is null or there is no matching header for headerName.
Params:
  • headerName – The name of the header to be returned.
Returns:The specified request header.
Since:3.0
/** * Returns the specified request header. Note that header-name matching is * case insensitive. <tt>null</tt> will be returned if either * <i>headerName</i> is <tt>null</tt> or there is no matching header for * <i>headerName</i>. * * @param headerName The name of the header to be returned. * * @return The specified request header. * * @since 3.0 */
public Header getRequestHeader(String headerName) { if (headerName == null) { return null; } else { return getRequestHeaderGroup().getCondensedHeader(headerName); } }
Returns an array of the requests headers that the HTTP method currently has
Returns:an array of my request headers.
/** * Returns an array of the requests headers that the HTTP method currently has * * @return an array of my request headers. */
public Header[] getRequestHeaders() { return getRequestHeaderGroup().getAllHeaders(); }
See Also:
  • getRequestHeaders.getRequestHeaders(String)
/** * @see org.apache.commons.httpclient.HttpMethod#getRequestHeaders(java.lang.String) */
public Header[] getRequestHeaders(String headerName) { return getRequestHeaderGroup().getHeaders(headerName); }
Gets the header group storing the request headers.
Returns:a HeaderGroup
Since:2.0beta1
/** * Gets the {@link HeaderGroup header group} storing the request headers. * * @return a HeaderGroup * * @since 2.0beta1 */
protected HeaderGroup getRequestHeaderGroup() { return requestHeaders; }
Gets the header group storing the response trailer headers as per RFC 2616 section 3.6.1.
Returns:a HeaderGroup
Since:2.0beta1
/** * Gets the {@link HeaderGroup header group} storing the response trailer headers * as per RFC 2616 section 3.6.1. * * @return a HeaderGroup * * @since 2.0beta1 */
protected HeaderGroup getResponseTrailerHeaderGroup() { return responseTrailerHeaders; }
Gets the header group storing the response headers.
Returns:a HeaderGroup
Since:2.0beta1
/** * Gets the {@link HeaderGroup header group} storing the response headers. * * @return a HeaderGroup * * @since 2.0beta1 */
protected HeaderGroup getResponseHeaderGroup() { return responseHeaders; }
See Also:
  • getResponseHeaders.getResponseHeaders(String)
Since:3.0
/** * @see org.apache.commons.httpclient.HttpMethod#getResponseHeaders(java.lang.String) * * @since 3.0 */
public Header[] getResponseHeaders(String headerName) { return getResponseHeaderGroup().getHeaders(headerName); }
Returns the response status code.
Returns:the status code associated with the latest response.
/** * Returns the response status code. * * @return the status code associated with the latest response. */
public int getStatusCode() { return statusLine.getStatusCode(); }
Provides access to the response status line.
Returns:the status line object from the latest response.
Since:2.0
/** * Provides access to the response status line. * * @return the status line object from the latest response. * @since 2.0 */
public StatusLine getStatusLine() { return statusLine; }
Checks if response data is available.
Returns:true if response data is available, false otherwise.
/** * Checks if response data is available. * @return <tt>true</tt> if response data is available, <tt>false</tt> otherwise. */
private boolean responseAvailable() { return (responseBody != null) || (responseStream != null); }
Returns an array of the response headers that the HTTP method currently has in the order in which they were read.
Returns:an array of response headers.
/** * Returns an array of the response headers that the HTTP method currently has * in the order in which they were read. * * @return an array of response headers. */
public Header[] getResponseHeaders() { return getResponseHeaderGroup().getAllHeaders(); }
Gets the response header associated with the given name. Header name matching is case insensitive. null will be returned if either headerName is null or there is no matching header for headerName.
Params:
  • headerName – the header name to match
Returns:the matching header
/** * Gets the response header associated with the given name. Header name * matching is case insensitive. <tt>null</tt> will be returned if either * <i>headerName</i> is <tt>null</tt> or there is no matching header for * <i>headerName</i>. * * @param headerName the header name to match * * @return the matching header */
public Header getResponseHeader(String headerName) { if (headerName == null) { return null; } else { return getResponseHeaderGroup().getCondensedHeader(headerName); } }
Return the length (in bytes) of the response body, as specified in a Content-Length header.

Return -1 when the content-length is unknown.

Returns:content length, if Content-Length header is available. 0 indicates that the request has no body. If Content-Length header is not present, the method returns -1.
/** * Return the length (in bytes) of the response body, as specified in a * <tt>Content-Length</tt> header. * * <p> * Return <tt>-1</tt> when the content-length is unknown. * </p> * * @return content length, if <tt>Content-Length</tt> header is available. * <tt>0</tt> indicates that the request has no body. * If <tt>Content-Length</tt> header is not present, the method * returns <tt>-1</tt>. */
public long getResponseContentLength() { Header[] headers = getResponseHeaderGroup().getHeaders("Content-Length"); if (headers.length == 0) { return -1; } if (headers.length > 1) { LOG.warn("Multiple content-length headers detected"); } for (int i = headers.length - 1; i >= 0; i--) { Header header = headers[i]; try { return Long.parseLong(header.getValue()); } catch (NumberFormatException e) { if (LOG.isWarnEnabled()) { LOG.warn("Invalid content-length value: " + e.getMessage()); } } // See if we can have better luck with another header, if present } return -1; }
Returns the response body of the HTTP method, if any, as an array of bytes. If response body is not available or cannot be read, returns null. Buffers the response and this method can be called several times yielding the same result each time. Note: This will cause the entire response body to be buffered in memory. A malicious server may easily exhaust all the VM memory. It is strongly recommended, to use getResponseAsStream if the content length of the response is unknown or resonably large.
Throws:
  • IOException – If an I/O (transport) problem occurs while obtaining the response body.
Returns:The response body.
/** * Returns the response body of the HTTP method, if any, as an array of bytes. * If response body is not available or cannot be read, returns <tt>null</tt>. * Buffers the response and this method can be called several times yielding * the same result each time. * * Note: This will cause the entire response body to be buffered in memory. A * malicious server may easily exhaust all the VM memory. It is strongly * recommended, to use getResponseAsStream if the content length of the response * is unknown or resonably large. * * @return The response body. * * @throws IOException If an I/O (transport) problem occurs while obtaining the * response body. */
public byte[] getResponseBody() throws IOException { if (this.responseBody == null) { InputStream instream = getResponseBodyAsStream(); if (instream != null) { long contentLength = getResponseContentLength(); if (contentLength > Integer.MAX_VALUE) { //guard below cast from overflow throw new IOException("Content too large to be buffered: "+ contentLength +" bytes"); } int limit = getParams().getIntParameter(HttpMethodParams.BUFFER_WARN_TRIGGER_LIMIT, 1024*1024); if ((contentLength == -1) || (contentLength > limit)) { LOG.warn("Going to buffer response body of large or unknown size. " +"Using getResponseBodyAsStream instead is recommended."); } LOG.debug("Buffering response body"); ByteArrayOutputStream outstream = new ByteArrayOutputStream( contentLength > 0 ? (int) contentLength : DEFAULT_INITIAL_BUFFER_SIZE); byte[] buffer = new byte[4096]; int len; while ((len = instream.read(buffer)) > 0) { outstream.write(buffer, 0, len); } outstream.close(); setResponseStream(null); this.responseBody = outstream.toByteArray(); } } return this.responseBody; }
Returns the response body of the HTTP method, if any, as an array of bytes. If response body is not available or cannot be read, returns null. Buffers the response and this method can be called several times yielding the same result each time. Note: This will cause the entire response body to be buffered in memory. This method is safe if the content length of the response is unknown, because the amount of memory used is limited.

If the response is large this method involves lots of array copying and many object allocations, which makes it unsuitable for high-performance / low-footprint applications. Those applications should use getResponseBodyAsStream().

Params:
  • maxlen – the maximum content length to accept (number of bytes).
Throws:
  • IOException – If an I/O (transport) problem occurs while obtaining the response body.
Returns:The response body.
/** * Returns the response body of the HTTP method, if any, as an array of bytes. * If response body is not available or cannot be read, returns <tt>null</tt>. * Buffers the response and this method can be called several times yielding * the same result each time. * * Note: This will cause the entire response body to be buffered in memory. This method is * safe if the content length of the response is unknown, because the amount of memory used * is limited.<p> * * If the response is large this method involves lots of array copying and many object * allocations, which makes it unsuitable for high-performance / low-footprint applications. * Those applications should use {@link #getResponseBodyAsStream()}. * * @param maxlen the maximum content length to accept (number of bytes). * @return The response body. * * @throws IOException If an I/O (transport) problem occurs while obtaining the * response body. */
public byte[] getResponseBody(int maxlen) throws IOException { if (maxlen < 0) throw new IllegalArgumentException("maxlen must be positive"); if (this.responseBody == null) { InputStream instream = getResponseBodyAsStream(); if (instream != null) { // we might already know that the content is larger long contentLength = getResponseContentLength(); if ((contentLength != -1) && (contentLength > maxlen)) { throw new HttpContentTooLargeException( "Content-Length is " + contentLength, maxlen); } LOG.debug("Buffering response body"); ByteArrayOutputStream rawdata = new ByteArrayOutputStream( contentLength > 0 ? (int) contentLength : DEFAULT_INITIAL_BUFFER_SIZE); byte[] buffer = new byte[2048]; int pos = 0; int len; do { len = instream.read(buffer, 0, Math.min(buffer.length, maxlen-pos)); if (len == -1) break; rawdata.write(buffer, 0, len); pos += len; } while (pos < maxlen); setResponseStream(null); // check if there is even more data if (pos == maxlen) { if (instream.read() != -1) throw new HttpContentTooLargeException( "Content-Length not known but larger than " + maxlen, maxlen); } this.responseBody = rawdata.toByteArray(); } } return this.responseBody; }
Returns the response body of the HTTP method, if any, as an InputStream. If response body is not available, returns null. If the response has been buffered this method returns a new stream object on every call. If the response has not been buffered the returned stream can only be read once.
Throws:
  • IOException – If an I/O (transport) problem occurs while obtaining the response body.
Returns:The response body or null.
/** * Returns the response body of the HTTP method, if any, as an {@link InputStream}. * If response body is not available, returns <tt>null</tt>. If the response has been * buffered this method returns a new stream object on every call. If the response * has not been buffered the returned stream can only be read once. * * @return The response body or <code>null</code>. * * @throws IOException If an I/O (transport) problem occurs while obtaining the * response body. */
public InputStream getResponseBodyAsStream() throws IOException { if (responseStream != null) { return responseStream; } if (responseBody != null) { InputStream byteResponseStream = new ByteArrayInputStream(responseBody); LOG.debug("re-creating response stream from byte array"); return byteResponseStream; } return null; }
Returns the response body of the HTTP method, if any, as a String. If response body is not available or cannot be read, returns null The string conversion on the data is done using the character encoding specified in Content-Type header. Buffers the response and this method can be called several times yielding the same result each time. Note: This will cause the entire response body to be buffered in memory. A malicious server may easily exhaust all the VM memory. It is strongly recommended, to use getResponseAsStream if the content length of the response is unknown or resonably large.
Throws:
  • IOException – If an I/O (transport) problem occurs while obtaining the response body.
Returns:The response body or null.
/** * Returns the response body of the HTTP method, if any, as a {@link String}. * If response body is not available or cannot be read, returns <tt>null</tt> * The string conversion on the data is done using the character encoding specified * in <tt>Content-Type</tt> header. Buffers the response and this method can be * called several times yielding the same result each time. * * Note: This will cause the entire response body to be buffered in memory. A * malicious server may easily exhaust all the VM memory. It is strongly * recommended, to use getResponseAsStream if the content length of the response * is unknown or resonably large. * * @return The response body or <code>null</code>. * * @throws IOException If an I/O (transport) problem occurs while obtaining the * response body. */
public String getResponseBodyAsString() throws IOException { byte[] rawdata = null; if (responseAvailable()) { rawdata = getResponseBody(); } if (rawdata != null) { return EncodingUtil.getString(rawdata, getResponseCharSet()); } else { return null; } }
Returns the response body of the HTTP method, if any, as a String. If response body is not available or cannot be read, returns null The string conversion on the data is done using the character encoding specified in Content-Type header. Buffers the response and this method can be called several times yielding the same result each time.

Note: This will cause the entire response body to be buffered in memory. This method is safe if the content length of the response is unknown, because the amount of memory used is limited.

If the response is large this method involves lots of array copying and many object allocations, which makes it unsuitable for high-performance / low-footprint applications. Those applications should use getResponseBodyAsStream().

Params:
  • maxlen – the maximum content length to accept (number of bytes). Note that, depending on the encoding, this is not equal to the number of characters.
Throws:
  • IOException – If an I/O (transport) problem occurs while obtaining the response body.
Returns:The response body or null.
/** * Returns the response body of the HTTP method, if any, as a {@link String}. * If response body is not available or cannot be read, returns <tt>null</tt> * The string conversion on the data is done using the character encoding specified * in <tt>Content-Type</tt> header. Buffers the response and this method can be * called several times yielding the same result each time.</p> * * Note: This will cause the entire response body to be buffered in memory. This method is * safe if the content length of the response is unknown, because the amount of memory used * is limited.<p> * * If the response is large this method involves lots of array copying and many object * allocations, which makes it unsuitable for high-performance / low-footprint applications. * Those applications should use {@link #getResponseBodyAsStream()}. * * @param maxlen the maximum content length to accept (number of bytes). Note that, * depending on the encoding, this is not equal to the number of characters. * @return The response body or <code>null</code>. * * @throws IOException If an I/O (transport) problem occurs while obtaining the * response body. */
public String getResponseBodyAsString(int maxlen) throws IOException { if (maxlen < 0) throw new IllegalArgumentException("maxlen must be positive"); byte[] rawdata = null; if (responseAvailable()) { rawdata = getResponseBody(maxlen); } if (rawdata != null) { return EncodingUtil.getString(rawdata, getResponseCharSet()); } else { return null; } }
Returns an array of the response footers that the HTTP method currently has in the order in which they were read.
Returns:an array of footers
/** * Returns an array of the response footers that the HTTP method currently has * in the order in which they were read. * * @return an array of footers */
public Header[] getResponseFooters() { return getResponseTrailerHeaderGroup().getAllHeaders(); }
Gets the response footer associated with the given name. Footer name matching is case insensitive. null will be returned if either footerName is null or there is no matching footer for footerName or there are no footers available. If there are multiple footers with the same name, there values will be combined with the ',' separator as specified by RFC2616.
Params:
  • footerName – the footer name to match
Returns:the matching footer
/** * Gets the response footer associated with the given name. * Footer name matching is case insensitive. * <tt>null</tt> will be returned if either <i>footerName</i> is * <tt>null</tt> or there is no matching footer for <i>footerName</i> * or there are no footers available. If there are multiple footers * with the same name, there values will be combined with the ',' separator * as specified by RFC2616. * * @param footerName the footer name to match * @return the matching footer */
public Header getResponseFooter(String footerName) { if (footerName == null) { return null; } else { return getResponseTrailerHeaderGroup().getCondensedHeader(footerName); } }
Sets the response stream.
Params:
  • responseStream – The new response stream.
/** * Sets the response stream. * @param responseStream The new response stream. */
protected void setResponseStream(InputStream responseStream) { this.responseStream = responseStream; }
Returns a stream from which the body of the current response may be read. If the method has not yet been executed, if responseBodyConsumed has been called, or if the stream returned by a previous call has been closed, null will be returned.
Returns:the current response stream
/** * Returns a stream from which the body of the current response may be read. * If the method has not yet been executed, if <code>responseBodyConsumed</code> * has been called, or if the stream returned by a previous call has been closed, * <code>null</code> will be returned. * * @return the current response stream */
protected InputStream getResponseStream() { return responseStream; }
Returns the status text (or "reason phrase") associated with the latest response.
Returns:The status text.
/** * Returns the status text (or "reason phrase") associated with the latest * response. * * @return The status text. */
public String getStatusText() { return statusLine.getReasonPhrase(); }
Defines how strictly HttpClient follows the HTTP protocol specification (RFC 2616 and other relevant RFCs). In the strict mode HttpClient precisely implements the requirements of the specification, whereas in non-strict mode it attempts to mimic the exact behaviour of commonly used HTTP agents, which many HTTP servers expect.
Params:
  • strictMode – true for strict mode, false otherwise
Deprecated:Use HttpParams.setParameter(String, Object) to exercise a more granular control over HTTP protocol strictness.
/** * Defines how strictly HttpClient follows the HTTP protocol specification * (RFC 2616 and other relevant RFCs). In the strict mode HttpClient precisely * implements the requirements of the specification, whereas in non-strict mode * it attempts to mimic the exact behaviour of commonly used HTTP agents, * which many HTTP servers expect. * * @param strictMode <tt>true</tt> for strict mode, <tt>false</tt> otherwise * * @deprecated Use {@link org.apache.commons.httpclient.params.HttpParams#setParameter(String, Object)} * to exercise a more granular control over HTTP protocol strictness. */
public void setStrictMode(boolean strictMode) { if (strictMode) { this.params.makeStrict(); } else { this.params.makeLenient(); } }
Deprecated:Use HttpParams.setParameter(String, Object) to exercise a more granular control over HTTP protocol strictness.
Returns:false
/** * @deprecated Use {@link org.apache.commons.httpclient.params.HttpParams#setParameter(String, Object)} * to exercise a more granular control over HTTP protocol strictness. * * @return <tt>false</tt> */
public boolean isStrictMode() { return false; }
Adds the specified request header, NOT overwriting any previous value. Note that header-name matching is case insensitive.
Params:
  • headerName – the header's name
  • headerValue – the header's value
/** * Adds the specified request header, NOT overwriting any previous value. * Note that header-name matching is case insensitive. * * @param headerName the header's name * @param headerValue the header's value */
public void addRequestHeader(String headerName, String headerValue) { addRequestHeader(new Header(headerName, headerValue)); }
Tests if the connection should be force-closed when no longer needed.
Returns:true if the connection must be closed
/** * Tests if the connection should be force-closed when no longer needed. * * @return <code>true</code> if the connection must be closed */
protected boolean isConnectionCloseForced() { return this.connectionCloseForced; }
Sets whether or not the connection should be force-closed when no longer needed. This value should only be set to true in abnormal circumstances, such as HTTP protocol violations.
Params:
  • b – true if the connection must be closed, false otherwise.
/** * Sets whether or not the connection should be force-closed when no longer * needed. This value should only be set to <code>true</code> in abnormal * circumstances, such as HTTP protocol violations. * * @param b <code>true</code> if the connection must be closed, <code>false</code> * otherwise. */
protected void setConnectionCloseForced(boolean b) { if (LOG.isDebugEnabled()) { LOG.debug("Force-close connection: " + b); } this.connectionCloseForced = b; }
Tests if the connection should be closed after the method has been executed. The connection will be left open when using HTTP/1.1 or if Connection: keep-alive header was sent.
Params:
  • conn – the connection in question
Returns:boolean true if we should close the connection.
/** * Tests if the connection should be closed after the method has been executed. * The connection will be left open when using HTTP/1.1 or if <tt>Connection: * keep-alive</tt> header was sent. * * @param conn the connection in question * * @return boolean true if we should close the connection. */
protected boolean shouldCloseConnection(HttpConnection conn) { // Connection must be closed due to an abnormal circumstance if (isConnectionCloseForced()) { LOG.debug("Should force-close connection."); return true; } Header connectionHeader = null; // In case being connected via a proxy server if (!conn.isTransparent()) { // Check for 'proxy-connection' directive connectionHeader = responseHeaders.getFirstHeader("proxy-connection"); } // In all cases Check for 'connection' directive // some non-complaint proxy servers send it instread of // expected 'proxy-connection' directive if (connectionHeader == null) { connectionHeader = responseHeaders.getFirstHeader("connection"); } // In case the response does not contain any explict connection // directives, check whether the request does if (connectionHeader == null) { connectionHeader = requestHeaders.getFirstHeader("connection"); } if (connectionHeader != null) { if (connectionHeader.getValue().equalsIgnoreCase("close")) { if (LOG.isDebugEnabled()) { LOG.debug("Should close connection in response to directive: " + connectionHeader.getValue()); } return true; } else if (connectionHeader.getValue().equalsIgnoreCase("keep-alive")) { if (LOG.isDebugEnabled()) { LOG.debug("Should NOT close connection in response to directive: " + connectionHeader.getValue()); } return false; } else { if (LOG.isDebugEnabled()) { LOG.debug("Unknown directive: " + connectionHeader.toExternalForm()); } } } LOG.debug("Resorting to protocol version default close connection policy"); // missing or invalid connection header, do the default if (this.effectiveVersion.greaterEquals(HttpVersion.HTTP_1_1)) { if (LOG.isDebugEnabled()) { LOG.debug("Should NOT close connection, using " + this.effectiveVersion.toString()); } } else { if (LOG.isDebugEnabled()) { LOG.debug("Should close connection, using " + this.effectiveVersion.toString()); } } return this.effectiveVersion.lessEquals(HttpVersion.HTTP_1_0); }
Tests if the this method is ready to be executed.
Params:
  • state – the state information associated with this method
  • conn – the connection to be used
Throws:
/** * Tests if the this method is ready to be executed. * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} to be used * @throws HttpException If the method is in invalid state. */
private void checkExecuteConditions(HttpState state, HttpConnection conn) throws HttpException { if (state == null) { throw new IllegalArgumentException("HttpState parameter may not be null"); } if (conn == null) { throw new IllegalArgumentException("HttpConnection parameter may not be null"); } if (this.aborted) { throw new IllegalStateException("Method has been aborted"); } if (!validate()) { throw new ProtocolException("HttpMethodBase object not valid"); } }
Executes this method using the specified HttpConnection and HttpState.
Params:
  • state – state information to associate with this request. Must be non-null.
  • conn – the connection to used to execute this HTTP method. Must be non-null.
Throws:
Returns:the integer status code if one was obtained, or -1
/** * Executes this method using the specified <code>HttpConnection</code> and * <code>HttpState</code>. * * @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. * * @return the integer status code if one was obtained, or <tt>-1</tt> * * @throws IOException if an I/O (transport) error occurs * @throws HttpException if a protocol exception occurs. */
public int execute(HttpState state, HttpConnection conn) throws HttpException, IOException { LOG.trace("enter HttpMethodBase.execute(HttpState, HttpConnection)"); // this is our connection now, assign it to a local variable so // that it can be released later this.responseConnection = conn; checkExecuteConditions(state, conn); this.statusLine = null; this.connectionCloseForced = false; conn.setLastResponseInputStream(null); // determine the effective protocol version if (this.effectiveVersion == null) { this.effectiveVersion = this.params.getVersion(); } writeRequest(state, conn); this.requestSent = true; readResponse(state, conn); // the method has successfully executed used = true; return statusLine.getStatusCode(); }
Aborts the execution of this method.
Since:3.0
/** * Aborts the execution of this method. * * @since 3.0 */
public void abort() { if (this.aborted) { return; } this.aborted = true; HttpConnection conn = this.responseConnection; if (conn != null) { conn.close(); } }
Returns true if the HTTP method has been already executed, but not recycled.
Returns:true if the method has been executed, false otherwise
/** * Returns <tt>true</tt> if the HTTP method has been already {@link #execute executed}, * but not {@link #recycle recycled}. * * @return <tt>true</tt> if the method has been executed, <tt>false</tt> otherwise */
public boolean hasBeenUsed() { return used; }
Recycles the HTTP method so that it can be used again. Note that all of the instance variables will be reset once this method has been called. This method will also release the connection being used by this HTTP method.
See Also:
  • releaseConnection()
Deprecated:no longer supported and will be removed in the future version of HttpClient
/** * Recycles the HTTP method so that it can be used again. * Note that all of the instance variables will be reset * once this method has been called. This method will also * release the connection being used by this HTTP method. * * @see #releaseConnection() * * @deprecated no longer supported and will be removed in the future * version of HttpClient */
public void recycle() { LOG.trace("enter HttpMethodBase.recycle()"); releaseConnection(); path = null; followRedirects = false; doAuthentication = true; queryString = null; getRequestHeaderGroup().clear(); getResponseHeaderGroup().clear(); getResponseTrailerHeaderGroup().clear(); statusLine = null; effectiveVersion = null; aborted = false; used = false; params = new HttpMethodParams(); responseBody = null; recoverableExceptionCount = 0; connectionCloseForced = false; hostAuthState.invalidate(); proxyAuthState.invalidate(); cookiespec = null; requestSent = false; }
Releases the connection being used by this HTTP method. In particular the connection is used to read the response(if there is one) and will be held until the response has been read. If the connection can be reused by other HTTP methods it is NOT closed at this point.
Since:2.0
/** * Releases the connection being used by this HTTP method. In particular the * connection is used to read the response(if there is one) and will be held * until the response has been read. If the connection can be reused by other * HTTP methods it is NOT closed at this point. * * @since 2.0 */
public void releaseConnection() { try { if (this.responseStream != null) { try { // FYI - this may indirectly invoke responseBodyConsumed. this.responseStream.close(); } catch (IOException ignore) { } } } finally { ensureConnectionRelease(); } }
Remove the request header associated with the given name. Note that header-name matching is case insensitive.
Params:
  • headerName – the header name
/** * Remove the request header associated with the given name. Note that * header-name matching is case insensitive. * * @param headerName the header name */
public void removeRequestHeader(String headerName) { Header[] headers = getRequestHeaderGroup().getHeaders(headerName); for (int i = 0; i < headers.length; i++) { getRequestHeaderGroup().removeHeader(headers[i]); } }
Removes the given request header.
Params:
  • header – the header
/** * Removes the given request header. * * @param header the header */
public void removeRequestHeader(final Header header) { if (header == null) { return; } getRequestHeaderGroup().removeHeader(header); } // ---------------------------------------------------------------- Queries
Returns true the method is ready to execute, false otherwise.
Returns:This implementation always returns true.
/** * Returns <tt>true</tt> the method is ready to execute, <tt>false</tt> otherwise. * * @return This implementation always returns <tt>true</tt>. */
public boolean validate() { return true; }
Returns the actual cookie policy
Params:
  • state – HTTP state. TODO: to be removed in the future
Returns:cookie spec
/** * Returns the actual cookie policy * * @param state HTTP state. TODO: to be removed in the future * * @return cookie spec */
private CookieSpec getCookieSpec(final HttpState state) { if (this.cookiespec == null) { int i = state.getCookiePolicy(); if (i == -1) { this.cookiespec = CookiePolicy.getCookieSpec(this.params.getCookiePolicy()); } else { this.cookiespec = CookiePolicy.getSpecByPolicy(i); } this.cookiespec.setValidDateFormats( (Collection)this.params.getParameter(HttpMethodParams.DATE_PATTERNS)); } return this.cookiespec; }
Generates Cookie request headers for those cookies that match the given host, port and path.
Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
/** * Generates <tt>Cookie</tt> request headers for those {@link Cookie cookie}s * that match the given host, port and path. * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. */
protected void addCookieRequestHeader(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter HttpMethodBase.addCookieRequestHeader(HttpState, " + "HttpConnection)"); Header[] cookieheaders = getRequestHeaderGroup().getHeaders("Cookie"); for (int i = 0; i < cookieheaders.length; i++) { Header cookieheader = cookieheaders[i]; if (cookieheader.isAutogenerated()) { getRequestHeaderGroup().removeHeader(cookieheader); } } CookieSpec matcher = getCookieSpec(state); String host = this.params.getVirtualHost(); if (host == null) { host = conn.getHost(); } Cookie[] cookies = matcher.match(host, conn.getPort(), getPath(), conn.isSecure(), state.getCookies()); if ((cookies != null) && (cookies.length > 0)) { if (getParams().isParameterTrue(HttpMethodParams.SINGLE_COOKIE_HEADER)) { // In strict mode put all cookies on the same header String s = matcher.formatCookies(cookies); getRequestHeaderGroup().addHeader(new Header("Cookie", s, true)); } else { // In non-strict mode put each cookie on a separate header for (int i = 0; i < cookies.length; i++) { String s = matcher.formatCookie(cookies[i]); getRequestHeaderGroup().addHeader(new Header("Cookie", s, true)); } } if (matcher instanceof CookieVersionSupport) { CookieVersionSupport versupport = (CookieVersionSupport) matcher; int ver = versupport.getVersion(); boolean needVersionHeader = false; for (int i = 0; i < cookies.length; i++) { if (ver != cookies[i].getVersion()) { needVersionHeader = true; } } if (needVersionHeader) { // Advertise cookie version support getRequestHeaderGroup().addHeader(versupport.getVersionHeader()); } } } }
Generates Host request header, as long as no Host request header already exists.
Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
/** * Generates <tt>Host</tt> request header, as long as no <tt>Host</tt> request * header already exists. * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. */
protected void addHostRequestHeader(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter HttpMethodBase.addHostRequestHeader(HttpState, " + "HttpConnection)"); // Per 19.6.1.1 of RFC 2616, it is legal for HTTP/1.0 based // applications to send the Host request-header. // TODO: Add the ability to disable the sending of this header for // HTTP/1.0 requests. String host = this.params.getVirtualHost(); if (host != null) { LOG.debug("Using virtual host name: " + host); } else { host = conn.getHost(); } int port = conn.getPort(); // Note: RFC 2616 uses the term "internet host name" for what goes on the // host line. It would seem to imply that host should be blank if the // host is a number instead of an name. Based on the behavior of web // browsers, and the fact that RFC 2616 never defines the phrase "internet // host name", and the bad behavior of HttpClient that follows if we // send blank, I interpret this as a small misstatement in the RFC, where // they meant to say "internet host". So IP numbers get sent as host // entries too. -- Eric Johnson 12/13/2002 if (LOG.isDebugEnabled()) { LOG.debug("Adding Host request header"); } //appends the port only if not using the default port for the protocol if (conn.getProtocol().getDefaultPort() != port) { host += (":" + port); } setRequestHeader("Host", host); }
Generates Proxy-Connection: Keep-Alive request header when communicating via a proxy server.
Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
/** * Generates <tt>Proxy-Connection: Keep-Alive</tt> request header when * communicating via a proxy server. * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. */
protected void addProxyConnectionHeader(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter HttpMethodBase.addProxyConnectionHeader(" + "HttpState, HttpConnection)"); if (!conn.isTransparent()) { if (getRequestHeader("Proxy-Connection") == null) { addRequestHeader("Proxy-Connection", "Keep-Alive"); } } }
Generates all the required request headers to be submitted via the given connection.

This implementation adds User-Agent, Host, Cookie, Authorization, Proxy-Authorization and Proxy-Connection headers, when appropriate.

Subclasses may want to override this method to to add additional headers, and may choose to invoke this implementation (via super) to add the "standard" headers.

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
See Also:
/** * Generates all the required request {@link Header header}s * to be submitted via the given {@link HttpConnection connection}. * * <p> * This implementation adds <tt>User-Agent</tt>, <tt>Host</tt>, * <tt>Cookie</tt>, <tt>Authorization</tt>, <tt>Proxy-Authorization</tt> * and <tt>Proxy-Connection</tt> headers, when appropriate. * </p> * * <p> * Subclasses may want to override this method to to add additional * headers, and may choose to invoke this implementation (via * <tt>super</tt>) to add the "standard" headers. * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. * * @see #writeRequestHeaders */
protected void addRequestHeaders(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter HttpMethodBase.addRequestHeaders(HttpState, " + "HttpConnection)"); addUserAgentRequestHeader(state, conn); addHostRequestHeader(state, conn); addCookieRequestHeader(state, conn); addProxyConnectionHeader(state, conn); }
Generates default User-Agent request header, as long as no User-Agent request header already exists.
Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
/** * Generates default <tt>User-Agent</tt> request header, as long as no * <tt>User-Agent</tt> request header already exists. * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. */
protected void addUserAgentRequestHeader(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter HttpMethodBase.addUserAgentRequestHeaders(HttpState, " + "HttpConnection)"); if (getRequestHeader("User-Agent") == null) { String agent = (String)getParams().getParameter(HttpMethodParams.USER_AGENT); if (agent == null) { agent = "Jakarta Commons-HttpClient"; } setRequestHeader("User-Agent", agent); } }
Throws an IllegalStateException if the HTTP method has been already executed, but not recycled.
Throws:
/** * Throws an {@link IllegalStateException} if the HTTP method has been already * {@link #execute executed}, but not {@link #recycle recycled}. * * @throws IllegalStateException if the method has been used and not * recycled */
protected void checkNotUsed() throws IllegalStateException { if (used) { throw new IllegalStateException("Already used."); } }
Throws an IllegalStateException if the HTTP method has not been executed since last recycle.
Throws:
/** * Throws an {@link IllegalStateException} if the HTTP method has not been * {@link #execute executed} since last {@link #recycle recycle}. * * * @throws IllegalStateException if not used */
protected void checkUsed() throws IllegalStateException { if (!used) { throw new IllegalStateException("Not Used."); } } // ------------------------------------------------- Static Utility Methods
Generates HTTP request line according to the specified attributes.
Params:
  • connection – the connection used to execute this HTTP method
  • name – the method name generate a request for
  • requestPath – the path string for the request
  • query – the query string for the request
  • version – the protocol version to use (e.g. HTTP/1.0)
Returns:HTTP request line
/** * Generates HTTP request line according to the specified attributes. * * @param connection the {@link HttpConnection connection} used to execute * this HTTP method * @param name the method name generate a request for * @param requestPath the path string for the request * @param query the query string for the request * @param version the protocol version to use (e.g. HTTP/1.0) * * @return HTTP request line */
protected static String generateRequestLine(HttpConnection connection, String name, String requestPath, String query, String version) { LOG.trace("enter HttpMethodBase.generateRequestLine(HttpConnection, " + "String, String, String, String)"); StringBuffer buf = new StringBuffer(); // Append method name buf.append(name); buf.append(" "); // Absolute or relative URL? if (!connection.isTransparent()) { Protocol protocol = connection.getProtocol(); buf.append(protocol.getScheme().toLowerCase()); buf.append("://"); buf.append(connection.getHost()); if ((connection.getPort() != -1) && (connection.getPort() != protocol.getDefaultPort()) ) { buf.append(":"); buf.append(connection.getPort()); } } // Append path, if any if (requestPath == null) { buf.append("/"); } else { if (!connection.isTransparent() && !requestPath.startsWith("/")) { buf.append("/"); } buf.append(requestPath); } // Append query, if any if (query != null) { if (query.indexOf("?") != 0) { buf.append("?"); } buf.append(query); } // Append protocol buf.append(" "); buf.append(version); buf.append("\r\n"); return buf.toString(); }
This method is invoked immediately after readResponseBody(HttpState, HttpConnection) and can be overridden by sub-classes in order to provide custom body processing.

This implementation does nothing.

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
See Also:
/** * This method is invoked immediately after * {@link #readResponseBody(HttpState,HttpConnection)} and can be overridden by * sub-classes in order to provide custom body processing. * * <p> * This implementation does nothing. * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @see #readResponse * @see #readResponseBody */
protected void processResponseBody(HttpState state, HttpConnection conn) { }
This method is invoked immediately after readResponseHeaders(HttpState, HttpConnection) and can be overridden by sub-classes in order to provide custom response headers processing.

This implementation will handle the Set-Cookie and Set-Cookie2 headers, if any, adding the relevant cookies to the given HttpState.

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
See Also:
/** * This method is invoked immediately after * {@link #readResponseHeaders(HttpState,HttpConnection)} and can be overridden by * sub-classes in order to provide custom response headers processing. * <p> * This implementation will handle the <tt>Set-Cookie</tt> and * <tt>Set-Cookie2</tt> headers, if any, adding the relevant cookies to * the given {@link HttpState}. * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @see #readResponse * @see #readResponseHeaders */
protected void processResponseHeaders(HttpState state, HttpConnection conn) { LOG.trace("enter HttpMethodBase.processResponseHeaders(HttpState, " + "HttpConnection)"); CookieSpec parser = getCookieSpec(state); // process set-cookie headers Header[] headers = getResponseHeaderGroup().getHeaders("set-cookie"); processCookieHeaders(parser, headers, state, conn); // see if the cookie spec supports cookie versioning. if (parser instanceof CookieVersionSupport) { CookieVersionSupport versupport = (CookieVersionSupport) parser; if (versupport.getVersion() > 0) { // process set-cookie2 headers. // Cookie2 will replace equivalent Cookie instances headers = getResponseHeaderGroup().getHeaders("set-cookie2"); processCookieHeaders(parser, headers, state, conn); } } }
This method processes the specified cookie headers. It is invoked from within processResponseHeaders(HttpState, HttpConnection)
Params:
  • headers – cookie Headers to be processed
  • state – the state information associated with this HTTP method
  • conn – the connection used to execute this HTTP method
/** * This method processes the specified cookie headers. It is invoked from * within {@link #processResponseHeaders(HttpState,HttpConnection)} * * @param headers cookie {@link Header}s to be processed * @param state the {@link HttpState state} information associated with * this HTTP method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method */
protected void processCookieHeaders( final CookieSpec parser, final Header[] headers, final HttpState state, final HttpConnection conn) { LOG.trace("enter HttpMethodBase.processCookieHeaders(Header[], HttpState, " + "HttpConnection)"); String host = this.params.getVirtualHost(); if (host == null) { host = conn.getHost(); } for (int i = 0; i < headers.length; i++) { Header header = headers[i]; Cookie[] cookies = null; try { cookies = parser.parse( host, conn.getPort(), getPath(), conn.isSecure(), header); } catch (MalformedCookieException e) { if (LOG.isWarnEnabled()) { LOG.warn("Invalid cookie header: \"" + header.getValue() + "\". " + e.getMessage()); } } if (cookies != null) { for (int j = 0; j < cookies.length; j++) { Cookie cookie = cookies[j]; try { parser.validate( host, conn.getPort(), getPath(), conn.isSecure(), cookie); state.addCookie(cookie); if (LOG.isDebugEnabled()) { LOG.debug("Cookie accepted: \"" + parser.formatCookie(cookie) + "\""); } } catch (MalformedCookieException e) { if (LOG.isWarnEnabled()) { LOG.warn("Cookie rejected: \"" + parser.formatCookie(cookie) + "\". " + e.getMessage()); } } } } } }
This method is invoked immediately after readStatusLine(HttpState, HttpConnection) and can be overridden by sub-classes in order to provide custom response status line processing.
Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
See Also:
/** * This method is invoked immediately after * {@link #readStatusLine(HttpState,HttpConnection)} and can be overridden by * sub-classes in order to provide custom response status line processing. * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @see #readResponse * @see #readStatusLine */
protected void processStatusLine(HttpState state, HttpConnection conn) { }
Reads the response from the given connection.

The response is processed as the following sequence of actions:

  1. readStatusLine(HttpState, HttpConnection) is invoked to read the request line.
  2. processStatusLine(HttpState, HttpConnection) is invoked, allowing the method to process the status line if desired.
  3. readResponseHeaders(HttpState, HttpConnection) is invoked to read the associated headers.
  4. processResponseHeaders(HttpState, HttpConnection) is invoked, allowing the method to process the headers if desired.
  5. readResponseBody(HttpState, HttpConnection) is invoked to read the associated body (if any).
  6. processResponseBody(HttpState, HttpConnection) is invoked, allowing the method to process the response body if desired.
Subclasses may want to override one or more of the above methods to to customize the processing. (Or they may choose to override this method if dramatically different processing is required.)

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
/** * Reads the response from the given {@link HttpConnection connection}. * * <p> * The response is processed as the following sequence of actions: * * <ol> * <li> * {@link #readStatusLine(HttpState,HttpConnection)} is * invoked to read the request line. * </li> * <li> * {@link #processStatusLine(HttpState,HttpConnection)} * is invoked, allowing the method to process the status line if * desired. * </li> * <li> * {@link #readResponseHeaders(HttpState,HttpConnection)} is invoked to read * the associated headers. * </li> * <li> * {@link #processResponseHeaders(HttpState,HttpConnection)} is invoked, allowing * the method to process the headers if desired. * </li> * <li> * {@link #readResponseBody(HttpState,HttpConnection)} is * invoked to read the associated body (if any). * </li> * <li> * {@link #processResponseBody(HttpState,HttpConnection)} is invoked, allowing the * method to process the response body if desired. * </li> * </ol> * * Subclasses may want to override one or more of the above methods to to * customize the processing. (Or they may choose to override this method * if dramatically different processing is required.) * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. */
protected void readResponse(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace( "enter HttpMethodBase.readResponse(HttpState, HttpConnection)"); // Status line & line may have already been received // if 'expect - continue' handshake has been used while (this.statusLine == null) { readStatusLine(state, conn); processStatusLine(state, conn); readResponseHeaders(state, conn); processResponseHeaders(state, conn); int status = this.statusLine.getStatusCode(); if ((status >= 100) && (status < 200)) { if (LOG.isInfoEnabled()) { LOG.info("Discarding unexpected response: " + this.statusLine.toString()); } this.statusLine = null; } } readResponseBody(state, conn); processResponseBody(state, conn); }
Read the response body from the given HttpConnection.

The current implementation wraps the socket level stream with an appropriate stream for the type of response (chunked, content-length, or auto-close). If there is no response body, the connection associated with the request will be returned to the connection manager.

Subclasses may want to override this method to to customize the processing.

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
See Also:
/** * Read the response body from the given {@link HttpConnection}. * * <p> * The current implementation wraps the socket level stream with * an appropriate stream for the type of response (chunked, content-length, * or auto-close). If there is no response body, the connection associated * with the request will be returned to the connection manager. * </p> * * <p> * Subclasses may want to override this method to to customize the * processing. * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. * * @see #readResponse * @see #processResponseBody */
protected void readResponseBody(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace( "enter HttpMethodBase.readResponseBody(HttpState, HttpConnection)"); // assume we are not done with the connection if we get a stream InputStream stream = readResponseBody(conn); if (stream == null) { // done using the connection! responseBodyConsumed(); } else { conn.setLastResponseInputStream(stream); setResponseStream(stream); } }
Returns the response body as an input stream corresponding to the values of the Content-Length and Transfer-Encoding headers. If no response body is available returns null.

Params:
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
See Also:
/** * Returns the response body as an {@link InputStream input stream} * corresponding to the values of the <tt>Content-Length</tt> and * <tt>Transfer-Encoding</tt> headers. If no response body is available * returns <tt>null</tt>. * <p> * * @see #readResponse * @see #processResponseBody * * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. */
private InputStream readResponseBody(HttpConnection conn) throws HttpException, IOException { LOG.trace("enter HttpMethodBase.readResponseBody(HttpConnection)"); responseBody = null; InputStream is = conn.getResponseInputStream(); if (Wire.CONTENT_WIRE.enabled()) { is = new WireLogInputStream(is, Wire.CONTENT_WIRE); } boolean canHaveBody = canResponseHaveBody(statusLine.getStatusCode()); InputStream result = null; Header transferEncodingHeader = responseHeaders.getFirstHeader("Transfer-Encoding"); // We use Transfer-Encoding if present and ignore Content-Length. // RFC2616, 4.4 item number 3 if (transferEncodingHeader != null) { String transferEncoding = transferEncodingHeader.getValue(); if (!"chunked".equalsIgnoreCase(transferEncoding) && !"identity".equalsIgnoreCase(transferEncoding)) { if (LOG.isWarnEnabled()) { LOG.warn("Unsupported transfer encoding: " + transferEncoding); } } HeaderElement[] encodings = transferEncodingHeader.getElements(); // The chunked encoding must be the last one applied // RFC2616, 14.41 int len = encodings.length; if ((len > 0) && ("chunked".equalsIgnoreCase(encodings[len - 1].getName()))) { // if response body is empty if (conn.isResponseAvailable(conn.getParams().getSoTimeout())) { result = new ChunkedInputStream(is, this); } else { if (getParams().isParameterTrue(HttpMethodParams.STRICT_TRANSFER_ENCODING)) { throw new ProtocolException("Chunk-encoded body declared but not sent"); } else { LOG.warn("Chunk-encoded body missing"); } } } else { LOG.info("Response content is not chunk-encoded"); // The connection must be terminated by closing // the socket as per RFC 2616, 3.6 setConnectionCloseForced(true); result = is; } } else { long expectedLength = getResponseContentLength(); if (expectedLength == -1) { if (canHaveBody && this.effectiveVersion.greaterEquals(HttpVersion.HTTP_1_1)) { Header connectionHeader = responseHeaders.getFirstHeader("Connection"); String connectionDirective = null; if (connectionHeader != null) { connectionDirective = connectionHeader.getValue(); } if (!"close".equalsIgnoreCase(connectionDirective)) { LOG.info("Response content length is not known"); setConnectionCloseForced(true); } } result = is; } else { result = new ContentLengthInputStream(is, expectedLength); } } // See if the response is supposed to have a response body if (!canHaveBody) { result = null; } // if there is a result - ALWAYS wrap it in an observer which will // close the underlying stream as soon as it is consumed, and notify // the watcher that the stream has been consumed. if (result != null) { result = new AutoCloseInputStream( result, new ResponseConsumedWatcher() { public void responseConsumed() { responseBodyConsumed(); } } ); } return result; }
Reads the response headers from the given connection.

Subclasses may want to override this method to to customize the processing.

"It must be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma." - HTTP/1.0 (4.3)

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
See Also:
/** * Reads the response headers from the given {@link HttpConnection connection}. * * <p> * Subclasses may want to override this method to to customize the * processing. * </p> * * <p> * "It must be possible to combine the multiple header fields into one * "field-name: field-value" pair, without changing the semantics of the * message, by appending each subsequent field-value to the first, each * separated by a comma." - HTTP/1.0 (4.3) * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. * * @see #readResponse * @see #processResponseHeaders */
protected void readResponseHeaders(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter HttpMethodBase.readResponseHeaders(HttpState," + "HttpConnection)"); getResponseHeaderGroup().clear(); Header[] headers = HttpParser.parseHeaders( conn.getResponseInputStream(), getParams().getHttpElementCharset()); // Wire logging moved to HttpParser getResponseHeaderGroup().setHeaders(headers); }
Read the status line from the given HttpConnection, setting my status code and status text.

Subclasses may want to override this method to to customize the processing.

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
See Also:
/** * Read the status line from the given {@link HttpConnection}, setting my * {@link #getStatusCode status code} and {@link #getStatusText status * text}. * * <p> * Subclasses may want to override this method to to customize the * processing. * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. * * @see StatusLine */
protected void readStatusLine(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter HttpMethodBase.readStatusLine(HttpState, HttpConnection)"); final int maxGarbageLines = getParams(). getIntParameter(HttpMethodParams.STATUS_LINE_GARBAGE_LIMIT, Integer.MAX_VALUE); //read out the HTTP status string int count = 0; String s; do { s = conn.readLine(getParams().getHttpElementCharset()); if (s == null && count == 0) { // The server just dropped connection on us throw new NoHttpResponseException("The server " + conn.getHost() + " failed to respond"); } if (Wire.HEADER_WIRE.enabled()) { Wire.HEADER_WIRE.input(s + "\r\n"); } if (s != null && StatusLine.startsWithHTTP(s)) { // Got one break; } else if (s == null || count >= maxGarbageLines) { // Giving up throw new ProtocolException("The server " + conn.getHost() + " failed to respond with a valid HTTP response"); } count++; } while(true); //create the status line from the status string statusLine = new StatusLine(s); //check for a valid HTTP-Version String versionStr = statusLine.getHttpVersion(); if (getParams().isParameterFalse(HttpMethodParams.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.effectiveVersion = HttpVersion.parse(versionStr); } } // ------------------------------------------------------ Protected Methods

Sends the request via the given connection.

The request is written as the following sequence of actions:

  1. writeRequestLine(HttpState, HttpConnection) is invoked to write the request line.
  2. writeRequestHeaders(HttpState, HttpConnection) is invoked to write the associated headers.
  3. \r\n is sent to close the head part of the request.
  4. writeRequestBody(HttpState, HttpConnection) is invoked to write the body part of the request.

Subclasses may want to override one or more of the above methods to to customize the processing. (Or they may choose to override this method if dramatically different processing is required.)

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
/** * <p> * Sends the request via the given {@link HttpConnection connection}. * </p> * * <p> * The request is written as the following sequence of actions: * </p> * * <ol> * <li> * {@link #writeRequestLine(HttpState, HttpConnection)} is invoked to * write the request line. * </li> * <li> * {@link #writeRequestHeaders(HttpState, HttpConnection)} is invoked * to write the associated headers. * </li> * <li> * <tt>\r\n</tt> is sent to close the head part of the request. * </li> * <li> * {@link #writeRequestBody(HttpState, HttpConnection)} is invoked to * write the body part of the request. * </li> * </ol> * * <p> * Subclasses may want to override one or more of the above methods to to * customize the processing. (Or they may choose to override this method * if dramatically different processing is required.) * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. */
protected void writeRequest(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace( "enter HttpMethodBase.writeRequest(HttpState, HttpConnection)"); writeRequestLine(state, conn); writeRequestHeaders(state, conn); conn.writeLine(); // close head if (Wire.HEADER_WIRE.enabled()) { Wire.HEADER_WIRE.output("\r\n"); } HttpVersion ver = getParams().getVersion(); Header expectheader = getRequestHeader("Expect"); String expectvalue = null; if (expectheader != null) { expectvalue = expectheader.getValue(); } if ((expectvalue != null) && (expectvalue.compareToIgnoreCase("100-continue") == 0)) { if (ver.greaterEquals(HttpVersion.HTTP_1_1)) { // make sure the status line and headers have been sent conn.flushRequestOutputStream(); int readTimeout = conn.getParams().getSoTimeout(); try { conn.setSocketTimeout(RESPONSE_WAIT_TIME_MS); readStatusLine(state, conn); processStatusLine(state, conn); readResponseHeaders(state, conn); processResponseHeaders(state, conn); if (this.statusLine.getStatusCode() == HttpStatus.SC_CONTINUE) { // Discard status line this.statusLine = null; LOG.debug("OK to continue received"); } else { return; } } catch (InterruptedIOException e) { if (!ExceptionUtil.isSocketTimeoutException(e)) { throw e; } // Most probably Expect header is not recongnized // Remove the header to signal the method // that it's okay to go ahead with sending data removeRequestHeader("Expect"); LOG.info("100 (continue) read timeout. Resume sending the request"); } finally { conn.setSocketTimeout(readTimeout); } } else { removeRequestHeader("Expect"); LOG.info("'Expect: 100-continue' handshake is only supported by " + "HTTP/1.1 or higher"); } } writeRequestBody(state, conn); // make sure the entire request body has been sent conn.flushRequestOutputStream(); }
Writes the request body to the given connection.

This method should return true if the request body was actually sent (or is empty), or false if it could not be sent for some reason.

This implementation writes nothing and returns true.

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
Returns:true
/** * Writes the request body to the given {@link HttpConnection connection}. * * <p> * This method should return <tt>true</tt> if the request body was actually * sent (or is empty), or <tt>false</tt> if it could not be sent for some * reason. * </p> * * <p> * This implementation writes nothing and returns <tt>true</tt>. * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @return <tt>true</tt> * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. */
protected boolean writeRequestBody(HttpState state, HttpConnection conn) throws IOException, HttpException { return true; }
Writes the request headers to the given connection.

This implementation invokes addRequestHeaders(HttpState, HttpConnection), and then writes each header to the request stream.

Subclasses may want to override this method to to customize the processing.

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
See Also:
/** * Writes the request headers to the given {@link HttpConnection connection}. * * <p> * This implementation invokes {@link #addRequestHeaders(HttpState,HttpConnection)}, * and then writes each header to the request stream. * </p> * * <p> * Subclasses may want to override this method to to customize the * processing. * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. * * @see #addRequestHeaders * @see #getRequestHeaders */
protected void writeRequestHeaders(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter HttpMethodBase.writeRequestHeaders(HttpState," + "HttpConnection)"); addRequestHeaders(state, conn); String charset = getParams().getHttpElementCharset(); Header[] headers = getRequestHeaders(); for (int i = 0; i < headers.length; i++) { String s = headers[i].toExternalForm(); if (Wire.HEADER_WIRE.enabled()) { Wire.HEADER_WIRE.output(s); } conn.print(s, charset); } }
Writes the request line to the given connection.

Subclasses may want to override this method to to customize the processing.

Params:
  • state – the state information associated with this method
  • conn – the connection used to execute this HTTP method
Throws:
  • IOException – if an I/O (transport) error occurs. Some transport exceptions can be recovered from.
  • HttpException – if a protocol exception occurs. Usually protocol exceptions cannot be recovered from.
See Also:
/** * Writes the request line to the given {@link HttpConnection connection}. * * <p> * Subclasses may want to override this method to to customize the * processing. * </p> * * @param state the {@link HttpState state} information associated with this method * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @throws IOException if an I/O (transport) error occurs. Some transport exceptions * can be recovered from. * @throws HttpException if a protocol exception occurs. Usually protocol exceptions * cannot be recovered from. * * @see #generateRequestLine */
protected void writeRequestLine(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace( "enter HttpMethodBase.writeRequestLine(HttpState, HttpConnection)"); String requestLine = getRequestLine(conn); if (Wire.HEADER_WIRE.enabled()) { Wire.HEADER_WIRE.output(requestLine); } conn.print(requestLine, getParams().getHttpElementCharset()); }
Returns the request line.
Params:
  • conn – the connection used to execute this HTTP method
Returns:The request line.
/** * Returns the request line. * * @param conn the {@link HttpConnection connection} used to execute * this HTTP method * * @return The request line. */
private String getRequestLine(HttpConnection conn) { return HttpMethodBase.generateRequestLine(conn, getName(), getPath(), getQueryString(), this.effectiveVersion.toString()); }
Returns HTTP protocol parameters associated with this method.
Returns:HTTP parameters.
Since:3.0
/** * Returns {@link HttpMethodParams HTTP protocol parameters} associated with this method. * * @return HTTP parameters. * * @since 3.0 */
public HttpMethodParams getParams() { return this.params; }
Assigns HTTP protocol parameters for this method.
See Also:
Since:3.0
/** * Assigns {@link HttpMethodParams HTTP protocol parameters} for this method. * * @since 3.0 * * @see HttpMethodParams */
public void setParams(final HttpMethodParams params) { if (params == null) { throw new IllegalArgumentException("Parameters may not be null"); } this.params = params; }
Returns the HTTP version used with this method (may be null if undefined, that is, the method has not been executed)
Returns:HTTP version.
Since:3.0
/** * Returns the HTTP version used with this method (may be <tt>null</tt> * if undefined, that is, the method has not been executed) * * @return HTTP version. * * @since 3.0 */
public HttpVersion getEffectiveVersion() { return this.effectiveVersion; }
Per RFC 2616 section 4.3, some response can never contain a message body.
Params:
  • status – - the HTTP status code
Returns:true if the message may contain a body, false if it can not contain a message body
/** * Per RFC 2616 section 4.3, some response can never contain a message * body. * * @param status - the HTTP status code * * @return <tt>true</tt> if the message may contain a body, <tt>false</tt> if it can not * contain a message body */
private static boolean canResponseHaveBody(int status) { LOG.trace("enter HttpMethodBase.canResponseHaveBody(int)"); boolean result = true; if ((status >= 100 && status <= 199) || (status == 204) || (status == 304)) { // NOT MODIFIED result = false; } return result; }
Returns proxy authentication realm, if it has been used during authentication process. Otherwise returns null.
Returns:proxy authentication realm
Deprecated:use #getProxyAuthState()
/** * Returns proxy authentication realm, if it has been used during authentication process. * Otherwise returns <tt>null</tt>. * * @return proxy authentication realm * * @deprecated use #getProxyAuthState() */
public String getProxyAuthenticationRealm() { return this.proxyAuthState.getRealm(); }
Returns authentication realm, if it has been used during authentication process. Otherwise returns null.
Returns:authentication realm
Deprecated:use #getHostAuthState()
/** * Returns authentication realm, if it has been used during authentication process. * Otherwise returns <tt>null</tt>. * * @return authentication realm * * @deprecated use #getHostAuthState() */
public String getAuthenticationRealm() { return this.hostAuthState.getRealm(); }
Returns the character set from the Content-Type header.
Params:
  • contentheader – The content header.
Returns:String The character set.
/** * Returns the character set from the <tt>Content-Type</tt> header. * * @param contentheader The content header. * @return String The character set. */
protected String getContentCharSet(Header contentheader) { LOG.trace("enter getContentCharSet( Header contentheader )"); String charset = null; if (contentheader != null) { HeaderElement values[] = contentheader.getElements(); // I expect only one header element to be there // No more. no less if (values.length == 1) { NameValuePair param = values[0].getParameterByName("charset"); if (param != null) { // If I get anything "funny" // UnsupportedEncondingException will result charset = param.getValue(); } } } if (charset == null) { charset = getParams().getContentCharset(); if (LOG.isDebugEnabled()) { LOG.debug("Default charset used: " + charset); } } return charset; }
Returns the character encoding of the request from the Content-Type header.
Returns:String The character set.
/** * Returns the character encoding of the request from the <tt>Content-Type</tt> header. * * @return String The character set. */
public String getRequestCharSet() { return getContentCharSet(getRequestHeader("Content-Type")); }
Returns the character encoding of the response from the Content-Type header.
Returns:String The character set.
/** * Returns the character encoding of the response from the <tt>Content-Type</tt> header. * * @return String The character set. */
public String getResponseCharSet() { return getContentCharSet(getResponseHeader("Content-Type")); }
Deprecated:no longer used Returns the number of "recoverable" exceptions thrown and handled, to allow for monitoring the quality of the connection.
Returns:The number of recoverable exceptions handled by the method.
/** * @deprecated no longer used * * Returns the number of "recoverable" exceptions thrown and handled, to * allow for monitoring the quality of the connection. * * @return The number of recoverable exceptions handled by the method. */
public int getRecoverableExceptionCount() { return recoverableExceptionCount; }
A response has been consumed.

The default behavior for this class is to check to see if the connection should be closed, and close if need be, and to ensure that the connection is returned to the connection manager - if and only if we are not still inside the execute call.

/** * A response has been consumed. * * <p>The default behavior for this class is to check to see if the connection * should be closed, and close if need be, and to ensure that the connection * is returned to the connection manager - if and only if we are not still * inside the execute call.</p> * */
protected void responseBodyConsumed() { // make sure this is the initial invocation of the notification, // ignore subsequent ones. responseStream = null; if (responseConnection != null) { responseConnection.setLastResponseInputStream(null); // At this point, no response data should be available. // If there is data available, regard the connection as being // unreliable and close it. if (shouldCloseConnection(responseConnection)) { responseConnection.close(); } else { try { if(responseConnection.isResponseAvailable()) { boolean logExtraInput = getParams().isParameterTrue(HttpMethodParams.WARN_EXTRA_INPUT); if(logExtraInput) { LOG.warn("Extra response data detected - closing connection"); } responseConnection.close(); } } catch (IOException e) { LOG.warn(e.getMessage()); responseConnection.close(); } } } this.connectionCloseForced = false; ensureConnectionRelease(); }
Insure that the connection is released back to the pool.
/** * Insure that the connection is released back to the pool. */
private void ensureConnectionRelease() { if (responseConnection != null) { responseConnection.releaseConnection(); responseConnection = null; } }
Returns the host configuration.
Returns:the host configuration
Deprecated:no longer applicable
/** * Returns the {@link HostConfiguration host configuration}. * * @return the host configuration * * @deprecated no longer applicable */
public HostConfiguration getHostConfiguration() { HostConfiguration hostconfig = new HostConfiguration(); hostconfig.setHost(this.httphost); return hostconfig; }
Params:
  • hostconfig – The hostConfiguration to set
Deprecated:no longer applicable
/** * Sets the {@link HostConfiguration host configuration}. * * @param hostconfig The hostConfiguration to set * * @deprecated no longer applicable */
public void setHostConfiguration(final HostConfiguration hostconfig) { if (hostconfig != null) { this.httphost = new HttpHost( hostconfig.getHost(), hostconfig.getPort(), hostconfig.getProtocol()); } else { this.httphost = null; } }
Returns the retry handler for this HTTP method
Returns:the methodRetryHandler
Deprecated:use HttpMethodParams
/** * Returns the {@link MethodRetryHandler retry handler} for this HTTP method * * @return the methodRetryHandler * * @deprecated use {@link HttpMethodParams} */
public MethodRetryHandler getMethodRetryHandler() { return methodRetryHandler; }
Sets the retry handler for this HTTP method
Params:
  • handler – the methodRetryHandler to use when this method executed
Deprecated:use HttpMethodParams
/** * Sets the {@link MethodRetryHandler retry handler} for this HTTP method * * @param handler the methodRetryHandler to use when this method executed * * @deprecated use {@link HttpMethodParams} */
public void setMethodRetryHandler(MethodRetryHandler handler) { methodRetryHandler = handler; }
This method is a dirty hack intended to work around current (2.0) design flaw that prevents the user from obtaining correct status code, headers and response body from the preceding HTTP CONNECT method. TODO: Remove this crap as soon as possible
/** * This method is a dirty hack intended to work around * current (2.0) design flaw that prevents the user from * obtaining correct status code, headers and response body from the * preceding HTTP CONNECT method. * * TODO: Remove this crap as soon as possible */
void fakeResponse( StatusLine statusline, HeaderGroup responseheaders, InputStream responseStream ) { // set used so that the response can be read this.used = true; this.statusLine = statusline; this.responseHeaders = responseheaders; this.responseBody = null; this.responseStream = responseStream; }
Returns the target host authentication state
Returns:host authentication state
Since:3.0
/** * Returns the target host {@link AuthState authentication state} * * @return host authentication state * * @since 3.0 */
public AuthState getHostAuthState() { return this.hostAuthState; }
Returns the proxy authentication state
Returns:host authentication state
Since:3.0
/** * Returns the proxy {@link AuthState authentication state} * * @return host authentication state * * @since 3.0 */
public AuthState getProxyAuthState() { return this.proxyAuthState; }
Tests whether the execution of this method has been aborted
Returns:true if the execution of this method has been aborted, false otherwise
Since:3.0
/** * Tests whether the execution of this method has been aborted * * @return <tt>true</tt> if the execution of this method has been aborted, * <tt>false</tt> otherwise * * @since 3.0 */
public boolean isAborted() { return this.aborted; }
Returns true if the HTTP has been transmitted to the target server in its entirety, false otherwise. This flag can be useful for recovery logic. If the request has not been transmitted in its entirety, it is safe to retry the failed method.
Returns:true if the request has been sent, false otherwise
/** * Returns <tt>true</tt> if the HTTP has been transmitted to the target * server in its entirety, <tt>false</tt> otherwise. This flag can be useful * for recovery logic. If the request has not been transmitted in its entirety, * it is safe to retry the failed method. * * @return <tt>true</tt> if the request has been sent, <tt>false</tt> otherwise */
public boolean isRequestSent() { return this.requestSent; } }