1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  */
  24 
  25 package java.net.http;
  26 
  27 import java.io.IOException;
  28 import java.io.UncheckedIOException;
  29 import java.net.URI;
  30 
  31 class RedirectFilter implements HeaderFilter {
  32 
  33     HttpRequestImpl requestImpl;
  34     HttpRequest request;
  35     HttpClientImpl client;
  36     HttpClient.Redirect policy;
  37     String method;
  38     final static int DEFAULT_MAX_REDIRECTS = 5;
  39     URI uri;
  40 
  41     final static int max_redirects = Utils.getIntegerNetProperty(
  42             "java.net.httpclient.redirects.retrylimit", DEFAULT_MAX_REDIRECTS
  43     );
  44 
  45     @Override
  46     public void request(HttpRequestImpl r) throws IOException {
  47         this.request = r;
  48         this.policy = request.followRedirects();
  49         this.client = r.getClient();
  50         this.method = r.method();
  51         this.requestImpl = r;
  52         this.uri = r.uri();
  53     }
  54 
  55     @Override
  56     public HttpRequestImpl response(HttpResponseImpl r) throws IOException {
  57         return handleResponse(r);
  58     }
  59 
  60     /**
  61      * checks to see if new request needed and returns it.
  62      * Null means response is ok to return to user.
  63      */
  64     private HttpRequestImpl handleResponse(HttpResponseImpl r) {
  65         int rcode = r.statusCode();
  66         if (rcode == 200 || policy == HttpClient.Redirect.NEVER) {
  67             return null;
  68         }
  69         if (rcode >= 300 && rcode <= 399) {
  70             URI redir = getRedirectedURI(r.headers());
  71             if (canRedirect(r) && ++r.request.exchange.numberOfRedirects < max_redirects) {
  72                 //System.out.println("Redirecting to: " + redir);
  73                 return new HttpRequestImpl(redir, request, client, method, requestImpl);
  74             } else {
  75                 //System.out.println("Redirect: giving up");
  76                 return null;
  77             }
  78         }
  79         return null;
  80     }
  81 
  82     private URI getRedirectedURI(HttpHeaders headers) {
  83         URI redirectedURI;
  84         String ss = headers.firstValue("Location").orElse("Not present");
  85         redirectedURI = headers.firstValue("Location")
  86                 .map((s) -> URI.create(s))
  87                 .orElseThrow(() -> new UncheckedIOException(
  88                         new IOException("Invalid redirection")));
  89 
  90         // redirect could be relative to original URL, but if not
  91         // then redirect is used.
  92         redirectedURI = uri.resolve(redirectedURI);
  93         return redirectedURI;
  94     }
  95 
  96     private boolean canRedirect(HttpResponse r) {
  97         return requestImpl.followRedirectsImpl().redirect(r);
  98     }
  99 }