001/*
002 * $HeadURL: file:///opt/dev/not-yet-commons-ssl-SVN-repo/tags/commons-ssl-0.3.17/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
032package org.apache.commons.ssl;
033
034import org.apache.commons.ssl.util.ReadLine;
035
036import java.io.IOException;
037import java.io.InputStream;
038import java.io.InterruptedIOException;
039import java.io.OutputStream;
040import java.net.InetSocketAddress;
041import java.net.ServerSocket;
042import 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 */
050public 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}