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 * questions. 24 */ 25 26 package jdk.incubator.http; 27 28 import java.io.IOException; 29 import java.io.UncheckedIOException; 30 import java.net.URI; 31 import jdk.incubator.http.internal.common.Utils; 32 33 class RedirectFilter implements HeaderFilter { 34 35 HttpRequestImpl request; 36 HttpClientImpl client; 37 HttpClient.Redirect policy; 38 String method; 39 MultiExchange<?,?> exchange; 40 static final int DEFAULT_MAX_REDIRECTS = 5; 41 URI uri; 42 43 static final int max_redirects = Utils.getIntegerNetProperty( 44 "jdk.httpclient.redirects.retrylimit", DEFAULT_MAX_REDIRECTS 45 ); 46 47 @Override 48 public synchronized void request(HttpRequestImpl r, MultiExchange<?,?> e) throws IOException { 49 this.request = r; 50 this.client = e.client(); 51 this.policy = client.followRedirects(); 52 53 this.method = r.method(); 54 this.uri = r.uri(); 55 this.exchange = e; 56 } 57 58 @Override 59 public synchronized HttpRequestImpl response(Response r) throws IOException { 60 return handleResponse(r); 61 } 62 63 /** 64 * checks to see if new request needed and returns it. 65 * Null means response is ok to return to user. 66 */ 67 private HttpRequestImpl handleResponse(Response r) { 68 int rcode = r.statusCode(); 69 if (rcode == 200 || policy == HttpClient.Redirect.NEVER) { 70 return null; 71 } 72 if (rcode >= 300 && rcode <= 399) { 73 URI redir = getRedirectedURI(r.headers()); 74 if (canRedirect(redir) && ++exchange.numberOfRedirects < max_redirects) { 75 //System.out.println("Redirecting to: " + redir); 76 return new HttpRequestImpl(redir, method, request); 77 } else { 78 //System.out.println("Redirect: giving up"); 79 return null; 80 } 81 } 82 return null; 83 } 84 85 private URI getRedirectedURI(HttpHeaders headers) { 86 URI redirectedURI; 87 String ss = headers.firstValue("Location").orElse("Not present"); 88 redirectedURI = headers.firstValue("Location") 89 .map((s) -> URI.create(s)) 90 .orElseThrow(() -> new UncheckedIOException( 91 new IOException("Invalid redirection"))); 92 93 // redirect could be relative to original URL, but if not 94 // then redirect is used. 95 redirectedURI = uri.resolve(redirectedURI); 96 return redirectedURI; 97 } 98 99 private boolean canRedirect(URI redir) { 100 String newScheme = redir.getScheme(); 101 String oldScheme = uri.getScheme(); 102 switch (policy) { 103 case ALWAYS: 104 return true; 105 case NEVER: 106 return false; 107 case SECURE: 108 return newScheme.equalsIgnoreCase("https"); 109 case SAME_PROTOCOL: 110 return newScheme.equalsIgnoreCase(oldScheme); 111 default: 112 throw new InternalError(); 113 } 114 } 115 }