Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/net/Socket/HttpProxy.java
38812 views
/*1* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 637090826* @summary Add support for HTTP_CONNECT proxy in Socket class27*/2829import java.io.IOException;30import java.io.InputStream;31import java.io.OutputStream;32import java.io.PrintWriter;33import static java.lang.System.out;34import java.net.InetAddress;35import java.net.InetSocketAddress;36import java.net.Proxy;37import java.net.ServerSocket;38import java.net.Socket;39import sun.net.www.MessageHeader;4041public class HttpProxy {42final String proxyHost;43final int proxyPort;44static final int SO_TIMEOUT = 15000;4546public static void main(String[] args) throws Exception {47String host;48int port;49if (args.length == 0) {50// Start internal proxy51ConnectProxyTunnelServer proxy = new ConnectProxyTunnelServer();52proxy.start();53host = "localhost";54port = proxy.getLocalPort();55out.println("Running with internal proxy: " + host + ":" + port);56} else if (args.length == 2) {57host = args[0];58port = Integer.valueOf(args[1]);59out.println("Running against specified proxy server: " + host + ":" + port);60} else {61System.err.println("Usage: java HttpProxy [<proxy host> <proxy port>]");62return;63}6465HttpProxy p = new HttpProxy(host, port);66p.test();67}6869public HttpProxy(String proxyHost, int proxyPort) {70this.proxyHost = proxyHost;71this.proxyPort = proxyPort;72}7374void test() throws Exception {75InetSocketAddress proxyAddress = new InetSocketAddress(proxyHost, proxyPort);76Proxy httpProxy = new Proxy(Proxy.Type.HTTP, proxyAddress);7778try (ServerSocket ss = new ServerSocket(0);79Socket sock = new Socket(httpProxy)) {80sock.setSoTimeout(SO_TIMEOUT);81sock.setTcpNoDelay(false);8283InetSocketAddress externalAddress =84new InetSocketAddress(InetAddress.getLocalHost(), ss.getLocalPort());8586out.println("Trying to connect to server socket on " + externalAddress);87sock.connect(externalAddress);88try (Socket externalSock = ss.accept()) {89// perform some simple checks90check(sock.isBound(), "Socket is not bound");91check(sock.isConnected(), "Socket is not connected");92check(!sock.isClosed(), "Socket should not be closed");93check(sock.getSoTimeout() == SO_TIMEOUT,94"Socket should have a previously set timeout");95check(sock.getTcpNoDelay() == false, "NODELAY should be false");9697simpleDataExchange(sock, externalSock);98}99}100}101102static void check(boolean condition, String message) {103if (!condition) out.println(message);104}105106static Exception unexpected(Exception e) {107out.println("Unexcepted Exception: " + e);108e.printStackTrace();109return e;110}111112// performs a simple exchange of data between the two sockets113// and throws an exception if there is any problem.114void simpleDataExchange(Socket s1, Socket s2) throws Exception {115try (final InputStream i1 = s1.getInputStream();116final InputStream i2 = s2.getInputStream();117final OutputStream o1 = s1.getOutputStream();118final OutputStream o2 = s2.getOutputStream()) {119startSimpleWriter("simpleWriter1", o1, 100);120startSimpleWriter("simpleWriter2", o2, 200);121simpleRead(i2, 100);122simpleRead(i1, 200);123}124}125126void startSimpleWriter(String threadName, final OutputStream os, final int start) {127(new Thread(new Runnable() {128public void run() {129try { simpleWrite(os, start); }130catch (Exception e) {unexpected(e); }131}}, threadName)).start();132}133134void simpleWrite(OutputStream os, int start) throws Exception {135byte b[] = new byte[2];136for (int i=start; i<start+100; i++) {137b[0] = (byte) (i / 256);138b[1] = (byte) (i % 256);139os.write(b);140}141}142143void simpleRead(InputStream is, int start) throws Exception {144byte b[] = new byte [2];145for (int i=start; i<start+100; i++) {146int x = is.read(b);147if (x == 1)148x += is.read(b,1,1);149if (x!=2)150throw new Exception("read error");151int r = bytes(b[0], b[1]);152if (r != i)153throw new Exception("read " + r + " expected " +i);154}155}156157int bytes(byte b1, byte b2) {158int i1 = (int)b1 & 0xFF;159int i2 = (int)b2 & 0xFF;160return i1 * 256 + i2;161}162163static class ConnectProxyTunnelServer extends Thread {164165private final ServerSocket ss;166167public ConnectProxyTunnelServer() throws IOException {168ss = new ServerSocket(0);169}170171@Override172public void run() {173try (Socket clientSocket = ss.accept()) {174processRequest(clientSocket);175} catch (Exception e) {176out.println("Proxy Failed: " + e);177e.printStackTrace();178} finally {179try { ss.close(); } catch (IOException x) { unexpected(x); }180}181}182183/**184* Returns the port on which the proxy is accepting connections.185*/186public int getLocalPort() {187return ss.getLocalPort();188}189190/*191* Processes the CONNECT request192*/193private void processRequest(Socket clientSocket) throws Exception {194MessageHeader mheader = new MessageHeader(clientSocket.getInputStream());195String statusLine = mheader.getValue(0);196197if (!statusLine.startsWith("CONNECT")) {198out.println("proxy server: processes only "199+ "CONNECT method requests, recieved: "200+ statusLine);201return;202}203204// retrieve the host and port info from the status-line205InetSocketAddress serverAddr = getConnectInfo(statusLine);206207//open socket to the server208try (Socket serverSocket = new Socket(serverAddr.getAddress(),209serverAddr.getPort())) {210Forwarder clientFW = new Forwarder(clientSocket.getInputStream(),211serverSocket.getOutputStream());212Thread clientForwarderThread = new Thread(clientFW, "ClientForwarder");213clientForwarderThread.start();214send200(clientSocket);215Forwarder serverFW = new Forwarder(serverSocket.getInputStream(),216clientSocket.getOutputStream());217serverFW.run();218clientForwarderThread.join();219}220}221222private void send200(Socket clientSocket) throws IOException {223OutputStream out = clientSocket.getOutputStream();224PrintWriter pout = new PrintWriter(out);225226pout.println("HTTP/1.1 200 OK");227pout.println();228pout.flush();229}230231/*232* This method retrieves the hostname and port of the tunnel destination233* from the request line.234* @param connectStr235* of the form: <i>CONNECT server-name:server-port HTTP/1.x</i>236*/237static InetSocketAddress getConnectInfo(String connectStr)238throws Exception239{240try {241int starti = connectStr.indexOf(' ');242int endi = connectStr.lastIndexOf(' ');243String connectInfo = connectStr.substring(starti+1, endi).trim();244// retrieve server name and port245endi = connectInfo.indexOf(':');246String name = connectInfo.substring(0, endi);247int port = Integer.parseInt(connectInfo.substring(endi+1));248return new InetSocketAddress(name, port);249} catch (Exception e) {250out.println("Proxy recieved a request: " + connectStr);251throw unexpected(e);252}253}254}255256/* Reads from the given InputStream and writes to the given OutputStream */257static class Forwarder implements Runnable258{259private final InputStream in;260private final OutputStream os;261262Forwarder(InputStream in, OutputStream os) {263this.in = in;264this.os = os;265}266267@Override268public void run() {269try {270byte[] ba = new byte[1024];271int count;272while ((count = in.read(ba)) != -1) {273os.write(ba, 0, count);274}275} catch (IOException e) {276unexpected(e);277}278}279}280}281282283