001    /*
002     * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.11/src/java/org/apache/commons/ssl/SSLProxyServer.java $
003     * $Revision: 132 $
004     * $Date: 2008-01-11 21:20:26 -0800 (Fri, 11 Jan 2008) $
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    
032    package org.apache.commons.ssl;
033    
034    import org.apache.commons.ssl.util.ReadLine;
035    
036    import java.io.IOException;
037    import java.io.InputStream;
038    import java.io.InterruptedIOException;
039    import java.io.OutputStream;
040    import java.net.InetSocketAddress;
041    import java.net.ServerSocket;
042    import java.net.Socket;
043    
044    /**
045     * @author Credit Union Central of British Columbia
046     * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
047     * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
048     * @since 5-May-2006
049     */
050    public class SSLProxyServer {
051    
052        public static void main(String[] args) throws Exception {
053            int port = 7444;
054            if (args.length >= 1) {
055                port = Integer.parseInt(args[0]);
056            }
057    
058            ServerSocket ss = new ServerSocket(port);
059    
060            System.out.println("SSL Proxy server listening on port: " + port);
061            while (true) {
062                Socket s = ss.accept();
063                s.setSoTimeout(10000);
064                ProxyRunnable r = new ProxyRunnable(s);
065                new Thread(r).start();
066            }
067    
068        }
069    
070        public static class ProxyRunnable implements Runnable {
071            private Socket s;
072    
073            public ProxyRunnable(Socket s) {
074                this.s = s;
075            }
076    
077            public void run() {
078                InputStream in = null;
079                OutputStream out = null;
080                InputStream newIn = null;
081                OutputStream newOut = null;
082                Socket newSocket = new Socket();
083                System.out.println("Socket accepted!");
084                try {
085                    in = s.getInputStream();
086                    out = s.getOutputStream();
087                    ReadLine readLine = new ReadLine(in);
088                    String line = readLine.next();
089                    line = line.trim();
090                    String connect = line.substring(0, "CONNECT".length());
091                    InetSocketAddress addr = null;
092                    if ("CONNECT".equalsIgnoreCase(connect)) {
093                        line = line.substring("CONNECT".length()).trim();
094                        line = line.substring(0, line.length() - "HTTP/1.1".length()).trim();
095                        HostPort hostPort = Util.toAddress(line, 443);
096                        addr = new InetSocketAddress(hostPort.host, hostPort.port);
097                        System.out.println("Attempting to proxy to: " + line);
098                    } else {
099                        throw new IOException("not a proxy request: " + line);
100                    }
101    
102                    int avail = in.available();
103                    in.skip(avail);
104                    Thread.yield();
105                    avail = in.available();
106                    while (avail != 0) {
107                        in.skip(avail);
108                        Thread.yield();
109                        avail = in.available();
110                    }
111    
112                    InetSocketAddress local = new InetSocketAddress(0);
113                    newSocket.setSoTimeout(10000);
114                    newSocket.bind(local);
115                    newSocket.connect(addr, 5000);
116                    newIn = newSocket.getInputStream();
117                    newOut = newSocket.getOutputStream();
118    
119                    out.write("HTTP/1.1 200 OKAY\r\n\r\n".getBytes());
120                    out.flush();
121    
122                    final IOException[] e = new IOException[1];
123                    final InputStream rIn = in;
124                    final OutputStream rNewOut = newOut;
125                    Runnable r = new Runnable() {
126                        public void run() {
127                            try {
128                                byte[] buf = new byte[4096];
129                                int read = rIn.read(buf);
130                                while (read >= 0) {
131                                    if (read > 0) {
132                                        rNewOut.write(buf, 0, read);
133                                        rNewOut.flush();
134                                    }
135                                    read = rIn.read(buf);
136                                }
137                            }
138                            catch (IOException ioe) {
139                                e[0] = ioe;
140                            }
141                        }
142                    };
143                    new Thread(r).start();
144    
145                    byte[] buf = new byte[4096];
146                    int read = newIn.read(buf);
147                    while (read >= 0) {
148                        if (read > 0) {
149                            out.write(buf, 0, read);
150                            out.flush();
151                        }
152                        if (e[0] != null) {
153                            throw e[0];
154                        }
155                        read = newIn.read(buf);
156                    }
157    
158    
159                }
160                catch (IOException ioe) {
161                    try {
162                        if (out != null) {
163                            out.close();
164                        }
165                        if (in != null) {
166                            in.close();
167                        }
168                        s.close();
169                    }
170                    catch (Exception e) {
171                    }
172    
173                    try {
174                        if (newOut != null) {
175                            newOut.close();
176                        }
177                        if (newIn != null) {
178                            newIn.close();
179                        }
180                        newSocket.close();
181                    }
182                    catch (Exception e) {
183                    }
184    
185    
186                    if (ioe instanceof InterruptedIOException) {
187                        System.out.println("Socket closed after 10 second timeout.");
188                    } else {
189                        ioe.printStackTrace();
190                    }
191    
192                }
193            }
194        }
195    
196    }