mirror of
https://github.com/apache/httpcomponents-client.git
synced 2025-02-28 05:39:07 +00:00
straightening out DefaultClientRequestDirector
git-svn-id: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpclient/trunk@500765 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7bb7a457d4
commit
ec7c0556b4
@ -46,9 +46,19 @@
|
|||||||
* It establishes connections and optionally processes redirects and
|
* It establishes connections and optionally processes redirects and
|
||||||
* authentication challenges. The director may therefore generate and
|
* authentication challenges. The director may therefore generate and
|
||||||
* send a sequence of requests in order to execute one initial request.
|
* send a sequence of requests in order to execute one initial request.
|
||||||
* <br/>
|
*
|
||||||
|
* <br/><b>Note:</b>
|
||||||
|
* It is most likely that implementations of this interface will
|
||||||
|
* allocate connections, and return responses that depend on those
|
||||||
|
* connections for reading the response entity. Such connections
|
||||||
|
* MUST be released, but that is out of the scope of a request director.
|
||||||
|
* The {@link #getConnection getConnection} provides access to the
|
||||||
|
* connection that must be released when the response is handled.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
* This interface and it's implementations replace the
|
* This interface and it's implementations replace the
|
||||||
* <code>HttpMethodDirector</code> in HttpClient 3.
|
* <code>HttpMethodDirector</code> in HttpClient 3.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:rolandw@apache.org">Roland Weber</a>
|
* @author <a href="mailto:rolandw@apache.org">Roland Weber</a>
|
||||||
*
|
*
|
||||||
|
@ -104,22 +104,26 @@ public HttpResponse execute(RoutedRequest roureq, HttpContext context)
|
|||||||
|
|
||||||
HttpResponse response = null;
|
HttpResponse response = null;
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
|
|
||||||
|
try {
|
||||||
while (!done) {
|
while (!done) {
|
||||||
allocateConnection(roureq.getRoute());
|
allocateConnection(roureq.getRoute());
|
||||||
establishRoute(roureq.getRoute(), context);
|
establishRoute(roureq.getRoute(), context);
|
||||||
//@@@ prepare request (authentication)
|
|
||||||
//@@@ will this be done here or via interceptor?
|
|
||||||
|
|
||||||
response = requestExec.execute
|
HttpRequest prepreq = prepareRequest(roureq, context);
|
||||||
(roureq.getRequest(), managedConn, context);
|
//@@@ handle authentication here or via interceptor?
|
||||||
|
|
||||||
RoutedRequest followup = handleResponse(roureq, response, context);
|
response = requestExec.execute(prepreq, managedConn, context);
|
||||||
|
|
||||||
|
RoutedRequest followup =
|
||||||
|
handleResponse(roureq, prepreq, response, context);
|
||||||
if (followup == null) {
|
if (followup == null) {
|
||||||
done = true;
|
done = true;
|
||||||
} else {
|
} else {
|
||||||
|
// check if we can use the same connection for the followup
|
||||||
if ((managedConn != null) &&
|
if ((managedConn != null) &&
|
||||||
!followup.getRoute().equals(roureq.getRoute())) {
|
!followup.getRoute().equals(roureq.getRoute())) {
|
||||||
// the followup has a different route, release connection
|
// the followup has a different route, release conn
|
||||||
//@@@ need to consume response body first?
|
//@@@ need to consume response body first?
|
||||||
//@@@ or let that be done in handleResponse(...)?
|
//@@@ or let that be done in handleResponse(...)?
|
||||||
connManager.releaseConnection(managedConn);
|
connManager.releaseConnection(managedConn);
|
||||||
@ -128,7 +132,10 @@ public HttpResponse execute(RoutedRequest roureq, HttpContext context)
|
|||||||
}
|
}
|
||||||
} // while not done
|
} // while not done
|
||||||
|
|
||||||
//@@@ check response for entity, release connection if possible
|
} finally {
|
||||||
|
// if 'done' is false, we're handling an exception
|
||||||
|
cleanupConnection(done, response);
|
||||||
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|
||||||
@ -194,10 +201,38 @@ protected void establishRoute(HostConfiguration route,
|
|||||||
} // establishConnection
|
} // establishConnection
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares a request for execution.
|
||||||
|
*
|
||||||
|
* @param roureq the request to be sent, along with the route
|
||||||
|
* @param context the context used for the current request execution
|
||||||
|
*
|
||||||
|
* @return the prepared request to send. This can be a different
|
||||||
|
* object than the request stored in <code>roureq</code>.
|
||||||
|
*/
|
||||||
|
protected HttpRequest prepareRequest(RoutedRequest roureq,
|
||||||
|
HttpContext context)
|
||||||
|
throws HttpException {
|
||||||
|
|
||||||
|
HttpRequest prepared = roureq.getRequest();
|
||||||
|
|
||||||
|
//@@@ Instantiate a wrapper to prevent modification of the original
|
||||||
|
//@@@ request object? It might be needed for retries.
|
||||||
|
//@@@ If proxied and non-tunnelled, make sure an absolute URL is
|
||||||
|
//@@@ given in the request line. The target host is in the route.
|
||||||
|
|
||||||
|
return prepared;
|
||||||
|
|
||||||
|
} // prepareRequest
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes a response to check need for a followup.
|
* Analyzes a response to check need for a followup.
|
||||||
*
|
*
|
||||||
* @param roureq the request that was sent
|
* @param roureq the request and route. This is the same object as
|
||||||
|
* was passed to {@link #prepareRequest prepareRequest}.
|
||||||
|
* @param request the request that was actually sent. This is the object
|
||||||
|
* returned by {@link #prepareRequest prepareRequest}.
|
||||||
* @param response the response to analayze
|
* @param response the response to analayze
|
||||||
* @param context the context used for the current request execution
|
* @param context the context used for the current request execution
|
||||||
*
|
*
|
||||||
@ -208,6 +243,7 @@ protected void establishRoute(HostConfiguration route,
|
|||||||
* @throws IOException in case of an IO problem
|
* @throws IOException in case of an IO problem
|
||||||
*/
|
*/
|
||||||
protected RoutedRequest handleResponse(RoutedRequest roureq,
|
protected RoutedRequest handleResponse(RoutedRequest roureq,
|
||||||
|
HttpRequest request,
|
||||||
HttpResponse response,
|
HttpResponse response,
|
||||||
HttpContext context)
|
HttpContext context)
|
||||||
throws HttpException, IOException {
|
throws HttpException, IOException {
|
||||||
@ -224,4 +260,53 @@ protected RoutedRequest handleResponse(RoutedRequest roureq,
|
|||||||
} // handleResponse
|
} // handleResponse
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases the connection if possible.
|
||||||
|
* This method is called from a <code>finally</code> block in
|
||||||
|
* {@link #execute execute}, possibly during exception handling.
|
||||||
|
*
|
||||||
|
* @param success <code>true</code> if a response is to be returned
|
||||||
|
* from {@link #execute execute}, or
|
||||||
|
* <code>false</code> if exception handling is in progress
|
||||||
|
* @param response the response available for return by
|
||||||
|
* {@link #execute execute}, or <code>null</code>
|
||||||
|
*
|
||||||
|
* @throws IOException in case of an IO problem
|
||||||
|
*/
|
||||||
|
protected void cleanupConnection(boolean success, HttpResponse response)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
ManagedClientConnection mcc = managedConn;
|
||||||
|
if (mcc == null)
|
||||||
|
return; // nothing to be cleaned up
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
// not in exception handling, there probably is a response
|
||||||
|
// the connection (if any) is in a re-usable state
|
||||||
|
// check for entity, release connection if possible
|
||||||
|
//@@@ provide hook that allows for entity buffering?
|
||||||
|
if ((response == null) || (response.getEntity() == null) ||
|
||||||
|
!response.getEntity().isStreaming()) {
|
||||||
|
// connection not needed and assumed to be in re-usable state
|
||||||
|
//@@@ evaluate connection re-use strategy, close if necessary
|
||||||
|
managedConn = null;
|
||||||
|
connManager.releaseConnection(mcc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we got here as the result of an exception
|
||||||
|
// no response will be returned, release the connection
|
||||||
|
managedConn = null;
|
||||||
|
//@@@ is the connection in a re-usable state?
|
||||||
|
//@@@ for now, just shut it down
|
||||||
|
try {
|
||||||
|
if (mcc.isOpen())
|
||||||
|
mcc.shutdown();
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
// can't allow exception while handling exception
|
||||||
|
}
|
||||||
|
connManager.releaseConnection(mcc);
|
||||||
|
}
|
||||||
|
} // cleanupConnection
|
||||||
|
|
||||||
|
|
||||||
} // class DefaultClientRequestDirector
|
} // class DefaultClientRequestDirector
|
||||||
|
Loading…
x
Reference in New Issue
Block a user