package com.android.proxyhandler; import android.net.ProxyProperties; import android.util.Log; import com.google.android.collect.Lists; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.ProxySelector; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @hide */ public class ProxyServer extends Thread { private static final String CONNECT = "CONNECT"; private static final String HTTP_OK = "HTTP/1.1 200 OK\n"; private static final String TAG = "ProxyServer"; private ExecutorService threadExecutor; public boolean mIsRunning = false; private ServerSocket serverSocket; private ProxyProperties mProxy; private class ProxyConnection implements Runnable { private Socket connection; private ProxyConnection(Socket connection) { this.connection = connection; } @Override public void run() { try { android.net.Proxy.setHttpProxySystemProperty(mProxy); String requestLine = getLine(connection.getInputStream()); if (requestLine == null) { connection.close(); return; } String[] splitLine = requestLine.split(" "); if (splitLine.length < 3) { connection.close(); return; } String requestType = splitLine[0]; String urlString = splitLine[1]; String host = ""; int port = 80; if (requestType.equals(CONNECT)) { String[] hostPortSplit = urlString.split(":"); host = hostPortSplit[0]; try { port = Integer.parseInt(hostPortSplit[1]); } catch (NumberFormatException nfe) { port = 443; } urlString = "Https://" + host + ":" + port; } else { try { URI url = new URI(urlString); host = url.getHost(); port = url.getPort(); if (port < 0) { port = 80; } } catch (URISyntaxException e) { connection.close(); return; } } List list = Lists.newArrayList(); try { list = ProxySelector.getDefault().select(new URI(urlString)); } catch (URISyntaxException e) { e.printStackTrace(); } Socket server = null; for (Proxy proxy : list) { try { if (!proxy.equals(Proxy.NO_PROXY)) { // Only Inets created by PacProxySelector. InetSocketAddress inetSocketAddress = (InetSocketAddress)list.get(0).address(); server = new Socket(inetSocketAddress.getAddress(), inetSocketAddress.getPort()); sendLine(server, requestLine); } else { server = new Socket(host, port); if (requestType.equals(CONNECT)) { while (getLine(connection.getInputStream()).length() != 0); // No proxy to respond so we must. sendLine(connection, HTTP_OK); } else { sendLine(server, requestLine); } } } catch (IOException ioe) { } if (server != null) { break; } } if (server == null) { server = new Socket(host, port); if (requestType.equals(CONNECT)) { while (getLine(connection.getInputStream()).length() != 0); // No proxy to respond so we must. sendLine(connection, HTTP_OK); } else { sendLine(server, requestLine); } } // Pass data back and forth until complete. SocketConnect.connect(connection, server); } catch (IOException e) { Log.d(TAG, "Problem Proxying", e); } try { connection.close(); } catch (IOException ioe) { } } private String getLine(InputStream inputStream) throws IOException { StringBuffer buffer = new StringBuffer(); int byteBuffer = inputStream.read(); if (byteBuffer < 0) return ""; do { if (byteBuffer != '\r') { buffer.append((char)byteBuffer); } byteBuffer = inputStream.read(); } while ((byteBuffer != '\n') && (byteBuffer >= 0)); return buffer.toString(); } private void sendLine(Socket socket, String line) throws IOException { OutputStream os = socket.getOutputStream(); os.write(line.getBytes()); os.write('\r'); os.write('\n'); os.flush(); } } public ProxyServer() { threadExecutor = Executors.newCachedThreadPool(); } @Override public void run() { try { serverSocket = new ServerSocket(ProxyService.PORT); serverSocket.setReuseAddress(true); while (mIsRunning) { try { ProxyConnection parser = new ProxyConnection(serverSocket.accept()); threadExecutor.execute(parser); } catch (IOException e) { e.printStackTrace(); } } } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } mIsRunning = false; } public synchronized void startServer() { mIsRunning = true; start(); } public synchronized void stopServer() { mIsRunning = false; if (serverSocket != null) { try { serverSocket.close(); serverSocket = null; } catch (IOException e) { e.printStackTrace(); } } } public void setProxy(ProxyProperties proxy) { mProxy = proxy; } }