Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpClient redirecting to URL with spaces throwing exception

I am accessing a URL that's redirecting me to a URL with spaces in it. (Using HttpClient 4.x) How do I prevent this from throwing an error (replacing the spaces with %20 not +)

08-06 02:45:56.486: WARN/System.err(655): org.apache.http.client.ClientProtocolException
08-06 02:45:56.493: WARN/System.err(655):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:557)
08-06 02:45:56.534: WARN/System.err(655):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:509)
08-06 02:45:56.603: WARN/System.err(655):     at com.romcessed.romsearch.searchproviders.DopeRomsConnector$DownloadROMTask.doInBackground(DopeRomsConnector.java:636)
08-06 02:45:56.623: WARN/System.err(655):     at com.romcessed.romsearch.searchproviders.DopeRomsConnector$DownloadROMTask.doInBackground(DopeRomsConnector.java:1)
08-06 02:45:56.643: WARN/System.err(655):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
08-06 02:45:56.663: WARN/System.err(655):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
08-06 02:45:56.683: WARN/System.err(655):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
08-06 02:45:56.693: WARN/System.err(655):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
08-06 02:45:56.713: WARN/System.err(655):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
08-06 02:45:56.713: WARN/System.err(655):     at java.lang.Thread.run(Thread.java:1096)
08-06 02:45:56.743: WARN/System.err(655): Caused by: org.apache.http.ProtocolException: Invalid redirect URI: http://somewebsite.com/some file with spaces.zip
08-06 02:45:56.787: WARN/System.err(655):     at org.apache.http.impl.client.DefaultRedirectHandler.getLocationURI(DefaultRedirectHandler.java:116)
08-06 02:45:56.803: WARN/System.err(655):     at org.apache.http.impl.client.DefaultRequestDirector.handleResponse(DefaultRequestDirector.java:892)
08-06 02:45:56.813: WARN/System.err(655):     at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:457)
08-06 02:45:56.843: WARN/System.err(655):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
08-06 02:45:56.843: WARN/System.err(655):     ... 9 more
08-06 02:45:56.873: WARN/System.err(655): Caused by: java.net.URISyntaxException: Illegal character in path at index #: http://somewebsite.com/some file with spaces.zip
08-06 02:45:56.913: WARN/System.err(655):     at java.net.URI$Helper.validatePath(URI.java:448)
08-06 02:45:56.923: WARN/System.err(655):     at java.net.URI$Helper.parseURI(URI.java:398)
08-06 02:45:56.953: WARN/System.err(655):     at java.net.URI$Helper.access$100(URI.java:302)
08-06 02:45:56.963: WARN/System.err(655):     at java.net.URI.<init>(URI.java:87)
08-06 02:45:56.993: WARN/System.err(655):     at org.apache.http.impl.client.DefaultRedirectHandler.getLocationURI(DefaultRedirectHandler.java:114)
08-06 02:45:57.013: WARN/System.err(655):     ... 12 more
like image 659
Aymon Fournier Avatar asked Aug 06 '10 03:08

Aymon Fournier


4 Answers

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);
like image 190
Trevor Johns Avatar answered Nov 17 '22 12:11

Trevor Johns


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;
                }
        }
like image 12
Aymon Fournier Avatar answered Nov 17 '22 10:11

Aymon Fournier


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
like image 3
expert Avatar answered Nov 17 '22 12:11

expert


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;
}
like image 2
Jakob Eriksson Avatar answered Nov 17 '22 10:11

Jakob Eriksson