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