| /* |
| * Copyright 2006 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.dev.util; |
| |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| |
| /** |
| * A blind byte-by-byte bi-directional proxy. |
| */ |
| public class NetProxy { |
| |
| private class ClientToServerProxyConnection extends ProxyConnection { |
| public ClientToServerProxyConnection(Socket clientSideSocket, |
| Socket serverSideSocket) { |
| super(clientSideSocket, serverSideSocket); |
| setName(fromPort + " => " + toPort + " #" + connections); |
| } |
| |
| @Override |
| protected void recordBytesTransferred(byte[] bytes, int avail) { |
| addBytesSent(avail, bytes); |
| } |
| } |
| |
| private abstract class ProxyConnection extends Thread { |
| private Socket fromSocket; |
| private Socket toSocket; |
| |
| public ProxyConnection(Socket fromSocket, Socket toSocket) { |
| this.fromSocket = fromSocket; |
| this.toSocket = toSocket; |
| } |
| |
| @Override |
| public void run() { |
| try { |
| InputStream fromSideInput = fromSocket.getInputStream(); |
| OutputStream toSideOutput = toSocket.getOutputStream(); |
| |
| /* |
| * Spin and pass data in one direction. |
| */ |
| int avail; |
| byte[] bytes = new byte[32768]; |
| while (true) { |
| // Read 'from' side |
| avail = fromSideInput.read(bytes); |
| if (avail > 0) { |
| // Forward to 'to' side |
| toSideOutput.write(bytes, 0, avail); |
| // Accumulate bytes received |
| recordBytesTransferred(bytes, avail); |
| } else if (avail == -1) { |
| break; |
| } |
| } |
| } catch (Throwable e) { |
| } finally { |
| try { |
| fromSocket.close(); |
| toSocket.close(); |
| } catch (Throwable e) { |
| } |
| } |
| } |
| |
| protected abstract void recordBytesTransferred(byte[] bytes, int avail); |
| } |
| private class ServerToClientProxyConnection extends ProxyConnection { |
| public ServerToClientProxyConnection(Socket clientSideSocket, |
| Socket serverSideSocket) { |
| super(serverSideSocket, clientSideSocket); |
| setName(fromPort + " <= " + toPort + " #" + connections); |
| } |
| |
| @Override |
| protected void recordBytesTransferred(byte[] bytes, int avail) { |
| addBytesReceived(avail, bytes); |
| } |
| } |
| |
| public static void main(String[] args) { |
| if (args.length < 2) { |
| System.out.println("Usage: NetProxy <local-port> <remote-port> [<remote-host>]"); |
| return; |
| } |
| |
| int localPort = Integer.parseInt(args[0]); |
| int remotePort = Integer.parseInt(args[1]); |
| String remoteHost = args.length < 3 ? "localhost" : args[2]; |
| NetProxy netProxy = new NetProxy(localPort, remoteHost, remotePort, true); |
| netProxy.run(); |
| } |
| |
| private boolean dumpChars; |
| private int fromPort; |
| private String toName; |
| private int toPort; |
| private int bytesSent; |
| private int bytesReceived; |
| |
| private int connections; |
| |
| private boolean end; |
| |
| private long startTime = System.currentTimeMillis(); |
| |
| public NetProxy(int fromPort, String toName, int toPort, boolean dumpChars) { |
| this.fromPort = fromPort; |
| this.toName = toName; |
| this.toPort = toPort; |
| this.dumpChars = dumpChars; |
| } |
| |
| public void end() { |
| end = true; |
| } |
| |
| public void run() { |
| try { |
| System.out.println("Time\tBytes Sent\tBytes Received\tTotal Bytes\tHTTP Data"); |
| ServerSocket serverSocket = new ServerSocket(fromPort); |
| while (!end) { |
| try { |
| ++connections; |
| |
| /* |
| * Listen for and accept the client-initiated connection. Connect to |
| * the real server. Spawn a thread to handle the data shuffling for |
| * newly-created connection. |
| */ |
| Socket clientSideSocket = serverSocket.accept(); |
| clientSideSocket.setTcpNoDelay(true); |
| |
| Socket serverSideSocket = new Socket(toName, toPort); |
| serverSideSocket.setTcpNoDelay(true); |
| |
| new ClientToServerProxyConnection(clientSideSocket, serverSideSocket).start(); |
| new ServerToClientProxyConnection(clientSideSocket, serverSideSocket).start(); |
| } catch (Throwable e) { |
| e.printStackTrace(); |
| } |
| } |
| } catch (Throwable e) { |
| // Failed to even be able to listen. |
| e.printStackTrace(); |
| } |
| } |
| |
| protected int getBytesReceived() { |
| return bytesReceived; |
| } |
| |
| protected int getBytesSent() { |
| return bytesSent; |
| } |
| |
| private synchronized void addBytesReceived(int byteCount, byte[] bytes) { |
| bytesReceived += byteCount; |
| log(0, byteCount, bytes); |
| } |
| |
| private synchronized void addBytesSent(int byteCount, byte[] bytes) { |
| this.bytesSent += byteCount; |
| log(byteCount, 0, bytes); |
| } |
| |
| private synchronized void log(int bytesSent, int bytesReceived, |
| byte[] dataBuffer) { |
| System.out.print(System.currentTimeMillis() - startTime); |
| System.out.print("\t"); |
| System.out.print(bytesSent); |
| System.out.print("\t"); |
| System.out.print(bytesReceived); |
| System.out.print("\t"); |
| System.out.print(this.bytesSent + this.bytesReceived); |
| System.out.print("\t"); |
| char ch; |
| int avail = (bytesSent != 0 ? bytesSent : bytesReceived); |
| if (dumpChars) { |
| int limit = (avail < 1024 ? avail : 1024); |
| for (int i = 0; i < limit; ++i) { |
| ch = (char) dataBuffer[i]; |
| if (ch >= 32 && ch < 128) { |
| System.out.print(ch); |
| } else if (ch == '\n') { |
| System.out.print("\\n"); |
| } else if (ch == '\r') { |
| System.out.print("\\r"); |
| } else { |
| System.out.print('.'); |
| } |
| } |
| } else { |
| // Just read up to the \r\n\r\n. |
| // |
| try { |
| String http = new String(dataBuffer, "UTF-8"); |
| int endOfHeaders = http.indexOf("\r\n\r\n"); |
| if (endOfHeaders != -1 && http.indexOf("HTTP") != -1) { |
| http = http.replaceAll("\\r", ""); |
| http = http.replaceAll("\\n", "\n\t\t\t\t"); |
| System.out.print(http.substring(0, endOfHeaders)); |
| } else { |
| System.out.print("(data)"); |
| } |
| } catch (UnsupportedEncodingException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| System.out.println(); |
| } |
| } |