001/*
002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/SSLProxyServer.java $
003 * $Revision: 121 $
004 * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
005 *
006 * ====================================================================
007 * Licensed to the Apache Software Foundation (ASF) under one
008 * or more contributor license agreements.  See the NOTICE file
009 * distributed with this work for additional information
010 * regarding copyright ownership.  The ASF licenses this file
011 * to you under the Apache License, Version 2.0 (the
012 * "License"); you may not use this file except in compliance
013 * with the License.  You may obtain a copy of the License at
014 *
015 *   http://www.apache.org/licenses/LICENSE-2.0
016 *
017 * Unless required by applicable law or agreed to in writing,
018 * software distributed under the License is distributed on an
019 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020 * KIND, either express or implied.  See the License for the
021 * specific language governing permissions and limitations
022 * under the License.
023 * ====================================================================
024 *
025 * This software consists of voluntary contributions made by many
026 * individuals on behalf of the Apache Software Foundation.  For more
027 * information on the Apache Software Foundation, please see
028 * <http://www.apache.org/>.
029 *
030 */
031
032package org.apache.commons.ssl;
033
034import java.io.IOException;
035import java.io.InputStream;
036import java.io.InterruptedIOException;
037import java.io.OutputStream;
038import java.net.InetSocketAddress;
039import java.net.ServerSocket;
040import java.net.Socket;
041
042/**
043 * @author Credit Union Central of British Columbia
044 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
045 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
046 * @since 5-May-2006
047 */
048public class SSLProxyServer {
049
050    public static void main(String[] args) throws Exception {
051        int port = 7444;
052        if (args.length >= 1) {
053            port = Integer.parseInt(args[0]);
054        }
055
056        ServerSocket ss = new ServerSocket(port);
057
058        System.out.println("SSL Proxy server listening on port: " + port);
059        while (true) {
060            Socket s = ss.accept();
061            s.setSoTimeout(10000);
062            ProxyRunnable r = new ProxyRunnable(s);
063            new Thread(r).start();
064        }
065
066    }
067
068    public static class ProxyRunnable implements Runnable {
069        private Socket s;
070
071        public ProxyRunnable(Socket s) {
072            this.s = s;
073        }
074
075        public void run() {
076            InputStream in = null;
077            OutputStream out = null;
078            InputStream newIn = null;
079            OutputStream newOut = null;
080            Socket newSocket = new Socket();
081            System.out.println("Socket accepted!");
082            try {
083                in = s.getInputStream();
084                out = s.getOutputStream();
085                String line = Util.readLine(in);
086                line = line.trim();
087                String connect = line.substring(0, "CONNECT".length());
088                InetSocketAddress addr = null;
089                if ("CONNECT".equalsIgnoreCase(connect)) {
090                    line = line.substring("CONNECT".length()).trim();
091                    line = line.substring(0, line.length() - "HTTP/1.1".length()).trim();
092                    HostPort hostPort = Util.toAddress(line, 443);
093                    addr = new InetSocketAddress(hostPort.host, hostPort.port);
094                    System.out.println("Attempting to proxy to: " + line);
095                } else {
096                    throw new IOException("not a proxy request: " + line);
097                }
098
099                int avail = in.available();
100                in.skip(avail);
101                Thread.yield();
102                avail = in.available();
103                while (avail != 0) {
104                    in.skip(avail);
105                    Thread.yield();
106                    avail = in.available();
107                }
108
109                InetSocketAddress local = new InetSocketAddress(0);
110                newSocket.setSoTimeout(10000);
111                newSocket.bind(local);
112                newSocket.connect(addr, 5000);
113                newIn = newSocket.getInputStream();
114                newOut = newSocket.getOutputStream();
115
116                out.write("HTTP/1.1 200 OKAY\r\n\r\n".getBytes());
117                out.flush();
118
119                final IOException[] e = new IOException[1];
120                final InputStream rIn = in;
121                final OutputStream rNewOut = newOut;
122                Runnable r = new Runnable() {
123                    public void run() {
124                        try {
125                            byte[] buf = new byte[4096];
126                            int read = rIn.read(buf);
127                            while (read >= 0) {
128                                if (read > 0) {
129                                    rNewOut.write(buf, 0, read);
130                                    rNewOut.flush();
131                                }
132                                read = rIn.read(buf);
133                            }
134                        }
135                        catch (IOException ioe) {
136                            e[0] = ioe;
137                        }
138                    }
139                };
140                new Thread(r).start();
141
142                byte[] buf = new byte[4096];
143                int read = newIn.read(buf);
144                while (read >= 0) {
145                    if (read > 0) {
146                        out.write(buf, 0, read);
147                        out.flush();
148                    }
149                    if (e[0] != null) {
150                        throw e[0];
151                    }
152                    read = newIn.read(buf);
153                }
154
155
156            }
157            catch (IOException ioe) {
158                try {
159                    if (out != null) {
160                        out.close();
161                    }
162                    if (in != null) {
163                        in.close();
164                    }
165                    s.close();
166                }
167                catch (Exception e) {
168                }
169
170                try {
171                    if (newOut != null) {
172                        newOut.close();
173                    }
174                    if (newIn != null) {
175                        newIn.close();
176                    }
177                    newSocket.close();
178                }
179                catch (Exception e) {
180                }
181
182
183                if (ioe instanceof InterruptedIOException) {
184                    System.out.println("Socket closed after 10 second timeout.");
185                } else {
186                    ioe.printStackTrace();
187                }
188
189            }
190        }
191    }
192
193}