• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2013, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.proxyhandler;
17 
18 import android.os.RemoteException;
19 import android.util.Log;
20 
21 import com.android.net.IProxyPortListener;
22 import com.google.android.collect.Lists;
23 
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.net.InetSocketAddress;
28 import java.net.Proxy;
29 import java.net.ProxySelector;
30 import java.net.ServerSocket;
31 import java.net.Socket;
32 import java.net.SocketException;
33 import java.net.URI;
34 import java.net.URISyntaxException;
35 import java.util.List;
36 import java.util.concurrent.ExecutorService;
37 import java.util.concurrent.Executors;
38 
39 /**
40  * @hide
41  */
42 public class ProxyServer extends Thread {
43 
44     private static final String CONNECT = "CONNECT";
45     private static final String HTTP_OK = "HTTP/1.1 200 OK\n";
46 
47     private static final String TAG = "ProxyServer";
48 
49     private ExecutorService threadExecutor;
50 
51     public boolean mIsRunning = false;
52 
53     private ServerSocket serverSocket;
54     private int mPort;
55     private IProxyPortListener mCallback;
56 
57     private class ProxyConnection implements Runnable {
58         private Socket connection;
59 
ProxyConnection(Socket connection)60         private ProxyConnection(Socket connection) {
61             this.connection = connection;
62         }
63 
64         @Override
run()65         public void run() {
66             try {
67                 String requestLine = getLine(connection.getInputStream());
68                 if (requestLine == null) {
69                     connection.close();
70                     return;
71                 }
72                 String[] splitLine = requestLine.split(" ");
73                 if (splitLine.length < 3) {
74                     connection.close();
75                     return;
76                 }
77                 String requestType = splitLine[0];
78                 String urlString = splitLine[1];
79 
80                 String host = "";
81                 int port = 80;
82 
83                 if (requestType.equals(CONNECT)) {
84                     String[] hostPortSplit = urlString.split(":");
85                     host = hostPortSplit[0];
86                     try {
87                         port = Integer.parseInt(hostPortSplit[1]);
88                     } catch (NumberFormatException nfe) {
89                         port = 443;
90                     }
91                     urlString = "Https://" + host + ":" + port;
92                 } else {
93                     try {
94                         URI url = new URI(urlString);
95                         host = url.getHost();
96                         port = url.getPort();
97                         if (port < 0) {
98                             port = 80;
99                         }
100                     } catch (URISyntaxException e) {
101                         connection.close();
102                         return;
103                     }
104                 }
105 
106                 List<Proxy> list = Lists.newArrayList();
107                 try {
108                     list = ProxySelector.getDefault().select(new URI(urlString));
109                 } catch (URISyntaxException e) {
110                     e.printStackTrace();
111                 }
112                 Socket server = null;
113                 for (Proxy proxy : list) {
114                     try {
115                         if (!proxy.equals(Proxy.NO_PROXY)) {
116                             // Only Inets created by PacProxySelector.
117                             InetSocketAddress inetSocketAddress =
118                                     (InetSocketAddress)proxy.address();
119                             server = new Socket(inetSocketAddress.getHostName(),
120                                     inetSocketAddress.getPort());
121                             sendLine(server, requestLine);
122                         } else {
123                             server = new Socket(host, port);
124                             if (requestType.equals(CONNECT)) {
125                                 while (getLine(connection.getInputStream()).length() != 0);
126                                 // No proxy to respond so we must.
127                                 sendLine(connection, HTTP_OK);
128                             } else {
129                                 sendLine(server, requestLine);
130                             }
131                         }
132                     } catch (IOException ioe) {
133 
134                     }
135                     if (server != null) {
136                         break;
137                     }
138                 }
139                 if (server == null) {
140                     server = new Socket(host, port);
141                     if (requestType.equals(CONNECT)) {
142                         while (getLine(connection.getInputStream()).length() != 0);
143                         // No proxy to respond so we must.
144                         sendLine(connection, HTTP_OK);
145                     } else {
146                         sendLine(server, requestLine);
147                     }
148                 }
149                 // Pass data back and forth until complete.
150                 SocketConnect.connect(connection, server);
151             } catch (IOException e) {
152                 Log.d(TAG, "Problem Proxying", e);
153             }
154             try {
155                 connection.close();
156             } catch (IOException ioe) {
157 
158             }
159         }
160 
getLine(InputStream inputStream)161         private String getLine(InputStream inputStream) throws IOException {
162             StringBuffer buffer = new StringBuffer();
163             int byteBuffer = inputStream.read();
164             if (byteBuffer < 0) return "";
165             do {
166                 if (byteBuffer != '\r') {
167                     buffer.append((char)byteBuffer);
168                 }
169                 byteBuffer = inputStream.read();
170             } while ((byteBuffer != '\n') && (byteBuffer >= 0));
171 
172             return buffer.toString();
173         }
174 
sendLine(Socket socket, String line)175         private void sendLine(Socket socket, String line) throws IOException {
176             OutputStream os = socket.getOutputStream();
177             os.write(line.getBytes());
178             os.write('\r');
179             os.write('\n');
180             os.flush();
181         }
182     }
183 
ProxyServer()184     public ProxyServer() {
185         threadExecutor = Executors.newCachedThreadPool();
186         mPort = -1;
187         mCallback = null;
188     }
189 
190     @Override
run()191     public void run() {
192         try {
193             serverSocket = new ServerSocket(0);
194 
195             if (serverSocket != null) {
196                 setPort(serverSocket.getLocalPort());
197 
198                 while (mIsRunning) {
199                     try {
200                         Socket socket = serverSocket.accept();
201                         // Only receive local connections.
202                         if (socket.getInetAddress().isLoopbackAddress()) {
203                             ProxyConnection parser = new ProxyConnection(socket);
204 
205                             threadExecutor.execute(parser);
206                         } else {
207                             socket.close();
208                         }
209                     } catch (IOException e) {
210                         e.printStackTrace();
211                     }
212                 }
213             }
214         } catch (SocketException e) {
215             Log.e(TAG, "Failed to start proxy server", e);
216         } catch (IOException e1) {
217             Log.e(TAG, "Failed to start proxy server", e1);
218         }
219 
220         mIsRunning = false;
221     }
222 
setPort(int port)223     public synchronized void setPort(int port) {
224         if (mCallback != null) {
225             try {
226                 mCallback.setProxyPort(port);
227             } catch (RemoteException e) {
228                 Log.w(TAG, "Proxy failed to report port to PacManager", e);
229             }
230         }
231         mPort = port;
232     }
233 
setCallback(IProxyPortListener callback)234     public synchronized void setCallback(IProxyPortListener callback) {
235         if (mPort != -1) {
236             try {
237                 callback.setProxyPort(mPort);
238             } catch (RemoteException e) {
239                 Log.w(TAG, "Proxy failed to report port to PacManager", e);
240             }
241         }
242         mCallback = callback;
243     }
244 
startServer()245     public synchronized void startServer() {
246         mIsRunning = true;
247         start();
248     }
249 
stopServer()250     public synchronized void stopServer() {
251         mIsRunning = false;
252         if (serverSocket != null) {
253             try {
254                 serverSocket.close();
255                 serverSocket = null;
256             } catch (IOException e) {
257                 e.printStackTrace();
258             }
259         }
260     }
261 
isBound()262     public boolean isBound() {
263         return (mPort != -1);
264     }
265 
getPort()266     public int getPort() {
267         return mPort;
268     }
269 }
270