HttpClient redirecting to URL with spaces throwing exception
Here is my working code :)
class spaceRedirectHandler extends DefaultRedirectHandler{
private static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";
public spaceRedirectHandler() {
super();
}
public boolean isRedirectRequested(
final HttpResponse response,
final HttpContext context) {
if (response == null) {
throw new IllegalArgumentException("HTTP response may not be null");
}
int statusCode = response.getStatusLine().getStatusCode();
switch (statusCode) {
case HttpStatus.SC_MOVED_TEMPORARILY:
case HttpStatus.SC_MOVED_PERMANENTLY:
case HttpStatus.SC_SEE_OTHER:
case HttpStatus.SC_TEMPORARY_REDIRECT:
return true;
default:
return false;
} //end of switch
}
public URI getLocationURI(
final HttpResponse response,
final HttpContext context) throws ProtocolException {
if (response == null) {
throw new IllegalArgumentException("HTTP response may not be null");
}
//get the location header to find out where to redirect to
Header locationHeader = response.getFirstHeader("location");
if (locationHeader == null) {
// got a redirect response, but no location header
throw new ProtocolException(
"Received redirect response " + response.getStatusLine()
+ " but no location header");
}
//HERE IS THE MODIFIED LINE OF CODE
String location = locationHeader.getValue().replaceAll (" ", "%20");
URI uri;
try {
uri = new URI(location);
} catch (URISyntaxException ex) {
throw new ProtocolException("Invalid redirect URI: " + location, ex);
}
HttpParams params = response.getParams();
// rfc2616 demands the location value be a complete URI
// Location = "Location" ":" absoluteURI
if (!uri.isAbsolute()) {
if (params.isParameterTrue(ClientPNames.REJECT_RELATIVE_REDIRECT)) {
throw new ProtocolException("Relative redirect location '"
+ uri + "' not allowed");
}
// Adjust location URI
HttpHost target = (HttpHost) context.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
if (target == null) {
throw new IllegalStateException("Target host not available " +
"in the HTTP context");
}
HttpRequest request = (HttpRequest) context.getAttribute(
ExecutionContext.HTTP_REQUEST);
try {
URI requestURI = new URI(request.getRequestLine().getUri());
URI absoluteRequestURI = URIUtils.rewriteURI(requestURI, target, true);
uri = URIUtils.resolve(absoluteRequestURI, uri);
} catch (URISyntaxException ex) {
throw new ProtocolException(ex.getMessage(), ex);
}
}
if (params.isParameterFalse(ClientPNames.ALLOW_CIRCULAR_REDIRECTS)) {
RedirectLocations redirectLocations = (RedirectLocations) context.getAttribute(
REDIRECT_LOCATIONS);
if (redirectLocations == null) {
redirectLocations = new RedirectLocations();
context.setAttribute(REDIRECT_LOCATIONS, redirectLocations);
}
URI redirectURI;
if (uri.getFragment() != null) {
try {
HttpHost target = new HttpHost(
uri.getHost(),
uri.getPort(),
uri.getScheme());
redirectURI = URIUtils.rewriteURI(uri, target, true);
} catch (URISyntaxException ex) {
throw new ProtocolException(ex.getMessage(), ex);
}
} else {
redirectURI = uri;
}
if (redirectLocations.contains(redirectURI)) {
throw new CircularRedirectException("Circular redirect to '" +
redirectURI + "'");
} else {
redirectLocations.add(redirectURI);
}
}
return uri;
}
}
Another working code example that will replace spaces with %20, based on https://stackoverflow.com/a/8962879/956415
private download(){
...
mHttpClient = new DefaultHttpClient(httpParams);
mHttpClient.setRedirectHandler(new DefaultRedirectHandler() {
@Override
public boolean isRedirectRequested(HttpResponse httpResponse, HttpContext httpContext) {
return super.isRedirectRequested(httpResponse, httpContext);
}
@Override
public URI getLocationURI(HttpResponse httpResponse, HttpContext httpContext) throws ProtocolException {
return sanitizeUrl(httpResponse.getFirstHeader("location").getValue());
}
});
}
private URI sanitizeUrl(String sanitizeURL) throws ProtocolException {
URI uri = null;
try {
URL url = new URL(URLDecoder.decode(sanitizeURL, UTF_8));
// https://stackoverflow.com/a/8962879/956415
uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
} catch (URISyntaxException | MalformedURLException | UnsupportedEncodingException e) {
throw new ProtocolException(e.getMessage(), e);
}
return uri;
}
I recommend creating custom redirect strategy
class CustomRedirectStrategy extends DefaultRedirectStrategy {
// NOTE: Hack for bad redirects such as: http://www.healio.com/Rss/Allergy%20Immunology
override def createLocationURI(location: String): URI = {
try {
super.createLocationURI(location)
} catch {
case ex: ProtocolException =>
val url = new URL(location)
val uri = new URI(url.getProtocol, url.getUserInfo, url.getHost, url.getPort, url.getPath, url.getQuery, url.getRef)
uri
}
}
}
that you can set in your client via setRedirectStrategy
method.
HttpAsyncClients.custom.setRedirectStrategy(new CustomRedirectStrategy).build
The Apache HTTP library allows you to register a RedirectHandler object that will get invoked whenever a redirect occurs. You can use this to intercept the redirect and fix it.
(That being said, the site that's sending you this redirect is broken. You should contact them and let them know.)
class CustomRedirectHandler extends DefaultRedirectHandler {
public URI getLocationURI(HttpResponse response, HttpContext context) {
// Extract the Location: header and manually convert spaces to %20's
// Return the corrected URI
}
}
DefaultHttpClient httpClient = new DefaultHttpClient();
RedirectHandler customRedirectHandler = new CustomRedirectHandler();
//...
httpClient.setRedirectHandler(customRedirectHandler);