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