* Added handling of exceptions to the HttpClient#execute methods that take a ResponseHandler as a parameter
* Modified AbstractVerifier to use log instead of printStackTrace() * Modified BasicResponseHandler to always throw an exception when status >= 300, even if entity == null * Fixed concurrency problem in ConnectionPoolByRoute. Before this change, the RouteSpecificPool could be removed between the time that the waiting thread was notified and it actually woke up. The code was modified to not remove the thread from the RSP until it wakes up, so pool.isUnused() returns false when a thread is actually still waiting. * Reordered date patterns in DateUtils. Someone claimed this enhanced performance. * Small Javadoc fix in NetscapeDraftSpec * Modified RFC2109Spec#formatCookies() to not modify the passed in list (it could be unmodifiable) Contributed by Bob Lee <crazybob at crazybob.org> Reviewed by Oleg Kalnichevski git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@677240 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9126cd2183
commit
e410739b7d
|
@ -32,7 +32,6 @@ package org.apache.http.client;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
|
||||
/**
|
||||
|
@ -49,11 +48,6 @@ public interface ResponseHandler<T> {
|
|||
* Processes an {@link HttpResponse} and returns some value
|
||||
* corresponding to that response.
|
||||
*
|
||||
* Implementations should make an effort to ensure that the
|
||||
* response {@link HttpEntity} is fully consumed before
|
||||
* returning from this method or document that users
|
||||
* must consume the entity.
|
||||
*
|
||||
* @param response The response to process
|
||||
* @return A value determined by the response
|
||||
*
|
||||
|
|
|
@ -45,6 +45,8 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
@ -299,8 +301,8 @@ public abstract class AbstractVerifier implements X509HostnameVerifier {
|
|||
c = cert.getSubjectAlternativeNames();
|
||||
}
|
||||
catch(CertificateParsingException cpe) {
|
||||
// Should probably log.debug() this?
|
||||
cpe.printStackTrace();
|
||||
Logger.getLogger(AbstractVerifier.class.getName())
|
||||
.log(Level.FINE, "Error parsing certificate.", cpe);
|
||||
}
|
||||
if(c != null) {
|
||||
for (List<?> aC : c) {
|
||||
|
|
|
@ -33,7 +33,10 @@ package org.apache.http.impl.client;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.ConnectionReuseStrategy;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpHost;
|
||||
|
@ -41,6 +44,7 @@ import org.apache.http.HttpRequest;
|
|||
import org.apache.http.HttpRequestInterceptor;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpResponseInterceptor;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.auth.AuthSchemeRegistry;
|
||||
import org.apache.http.client.AuthenticationHandler;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
|
@ -78,6 +82,8 @@ import org.apache.http.protocol.HttpRequestExecutor;
|
|||
*/
|
||||
public abstract class AbstractHttpClient implements HttpClient {
|
||||
|
||||
private final Log log = LogFactory.getLog(getClass());
|
||||
|
||||
/** The parameters. */
|
||||
private HttpParams defaultParams;
|
||||
|
||||
|
@ -479,22 +485,24 @@ public abstract class AbstractHttpClient implements HttpClient {
|
|||
("Request must not be null.");
|
||||
}
|
||||
|
||||
return execute(determineTarget(request), request, context);
|
||||
}
|
||||
|
||||
private HttpHost determineTarget(HttpUriRequest request) {
|
||||
// A null target may be acceptable if there is a default target.
|
||||
// Otherwise, the null target is detected in the director.
|
||||
HttpHost target = null;
|
||||
|
||||
|
||||
URI requestURI = request.getURI();
|
||||
if (requestURI.isAbsolute()) {
|
||||
target = new HttpHost(
|
||||
requestURI.getHost(),
|
||||
requestURI.getPort(),
|
||||
requestURI.getHost(),
|
||||
requestURI.getPort(),
|
||||
requestURI.getScheme());
|
||||
}
|
||||
|
||||
return execute(target, request, context);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
// non-javadoc, see interface HttpClient
|
||||
public final HttpResponse execute(HttpHost target, HttpRequest request)
|
||||
throws IOException, ClientProtocolException {
|
||||
|
@ -619,12 +627,7 @@ public abstract class AbstractHttpClient implements HttpClient {
|
|||
final HttpUriRequest request,
|
||||
final ResponseHandler<? extends T> responseHandler)
|
||||
throws IOException, ClientProtocolException {
|
||||
if (responseHandler == null) {
|
||||
throw new IllegalArgumentException
|
||||
("Response handler must not be null.");
|
||||
}
|
||||
HttpResponse response = execute(request);
|
||||
return responseHandler.handleResponse(response);
|
||||
return execute(request, responseHandler, null);
|
||||
}
|
||||
|
||||
|
||||
|
@ -634,12 +637,8 @@ public abstract class AbstractHttpClient implements HttpClient {
|
|||
final ResponseHandler<? extends T> responseHandler,
|
||||
final HttpContext context)
|
||||
throws IOException, ClientProtocolException {
|
||||
if (responseHandler == null) {
|
||||
throw new IllegalArgumentException
|
||||
("Response handler must not be null.");
|
||||
}
|
||||
HttpResponse response = execute(request, context);
|
||||
return responseHandler.handleResponse(response);
|
||||
HttpHost target = determineTarget(request);
|
||||
return execute(target, request, responseHandler, context);
|
||||
}
|
||||
|
||||
|
||||
|
@ -649,12 +648,7 @@ public abstract class AbstractHttpClient implements HttpClient {
|
|||
final HttpRequest request,
|
||||
final ResponseHandler<? extends T> responseHandler)
|
||||
throws IOException, ClientProtocolException {
|
||||
if (responseHandler == null) {
|
||||
throw new IllegalArgumentException
|
||||
("Response handler must not be null.");
|
||||
}
|
||||
HttpResponse response = execute(target, request);
|
||||
return responseHandler.handleResponse(response);
|
||||
return execute(target, request, responseHandler, null);
|
||||
}
|
||||
|
||||
|
||||
|
@ -669,8 +663,48 @@ public abstract class AbstractHttpClient implements HttpClient {
|
|||
throw new IllegalArgumentException
|
||||
("Response handler must not be null.");
|
||||
}
|
||||
|
||||
HttpResponse response = execute(target, request, context);
|
||||
return responseHandler.handleResponse(response);
|
||||
|
||||
T result;
|
||||
try {
|
||||
result = responseHandler.handleResponse(response);
|
||||
} catch (Throwable t) {
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity != null) {
|
||||
try {
|
||||
entity.consumeContent();
|
||||
} catch (Throwable t2) {
|
||||
// Log this exception. The original exception is more
|
||||
// important and will be thrown to the caller.
|
||||
this.log.warn("Error consuming content after an exception.", t2);
|
||||
}
|
||||
}
|
||||
|
||||
if (t instanceof Error) {
|
||||
throw (Error) t;
|
||||
}
|
||||
|
||||
if (t instanceof RuntimeException) {
|
||||
throw (RuntimeException) t;
|
||||
}
|
||||
|
||||
if (t instanceof IOException) {
|
||||
throw (IOException) t;
|
||||
}
|
||||
|
||||
throw new UndeclaredThrowableException(t);
|
||||
}
|
||||
|
||||
// Handling the response was successful. Ensure that the content has
|
||||
// been fully consumed.
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity != null) {
|
||||
// Let this exception go to the caller.
|
||||
entity.consumeContent();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import java.io.IOException;
|
|||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.ResponseHandler;
|
||||
import org.apache.http.client.HttpResponseException;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
@ -47,7 +46,8 @@ import org.apache.http.util.EntityUtils;
|
|||
* body is consumed and an {@link HttpResponseException} is thrown.
|
||||
*
|
||||
* If this is used with
|
||||
* {@link HttpClient#execute(org.apache.http.client.methods.HttpUriRequest, ClientResponseHandler),
|
||||
* {@link org.apache.http.client.HttpClient#execute(
|
||||
* org.apache.http.client.methods.HttpUriRequest, ResponseHandler),
|
||||
* HttpClient may handle redirects (3xx responses) internally.
|
||||
*
|
||||
* @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
|
||||
|
@ -64,20 +64,16 @@ public class BasicResponseHandler implements ResponseHandler<String> {
|
|||
* response was unsuccessful (>= 300 status code), throws an
|
||||
* {@link HttpResponseException}.
|
||||
*/
|
||||
public String handleResponse(
|
||||
final HttpResponse response) throws ClientProtocolException, IOException {
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity != null) {
|
||||
StatusLine statusLine = response.getStatusLine();
|
||||
if (statusLine.getStatusCode() >= 300) {
|
||||
entity.consumeContent();
|
||||
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
|
||||
} else {
|
||||
return EntityUtils.toString(entity);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
public String handleResponse(final HttpResponse response)
|
||||
throws HttpResponseException, IOException {
|
||||
StatusLine statusLine = response.getStatusLine();
|
||||
if (statusLine.getStatusCode() >= 300) {
|
||||
throw new HttpResponseException(statusLine.getStatusCode(),
|
||||
statusLine.getReasonPhrase());
|
||||
}
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
return entity == null ? null : EntityUtils.toString(entity);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -343,14 +343,8 @@ public class ConnPoolByRoute extends AbstractConnPool {
|
|||
// connection pool and should now have a connection
|
||||
// waiting for us, or else we're shutting down.
|
||||
// Just continue in the loop, both cases are checked.
|
||||
if (!success) {
|
||||
// Either we timed out, experienced a
|
||||
// "spurious wakeup", or were interrupted by
|
||||
// an external thread. Regardless, we need to
|
||||
// cleanup for ourselves in the wait queue.
|
||||
rospl.removeThread(waitingThread);
|
||||
waitingThreads.remove(waitingThread);
|
||||
}
|
||||
rospl.removeThread(waitingThread);
|
||||
waitingThreads.remove(waitingThread);
|
||||
}
|
||||
|
||||
// check for spurious wakeup vs. timeout
|
||||
|
@ -622,16 +616,12 @@ public class ConnPoolByRoute extends AbstractConnPool {
|
|||
log.debug("Notifying thread waiting on pool" +
|
||||
" [" + rospl.getRoute() + "]");
|
||||
}
|
||||
waitingThread = rospl.dequeueThread();
|
||||
waitingThreads.remove(waitingThread);
|
||||
|
||||
waitingThread = rospl.nextThread();
|
||||
} else if (!waitingThreads.isEmpty()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Notifying thread waiting on any pool");
|
||||
}
|
||||
waitingThread = waitingThreads.remove();
|
||||
waitingThread.getPool().removeThread(waitingThread);
|
||||
|
||||
} else if (log.isDebugEnabled()) {
|
||||
log.debug("Notifying no-one, there are no waiting threads");
|
||||
}
|
||||
|
|
|
@ -276,12 +276,12 @@ public class RouteSpecificPool {
|
|||
|
||||
|
||||
/**
|
||||
* Obtains and removes a waiting thread.
|
||||
* Returns the next thread in the queue.
|
||||
*
|
||||
* @return a waiting thread, or <code>null</code> if there is none
|
||||
*/
|
||||
public WaitingThread dequeueThread() {
|
||||
return this.waitingThreads.poll();
|
||||
public WaitingThread nextThread() {
|
||||
return this.waitingThreads.peek();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -67,11 +67,12 @@ public final class DateUtils {
|
|||
*/
|
||||
public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
|
||||
|
||||
private static final String[] DEFAULT_PATTERNS = new String[] {
|
||||
PATTERN_ASCTIME,
|
||||
PATTERN_RFC1036,
|
||||
PATTERN_RFC1123 };
|
||||
|
||||
private static final String[] DEFAULT_PATTERNS = new String[] {
|
||||
PATTERN_RFC1036,
|
||||
PATTERN_RFC1123,
|
||||
PATTERN_ASCTIME
|
||||
};
|
||||
|
||||
private static final Date DEFAULT_TWO_DIGIT_YEAR_START;
|
||||
|
||||
public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
|
||||
|
|
|
@ -109,8 +109,9 @@ public class NetscapeDraftSpec extends CookieSpecBase {
|
|||
* character may be present in unquoted cookie value or unquoted
|
||||
* parameter value.</p>
|
||||
*
|
||||
* @link http://wp.netscape.com/newsref/std/cookie_spec.html
|
||||
*
|
||||
* @see <a href="http://wp.netscape.com/newsref/std/cookie_spec.html">
|
||||
* The Cookie Spec.</a>
|
||||
*
|
||||
* @param header the <tt>Set-Cookie</tt> received from the server
|
||||
* @return an array of <tt>Cookie</tt>s parsed from the Set-Cookie value
|
||||
* @throws MalformedCookieException if an exception occurs during parsing
|
||||
|
|
|
@ -128,14 +128,18 @@ public class RFC2109Spec extends CookieSpecBase {
|
|||
super.validate(cookie, origin);
|
||||
}
|
||||
|
||||
public List<Header> formatCookies(final List<Cookie> cookies) {
|
||||
public List<Header> formatCookies(List<Cookie> cookies) {
|
||||
if (cookies == null) {
|
||||
throw new IllegalArgumentException("List of cookies may not be null");
|
||||
}
|
||||
if (cookies.isEmpty()) {
|
||||
throw new IllegalArgumentException("List of cookies may not be empty");
|
||||
}
|
||||
Collections.sort(cookies, PATH_COMPARATOR);
|
||||
if (cookies.size() > 1) {
|
||||
// Create a mutable copy and sort the copy.
|
||||
cookies = new ArrayList<Cookie>(cookies);
|
||||
Collections.sort(cookies, PATH_COMPARATOR);
|
||||
}
|
||||
if (this.oneHeader) {
|
||||
return doFormatOneHeader(cookies);
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue