PerConnectionProxy.java revision 6073:cea72c2bf071
1/*
2 * Copyright (c) 2003, 2012, 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/* @test
25 * @bug 4920526
26 * @summary Needs per connection proxy support for URLs
27 * @library ../../../sun/net/www/httptest/
28 * @build ClosedChannelList TestHttpServer HttpTransaction HttpCallback
29 * @compile PerConnectionProxy.java
30 * @run main/othervm -Dhttp.proxyHost=inexistant -Dhttp.proxyPort=8080 PerConnectionProxy
31 */
32
33import java.net.*;
34import java.io.*;
35import sun.net.www.*;
36
37public class PerConnectionProxy implements HttpCallback {
38    static TestHttpServer server;
39
40    public void request (HttpTransaction req) {
41        req.setResponseEntityBody ("Hello .");
42        try {
43            req.sendResponse (200, "Ok");
44            req.orderlyClose();
45        } catch (IOException e) {
46        }
47    }
48
49    public static void main(String[] args) {
50        try {
51            server = new TestHttpServer (new PerConnectionProxy(), 1, 10, 0);
52            ProxyServer pserver = new ProxyServer(InetAddress.getByName("localhost"), server.getLocalPort());
53            // start proxy server
54            new Thread(pserver).start();
55
56            URL url = new URL("http://localhost:"+server.getLocalPort());
57
58            // for non existing proxy expect an IOException
59            try {
60                InetSocketAddress isa = InetSocketAddress.createUnresolved("inexistent", 8080);
61                Proxy proxy = new Proxy(Proxy.Type.HTTP, isa);
62                HttpURLConnection urlc = (HttpURLConnection)url.openConnection (proxy);
63                InputStream is = urlc.getInputStream ();
64                is.close();
65                throw new RuntimeException("non existing per connection proxy should lead to IOException");
66            } catch (IOException ioex) {
67                // expected
68            }
69
70            // for NO_PROXY, expect direct connection
71            try {
72                HttpURLConnection urlc = (HttpURLConnection)url.openConnection (Proxy.NO_PROXY);
73                int respCode = urlc.getResponseCode();
74                urlc.disconnect();
75            } catch (IOException ioex) {
76                throw new RuntimeException("direct connection should succeed :"+ioex.getMessage());
77            }
78
79            // for a normal proxy setting expect to see connection
80            // goes through that proxy
81            try {
82                InetSocketAddress isa = InetSocketAddress.createUnresolved("localhost", pserver.getPort());
83                Proxy p = new Proxy(Proxy.Type.HTTP, isa);
84                HttpURLConnection urlc = (HttpURLConnection)url.openConnection (p);
85                int respCode = urlc.getResponseCode();
86                urlc.disconnect();
87            } catch (IOException ioex) {
88                throw new RuntimeException("connection through a local proxy should succeed :"+ioex.getMessage());
89            }
90
91        } catch (Exception e) {
92            throw new RuntimeException(e);
93        } finally {
94            if (server != null) {
95                server.terminate();
96            }
97        }
98
99    }
100
101    static class ProxyServer extends Thread {
102        private static ServerSocket ss = null;
103
104        // client requesting for a tunnel
105        private Socket clientSocket = null;
106
107        /*
108         * Origin server's address and port that the client
109         * wants to establish the tunnel for communication.
110         */
111        private InetAddress serverInetAddr;
112        private int     serverPort;
113
114        public ProxyServer(InetAddress server, int port) throws IOException {
115            serverInetAddr = server;
116            serverPort = port;
117            ss = new ServerSocket(0);
118        }
119
120        public void run() {
121            try {
122                clientSocket = ss.accept();
123                processRequests();
124            } catch (Exception e) {
125                System.out.println("Proxy Failed: " + e);
126                e.printStackTrace();
127                try {
128                    ss.close();
129                }
130                catch (IOException excep) {
131                    System.out.println("ProxyServer close error: " + excep);
132                    excep.printStackTrace();
133                }
134            }
135        }
136
137        private void processRequests() throws Exception {
138            // connection set to the tunneling mode
139
140            Socket serverSocket = new Socket(serverInetAddr, serverPort);
141            ProxyTunnel clientToServer = new ProxyTunnel(
142                                                         clientSocket, serverSocket);
143            ProxyTunnel serverToClient = new ProxyTunnel(
144                                                         serverSocket, clientSocket);
145            clientToServer.start();
146            serverToClient.start();
147            System.out.println("Proxy: Started tunneling.......");
148
149            clientToServer.join();
150            serverToClient.join();
151            System.out.println("Proxy: Finished tunneling........");
152
153            clientToServer.close();
154            serverToClient.close();
155
156        }
157
158        /**
159***************************************************************
160*                       helper methods follow
161***************************************************************
162*/
163        public int getPort() {
164            return ss.getLocalPort();
165        }
166        /*
167         * This inner class provides unidirectional data flow through the sockets
168         * by continuously copying bytes from the input socket onto the output
169         * socket, until both sockets are open and EOF has not been received.
170         */
171        static class ProxyTunnel extends Thread {
172            Socket sockIn;
173            Socket sockOut;
174            InputStream input;
175            OutputStream output;
176
177            public ProxyTunnel(Socket sockIn, Socket sockOut)
178                throws Exception {
179                this.sockIn = sockIn;
180                this.sockOut = sockOut;
181                input = sockIn.getInputStream();
182                output = sockOut.getOutputStream();
183            }
184
185            public void run() {
186                int BUFFER_SIZE = 400;
187                byte[] buf = new byte[BUFFER_SIZE];
188                int bytesRead = 0;
189                int count = 0;  // keep track of the amount of data transfer
190
191                try {
192                    while ((bytesRead = input.read(buf)) >= 0) {
193                        output.write(buf, 0, bytesRead);
194                        output.flush();
195                        count += bytesRead;
196                    }
197                } catch (IOException e) {
198                    /*
199                     * The peer end has closed the connection
200                     * we will close the tunnel
201                     */
202                    close();
203                }
204            }
205
206            public void close() {
207                try {
208                    if (!sockIn.isClosed())
209                        sockIn.close();
210                    if (!sockOut.isClosed())
211                        sockOut.close();
212                } catch (IOException ignored) { }
213            }
214        }
215
216    }
217}
218