    001/*
    002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.15/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}