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 }