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;