Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: src/org/adblockplus/brazil/RequestHandler.java

Issue 8484110: ABP/Android proxy service (Closed)
Left Patch Set: Created Oct. 5, 2012, 9:28 a.m.
Right Patch Set: ABP/Android proxy service Created Nov. 12, 2012, 8:53 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 package org.adblockplus.brazil; 1 package org.adblockplus.brazil;
2 2
3 import java.io.BufferedInputStream;
4 import java.io.EOFException; 3 import java.io.EOFException;
5 import java.io.FilterInputStream; 4 import java.io.FilterInputStream;
6 import java.io.FilterOutputStream; 5 import java.io.FilterOutputStream;
7 import java.io.IOException; 6 import java.io.IOException;
8 import java.io.InterruptedIOException; 7 import java.io.InterruptedIOException;
9 import java.io.OutputStream; 8 import java.io.OutputStream;
10 import java.net.ConnectException; 9 import java.net.ConnectException;
11 import java.net.MalformedURLException; 10 import java.net.MalformedURLException;
12 import java.net.URL; 11 import java.net.URL;
13 import java.net.UnknownHostException; 12 import java.net.UnknownHostException;
14 import java.util.List; 13 import java.util.List;
15 import java.util.Properties; 14 import java.util.regex.Pattern;
16 import java.util.zip.GZIPInputStream; 15 import java.util.zip.GZIPInputStream;
17 import java.util.zip.InflaterInputStream; 16 import java.util.zip.InflaterInputStream;
18 17
19 import org.adblockplus.ChunkedOutputStream; 18 import org.adblockplus.ChunkedOutputStream;
20 import org.adblockplus.android.AdblockPlus; 19 import org.adblockplus.android.AdblockPlus;
21 import org.literateprograms.BoyerMoore; 20 import org.literateprograms.BoyerMoore;
22 21
23 import sunlabs.brazil.server.Handler;
24 import sunlabs.brazil.server.Request; 22 import sunlabs.brazil.server.Request;
25 import sunlabs.brazil.server.Server; 23 import sunlabs.brazil.server.Server;
26 import sunlabs.brazil.util.MatchString; 24 import sunlabs.brazil.util.MatchString;
27 import sunlabs.brazil.util.http.HttpInputStream; 25 import sunlabs.brazil.util.http.HttpInputStream;
28 import sunlabs.brazil.util.http.HttpRequest; 26 import sunlabs.brazil.util.http.HttpRequest;
29 import sunlabs.brazil.util.http.MimeHeaders; 27 import sunlabs.brazil.util.http.MimeHeaders;
30 import android.util.Log; 28 import android.util.Log;
31 29
32 /** 30 /**
33 * The <code>RequestHandler</code> implements a proxy service optionally 31 * The <code>RequestHandler</code> implements a proxy service optionally
(...skipping 22 matching lines...) Expand all
56 * 54 *
57 * <pre> 55 * <pre>
58 * handler=adblock 56 * handler=adblock
59 * adblock.class=org.adblockplus.brazil.RequestHandler 57 * adblock.class=org.adblockplus.brazil.RequestHandler
60 * </pre> 58 * </pre>
61 * 59 *
62 * See the description under {@link sunlabs.brazil.server.Handler#respond 60 * See the description under {@link sunlabs.brazil.server.Handler#respond
63 * respond} for a more detailed explanation. 61 * respond} for a more detailed explanation.
64 */ 62 */
65 63
66 public class RequestHandler implements Handler 64 public class RequestHandler extends BaseRequestHandler
67 { 65 {
68 public static final String PROXY_HOST = "proxyHost";
69 public static final String PROXY_PORT = "proxyPort";
70 public static final String AUTH = "auth";
71
72 private AdblockPlus application; 66 private AdblockPlus application;
73 private String prefix;
74
75 private String via; 67 private String via;
76 68 private static Pattern RE_HTTP = Pattern.compile("^https?:");
77 private String proxyHost; 69
78 private int proxyPort = 80; 70 private boolean shouldLogHeaders;
79 private String auth;
80
81 private boolean shouldLog; // if true, log all headers
82 71
83 @Override 72 @Override
84 public boolean init(Server server, String prefix) 73 public boolean init(Server server, String prefix)
85 { 74 {
86 this.prefix = prefix; 75 super.init(server, prefix);
76
87 application = AdblockPlus.getApplication(); 77 application = AdblockPlus.getApplication();
88 78 shouldLogHeaders = (server.props.getProperty(prefix + "proxylog") != null);
89 Properties props = server.props;
90
91 proxyHost = props.getProperty(prefix + PROXY_HOST);
92
93 String s = props.getProperty(prefix + PROXY_PORT);
94 try
95 {
96 proxyPort = Integer.decode(s).intValue();
97 }
98 catch (Exception e)
99 {
100 }
101
102 auth = props.getProperty(prefix + AUTH);
103
104 shouldLog = (props.getProperty(prefix + "proxylog") != null);
105
106 via = " " + server.hostName + ":" + server.listen.getLocalPort() + " (" + se rver.name + ")"; 79 via = " " + server.hostName + ":" + server.listen.getLocalPort() + " (" + se rver.name + ")";
107 80
108 return true; 81 return true;
109 } 82 }
110 83
111 @Override 84 @Override
112 public boolean respond(Request request) throws IOException 85 public boolean respond(Request request) throws IOException
113 { 86 {
114 boolean block = false; 87 boolean block = false;
115 String reqHost = null; 88 String reqHost = null;
116 String refHost = null; 89 String refHost = null;
117 90
91 String referrer = request.getRequestHeader("referer");
92
118 try 93 try
119 { 94 {
120 reqHost = (new URL(request.url)).getHost(); 95 reqHost = (new URL(request.url)).getHost();
121 refHost = (new URL(request.getRequestHeader("referer"))).getHost(); 96 if (referrer != null)
97 refHost = (new URL(referrer)).getHost();
122 } 98 }
123 catch (MalformedURLException e) 99 catch (MalformedURLException e)
124 { 100 {
101 // We are transparent, it's not our deal if it's malformed.
125 } 102 }
126 103
127 try 104 try
128 { 105 {
129 block = application.matches(request.url, request.query, reqHost, refHost, request.getRequestHeader("accept")); 106 if (referrer != null)
107 block = application.matches(request.url, request.query, reqHost, refHost , request.getRequestHeader("accept"));
130 } 108 }
131 catch (Exception e) 109 catch (Exception e)
132 { 110 {
133 Log.e(prefix, "Filter error", e); 111 Log.e(prefix, "Filter error", e);
134 } 112 }
135 113
136 request.log(Server.LOG_LOG, prefix, block + ": " + request.url); 114 request.log(Server.LOG_LOG, prefix, block + ": " + request.url + " ("+ refHo st +")");
115
116 int count = request.server.requestCount;
117 if (shouldLogHeaders)
118 {
119 System.err.println(dumpHeaders(count, request, request.headers, true));
120 }
137 121
138 if (block) 122 if (block)
139 { 123 {
140 request.sendError(403, "Blocked by Adblock Plus"); 124 request.sendHeaders(204, null, 0);
141 return true; 125 return true;
142 } 126 }
143 127
144 // Do not further process non-http requests 128 // Do not further process non-http requests
145 if (request.url.startsWith("http:") == false && request.url.startsWith("http s:") == false) 129 if (!RE_HTTP.matcher(request.url).find())
146 { 130 {
147 return false; 131 return false;
148 } 132 }
149 133
150 String url = request.url; 134 String url = request.url;
151 135
152 if ((request.query != null) && (request.query.length() > 0)) 136 if ((request.query != null) && (request.query.length() > 0))
153 { 137 {
154 url += "?" + request.query; 138 url += "?" + request.query;
155 }
156
157 int count = request.server.requestCount;
158 if (shouldLog)
159 {
160 System.err.println(dumpHeaders(count, request, request.headers, true));
161 } 139 }
162 140
163 /* 141 /*
164 * "Proxy-Connection" may be used (instead of just "Connection") 142 * "Proxy-Connection" may be used (instead of just "Connection")
165 * to keep alive a connection between a client and this proxy. 143 * to keep alive a connection between a client and this proxy.
166 */ 144 */
167 String pc = request.headers.get("Proxy-Connection"); 145 String pc = request.headers.get("Proxy-Connection");
168 if (pc != null) 146 if (pc != null)
169 { 147 {
170 request.connectionHeader = "Proxy-Connection"; 148 request.connectionHeader = "Proxy-Connection";
(...skipping 19 matching lines...) Expand all
190 168
191 if (request.postData != null) 169 if (request.postData != null)
192 { 170 {
193 OutputStream out = target.getOutputStream(); 171 OutputStream out = target.getOutputStream();
194 out.write(request.postData); 172 out.write(request.postData);
195 out.close(); 173 out.close();
196 } 174 }
197 175
198 target.connect(); 176 target.connect();
199 177
200 if (shouldLog) 178 if (shouldLogHeaders)
201 { 179 {
202 System.err.println(" " + target.status + "\n" + dumpHeaders(count, request, target.responseHeaders, false)); 180 System.err.println(" " + target.status + "\n" + dumpHeaders(count, request, target.responseHeaders, false));
203 } 181 }
204 HttpRequest.removePointToPointHeaders(target.responseHeaders, true); 182 HttpRequest.removePointToPointHeaders(target.responseHeaders, true);
205 183
206 request.setStatus(target.getResponseCode()); 184 request.setStatus(target.getResponseCode());
207 target.responseHeaders.copyTo(request.responseHeaders); 185 target.responseHeaders.copyTo(request.responseHeaders);
208 try 186 try
209 { 187 {
210 request.responseHeaders.add("Via", target.status.substring(0, 8) + via); 188 request.responseHeaders.add("Via", target.status.substring(0, 8) + via);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 { 237 {
260 in = new GZIPInputStream(his); 238 in = new GZIPInputStream(his);
261 } 239 }
262 else if (encodingHeader.equals("compress") || encodingHeader.equals("x -compress")) 240 else if (encodingHeader.equals("compress") || encodingHeader.equals("x -compress"))
263 { 241 {
264 in = new InflaterInputStream(his); 242 in = new InflaterInputStream(his);
265 } 243 }
266 else 244 else
267 { 245 {
268 // Unsupported encoding, proxy content as-is 246 // Unsupported encoding, proxy content as-is
269 in = new BufferedInputStream(his); 247 in = his;
270 out = request.out; 248 out = request.out;
271 selectors = null; 249 selectors = null;
272 } 250 }
273 } 251 }
274 else 252 else
275 { 253 {
276 in = new BufferedInputStream(his); 254 in = his;
277 } 255 }
278 // Use chunked encoding when injecting filters in page 256 // Use chunked encoding when injecting filters in page
279 if (out == null) 257 if (out == null)
280 { 258 {
281 request.responseHeaders.remove("Content-Length"); 259 request.responseHeaders.remove("Content-Length");
282 request.responseHeaders.remove("Content-Encoding"); 260 request.responseHeaders.remove("Content-Encoding");
283 out = new ChunkedOutputStream(request.out); 261 out = new ChunkedOutputStream(request.out);
284 request.responseHeaders.add("Transfer-Encoding", "chunked"); 262 request.responseHeaders.add("Transfer-Encoding", "chunked");
285 size = Integer.MAX_VALUE; 263 size = Integer.MAX_VALUE;
286 } 264 }
287 265
288 request.sendHeaders(-1, null, -1); 266 request.sendHeaders(-1, null, -1);
289 267
290 byte[] buf = new byte[Math.min(4096, size)]; 268 byte[] buf = new byte[Math.min(4096, size)];
291
292 Log.e(prefix, request.url);
293 269
294 boolean sent = selectors == null; 270 boolean sent = selectors == null;
295 // TODO Do we need to set encoding here? 271 // TODO Do we need to set encoding here?
296 BoyerMoore matcher = new BoyerMoore("<html".getBytes()); 272 BoyerMoore matcher = new BoyerMoore("<html".getBytes());
297 273
298 while (size > 0) 274 while (size > 0)
299 { 275 {
300 out.flush(); 276 out.flush();
301 277
302 count = in.read(buf, 0, Math.min(buf.length, size)); 278 count = in.read(buf, 0, Math.min(buf.length, size));
(...skipping 24 matching lines...) Expand all
327 out.write(buf, 0, count); 303 out.write(buf, 0, count);
328 } 304 }
329 catch (IOException e) 305 catch (IOException e)
330 { 306 {
331 break; 307 break;
332 } 308 }
333 } 309 }
334 // The correct way would be to close ChunkedOutputStream 310 // The correct way would be to close ChunkedOutputStream
335 // but we can not do it because underlying output stream is 311 // but we can not do it because underlying output stream is
336 // used later in caller code. So we use this ugly hack: 312 // used later in caller code. So we use this ugly hack:
337 try 313 if (out instanceof ChunkedOutputStream)
338 {
339 ((ChunkedOutputStream) out).writeFinalChunk(); 314 ((ChunkedOutputStream) out).writeFinalChunk();
340 }
341 catch (ClassCastException e)
342 {
343 // ignore
344 }
345 } 315 }
346 } 316 }
347 catch (InterruptedIOException e) 317 catch (InterruptedIOException e)
348 { 318 {
349 /* 319 /*
350 * Read timeout while reading from the remote side. We use a 320 * Read timeout while reading from the remote side. We use a
351 * read timeout in case the target never responds. 321 * read timeout in case the target never responds.
352 */ 322 */
353 request.sendError(408, "Timeout / No response"); 323 request.sendError(408, "Timeout / No response");
354 } 324 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 } 378 }
409 379
410 for (int i = 0; i < headers.size(); i++) 380 for (int i = 0; i < headers.size(); i++)
411 { 381 {
412 sb.append(prompt).append(headers.getKey(i)); 382 sb.append(prompt).append(headers.getKey(i));
413 sb.append(": ").append(headers.get(i)).append("\n"); 383 sb.append(": ").append(headers.get(i)).append("\n");
414 } 384 }
415 return (sb.toString()); 385 return (sb.toString());
416 } 386 }
417 } 387 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld