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}