Index: trunk/http-core/src/java/org/apache/http/protocol/HttpRequestExecutor.java
===================================================================
--- trunk/http-core/src/java/org/apache/http/protocol/HttpRequestExecutor.java (revision 377189)
+++ trunk/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,131 @@
*/
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;
+
+ /** The operations to use for executing requests. */
+ protected final Operations operations;
+
- 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);
+ this.operations = createOperations();
}
-
+
+ /**
+ * Create a new request executor.
+ */
public HttpRequestExecutor() {
this(null);
}
-
- public HttpParams getParams() {
+
+
+ /**
+ * Create an instance of the {@link Operations operations}.
+ * This method is called once only, when the executor is created.
+ * Derived classes can override it to return an instance of a
+ * class derived from {@link Operations Operations}.
+ *
+ * @return the operations to use when executing requests
+ */
+ protected Operations createOperations() {
+ return new Operations();
+ }
+
+ /**
+ * Not designed for use by application developers.
+ * Obtain the operations used by this executor.
+ * The operations are used internally by the request executor.
+ * This method makes them available to asynchronous dispatchers.
+ * Application developers should not bother with these operations at all.
+ *
+ * @return the operations
+ */
+ public final Operations getOperations() {
+ return this.operations;
+ }
+
+
+ /**
+ * 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,57 +193,50 @@
&& status != HttpStatus.SC_RESET_CONTENT;
}
- private HttpMutableResponse doExecute(
+
+ /**
+ * Send a request and obtain the response, without pre- and postprocessing.
+ * This method uses the default {@link #getContext context}
+ * and handles expect-continue handshake if necessary.
+ *
+ * @param request the request to send, already
+ * {@link Operations#prepareRequest prepared}
+ * @param conn the connection over which to send the request, already
+ * {@link Operations#prepareConnection prepared}
+ *
+ * @throws HttpException in case of a protocol problem
+ * @throws IOException in case of an IO problem
+ */
+ protected HttpMutableResponse doExecute(
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;
- }
- }
+
+ HttpMutableResponse response =
+ operations.transmitRequest(request, this.defaultContext, conn,
+ true); // handle expect-continue
+
+ if (response == null)
+ response = operations.obtainResponse(request, conn, true);
+
return response;
}
-
- public HttpResponse execute(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 IO problem
+ */
+ public HttpResponse execute(final HttpRequest request,
+ final HttpClientConnection conn)
throws IOException, HttpException {
if (request == null) {
@@ -151,32 +245,16 @@
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);
-
- if (request instanceof HttpMutableRequest) {
- preprocessRequest((HttpMutableRequest)request, this.context);
- }
-
+ operations.prepareRequest(request, conn.getTargetHost(),
+ null, conn);
+
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();
- }
- }
- if (!conn.isOpen()) {
- conn.open(this.params);
- // TODO: Implement secure tunnelling
- }
+ operations.prepareConnection(conn, null, null);
response = doExecute(request, conn);
// exit retry loop
break;
@@ -196,16 +274,315 @@
throw ex;
}
}
- postprocessResponse(response, this.context);
+
+ operations.finishResponse(response, null);
+
return response;
- }
- public HttpRequestRetryHandler getRetryHandler() {
- return this.retryhandler;
- }
+ } // execute
- public void setRetryHandler(final HttpRequestRetryHandler retryhandler) {
- this.retryhandler = retryhandler;
- }
-
-}
+
+
+ // =======================================================================
+
+ /**
+ * Not designed for use by application developers.
+ * Provides fine-grained operations for request execution.
+ * Application developers should not bother to use these.
+ *
+ * @author Oleg Kalnichevski
+ * @author Roland Weber
+ *
+ * @version $Revision$
+ *
+ * @since 4.0
+ */
+ public class Operations {
+
+ /**
+ * Restricted default constructor.
+ */
+ protected Operations() {
+ // no body
+ }
+
+ /**
+ * Prepare a request for sending.
+ *
+ * @param request the request to prepare
+ * @param target the target host for the request
+ * @param context the context for sending the request,
+ * or null to use the default
+ * {@link #getContext context}
+ * @param conn the connection for sending the request,
+ * or null if not yet known
+ *
+ * @throws HttpException if the request can not be prepared
+ * @throws IOException in case of an IO problem
+ */
+ public void prepareRequest(HttpRequest request,
+ HttpHost target,
+ HttpContext context,
+ HttpClientConnection conn)
+ throws HttpException, IOException {
+
+ if (request == null)
+ throw new IllegalArgumentException
+ ("request must not be null");
+ if (request == null)
+ throw new IllegalArgumentException
+ ("target host must not be null");
+
+ if (context == null)
+ context = HttpRequestExecutor.this.defaultContext;
+
+ context.setAttribute(HttpExecutionContext.HTTP_REQUEST,
+ request);
+ //@@@ behavior if proxying - set real target or proxy, or both?
+ context.setAttribute(HttpExecutionContext.HTTP_TARGET_HOST,
+ target);
+ if (conn != null)
+ context.setAttribute(HttpExecutionContext.HTTP_CONNECTION,
+ conn);
+ else
+ context.removeAttribute(HttpExecutionContext.HTTP_CONNECTION);
+
+ // link default parameters
+ request.getParams().setDefaults(HttpRequestExecutor.this.params);
+
+ if (request instanceof HttpMutableRequest)
+ preprocessRequest((HttpMutableRequest) request, context);
+
+ } // prepareRequest
+
+
+ /**
+ * Prepare a connection before sending a request.
+ *
+ * @param conn the connection to prepare
+ * @param target the target host for the request, or
+ * null to send to the host already
+ * set as the connection target
+ * @param params the parameters for preparing the connection, or
+ * null to use the default
+ * {@link #getParams parameters}
+ *
+ * @throws HttpException in case of a problem
+ * @throws IOException in case of an IO problem
+ */
+ public void prepareConnection(HttpClientConnection conn,
+ HttpHost target,
+ HttpParams params)
+ throws HttpException, IOException {
+
+ if (conn == null)
+ throw new IllegalArgumentException
+ ("connection must not be null");
+
+ if (params == null)
+ params = HttpRequestExecutor.this.params;
+
+ // make sure the connection is open and points to the target host
+ if ((target == null) ||
+ target.equals(conn.getTargetHost())) {
+
+ // host+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 @@@
+ }
+
+ } else {
+
+ // wrong target, point connection to target
+ if (conn.isOpen())
+ conn.close();
+ conn.setTargetHost(target);
+ conn.open(params);
+
+ } // if connection points to target else
+
+ } // prepareConnection
+
+
+ /**
+ * 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 context the context for sending the request,
+ * or null to use the default
+ * {@link #getContext context}
+ * @param conn the connection over which to send the request,
+ * already {@link #prepareConnection prepared}
+ * @param exconhs true if an expect-continue handshake
+ * should be handled, or
+ * false to disable it.
+ * If false is passed, this method will
+ * exclusively send over the connection, otherwise it
+ * may also have to receive responses.
+ *
+ * @return a terminal response received as part of an expect-continue
+ * handshake. Always null if the
+ * exconhs argument is false.
+ *
+ * @throws HttpException in case of a problem
+ * @throws IOException in case of an IO problem
+ */
+ public HttpMutableResponse transmitRequest(
+ final HttpRequest request,
+ HttpContext context,
+ final HttpClientConnection conn,
+ final boolean exconhs)
+
+ throws IOException, HttpException {
+
+ if (request == null)
+ throw new IllegalArgumentException
+ ("request must not be null");
+ if (conn == null)
+ throw new IllegalArgumentException
+ ("connection must not be null");
+
+ if (context == null)
+ context = HttpRequestExecutor.this.defaultContext;
+
+ HttpMutableResponse response = null;
+ context.setAttribute(HttpExecutionContext.HTTP_REQ_SENT,
+ Boolean.FALSE);
+
+ conn.sendRequestHeader(request);
+ if (request instanceof HttpEntityEnclosingRequest) {
+ final HttpEntityEnclosingRequest heer =
+ (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 (exconhs && heer.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, assume
+ // a non-compliant server and send the entity anyway.
+ if (conn.isResponseAvailable(WAIT_FOR_CONTINUE_MS)) {
+
+ response = obtainResponse(request, conn, false);
+ 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(heer);
+ }
+ conn.flush();
+
+ context.setAttribute(HttpExecutionContext.HTTP_REQ_SENT,
+ Boolean.TRUE);
+
+ return response;
+
+ } // transmitRequest
+
+
+ /**
+ * 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 terminal true to wait for a terminal response,
+ * or false if informational responses
+ * with status code 1xx should be returned
+ *
+ * @return the response, not yet post-processed
+ *
+ * @throws HttpException in case of a problem
+ * @throws IOException in case of an IO problem
+ */
+ public HttpMutableResponse obtainResponse(
+ final HttpRequest request,
+ final HttpClientConnection conn,
+ final boolean terminal)
+ throws HttpException, IOException {
+
+ if (request == null)
+ throw new IllegalArgumentException
+ ("request must not be null");
+ if (conn == null)
+ throw new IllegalArgumentException
+ ("connection must not be null");
+
+ // see HttpRequestExecutor.doExecute, final part
+ HttpMutableResponse response = null;
+ int statuscode = 0;
+
+ while ((response == null) ||
+ (terminal && (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, or
+ * null to use the default
+ * {@link #getContext context}
+ *
+ * @throws HttpException in case of a problem
+ * @throws IOException in case of an IO problem
+ */
+ public void finishResponse(HttpMutableResponse response,
+ HttpContext context)
+ throws HttpException, IOException {
+
+ if (response == null)
+ throw new IllegalArgumentException
+ ("response must not be null");
+
+ if (context == null)
+ context = HttpRequestExecutor.this.defaultContext;
+
+ postprocessResponse(response, context);
+
+ } // finishResponse
+
+ } // class Operations
+
+
+} // class HttpRequestExecutor
Index: trunk/http-core/src/examples/org/apache/http/examples/ElementalHttpServer.java
===================================================================
--- trunk/http-core/src/examples/org/apache/http/examples/ElementalHttpServer.java (revision 377149)
+++ trunk/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: trunk/http-async/src/java/org/apache/http/async/impl/SimpleHttpDispatcher.java
===================================================================
--- trunk/http-async/src/java/org/apache/http/async/impl/SimpleHttpDispatcher.java (revision 377149)
+++ trunk/http-async/src/java/org/apache/http/async/impl/SimpleHttpDispatcher.java (working copy)
@@ -45,10 +45,10 @@
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpException;
import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestExecutor;
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;
@@ -78,22 +78,20 @@
public class SimpleHttpDispatcher extends AbstractHttpDispatcher
implements HttpDispatcher {
// @@@ move some of this stuff to an abstract base class?
+ // @@@ the HttpRequestExecutor and getDefaultContext method, for example
/** The one and only connection. */
private final HttpClientConnection client_connection;
/**
- * The HTTP processor.
+ * The request executor.
* For pre- and postprocessing of requests and responses, respectively.
*/
- protected final AsyncHttpProcessor async_processor;
+ protected final HttpRequestExecutor request_executor;
/** The connection re-use strategy. */
private ConnectionReuseStrategy reuse_strategy;
- /** The parameters to use. */
- private HttpParams http_params;
-
/** The background thread. */
private SimpleHttpDispatcherThread background_thread;
@@ -127,29 +125,26 @@
* Create a new simple HTTP dispatcher.
*
* @param conn the connection to use
- * @param proc the HTTP processor to use,
- * including the default context
+ * @param reqexec the request processor to use,
+ * including the default context and parameters
* @param reuse the strategy for re-using connections, or
* null to disable connection re-use
- * @param params the parameters to use
*/
public SimpleHttpDispatcher(HttpClientConnection conn,
- AsyncHttpProcessor proc,
- ConnectionReuseStrategy reuse,
- HttpParams params) {
+ HttpRequestExecutor reqexec,
+ 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");
+ throw new IllegalArgumentException
+ ("connection must not be null");
+ if (reqexec == null)
+ throw new IllegalArgumentException
+ ("request executor must not be null");
client_connection = conn;
- async_processor = proc;
+ request_executor = reqexec;
reuse_strategy = reuse;
- http_params = params;
request_handle_queue = new LinkedList();
response_handles = new LinkedList();
@@ -184,7 +179,7 @@
//@@@ - for now: no proxy (how to indicate proxy in the first place?)
HttpContext ctxt = prepareRequest
- (async_processor, request, target, http_params, context);
+ (request_executor, request, target, context);
SimpleHttpHandle hdl = new SimpleHttpHandle(this, request, ctxt);
// linked handles need to be tracked for abortAll()
@@ -218,7 +213,7 @@
throw new IllegalArgumentException("response must not be null");
handle.checkDispatcher(this);
- finishResponse(async_processor, response, handle.getContext());
+ finishResponse(request_executor, response, handle.getContext());
} // postprocessResponse
@@ -227,7 +222,7 @@
// non-javadoc, see interface HttpDispatcher
public final HttpContext getDefaultContext() {
- return async_processor.getDefaultContext();
+ return request_executor.getContext();
}
@@ -392,14 +387,14 @@
}
//@@@ TODO: retry handling!
- transmitRequest(async_processor,
+ transmitRequest(request_executor,
handle.getRequest(),
handle.getContext(),
client_connection);
//@@@ TODO: timeout handling!
HttpMutableResponse response =
- obtainResponse(async_processor,
+ obtainResponse(request_executor,
handle.getRequest(),
client_connection);
handle.provideResponse(response);
Index: trunk/http-async/src/java/org/apache/http/async/AbstractHttpDispatcher.java
===================================================================
--- trunk/http-async/src/java/org/apache/http/async/AbstractHttpDispatcher.java (revision 377149)
+++ trunk/http-async/src/java/org/apache/http/async/AbstractHttpDispatcher.java (working copy)
@@ -41,12 +41,12 @@
import org.apache.http.HttpRequest;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpExecutionContext;
+import org.apache.http.protocol.HttpRequestExecutor;
/**
* Abstract base for implementations of {@link HttpDispatcher HttpDispatcher}.
- * Provides access to protected methods in
- * {@link AsyncHttpProcessor AsyncHttpProcessor}.
*
* @version $Revision$ $Date$
*
@@ -121,12 +121,13 @@
/**
* Prepare a request for sending.
- * Maps to {@link AsyncHttpProcessor#prepareRequest proc.prepareRequest}.
+ * Maps to {@link
+ * org.apache.http.protocol.HttpRequestExecutor.Operations#prepareRequest
+ * reqexec.getOperations().prepareRequest}.
*
- * @param proc the processor to use for preparing
+ * @param reqexec the request executor to use
* @param request the request to prepare
* @param target the target host for the request
- * @param params the default parameters
* @param context the parent context for sending the request,
* or null to use the default context
*
@@ -135,50 +136,78 @@
* @throws HttpException if the request can not be prepared
* @throws IOException in case of an IO problem
*/
- protected static HttpContext prepareRequest(AsyncHttpProcessor proc,
- HttpRequest request,
- HttpHost target,
- HttpParams params,
- HttpContext context)
+ protected static HttpContext prepareRequest(HttpRequestExecutor reqexec,
+ HttpRequest request,
+ HttpHost target,
+ HttpContext context)
throws HttpException, IOException {
- return proc.prepareRequest(request, target, params, context);
+ HttpExecutionContext hxc = new HttpExecutionContext(context);
+ // argument checking is done here...
+ reqexec.getOperations().prepareRequest(request, target, hxc, null);
+
+ return hxc;
+
} // prepareRequest
/**
* Send a request.
- * Maps to {@link AsyncHttpProcessor#transmitRequest proc.transmitRequest}.
+ * Calls {@link
+ * org.apache.http.protocol.HttpRequestExecutor.Operations#prepareConnection
+ * reqexec.getOperations().prepareConnection}
+ * and {@link
+ * org.apache.http.protocol.HttpRequestExecutor.Operations#transmitRequest
+ * reqexec.getOperations().transmitRequest}.
*
- * @param proc the processor to use for transmission
- * @param request the request to send, already prepared
- * @param context the request specific context returned by
- * {@link #prepareRequest prepareRequest}
- * when the request was prepared
- * @param connection the connection over which to send the request
+ * @param reqexec the request executor to use
+ * @param request the request to send, already prepared
+ * @param context the request specific context returned by
+ * {@link #prepareRequest prepareRequest}
+ * when the request was prepared
+ * @param conn the connection over which to send the request
*
* @throws HttpException in case of a problem
* @throws IOException in case of an IO problem
*/
- protected static void transmitRequest(AsyncHttpProcessor proc,
+ protected static void transmitRequest(HttpRequestExecutor reqexec,
HttpRequest request,
HttpContext context,
- HttpClientConnection connection)
+ HttpClientConnection conn)
throws HttpException, IOException {
- proc.transmitRequest(request, context, connection);
+ if (request == null)
+ throw new IllegalArgumentException("request must not be null");
+ if (context == null)
+ throw new IllegalArgumentException("context must not be null");
+ if (conn == null)
+ throw new IllegalArgumentException("connection must not be null");
+ HttpHost target = (HttpHost)
+ context.getAttribute(HttpExecutionContext.HTTP_TARGET_HOST);
+ if (target == null)
+ throw new IllegalStateException
+ ("target host missing in request context");
+
+ reqexec.getOperations().
+ prepareConnection(conn, target, request.getParams());
+ reqexec.getOperations().
+ transmitRequest(request, context, conn,
+ false); // no expect-continue, returns null
+
} // transmitRequest
/**
* Wait for and receive a response.
- * Maps to {@link AsyncHttpProcessor#obtainResponse proc.obtainResponse}.
+ * Maps to {@link
+ * org.apache.http.protocol.HttpRequestExecutor.Operations#obtainResponse
+ * reqexec.getOperations().obtainResponse}.
*
- * @param proc the processor to use for transmission
- * @param request the request for which to obtain the response
- * @param connection the connection over which the request was sent
+ * @param reqexec the request executor to use
+ * @param request the request for which to obtain the response
+ * @param conn the connection over which the request was sent
*
* @return the response, not yet post-processed
*
@@ -186,34 +215,37 @@
* @throws IOException in case of an IO problem
*/
protected static
- HttpMutableResponse obtainResponse(AsyncHttpProcessor proc,
+ HttpMutableResponse obtainResponse(HttpRequestExecutor reqexec,
HttpRequest request,
- HttpClientConnection connection)
+ HttpClientConnection conn)
throws HttpException, IOException {
- return proc.obtainResponse(request, connection);
+ return reqexec.getOperations().obtainResponse(request, conn, true);
} // obtainResponse
/**
* Finish a response.
- * Maps to {@link AsyncHttpProcessor#finishResponse proc.finishResponse}.
+ * Maps to {@link
+ * org.apache.http.protocol.HttpRequestExecutor.Operations#finishResponse
+ * reqexec.getOperations().finishResponse}.
*
- * @param response the response object to finish
- * @param context the context obtained from
- * {@link #prepareRequest prepareRequest}
- * for the matching request
+ * @param reqexec the request executor to use
+ * @param response the response object to finish
+ * @param context the context obtained from
+ * {@link #prepareRequest prepareRequest}
+ * for the matching request
*
* @throws HttpException in case of a problem
* @throws IOException in case of an IO problem
*/
- protected static void finishResponse(AsyncHttpProcessor proc,
+ protected static void finishResponse(HttpRequestExecutor reqexec,
HttpMutableResponse response,
HttpContext context)
throws HttpException, IOException {
- proc.finishResponse(response, context);
+ reqexec.getOperations().finishResponse(response, context);
} // finishResponse
Index: trunk/http-async/src/java/org/apache/http/async/AsyncHttpProcessor.java
===================================================================
--- trunk/http-async/src/java/org/apache/http/async/AsyncHttpProcessor.java (revision 377149)
+++ trunk/http-async/src/java/org/apache/http/async/AsyncHttpProcessor.java (working copy)
@@ -1,322 +0,0 @@
-/*
- * $HeadURL$
- * $Revision$
- * $Date$
- *
- * ====================================================================
- *
- * Copyright 2006 The Apache Software Foundation
- *
- * Licensed 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
- * .
- *
- */
-
-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.HttpException;
-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;
-
-
-
-/**
- * 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;
-
-
- /**
- * 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;
- }
-
-
- /**
- * Create a new HTTP processor with empty default context.
- */
- public AsyncHttpProcessor() {
- this(new HttpExecutionContext(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 context the parent context for sending the request,
- * or null to use the default context
- *
- * @return a new context specific to the request
- *
- * @throws HttpException if the request can not be prepared
- * @throws IOException in case of an IO problem
- */
- 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);
-
- //@@@ Can't set connection in the context, it's not available yet.
- //@@@ Is it required for one of the interceptors?
-
- // link default parameters
- request.getParams().setDefaults(params);
-
- if (request instanceof HttpMutableRequest)
- preprocessRequest((HttpMutableRequest) request, hxc);
-
- return hxc;
-
- } // prepareRequest
-
-
- /**
- * Send a request.
- *
- * @param request the request to send, already prepared
- * @param context the request specific context returned by
- * {@link #prepareRequest prepareRequest}
- * when the request was prepared
- * @param connection the connection over which to send the request
- *
- * @throws HttpException in case of a problem
- * @throws IOException in case of an IO problem
- */
- protected void transmitRequest(HttpRequest request,
- HttpContext context,
- HttpClientConnection connection)
- throws HttpException, IOException {
-
- 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");
-
- HttpHost target = (HttpHost)
- context.getAttribute(HttpExecutionContext.HTTP_TARGET_HOST);
- 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();
-
- 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
- *
- * @return the response, not yet post-processed
- *
- * @throws HttpException in case of a problem
- * @throws IOException in case of an IO problem
- */
- protected
- HttpMutableResponse obtainResponse(HttpRequest request,
- 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");
-
- // 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
- * re-use of the connection over which the response is coming in.
- *
- * @param response the response object to finish
- * @param context the context obtained from
- * {@link #prepareRequest prepareRequest}
- * for the matching request
- *
- * @throws HttpException in case of a problem
- * @throws IOException in case of an IO problem
- */
- protected void finishResponse(HttpMutableResponse response,
- 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");
-
- postprocessResponse(response, context);
-
- } // finishResponse
-
-
-} // class AsyncHttpProcessor
Index: trunk/http-async/src/examples/org/apache/http/examples/ElementalAsyncGet.java
===================================================================
--- trunk/http-async/src/examples/org/apache/http/examples/ElementalAsyncGet.java (revision 377149)
+++ trunk/http-async/src/examples/org/apache/http/examples/ElementalAsyncGet.java (working copy)
@@ -46,8 +46,8 @@
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.async.HttpDispatcher;
import org.apache.http.async.HttpHandle;
-import org.apache.http.async.AsyncHttpProcessor;
import org.apache.http.async.impl.SimpleHttpDispatcher;
+import org.apache.http.protocol.HttpRequestExecutor;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestTargetHost;
@@ -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++) {
@@ -156,20 +156,20 @@
HttpProtocolParams.setUserAgent(params, "Jakarta-HttpComponents/1.1");
HttpProtocolParams.setUseExpectContinue(params, false);
- HttpClientConnection conn = new DefaultHttpClientConnection();
-
- AsyncHttpProcessor proc = new AsyncHttpProcessor();
+ HttpRequestExecutor reqexec = new HttpRequestExecutor();
+ reqexec.setParams(params);
// Required request interceptors
- proc.addInterceptor(new RequestContent());
- proc.addInterceptor(new RequestTargetHost());
+ reqexec.addInterceptor(new RequestContent());
+ reqexec.addInterceptor(new RequestTargetHost());
// Recommended request interceptors
- proc.addInterceptor(new RequestConnControl());
- proc.addInterceptor(new RequestUserAgent());
- // not supported: proc.addInterceptor(new RequestExpectContinue());
+ reqexec.addInterceptor(new RequestConnControl());
+ reqexec.addInterceptor(new RequestUserAgent());
+ // not supported: reqexec.addInterceptor(new RequestExpectContinue());
+ HttpClientConnection conn = new DefaultHttpClientConnection();
ConnectionReuseStrategy crs = new DefaultConnectionReuseStrategy();
- HttpDispatcher hdp = new SimpleHttpDispatcher(conn, proc, crs, params);
+ HttpDispatcher hdp = new SimpleHttpDispatcher(conn, reqexec, crs);
return hdp;