HTTPCLIENT-1542: Caching HttpClient uses absolute URIs for validation

Based on contribution by Joseph Walton <joe at kafsemo.org>

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1618324 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2014-08-16 10:51:35 +00:00
parent d5e17d7ec0
commit 683bb070fd
6 changed files with 86 additions and 25 deletions

View File

@ -27,6 +27,8 @@
package org.apache.http.impl.client.cache; package org.apache.http.impl.client.cache;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -44,6 +46,7 @@ import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion; import org.apache.http.HttpVersion;
import org.apache.http.ProtocolException;
import org.apache.http.ProtocolVersion; import org.apache.http.ProtocolVersion;
import org.apache.http.RequestLine; import org.apache.http.RequestLine;
import org.apache.http.annotation.ThreadSafe; import org.apache.http.annotation.ThreadSafe;
@ -58,6 +61,7 @@ import org.apache.http.client.methods.HttpExecutionAware;
import org.apache.http.client.methods.HttpRequestWrapper; import org.apache.http.client.methods.HttpRequestWrapper;
import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.DateUtils; import org.apache.http.client.utils.DateUtils;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.impl.execchain.ClientExecChain; import org.apache.http.impl.execchain.ClientExecChain;
import org.apache.http.message.BasicHttpResponse; import org.apache.http.message.BasicHttpResponse;
@ -738,6 +742,14 @@ public class CachingExec implements ClientExecChain {
final HttpCacheEntry cacheEntry) throws IOException, HttpException { final HttpCacheEntry cacheEntry) throws IOException, HttpException {
final HttpRequestWrapper conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(request, cacheEntry); final HttpRequestWrapper conditionalRequest = conditionalRequestBuilder.buildConditionalRequest(request, cacheEntry);
final URI uri = conditionalRequest.getURI();
if (uri != null) {
try {
request.setURI(URIUtils.rewriteURIForRoute(uri, route));
} catch (final URISyntaxException ex) {
throw new ProtocolException("Invalid URI: " + uri, ex);
}
}
Date requestDate = getCurrentDate(); Date requestDate = getCurrentDate();
CloseableHttpResponse backendResponse = backend.execute( CloseableHttpResponse backendResponse = backend.execute(

View File

@ -93,6 +93,8 @@ public class TestHttpCacheJiraNumber1147 {
final HttpHost target = new HttpHost("somehost"); final HttpHost target = new HttpHost("somehost");
final HttpRoute route = new HttpRoute(target); final HttpRoute route = new HttpRoute(target);
context.setTargetHost(target);
final Date now = new Date(); final Date now = new Date();
final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);

View File

@ -34,6 +34,7 @@ import java.util.Stack;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.apache.http.annotation.Immutable; import org.apache.http.annotation.Immutable;
import org.apache.http.conn.routing.RouteInfo;
import org.apache.http.util.Args; import org.apache.http.util.Args;
import org.apache.http.util.TextUtils; import org.apache.http.util.TextUtils;
@ -195,6 +196,39 @@ public class URIUtils {
return uribuilder.build(); return uribuilder.build();
} }
/**
* A convenience method that optionally converts the original {@link java.net.URI} either
* to a relative or an absolute form as required by the specified route.
*
* @param uri
* original URI.
* @throws URISyntaxException
* If the resulting URI is invalid.
*
* @since 4.4
*/
public static URI rewriteURIForRoute(final URI uri, final RouteInfo route) throws URISyntaxException {
if (uri == null) {
return null;
}
if (route.getProxyHost() != null && !route.isTunnelled()) {
// Make sure the request URI is absolute
if (!uri.isAbsolute()) {
final HttpHost target = route.getTargetHost();
return rewriteURI(uri, target, true);
} else {
return rewriteURI(uri);
}
} else {
// Make sure the request URI is relative
if (uri.isAbsolute()) {
return rewriteURI(uri, null, true);
} else {
return rewriteURI(uri);
}
}
}
/** /**
* Resolves a URI reference against a base URI. Work-around for bug in * Resolves a URI reference against a base URI. Work-around for bug in
* java.net.URI (<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>) * java.net.URI (<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)

View File

@ -87,29 +87,13 @@ public class ProtocolExec implements ClientExecChain {
void rewriteRequestURI( void rewriteRequestURI(
final HttpRequestWrapper request, final HttpRequestWrapper request,
final HttpRoute route) throws ProtocolException { final HttpRoute route) throws ProtocolException {
try { final URI uri = request.getURI();
URI uri = request.getURI(); if (uri != null) {
if (uri != null) { try {
if (route.getProxyHost() != null && !route.isTunnelled()) { request.setURI(URIUtils.rewriteURIForRoute(uri, route));
// Make sure the request URI is absolute } catch (final URISyntaxException ex) {
if (!uri.isAbsolute()) { throw new ProtocolException("Invalid URI: " + uri, ex);
final HttpHost target = route.getTargetHost();
uri = URIUtils.rewriteURI(uri, target, true);
} else {
uri = URIUtils.rewriteURI(uri);
}
} else {
// Make sure the request URI is relative
if (uri.isAbsolute()) {
uri = URIUtils.rewriteURI(uri, null, true);
} else {
uri = URIUtils.rewriteURI(uri);
}
}
request.setURI(uri);
} }
} catch (final URISyntaxException ex) {
throw new ProtocolException("Invalid URI: " + request.getRequestLine().getUri(), ex);
} }
} }

View File

@ -30,6 +30,7 @@ import java.net.URI;
import java.util.Arrays; import java.util.Arrays;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.apache.http.conn.routing.HttpRoute;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -100,6 +101,34 @@ public class TestURIUtils {
URI.create("http://thishost:80/stuff#crap"), target, true).toString()); URI.create("http://thishost:80/stuff#crap"), target, true).toString());
} }
@Test
public void testRewriteForRoute() throws Exception {
final HttpHost target1 = new HttpHost("foo", 80);
final HttpHost target2 = new HttpHost("foo", 443, "https");
final HttpHost proxy = new HttpHost("bar", 8888);
// Direct route
Assert.assertEquals(new URI("/test"), URIUtils
.rewriteURIForRoute(new URI("http://foo/test"), new HttpRoute(target1)));
// Direct route
Assert.assertEquals(new URI("/"), URIUtils
.rewriteURIForRoute(new URI(""), new HttpRoute(target1)));
// Via proxy
Assert.assertEquals(new URI("http://foo/test"), URIUtils
.rewriteURIForRoute(new URI("http://foo/test"), new HttpRoute(target1, proxy)));
// Via proxy
Assert.assertEquals(new URI("http://foo:80/test"), URIUtils
.rewriteURIForRoute(new URI("/test"), new HttpRoute(target1, proxy)));
// Via proxy tunnel
Assert.assertEquals(new URI("/test"), URIUtils
.rewriteURIForRoute(new URI("https://foo:443/test"), new HttpRoute(target2, null, proxy, true)));
}
@Test @Test
public void testNormalization() { public void testNormalization() {
Assert.assertEquals("example://a/b/c/%7Bfoo%7D", URIUtils.resolve(this.baseURI, "eXAMPLE://a/./b/../b/%63/%7bfoo%7d").toString()); Assert.assertEquals("example://a/b/c/%7Bfoo%7D", URIUtils.resolve(this.baseURI, "eXAMPLE://a/./b/../b/%63/%7bfoo%7d").toString());

View File

@ -26,6 +26,9 @@
*/ */
package org.apache.http.impl.execchain; package org.apache.http.impl.execchain;
import java.io.IOException;
import java.net.URI;
import org.apache.http.HttpException; import org.apache.http.HttpException;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthScope;
@ -47,9 +50,6 @@ import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.io.IOException;
import java.net.URI;
@SuppressWarnings({"static-access"}) // test code @SuppressWarnings({"static-access"}) // test code
public class TestProtocolExec { public class TestProtocolExec {