/* * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ /* * @test * @bug 6226610 * @run main/othervm B6226610 * @summary HTTP tunnel connections send user headers to proxy */ /* This class includes a proxy server that processes the HTTP CONNECT request, * and validates that the request does not have the user defined header in it. * The proxy server always returns 400 Bad Request so that the Http client * will not try to proceed with the connection as there is no back end http server. */ import java.io.*; import java.net.*; import javax.net.ssl.*; import javax.net.ServerSocketFactory; import sun.net.www.*; import java.util.Enumeration; public class B6226610 { static HeaderCheckerProxyTunnelServer proxy; // it seems there's no proxy ever if a url points to 'localhost', // even if proxy related properties are set. so we need to bind // our simple http proxy and http server to a non-loopback address static InetAddress firstNonLoAddress = null; public static void main(String[] args) { try { proxy = new HeaderCheckerProxyTunnelServer(); proxy.start(); } catch (Exception e) { System.out.println("Cannot create proxy: " + e); } try { firstNonLoAddress = getNonLoAddress(); if (firstNonLoAddress == null) { System.out.println("The test needs at least one non-loopback address to run. Quit now."); System.exit(0); } } catch (Exception e) { e.printStackTrace(); } System.setProperty( "https.proxyHost", firstNonLoAddress.getHostAddress()); System.setProperty( "https.proxyPort", (new Integer(proxy.getLocalPort())).toString() ); try { URL u = new URL("https://" + firstNonLoAddress.getHostAddress()); java.net.URLConnection c = u.openConnection(); /* I want this header to go to the destination server only, protected * by SSL */ c.setRequestProperty("X-TestHeader", "value"); c.connect(); } catch (IOException e) { if ( e.getMessage().equals("Unable to tunnel through proxy. Proxy returns \"HTTP/1.1 400 Bad Request\"") ) { // OK. Proxy will always return 400 so that the main thread can terminate correctly. } else System.out.println(e); } if (HeaderCheckerProxyTunnelServer.failed) throw new RuntimeException("Test failed: Proxy should not receive user defined headers for tunneled requests"); } public static InetAddress getNonLoAddress() throws Exception { NetworkInterface loNIC = NetworkInterface.getByInetAddress(InetAddress.getByName("localhost")); Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces(); while (nics.hasMoreElements()) { NetworkInterface nic = nics.nextElement(); if (!nic.getName().equalsIgnoreCase(loNIC.getName())) { Enumeration<InetAddress> addrs = nic.getInetAddresses(); while (addrs.hasMoreElements()) { InetAddress addr = addrs.nextElement(); if (!addr.isLoopbackAddress()) return addr; } } } return null; } } class HeaderCheckerProxyTunnelServer extends Thread { public static boolean failed = false; private static ServerSocket ss = null; // client requesting for a tunnel private Socket clientSocket = null; /* * Origin server's address and port that the client * wants to establish the tunnel for communication. */ private InetAddress serverInetAddr; private int serverPort; public HeaderCheckerProxyTunnelServer() throws IOException { if (ss == null) { ss = new ServerSocket(0); } } public void run() { try { clientSocket = ss.accept(); processRequests(); } catch (IOException e) { System.out.println("Proxy Failed: " + e); e.printStackTrace(); try { ss.close(); } catch (IOException excep) { System.out.println("ProxyServer close error: " + excep); excep.printStackTrace(); } } } /** * Returns the port on which the proxy is accepting connections. */ public int getLocalPort() { return ss.getLocalPort(); } /* * Processes the CONNECT request */ private void processRequests() throws IOException { InputStream in = clientSocket.getInputStream(); MessageHeader mheader = new MessageHeader(in); String statusLine = mheader.getValue(0); if (statusLine.startsWith("CONNECT")) { // retrieve the host and port info from the status-line retrieveConnectInfo(statusLine); if (mheader.findValue("X-TestHeader") != null) { failed = true; } //This will allow the main thread to terminate without trying to perform the SSL handshake. send400(); in.close(); clientSocket.close(); ss.close(); } else { System.out.println("proxy server: processes only " + "CONNECT method requests, recieved: " + statusLine); } } private void send400() throws IOException { OutputStream out = clientSocket.getOutputStream(); PrintWriter pout = new PrintWriter(out); pout.println("HTTP/1.1 400 Bad Request"); pout.println(); pout.flush(); } private void restart() throws IOException { (new Thread(this)).start(); } /* * This method retrieves the hostname and port of the destination * that the connect request wants to establish a tunnel for * communication. * The input, connectStr is of the form: * CONNECT server-name:server-port HTTP/1.x */ private void retrieveConnectInfo(String connectStr) throws IOException { int starti; int endi; String connectInfo; String serverName = null; try { starti = connectStr.indexOf(' '); endi = connectStr.lastIndexOf(' '); connectInfo = connectStr.substring(starti+1, endi).trim(); // retrieve server name and port endi = connectInfo.indexOf(':'); serverName = connectInfo.substring(0, endi); serverPort = Integer.parseInt(connectInfo.substring(endi+1)); } catch (Exception e) { throw new IOException("Proxy recieved a request: " + connectStr); } serverInetAddr = InetAddress.getByName(serverName); } }