HTTPCLIENT-1351: Added utility method to resolve final location from original request, target host and a list of redirects

Contributed by James Leigh <james at 3roundstones.com>

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1487413 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2013-05-29 09:04:54 +00:00
parent 26ee6689f3
commit eeaec64f5c
5 changed files with 150 additions and 2 deletions

View File

@ -4,7 +4,8 @@ Changes since release 4.3 BETA1
* [HTTPCLIENT-1354] do not quote algorithm parameter in DIGEST auth response.
Contributed by Oleg Kalnichevski <olegk at apache.org>
* [HTTPCLIENT-1351] Preserve last request URI in the execution context.
* [HTTPCLIENT-1351] Added utility method to resolve final location from original request,
target host and a list of redirects.
Contributed by James Leigh <james at 3roundstones.com>
* [HTTPCLIENT-1344] Userinfo credentials in URI should not default to preemptive BASIC

View File

@ -28,11 +28,13 @@ package org.apache.http.client.utils;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
import org.apache.http.HttpHost;
import org.apache.http.annotation.Immutable;
import org.apache.http.client.URICollection;
import org.apache.http.util.Args;
import org.apache.http.util.TextUtils;
@ -349,6 +351,52 @@ public class URIUtils {
return target;
}
/**
* Derives the interpreted (absolute) URI that was used to generate the last
* request. This is done by extracting the request-uri and target origin for
* the last request and scanning all the redirect locations for the last
* fragment identifier, then combining the result into a {@link URI}.
*
* @param originalURI
* original request before any redirects
* @param target
* if the last URI is relative, it is resolved against this target,
* or <code>null</code> if not available.
* @param redirects
* collection of redirect locations since the original request
* or <code>null</code> if not available.
* @return interpreted (absolute) URI
*/
public static URI resolve(
final URI originalURI,
final HttpHost target,
final List<URI> redirects) throws URISyntaxException {
Args.notNull(originalURI, "Request URI");
final URIBuilder uribuilder;
if (redirects == null || redirects.isEmpty()) {
uribuilder = new URIBuilder(originalURI);
} else {
uribuilder = new URIBuilder(redirects.get(redirects.size() - 1));
String frag = uribuilder.getFragment();
// read interpreted fragment identifier from redirect locations
for (int i = redirects.size() - 1; frag == null && i >= 0; i--) {
frag = redirects.get(i).getFragment();
}
uribuilder.setFragment(frag);
}
// read interpreted fragment identifier from original request
if (uribuilder.getFragment() == null) {
uribuilder.setFragment(originalURI.getFragment());
}
// last target origin
if (target != null && !uribuilder.isAbsolute()) {
uribuilder.setScheme(target.getSchemeName());
uribuilder.setHost(target.getHostName());
uribuilder.setPort(target.getPort());
}
return uribuilder.build();
}
/**
* This class should not be instantiated.
*/

View File

@ -27,8 +27,19 @@
package org.apache.http.client.utils;
import java.net.URI;
import java.util.Arrays;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.protocol.HttpCoreContext;
import org.junit.Assert;
import org.junit.Test;
@ -203,4 +214,68 @@ public class TestURIUtils {
URIUtils.extractHost(new URI("http://localhost:;sessionid=stuff/abcd")));
}
@Test
public void testHttpLocationWithRelativeFragment() throws Exception {
final HttpHost target = new HttpHost("localhost", -1, "http");
final URI requestURI = new URI("/stuff#blahblah");
final URI location = URIUtils.resolve(requestURI, target, null);
final URI expectedURI = new URIBuilder(requestURI)
.setHost(target.getHostName())
.setScheme(target.getSchemeName())
.build();
Assert.assertEquals(expectedURI, location);
}
@Test
public void testHttpLocationWithAbsoluteFragment() throws Exception {
final HttpHost target = new HttpHost("localhost", 80, "http");
final URI requestURI = new URIBuilder()
.setHost(target.getHostName())
.setScheme(target.getSchemeName())
.setPath("/stuff")
.setFragment("blahblah")
.build();
final URI location = URIUtils.resolve(requestURI, target, null);
final URI expectedURI = requestURI;
Assert.assertEquals(expectedURI, location);
}
@Test
public void testHttpLocationRedirect() throws Exception {
final HttpHost target = new HttpHost("localhost", -1, "http");
final URI requestURI = new URI("/People.htm#tim");
final URI redirect = new URI("http://localhost/people.html");
final URI location = URIUtils.resolve(requestURI, target, Arrays.asList(redirect));
final URI expectedURI = new URIBuilder()
.setHost(target.getHostName())
.setScheme(target.getSchemeName())
.setPath("/people.html")
.setFragment("tim")
.build();
Assert.assertEquals(expectedURI, location);
}
@Test
public void testHttpLocationWithRedirectFragment() throws Exception {
final HttpHost target = new HttpHost("localhost", -1, "http");
final URI requestURI = new URI("/~tim");
final URI redirect1 = new URI("http://localhost/People.htm#tim");
final URI redirect2 = new URI("http://localhost/people.html");
final URI location = URIUtils.resolve(requestURI, target, Arrays.asList(redirect1, redirect2));
final URI expectedURI = new URIBuilder()
.setHost(target.getHostName())
.setScheme(target.getSchemeName())
.setPath("/people.html")
.setFragment("tim")
.build();
Assert.assertEquals(expectedURI, location);
}
}

View File

@ -41,10 +41,12 @@ import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.NonRepeatableRequestException;
import org.apache.http.client.URICollection;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
@ -256,8 +258,13 @@ public class TestClientRequestExecution extends IntegrationTestBase {
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
EntityUtils.consume(response.getEntity());
final HttpRequest request = (HttpRequest) context.getAttribute(HttpCoreContext.HTTP_REQUEST);
final HttpRequest request = context.getRequest();
Assert.assertEquals("/stuff", request.getRequestLine().getUri());
final URICollection redirectLocations = context.getRedirectLocations();
final URI location = URIUtils.resolve(uri, target,
redirectLocations != null ? redirectLocations.getAll() : null);
Assert.assertEquals(uri, location);
}
}

17
src/docbkx/httpagent.xml Normal file → Executable file
View File

@ -205,6 +205,23 @@ HttpUriRequest req = (HttpUriRequest) localContext.getAttribute(
System.out.println("Target host: " + target);
System.out.println("Final request URI: " + req.getURI()); // relative URI (no proxy used)
System.out.println("Final request method: " + req.getMethod());
]]></programlisting>
<para>The final interpreted absolute HTTP location can be built using the original request
and the context. The utility method URIUtils.resolve(URI,HttpHost,URICollection)
can be used to build the interpreted absolute URI used to generate the final request.
This method includes the last fragment identifier from the redirect requests or
the original request.</para>
<programlisting><![CDATA[
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = new HttpGet("http://localhost:8080/");
HttpResponse response = httpclient.execute(httpget, context);
HttpHost target = context.getTargetHost();
URICollection redirectLocations = context.getRedirectLocations();
URI location = URIUtils.resolve(httpget.getURI(), target,
redirectLocations != null ? redirectLocations.getAll() : null);
System.out.println("Final HTTP location: " + location.toASCIIString()); // absolute URI
]]></programlisting>
</section>
<section>