Index: http-core/src/java/org/apache/http/protocol/HttpRequestExecutor.java =================================================================== --- http-core/src/java/org/apache/http/protocol/HttpRequestExecutor.java (revision 376961) +++ http-core/src/java/org/apache/http/protocol/HttpRequestExecutor.java (working copy) @@ -35,6 +35,7 @@ import org.apache.http.HttpClientConnection; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpException; +import org.apache.http.HttpHost; import org.apache.http.HttpMutableRequest; import org.apache.http.HttpMutableResponse; import org.apache.http.HttpRequest; @@ -57,31 +58,97 @@ */ public class HttpRequestExecutor extends AbstractHttpProcessor { - private static final int WAIT_FOR_CONTINUE_MS = 10000; + protected static final int WAIT_FOR_CONTINUE_MS = 10000; + + /** The context holding the default context information. */ + protected final HttpContext defaultContext; - private final HttpContext context; - private HttpParams params = null; private HttpRequestRetryHandler retryhandler = null; - + + /** + * Create a new request executor with default context information. + * The attributes in the argument context will be made available + * in the context used for executing a request. + * + * @param parentContext the default context information, + * or null + */ public HttpRequestExecutor(final HttpContext parentContext) { super(); - this.context = new HttpExecutionContext(parentContext); + this.defaultContext = new HttpExecutionContext(parentContext); } - + + /** + * Create a new request executor. + */ public HttpRequestExecutor() { this(null); } - - public HttpParams getParams() { + + /** + * Obtain the default context information. + * This is not necessarily the same object passed to the constructor, + * but the default context information will be available here. + * + * @return the context holding the default context information + */ + public final HttpContext getContext() { + return this.defaultContext; + } + + /** + * Obtain the parameters for executing requests. + * + * @return the currently installed parameters + */ + public final HttpParams getParams() { return this.params; } - public void setParams(final HttpParams params) { + /** + * Set new parameters for executing requests. + * + * @param params the new parameters to use from now on + */ + public final void setParams(final HttpParams params) { this.params = params; } - - private boolean canResponseHaveBody(final HttpRequest request, final HttpResponse response) { + + /** + * Obtain the retry handler. + * + * @return the handler deciding whether a request should be retried + */ + public final HttpRequestRetryHandler getRetryHandler() { + return this.retryhandler; + } + + /** + * Set the retry handler. + * + * @param retryhandler the handler to decide whether a request + * should be retried + */ + public final void setRetryHandler(final HttpRequestRetryHandler retryhandler) { + this.retryhandler = retryhandler; + } + + /** + * Decide whether a response comes with an entity. + * The implementation in this class is based on RFC 2616. + * Unknown methods and response codes are supposed to + * indicate responses with an entity. + *
+ * Derived executors can override this method to handle + * methods and response codes not specified in RFC 2616. + * + * @param request the request, to obtain the executed method + * @param response the response, to obtain the status code + */ + protected boolean canResponseHaveBody(final HttpRequest request, + final HttpResponse response) { + if ("HEAD".equalsIgnoreCase(request.getRequestLine().getMethod())) { return false; } @@ -92,92 +159,51 @@ && status != HttpStatus.SC_RESET_CONTENT; } - private HttpMutableResponse doExecute( - final HttpRequest request, final HttpClientConnection conn) + /** + * Synchronously send a request and obtain the response. + * + * @param request the request to send. It will be preprocessed. + * @param conn the connection over which to send. + * The {@link HttpClientConnection#setTargetHost target} + * host has to be set before calling this method. + * + * @return the response to the request, postprocessed + * + * @throws HttpException in case of a protocol or processing problem + * @throws IOException in case of an I/O problem + */ + public HttpResponse execute( + final HttpRequest request, + final HttpClientConnection conn) throws IOException, HttpException { - HttpMutableResponse response = null; - this.context.setAttribute(HttpExecutionContext.HTTP_REQ_SENT, - new Boolean(false)); - // Send request header - conn.sendRequestHeader(request); - if (request instanceof HttpEntityEnclosingRequest) { - HttpVersion ver = request.getRequestLine().getHttpVersion(); - if (ver.greaterEquals(HttpVersion.HTTP_1_1) - && ((HttpEntityEnclosingRequest)request).expectContinue()) { - // Flush headers - conn.flush(); - if (conn.isResponseAvailable(WAIT_FOR_CONTINUE_MS)) { - response = conn.receiveResponseHeader(this.params); - if (canResponseHaveBody(request, response)) { - conn.receiveResponseEntity(response); - } - int status = response.getStatusLine().getStatusCode(); - if (status < 200) { - if (status != HttpStatus.SC_CONTINUE) { - throw new ProtocolException("Unexpected response: " + - response.getStatusLine()); - } - } else { - return response; - } - } - } - conn.sendRequestEntity((HttpEntityEnclosingRequest) request); - } - conn.flush(); - - this.context.setAttribute(HttpExecutionContext.HTTP_REQ_SENT, - new Boolean(true)); - for (;;) { - // Loop until non 1xx resposne is received - response = conn.receiveResponseHeader(this.params); - if (canResponseHaveBody(request, response)) { - conn.receiveResponseEntity(response); - } - int statuscode = response.getStatusLine().getStatusCode(); - if (statuscode >= HttpStatus.SC_OK) { - break; - } - } - return response; - } - - public HttpResponse execute(final HttpRequest request, final HttpClientConnection conn) - throws IOException, HttpException { - if (request == null) { throw new IllegalArgumentException("HTTP request may not be null"); } if (conn == null) { throw new IllegalArgumentException("Client connection may not be null"); } - this.context.setAttribute(HttpExecutionContext.HTTP_REQUEST, request); - this.context.setAttribute(HttpExecutionContext.HTTP_CONNECTION, conn); - this.context.setAttribute(HttpExecutionContext.HTTP_TARGET_HOST, - conn.getTargetHost()); - // Link own parameters as defaults - request.getParams().setDefaults(this.params); + //@@@ behavior if proxying - set real target or proxy, or both? + this.defaultContext.setAttribute(HttpExecutionContext.HTTP_TARGET_HOST, + conn.getTargetHost()); + this.defaultContext.setAttribute(HttpExecutionContext.HTTP_CONNECTION, + conn); - if (request instanceof HttpMutableRequest) { - preprocessRequest((HttpMutableRequest)request, this.context); - } + prepareRequest(request, this.defaultContext); + + this.defaultContext.setAttribute(HttpExecutionContext.HTTP_REQUEST, + request); HttpMutableResponse response = null; // loop until the method is successfully processed, the retryHandler // returns false or a non-recoverable exception is thrown for (int execCount = 0; ; execCount++) { try { - if (HttpConnectionParams.isStaleCheckingEnabled(this.params)) { - if (conn.isOpen() && conn.isStale()) { - conn.close(); - } + establishConnection(conn, conn.getTargetHost(), request.getParams()); + response = sendRequest(request, conn, this.defaultContext); + if (response == null) { + response = receiveResponse(request, conn, this.defaultContext); } - if (!conn.isOpen()) { - conn.open(this.params); - // TODO: Implement secure tunnelling - } - response = doExecute(request, conn); // exit retry loop break; } catch (IOException ex) { @@ -196,16 +222,231 @@ throw ex; } } - postprocessResponse(response, this.context); + + finishResponse(response, this.defaultContext); + return response; + } - public HttpRequestRetryHandler getRetryHandler() { - return this.retryhandler; + /** + * Prepare a request for sending. + * + * @param request the request to prepare + * @param context the context for sending the request + * + * @throws HttpException in case of a protocol or processing problem + * @throws IOException in case of an I/O problem + */ + protected void prepareRequest( + final HttpRequest request, + final HttpContext context) + throws HttpException, IOException { + if (request == null) { + throw new IllegalArgumentException("HTTP request may not be null"); + } + if (context == null) { + throw new IllegalArgumentException("HTTP context may not be null"); + } + // link default parameters + request.getParams().setDefaults(this.params); + if (request instanceof HttpMutableRequest) { + preprocessRequest((HttpMutableRequest) request, context); + } } - public void setRetryHandler(final HttpRequestRetryHandler retryhandler) { - this.retryhandler = retryhandler; + /** + * Establish a connection with the target host. + * + * @param conn the HTTP connection + * @param target the target host for the request, or + * null to send to the host already + * set as the connection target + * + * @throws HttpException in case of a problem + * @throws IOException in case of an IO problem + */ + protected void establishConnection( + final HttpClientConnection conn, + final HttpHost target, + final HttpParams params) + throws HttpException, IOException { + if (conn == null) { + throw new IllegalArgumentException("HTTP connection may not be null"); + } + if (target == null) { + throw new IllegalArgumentException("Target host may not be null"); + } + if (params == null) { + throw new IllegalArgumentException("HTTP parameters may not be null"); + } + // make sure the connection is open and points to the target host + if ((target == null) || target.equals(conn.getTargetHost())) { + // host and port ok, check whether connection needs to be opened + if (HttpConnectionParams.isStaleCheckingEnabled(params)) { + if (conn.isOpen() && conn.isStale()) { + conn.close(); + } + } + if (!conn.isOpen()) { + conn.open(params); + //TODO: Implement secure tunnelling (@@@ HttpRequestExecutor) + } + + } else { + // wrong target, point connection to target + if (conn.isOpen()) { + conn.close(); + } + conn.setTargetHost(target); + conn.open(params); + + } // if connection points to target else } - -} + + /** + * Send a request over a connection. + * This method also handles the expect-continue handshake, if requested. + * + * @param request the request to send, already + * {@link #prepareRequest prepared} + * @param conn the connection over which to send the request, already + * {@link #establishConnection established} + * @param context the context for sending the request + * + * @return a terminal response received as part of an expect-continue + * handshake or null if the expect-continue handshake + * is not used. + * + * @throws HttpException in case of a protocol or processing problem + * @throws IOException in case of an I/O problem + */ + protected HttpMutableResponse sendRequest( + final HttpRequest request, + final HttpClientConnection conn, + final HttpContext context) + throws IOException, HttpException { + if (request == null) { + throw new IllegalArgumentException("HTTP request may not be null"); + } + if (conn == null) { + throw new IllegalArgumentException("HTTP connection may not be null"); + } + if (context == null) { + throw new IllegalArgumentException("HTTP context may not be null"); + } + + HttpMutableResponse response = null; + context.setAttribute(HttpExecutionContext.HTTP_REQ_SENT, Boolean.FALSE); + + conn.sendRequestHeader(request); + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntityEnclosingRequest entityEnclRequest = (HttpEntityEnclosingRequest) request; + + // Check for expect-continue handshake. We have to flush the + // headers and wait for an 100-continue response to handle it. + // If we get a different response, we must not send the entity. + boolean sendentity = true; + final HttpVersion ver = request.getRequestLine().getHttpVersion(); + if (entityEnclRequest.expectContinue() && ver.greaterEquals(HttpVersion.HTTP_1_1)) { + + conn.flush(); + // As suggested by RFC 2616 section 8.2.3, we don't wait for a + // 100-continue response forever. On timeout, send the entity. + if (conn.isResponseAvailable(WAIT_FOR_CONTINUE_MS)) { + response = conn.receiveResponseHeader(request.getParams()); + if (canResponseHaveBody(request, response)) { + conn.receiveResponseEntity(response); + } + int status = response.getStatusLine().getStatusCode(); + if (status < 200) { + //@@@ TODO: is this in line with RFC 2616, 10.1? + if (status != HttpStatus.SC_CONTINUE) { + throw new ProtocolException( + "Unexpected response: " + response.getStatusLine()); + } + } else { + sendentity = false; + } + } + } + if (sendentity) { + conn.sendRequestEntity(entityEnclRequest); + } + } + conn.flush(); + context.setAttribute(HttpExecutionContext.HTTP_REQ_SENT, Boolean.TRUE); + return response; + } + + /** + * Wait for and receive a response. + * + * @param request the request for which to obtain the response + * @param conn the connection over which the request was sent + * @param context the context for receiving the response + * + * @return the response, not yet post-processed + * + * @throws HttpException in case of a protocol or processing problem + * @throws IOException in case of an I/O problem + */ + protected HttpMutableResponse receiveResponse( + final HttpRequest request, + final HttpClientConnection conn, + final HttpContext context) + throws HttpException, IOException { + if (request == null) { + throw new IllegalArgumentException("HTTP request may not be null"); + } + if (conn == null) { + throw new IllegalArgumentException("HTTP connection may not be null"); + } + if (context == null) { + throw new IllegalArgumentException("HTTP context may not be null"); + } + // see HttpRequestExecutor.doExecute, final part + HttpMutableResponse response = null; + int statuscode = 0; + + while (response == null || statuscode < HttpStatus.SC_OK) { + + response = conn.receiveResponseHeader(request.getParams()); + if (canResponseHaveBody(request, response)) { + conn.receiveResponseEntity(response); + } + statuscode = response.getStatusLine().getStatusCode(); + + } // while intermediate response + + return response; + + } // obtainResponse + + /** + * Finish a response. + * This includes post-processing of the response object. + * It does not read the response entity, if any. + * It does not allow for immediate re-use of the + * connection over which the response is coming in. + * + * @param response the response object to finish + * @param context the context for post-processing the response + * + * @throws HttpException in case of a protocol or processing problem + * @throws IOException in case of an I/O problem + */ + protected void finishResponse( + final HttpMutableResponse response, + final HttpContext context) + throws HttpException, IOException { + if (response == null) { + throw new IllegalArgumentException("HTTP response may not be null"); + } + if (context == null) { + throw new IllegalArgumentException("HTTP context may not be null"); + } + postprocessResponse(response, context); + } + +} // class HttpRequestExecutor Index: http-core/src/examples/org/apache/http/examples/ElementalHttpServer.java =================================================================== --- http-core/src/examples/org/apache/http/examples/ElementalHttpServer.java (revision 376458) +++ http-core/src/examples/org/apache/http/examples/ElementalHttpServer.java (working copy) @@ -94,7 +94,7 @@ StringEntity body = new StringEntity("File not found", "UTF-8"); response.setEntity(body); System.out.println("File " + file.getPath() + " not found"); - } else if (!file.canRead()) { + } else if (!file.canRead() || file.isDirectory()) { response.setStatusCode(HttpStatus.SC_FORBIDDEN); StringEntity body = new StringEntity("Access Denied", "UTF-8"); response.setEntity(body); Index: http-async/src/java/org/apache/http/async/impl/SimpleHttpDispatcher.java =================================================================== --- http-async/src/java/org/apache/http/async/impl/SimpleHttpDispatcher.java (revision 375356) +++ http-async/src/java/org/apache/http/async/impl/SimpleHttpDispatcher.java (working copy) @@ -29,7 +29,6 @@ package org.apache.http.async.impl; - import java.io.IOException; import java.util.List; import java.util.LinkedList; @@ -45,15 +44,12 @@ import org.apache.http.ConnectionReuseStrategy; import org.apache.http.HttpException; import org.apache.http.protocol.HttpContext; -import org.apache.http.params.HttpParams; import org.apache.http.async.HttpHandle; import org.apache.http.async.HttpDispatcher; import org.apache.http.async.AsyncHttpProcessor; import org.apache.http.async.AbstractHttpHandle; import org.apache.http.async.AbstractHttpDispatcher; - - /** * Minimal implementation of an {@link HttpDispatcher HttpDispatcher}. * This dispatcher uses a single connection and background thread. @@ -78,6 +74,7 @@ public class SimpleHttpDispatcher extends AbstractHttpDispatcher implements HttpDispatcher { // @@@ move some of this stuff to an abstract base class? + // @@@ the AsyncHttpProcessor and getDefaultContext method, for example /** The one and only connection. */ private final HttpClientConnection client_connection; @@ -91,9 +88,6 @@ /** The connection re-use strategy. */ private ConnectionReuseStrategy reuse_strategy; - /** The parameters to use. */ - private HttpParams http_params; - /** The background thread. */ private SimpleHttpDispatcherThread background_thread; @@ -135,21 +129,17 @@ */ public SimpleHttpDispatcher(HttpClientConnection conn, AsyncHttpProcessor proc, - ConnectionReuseStrategy reuse, - HttpParams params) { + ConnectionReuseStrategy reuse) { super(null); if (conn == null) throw new IllegalArgumentException("connection must not be null"); if (proc == null) throw new IllegalArgumentException("processor must not be null"); - if (params == null) - throw new IllegalArgumentException("parameters must not be null"); client_connection = conn; async_processor = proc; reuse_strategy = reuse; - http_params = params; request_handle_queue = new LinkedList(); response_handles = new LinkedList(); @@ -184,7 +174,7 @@ //@@@ - for now: no proxy (how to indicate proxy in the first place?) HttpContext ctxt = prepareRequest - (async_processor, request, target, http_params, context); + (async_processor, request, target, context); SimpleHttpHandle hdl = new SimpleHttpHandle(this, request, ctxt); // linked handles need to be tracked for abortAll() @@ -227,7 +217,7 @@ // non-javadoc, see interface HttpDispatcher public final HttpContext getDefaultContext() { - return async_processor.getDefaultContext(); + return async_processor.getContext(); } @@ -401,6 +391,7 @@ HttpMutableResponse response = obtainResponse(async_processor, handle.getRequest(), + handle.getContext(), client_connection); handle.provideResponse(response); Index: http-async/src/java/org/apache/http/async/AbstractHttpDispatcher.java =================================================================== --- http-async/src/java/org/apache/http/async/AbstractHttpDispatcher.java (revision 375361) +++ http-async/src/java/org/apache/http/async/AbstractHttpDispatcher.java (working copy) @@ -39,10 +39,8 @@ import org.apache.http.HttpHost; import org.apache.http.HttpMutableResponse; import org.apache.http.HttpRequest; -import org.apache.http.params.HttpParams; import org.apache.http.protocol.HttpContext; - /** * Abstract base for implementations of {@link HttpDispatcher HttpDispatcher}. * Provides access to protected methods in @@ -138,11 +136,10 @@ protected static HttpContext prepareRequest(AsyncHttpProcessor proc, HttpRequest request, HttpHost target, - HttpParams params, HttpContext context) throws HttpException, IOException { - return proc.prepareRequest(request, target, params, context); + return proc.prepareRequest(request, target, context); } // prepareRequest @@ -188,10 +185,11 @@ protected static HttpMutableResponse obtainResponse(AsyncHttpProcessor proc, HttpRequest request, + HttpContext context, HttpClientConnection connection) throws HttpException, IOException { - return proc.obtainResponse(request, connection); + return proc.obtainResponse(request, context, connection); } // obtainResponse Index: http-async/src/java/org/apache/http/async/AsyncHttpProcessor.java =================================================================== --- http-async/src/java/org/apache/http/async/AsyncHttpProcessor.java (revision 375356) +++ http-async/src/java/org/apache/http/async/AsyncHttpProcessor.java (working copy) @@ -29,54 +29,37 @@ package org.apache.http.async; - import java.io.IOException; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpMutableRequest; -import org.apache.http.HttpEntityEnclosingRequest; -import org.apache.http.HttpResponse; -import org.apache.http.HttpMutableResponse; import org.apache.http.HttpClientConnection; -import org.apache.http.HttpStatus; +import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpException; +import org.apache.http.HttpHost; +import org.apache.http.HttpMutableResponse; +import org.apache.http.HttpRequest; +import org.apache.http.ProtocolException; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpExecutionContext; -import org.apache.http.protocol.AbstractHttpProcessor; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpConnectionParams; +import org.apache.http.protocol.HttpRequestExecutor; - - /** * HTTP processor for asynchronously dispatched requests. * This is the asynchronous equivalent to * {@link org.apache.http.protocol.HttpRequestExecutor HttpRequestExecutor}. - * * * @version $Revision$ $Date$ * * @since 4.0 */ -public class AsyncHttpProcessor extends AbstractHttpProcessor { - - /** The default (parent) context. */ - private HttpContext default_context; - - +public class AsyncHttpProcessor extends HttpRequestExecutor { + /** * Create a new HTTP processor with the given default context. * * @param context the default context */ public AsyncHttpProcessor(HttpContext context) { - - if (context == null) - throw new IllegalArgumentException - ("default context must not be null"); - - default_context = context; + super(context); } @@ -84,26 +67,18 @@ * Create a new HTTP processor with empty default context. */ public AsyncHttpProcessor() { - this(new HttpExecutionContext(null)); + this(null); } - /** - * Obtain the default context. - * - * @return the default context, or null if there is none - */ - public final HttpContext getDefaultContext() { - return default_context; - } - - /** * Prepare a request for sending. * * @param request the request to prepare * @param target the target host for the request - * @param params the default parameters + * @param params the parameters for executing this request, or + * null to use the default + * {@link #getParams parameters} * @param context the parent context for sending the request, * or null to use the default context * @@ -114,31 +89,19 @@ */ protected HttpContext prepareRequest(HttpRequest request, HttpHost target, - HttpParams params, HttpContext context) throws HttpException, IOException { - if (request == null) - throw new IllegalArgumentException("request must not be null"); - if (context == null) - context = default_context; - - // see also HttpRequestExecutor.execute(), initial part - HttpExecutionContext hxc = new HttpExecutionContext(context); - hxc.setAttribute(HttpExecutionContext.HTTP_REQUEST, request); - //@@@ behavior if proxying - set real target or proxy, or both? - hxc.setAttribute(HttpExecutionContext.HTTP_TARGET_HOST, target); + hxc.setAttribute(HttpExecutionContext.HTTP_TARGET_HOST, + target); - //@@@ Can't set connection in the context, it's not available yet. - //@@@ Is it required for one of the interceptors? + // argument checking is done here... + super.prepareRequest(request, hxc); - // link default parameters - request.getParams().setDefaults(params); + hxc.setAttribute(HttpExecutionContext.HTTP_REQUEST, + request); - if (request instanceof HttpMutableRequest) - preprocessRequest((HttpMutableRequest) request, hxc); - return hxc; } // prepareRequest @@ -163,68 +126,33 @@ if (request == null) throw new IllegalArgumentException("request must not be null"); - if (context == null) - throw new IllegalArgumentException("context must not be null"); if (connection == null) throw new IllegalArgumentException("connection must not be null"); + if (context == null) + throw new IllegalArgumentException("context must not be null"); HttpHost target = (HttpHost) context.getAttribute(HttpExecutionContext.HTTP_TARGET_HOST); - if (target == null) + if (target == null) { throw new IllegalStateException ("target host missing in request context"); - - // see also HttpRequestExecutor.execute() and .doExecute() - // Retry handling should be implemented by caller, since the retry - // may be triggered by receiving the response, too. - - // make sure the connection is open and points to the target host - HttpParams params = request.getParams(); - if (target.equals(connection.getTargetHost())) { - - // host and port ok, check whether connection needs to be opened - if (HttpConnectionParams.isStaleCheckingEnabled(params)) { - if (connection.isOpen() && connection.isStale()) { - connection.close(); - } - } - if (!connection.isOpen()) { - connection.open(params); - //TODO: Implement secure tunnelling (@@@ HttpRequestExecutor) - } - - } else { - - // wrong target, point connection to target - if (connection.isOpen()) - connection.close(); - connection.setTargetHost(target); - connection.open(params); - - } // if connection points to target else - - - // this is the initial part of HttpRequestExecutor.doExecute, - // minus the handling of expect/continue handshakes - - context.setAttribute(HttpExecutionContext.HTTP_REQ_SENT, - Boolean.FALSE); - - connection.sendRequestHeader(request); - if (request instanceof HttpEntityEnclosingRequest) { - connection.sendRequestEntity((HttpEntityEnclosingRequest) request); } - connection.flush(); + if (request instanceof HttpEntityEnclosingRequest + && ((HttpEntityEnclosingRequest)request).expectContinue()) { + throw new ProtocolException("Expect-continue handshake not supported"); + } + super.establishConnection(connection, target, request.getParams()); + + context.setAttribute(HttpExecutionContext.HTTP_CONNECTION, + connection); + + super.sendRequest(request, connection, context); - context.setAttribute(HttpExecutionContext.HTTP_REQ_SENT, - Boolean.TRUE); - } // transmitRequest /** * Wait for and receive a response. - * clarify sematics - will the response body be received? * * @param request the request for which to obtain the response * @param connection the connection over which the request was sent @@ -236,62 +164,17 @@ */ protected HttpMutableResponse obtainResponse(HttpRequest request, + HttpContext context, HttpClientConnection connection) throws HttpException, IOException { - if (request == null) - throw new IllegalArgumentException("request must not be null"); - if (connection == null) - throw new IllegalArgumentException("connection must not be null"); + // argument checking is done here... + return super.receiveResponse(request, connection, context); - // see HttpRequestExecutor.doExecute, final part - HttpMutableResponse response = null; - int statuscode = 0; - - // skip 1xx responses - while (statuscode < HttpStatus.SC_OK) { - response = connection.receiveResponseHeader(request.getParams()); - - //@@@ does this actually receive, or just wrap the stream? - //@@@ how to make sure we get only a wrapped stream here? - //@@@ don't call receiveResponseEntity here at all? - //@@@ could there be 1xx responses with an entity? check RFC 2616 - if (canResponseHaveBody(request, response)) { - connection.receiveResponseEntity(response); - } - statuscode = response.getStatusLine().getStatusCode(); - - } // while intermediate response - - return response; - } // obtainResponse /** - * Decide whether a response comes with an entity. - * - * @param request the request responded to - * @param response the response, initialized from headers only - * - * @return true if the response should have an entity, or - * false if it doesn't - */ - //@@@ duplicated from HttpRequestExecutor.canResponseHaveBody - private boolean canResponseHaveBody(final HttpRequest request, - final HttpResponse response) { - if ("HEAD".equalsIgnoreCase(request.getRequestLine().getMethod())) { - return false; - } - int status = response.getStatusLine().getStatusCode(); - return status >= HttpStatus.SC_OK - && status != HttpStatus.SC_NO_CONTENT - && status != HttpStatus.SC_NOT_MODIFIED - && status != HttpStatus.SC_RESET_CONTENT; - } - - - /** * Finish a response. * This includes post-processing of the response object. * It does not read the response entity (if any), nor allows @@ -309,13 +192,9 @@ HttpContext context) throws HttpException, IOException { - if (response == null) - throw new IllegalArgumentException("response must not be null"); - if (context == null) - throw new IllegalArgumentException("context must not be null"); + // argument checking is done here... + super.finishResponse(response, context); - postprocessResponse(response, context); - } // finishResponse Index: http-async/src/examples/org/apache/http/examples/ElementalAsyncGet.java =================================================================== --- http-async/src/examples/org/apache/http/examples/ElementalAsyncGet.java (revision 375356) +++ http-async/src/examples/org/apache/http/examples/ElementalAsyncGet.java (working copy) @@ -80,12 +80,12 @@ if ((targets == null) || (targets.length < 1)) { targets = new String[] { "/", - "/manual/", + "/servlets-examples/servlet/RequestInfoExample", "/somewhere%20in%20pampa" }; } - HttpHost host = new HttpHost("localhost", 80); + HttpHost host = new HttpHost("localhost", 8080); HttpHandle[] handles = new HttpHandle[targets.length]; for (int i = 0; i < targets.length; i++) { @@ -159,6 +159,7 @@ HttpClientConnection conn = new DefaultHttpClientConnection(); AsyncHttpProcessor proc = new AsyncHttpProcessor(); + proc.setParams(params); // Required request interceptors proc.addInterceptor(new RequestContent()); proc.addInterceptor(new RequestTargetHost()); @@ -169,7 +170,7 @@ ConnectionReuseStrategy crs = new DefaultConnectionReuseStrategy(); - HttpDispatcher hdp = new SimpleHttpDispatcher(conn, proc, crs, params); + HttpDispatcher hdp = new SimpleHttpDispatcher(conn, proc, crs); return hdp;