2010-08-06 18 views
11

J'accède à une URL qui me redirige vers une URL contenant des espaces. (À l'aide HttpClient 4.x) Comment puis-je empêcher cela de jeter une erreur (en remplaçant les espaces avec 20% non +)HttpClient redirigeant vers une URL avec des espaces émettant une exception

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 

Répondre

17

La bibliothèque HTTP Apache vous permet d'enregistrer un objet RedirectHandler qui se invoqué chaque fois qu'une redirection se produit. Vous pouvez l'utiliser pour intercepter la redirection et la corriger.

(Cela étant dit, le site qui vous envoie cette redirection est cassé. Vous devez les contacter et leur faire savoir.)

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); 
+7

'setRedirectHandler' est maintenant abandonné au profit de' RedirectStrategy'. –

12

Voici mon code de travail :)

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; 
       } 
     } 
2

Un autre exemple de code de travail qui remplacera les espaces avec% 20, basé sur 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; 
} 
+0

Je suppose que cette solution ne fonctionne pas pour l'adresse uri relative. – Ales

0

Je recommande la création d'une stratégie de redirection personnalisée

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 
    } 
    } 
} 

que vous pouvez définir dans votre client via la méthode setRedirectStrategy.

HttpAsyncClients.custom.setRedirectStrategy(new CustomRedirectStrategy).build