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