1 /* 2 * Copyright (c) 2015, 2018, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8156514 27 * @library /lib/testlibrary server 28 * @build jdk.testlibrary.SimpleSSLContext 29 * @modules java.base/sun.net.www.http 30 * java.net.http/jdk.internal.net.http.common 31 * java.net.http/jdk.internal.net.http.frame 32 * java.net.http/jdk.internal.net.http.hpack 33 * @run testng/othervm 34 * -Djdk.httpclient.HttpClient.log=frames,ssl,requests,responses,errors 35 * -Djdk.internal.httpclient.debug=true 36 * RedirectTest 37 */ 38 39 import java.net.InetSocketAddress; 40 import java.net.URI; 41 import java.net.http.HttpClient; 42 import java.net.http.HttpRequest; 43 import java.net.http.HttpRequest.BodyPublishers; 44 import java.net.http.HttpResponse; 45 import java.net.http.HttpResponse.BodyHandlers; 46 import java.util.concurrent.*; 47 import java.util.function.*; 48 import java.util.Arrays; 49 import java.util.Iterator; 50 import org.testng.annotations.Test; 51 import static java.net.http.HttpClient.Version.HTTP_2; 52 53 public class RedirectTest { 54 static int httpPort; 55 static Http2TestServer httpServer; 56 static HttpClient client; 57 58 static String httpURIString, altURIString1, altURIString2; 59 static URI httpURI, altURI1, altURI2; 60 sup(String... args)61 static Supplier<String> sup(String... args) { 62 Iterator<String> i = Arrays.asList(args).iterator(); 63 // need to know when to stop calling it. 64 return () -> i.next(); 65 } 66 67 static class Redirector extends Http2RedirectHandler { 68 private InetSocketAddress remoteAddr; 69 private boolean error = false; 70 Redirector(Supplier<String> supplier)71 Redirector(Supplier<String> supplier) { 72 super(supplier); 73 } 74 examineExchange(Http2TestExchange ex)75 protected synchronized void examineExchange(Http2TestExchange ex) { 76 InetSocketAddress addr = ex.getRemoteAddress(); 77 if (remoteAddr == null) { 78 remoteAddr = addr; 79 return; 80 } 81 // check that the client addr/port stays the same, proving 82 // that the connection didn't get dropped. 83 if (!remoteAddr.equals(addr)) { 84 System.err.printf("Error %s/%s\n", remoteAddr.toString(), 85 addr.toString()); 86 error = true; 87 } 88 } 89 error()90 public synchronized boolean error() { 91 return error; 92 } 93 } 94 initialize()95 static void initialize() throws Exception { 96 try { 97 client = getClient(); 98 httpServer = new Http2TestServer(false, 0, null, null); 99 httpPort = httpServer.getAddress().getPort(); 100 101 // urls are accessed in sequence below. The first two are on 102 // different servers. Third on same server as second. So, the 103 // client should use the same http connection. 104 httpURIString = "http://localhost:" + httpPort + "/foo/"; 105 httpURI = URI.create(httpURIString); 106 altURIString1 = "http://localhost:" + httpPort + "/redir"; 107 altURI1 = URI.create(altURIString1); 108 altURIString2 = "http://localhost:" + httpPort + "/redir_again"; 109 altURI2 = URI.create(altURIString2); 110 111 Redirector r = new Redirector(sup(altURIString1, altURIString2)); 112 httpServer.addHandler(r, "/foo"); 113 httpServer.addHandler(r, "/redir"); 114 httpServer.addHandler(new Http2EchoHandler(), "/redir_again"); 115 116 httpServer.start(); 117 } catch (Throwable e) { 118 System.err.println("Throwing now"); 119 e.printStackTrace(); 120 throw e; 121 } 122 } 123 124 @Test test()125 public static void test() throws Exception { 126 try { 127 initialize(); 128 simpleTest(); 129 } finally { 130 httpServer.stop(); 131 } 132 } 133 getClient()134 static HttpClient getClient() { 135 if (client == null) { 136 client = HttpClient.newBuilder() 137 .followRedirects(HttpClient.Redirect.ALWAYS) 138 .version(HTTP_2) 139 .build(); 140 } 141 return client; 142 } 143 getURI()144 static URI getURI() { 145 return URI.create(httpURIString); 146 } 147 checkStatus(int expected, int found)148 static void checkStatus(int expected, int found) throws Exception { 149 if (expected != found) { 150 System.err.printf ("Test failed: wrong status code %d/%d\n", 151 expected, found); 152 throw new RuntimeException("Test failed"); 153 } 154 } 155 checkURIs(URI expected, URI found)156 static void checkURIs(URI expected, URI found) throws Exception { 157 System.out.printf ("Expected: %s, Found: %s\n", expected.toString(), found.toString()); 158 if (!expected.equals(found)) { 159 System.err.printf ("Test failed: wrong URI %s/%s\n", 160 expected.toString(), found.toString()); 161 throw new RuntimeException("Test failed"); 162 } 163 } 164 checkStrings(String expected, String found)165 static void checkStrings(String expected, String found) throws Exception { 166 if (!expected.equals(found)) { 167 System.err.printf ("Test failed: wrong string %s/%s\n", 168 expected, found); 169 throw new RuntimeException("Test failed"); 170 } 171 } 172 check(boolean cond, Object... msg)173 static void check(boolean cond, Object... msg) { 174 if (cond) 175 return; 176 StringBuilder sb = new StringBuilder(); 177 for (Object o : msg) 178 sb.append(o); 179 throw new RuntimeException(sb.toString()); 180 } 181 182 static final String SIMPLE_STRING = "Hello world Goodbye world"; 183 simpleTest()184 static void simpleTest() throws Exception { 185 URI uri = getURI(); 186 System.err.println("Request to " + uri); 187 188 HttpClient client = getClient(); 189 HttpRequest req = HttpRequest.newBuilder(uri) 190 .POST(BodyPublishers.ofString(SIMPLE_STRING)) 191 .build(); 192 CompletableFuture<HttpResponse<String>> cf = client.sendAsync(req, BodyHandlers.ofString()); 193 HttpResponse<String> response = cf.join(); 194 195 checkStatus(200, response.statusCode()); 196 String responseBody = response.body(); 197 checkStrings(SIMPLE_STRING, responseBody); 198 checkURIs(response.uri(), altURI2); 199 200 // check two previous responses 201 HttpResponse<String> prev = response.previousResponse() 202 .orElseThrow(() -> new RuntimeException("no previous response")); 203 checkURIs(prev.uri(), altURI1); 204 205 prev = prev.previousResponse() 206 .orElseThrow(() -> new RuntimeException("no previous response")); 207 checkURIs(prev.uri(), httpURI); 208 209 checkPreviousRedirectResponses(req, response); 210 211 System.err.println("DONE"); 212 } 213 checkPreviousRedirectResponses(HttpRequest initialRequest, HttpResponse<?> finalResponse)214 static void checkPreviousRedirectResponses(HttpRequest initialRequest, 215 HttpResponse<?> finalResponse) { 216 // there must be at least one previous response 217 finalResponse.previousResponse() 218 .orElseThrow(() -> new RuntimeException("no previous response")); 219 220 HttpResponse<?> response = finalResponse; 221 do { 222 URI uri = response.uri(); 223 response = response.previousResponse().get(); 224 check(300 <= response.statusCode() && response.statusCode() <= 309, 225 "Expected 300 <= code <= 309, got:" + response.statusCode()); 226 check(response.body() == null, "Unexpected body: " + response.body()); 227 String locationHeader = response.headers().firstValue("Location") 228 .orElseThrow(() -> new RuntimeException("no previous Location")); 229 check(uri.toString().endsWith(locationHeader), 230 "URI: " + uri + ", Location: " + locationHeader); 231 } while (response.previousResponse().isPresent()); 232 233 // initial 234 check(initialRequest.equals(response.request()), 235 "Expected initial request [%s] to equal last prev req [%s]", 236 initialRequest, response.request()); 237 } 238 } 239