Home | History | Annotate | Download | only in client
      1 /*
      2  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultRedirectHandler.java $
      3  * $Revision: 673450 $
      4  * $Date: 2008-07-02 10:35:05 -0700 (Wed, 02 Jul 2008) $
      5  *
      6  * ====================================================================
      7  * Licensed to the Apache Software Foundation (ASF) under one
      8  * or more contributor license agreements.  See the NOTICE file
      9  * distributed with this work for additional information
     10  * regarding copyright ownership.  The ASF licenses this file
     11  * to you under the Apache License, Version 2.0 (the
     12  * "License"); you may not use this file except in compliance
     13  * with the License.  You may obtain a copy of the License at
     14  *
     15  *   http://www.apache.org/licenses/LICENSE-2.0
     16  *
     17  * Unless required by applicable law or agreed to in writing,
     18  * software distributed under the License is distributed on an
     19  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     20  * KIND, either express or implied.  See the License for the
     21  * specific language governing permissions and limitations
     22  * under the License.
     23  * ====================================================================
     24  *
     25  * This software consists of voluntary contributions made by many
     26  * individuals on behalf of the Apache Software Foundation.  For more
     27  * information on the Apache Software Foundation, please see
     28  * <http://www.apache.org/>.
     29  *
     30  */
     31 
     32 package org.apache.http.impl.client;
     33 
     34 import java.net.URI;
     35 import java.net.URISyntaxException;
     36 
     37 import org.apache.commons.logging.Log;
     38 import org.apache.commons.logging.LogFactory;
     39 import org.apache.http.Header;
     40 import org.apache.http.HttpHost;
     41 import org.apache.http.HttpRequest;
     42 import org.apache.http.HttpResponse;
     43 import org.apache.http.HttpStatus;
     44 import org.apache.http.ProtocolException;
     45 import org.apache.http.client.CircularRedirectException;
     46 import org.apache.http.client.RedirectHandler;
     47 import org.apache.http.client.params.ClientPNames;
     48 import org.apache.http.client.utils.URIUtils;
     49 import org.apache.http.params.HttpParams;
     50 import org.apache.http.protocol.HttpContext;
     51 import org.apache.http.protocol.ExecutionContext;
     52 
     53 
     54 /**
     55  * Default implementation of {@link RedirectHandler}.
     56  *
     57  * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
     58  *
     59  *
     60  * <!-- empty lines to avoid svn diff problems -->
     61  * @version $Revision: 673450 $
     62  *
     63  * @since 4.0
     64  */
     65 public class DefaultRedirectHandler implements RedirectHandler {
     66 
     67     private final Log log = LogFactory.getLog(getClass());
     68 
     69     private static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";
     70 
     71     public DefaultRedirectHandler() {
     72         super();
     73     }
     74 
     75     public boolean isRedirectRequested(
     76             final HttpResponse response,
     77             final HttpContext context) {
     78         if (response == null) {
     79             throw new IllegalArgumentException("HTTP response may not be null");
     80         }
     81         int statusCode = response.getStatusLine().getStatusCode();
     82         switch (statusCode) {
     83         case HttpStatus.SC_MOVED_TEMPORARILY:
     84         case HttpStatus.SC_MOVED_PERMANENTLY:
     85         case HttpStatus.SC_SEE_OTHER:
     86         case HttpStatus.SC_TEMPORARY_REDIRECT:
     87             return true;
     88         default:
     89             return false;
     90         } //end of switch
     91     }
     92 
     93     public URI getLocationURI(
     94             final HttpResponse response,
     95             final HttpContext context) throws ProtocolException {
     96         if (response == null) {
     97             throw new IllegalArgumentException("HTTP response may not be null");
     98         }
     99         //get the location header to find out where to redirect to
    100         Header locationHeader = response.getFirstHeader("location");
    101         if (locationHeader == null) {
    102             // got a redirect response, but no location header
    103             throw new ProtocolException(
    104                     "Received redirect response " + response.getStatusLine()
    105                     + " but no location header");
    106         }
    107         String location = locationHeader.getValue();
    108         if (this.log.isDebugEnabled()) {
    109             this.log.debug("Redirect requested to location '" + location + "'");
    110         }
    111 
    112         URI uri;
    113         try {
    114             uri = new URI(location);
    115         } catch (URISyntaxException ex) {
    116             throw new ProtocolException("Invalid redirect URI: " + location, ex);
    117         }
    118 
    119         HttpParams params = response.getParams();
    120         // rfc2616 demands the location value be a complete URI
    121         // Location       = "Location" ":" absoluteURI
    122         if (!uri.isAbsolute()) {
    123             if (params.isParameterTrue(ClientPNames.REJECT_RELATIVE_REDIRECT)) {
    124                 throw new ProtocolException("Relative redirect location '"
    125                         + uri + "' not allowed");
    126             }
    127             // Adjust location URI
    128             HttpHost target = (HttpHost) context.getAttribute(
    129                     ExecutionContext.HTTP_TARGET_HOST);
    130             if (target == null) {
    131                 throw new IllegalStateException("Target host not available " +
    132                         "in the HTTP context");
    133             }
    134 
    135             HttpRequest request = (HttpRequest) context.getAttribute(
    136                     ExecutionContext.HTTP_REQUEST);
    137 
    138             try {
    139                 URI requestURI = new URI(request.getRequestLine().getUri());
    140                 URI absoluteRequestURI = URIUtils.rewriteURI(requestURI, target, true);
    141                 uri = URIUtils.resolve(absoluteRequestURI, uri);
    142             } catch (URISyntaxException ex) {
    143                 throw new ProtocolException(ex.getMessage(), ex);
    144             }
    145         }
    146 
    147         if (params.isParameterFalse(ClientPNames.ALLOW_CIRCULAR_REDIRECTS)) {
    148 
    149             RedirectLocations redirectLocations = (RedirectLocations) context.getAttribute(
    150                     REDIRECT_LOCATIONS);
    151 
    152             if (redirectLocations == null) {
    153                 redirectLocations = new RedirectLocations();
    154                 context.setAttribute(REDIRECT_LOCATIONS, redirectLocations);
    155             }
    156 
    157             URI redirectURI;
    158             if (uri.getFragment() != null) {
    159                 try {
    160                     HttpHost target = new HttpHost(
    161                             uri.getHost(),
    162                             uri.getPort(),
    163                             uri.getScheme());
    164                     redirectURI = URIUtils.rewriteURI(uri, target, true);
    165                 } catch (URISyntaxException ex) {
    166                     throw new ProtocolException(ex.getMessage(), ex);
    167                 }
    168             } else {
    169                 redirectURI = uri;
    170             }
    171 
    172             if (redirectLocations.contains(redirectURI)) {
    173                 throw new CircularRedirectException("Circular redirect to '" +
    174                         redirectURI + "'");
    175             } else {
    176                 redirectLocations.add(redirectURI);
    177             }
    178         }
    179 
    180         return uri;
    181     }
    182 
    183 }
    184