1 /* 2 * Copyright (c) 2005, 2015, 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 // SunJSSE does not support dynamic system properties, no way to re-use 26 // system properties in samevm/agentvm mode. 27 // 28 29 /* 30 * @test 31 * @bug 6216082 32 * @summary Redirect problem with HttpsURLConnection using a proxy 33 * @modules java.base/sun.net.www 34 * @library .. /lib/testlibrary 35 * @build HttpCallback TestHttpsServer ClosedChannelList 36 * HttpTransaction TunnelProxy jdk.testlibrary.NetworkConfiguration 37 * @key intermittent 38 * @run main/othervm B6216082 39 */ 40 41 import java.io.*; 42 import java.net.*; 43 import javax.net.ssl.*; 44 import java.util.*; 45 46 import jdk.testlibrary.NetworkConfiguration; 47 48 public class B6216082 { 49 static SimpleHttpTransaction httpTrans; 50 static TestHttpsServer server; 51 static TunnelProxy proxy; 52 53 // it seems there's no proxy ever if a url points to 'localhost', 54 // even if proxy related properties are set. so we need to bind 55 // our simple http proxy and http server to a non-loopback address 56 static InetAddress firstNonLoAddress = null; 57 58 public static void main(String[] args) throws Exception { 59 HostnameVerifier reservedHV = 60 HttpsURLConnection.getDefaultHostnameVerifier(); 61 try { 62 // XXX workaround for CNFE 63 Class.forName("java.nio.channels.ClosedByInterruptException"); 64 if (!setupEnv()) { 65 return; 66 } 67 68 startHttpServer(); 69 70 // https.proxyPort can only be set after the TunnelProxy has been 71 // created as it will use an ephemeral port. 72 System.setProperty("https.proxyPort", 73 (new Integer(proxy.getLocalPort())).toString() ); 74 75 makeHttpCall(); 76 77 if (httpTrans.hasBadRequest) { 78 throw new RuntimeException("Test failed : bad http request"); 79 } 80 } finally { 81 if (proxy != null) { 82 proxy.terminate(); 83 } 84 if (server != null) { 85 server.terminate(); 86 } 87 HttpsURLConnection.setDefaultHostnameVerifier(reservedHV); 88 } 89 } 90 91 /* 92 * Where do we find the keystores for ssl? 93 */ 94 static String pathToStores = "../../../../../../javax/net/ssl/etc"; 95 static String keyStoreFile = "keystore"; 96 static String trustStoreFile = "truststore"; 97 static String passwd = "passphrase"; 98 public static boolean setupEnv() throws Exception { 99 firstNonLoAddress = getNonLoAddress(); 100 if (firstNonLoAddress == null) { 101 System.err.println("The test needs at least one non-loopback address to run. Quit now."); 102 return false; 103 } 104 System.out.println(firstNonLoAddress.getHostAddress()); 105 // will use proxy 106 System.setProperty( "https.proxyHost", firstNonLoAddress.getHostAddress()); 107 108 // setup properties to do ssl 109 String keyFilename = System.getProperty("test.src", "./") + "/" + 110 pathToStores + "/" + keyStoreFile; 111 String trustFilename = System.getProperty("test.src", "./") + "/" + 112 pathToStores + "/" + trustStoreFile; 113 114 System.setProperty("javax.net.ssl.keyStore", keyFilename); 115 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 116 System.setProperty("javax.net.ssl.trustStore", trustFilename); 117 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 118 HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier()); 119 return true; 120 } 121 122 public static InetAddress getNonLoAddress() throws Exception { 123 InetAddress lh = InetAddress.getByName("localhost"); 124 NetworkInterface loNIC = NetworkInterface.getByInetAddress(lh); 125 126 NetworkConfiguration nc = NetworkConfiguration.probe(); 127 Optional<InetAddress> oaddr = nc.interfaces() 128 .filter(nif -> !nif.getName().equalsIgnoreCase(loNIC.getName())) 129 .flatMap(nif -> nc.addresses(nif)) 130 .filter(a -> !a.isLoopbackAddress()) 131 .findFirst(); 132 133 return oaddr.orElseGet(() -> null); 134 } 135 136 public static void startHttpServer() throws IOException { 137 // Both the https server and the proxy let the 138 // system pick up an ephemeral port. 139 httpTrans = new SimpleHttpTransaction(); 140 server = new TestHttpsServer(httpTrans, 1, 10, 0); 141 proxy = new TunnelProxy(1, 10, 0); 142 } 143 144 public static void makeHttpCall() throws Exception { 145 System.out.println("https server listen on: " + server.getLocalPort()); 146 System.out.println("https proxy listen on: " + proxy.getLocalPort()); 147 URL url = new URL("https" , firstNonLoAddress.getHostAddress(), 148 server.getLocalPort(), "/"); 149 HttpURLConnection uc = (HttpURLConnection)url.openConnection(); 150 System.out.println(uc.getResponseCode()); 151 uc.disconnect(); 152 } 153 154 static class NameVerifier implements HostnameVerifier { 155 public boolean verify(String hostname, SSLSession session) { 156 return true; 157 } 158 } 159 } 160 161 class SimpleHttpTransaction implements HttpCallback { 162 public boolean hasBadRequest = false; 163 164 /* 165 * Our http server which simply redirect first call 166 */ 167 public void request(HttpTransaction trans) { 168 try { 169 String path = trans.getRequestURI().getPath(); 170 if (path.equals("/")) { 171 // the first call, redirect it 172 String location = "/redirect"; 173 trans.addResponseHeader("Location", location); 174 trans.sendResponse(302, "Moved Temporarily"); 175 } else { 176 // if the bug exsits, it'll send 2 GET commands 177 // check 2nd GET here 178 String duplicatedGet = trans.getRequestHeader(null); 179 if (duplicatedGet != null && 180 duplicatedGet.toUpperCase().indexOf("GET") >= 0) { 181 trans.sendResponse(400, "Bad Request"); 182 hasBadRequest = true; 183 } else { 184 trans.sendResponse(200, "OK"); 185 } 186 } 187 } catch (Exception e) { 188 throw new RuntimeException(e); 189 } 190 } 191 }