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

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

Issue 5697499218051072: Usage of new API, cleanups (reduced) (Closed)
Left Patch Set: Created April 11, 2014, 1:31 p.m.
Right Patch Set: Even more review issues fixed. Created April 28, 2014, 10:18 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
« no previous file with change/comment | « src/org/adblockplus/brazil/BaseRequestHandler.java ('k') | src/org/adblockplus/brazil/SSLConnectionHandler.java » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2014 Eyeo GmbH 3 * Copyright (C) 2006-2014 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 30 matching lines...) Expand all
41 41
42 import sunlabs.brazil.server.Request; 42 import sunlabs.brazil.server.Request;
43 import sunlabs.brazil.server.Server; 43 import sunlabs.brazil.server.Server;
44 import sunlabs.brazil.util.MatchString; 44 import sunlabs.brazil.util.MatchString;
45 import sunlabs.brazil.util.http.HttpInputStream; 45 import sunlabs.brazil.util.http.HttpInputStream;
46 import sunlabs.brazil.util.http.HttpRequest; 46 import sunlabs.brazil.util.http.HttpRequest;
47 import android.util.Log; 47 import android.util.Log;
48 48
49 /** 49 /**
50 * The <code>RequestHandler</code> implements a proxy service optionally 50 * The <code>RequestHandler</code> implements a proxy service optionally
51 * modifying output. The following configuration parameters are used to 51 * modifying output.
52 * initialize this <code>Handler</code>: 52 * The following configuration parameters are used to initialize this
53 * <code>Handler</code>:
53 * <dl class=props> 54 * <dl class=props>
54 * 55 *
55 * <dt>prefix, suffix, glob, match 56 * <dt>prefix, suffix, glob, match
56 * <dd>Specify the URL that triggers this handler. (See {@link MatchString}). 57 * <dd>Specify the URL that triggers this handler. (See {@link MatchString}).
57 * <dt>auth 58 * <dt>auth
58 * <dd>The value of the proxy-authenticate header (if any) sent to the upstream 59 * <dd>The value of the proxy-authenticate header (if any) sent to the upstream
59 * proxy 60 * proxy
60 * <dt>proxyHost 61 * <dt>proxyHost
61 * <dd>If specified, the name of the upstream proxy 62 * <dd>If specified, the name of the upstream proxy
62 * <dt>proxyPort 63 * <dt>proxyPort
63 * <dd>The upstream proxy port, if a proxyHost is specified (defaults to 80) 64 * <dd>The upstream proxy port, if a proxyHost is specified (defaults to 80)
64 * <dt>proxylog 65 * <dt>proxylog
65 * <dd>If set all http headers will be logged to the console. This is for 66 * <dd>If set all http headers will be logged to the console. This is for
66 * debugging. 67 * debugging.
67 * 68 *
68 * </dl> 69 * </dl>
69 * 70 *
70 * A sample set of configuration parameters illustrating how to use this handler 71 * A sample set of configuration parameters illustrating how to use this
71 * follows: 72 * handler follows:
72 * 73 *
73 * <pre> 74 * <pre>
74 * handler=adblock 75 * handler=adblock
75 * adblock.class=org.adblockplus.brazil.RequestHandler 76 * adblock.class=org.adblockplus.brazil.RequestHandler
76 * </pre> 77 * </pre>
77 * 78 *
78 * See the description under {@link sunlabs.brazil.server.Handler#respond 79 * See the description under {@link sunlabs.brazil.server.Handler#respond
79 * respond} for a more detailed explanation. 80 * respond} for a more detailed explanation.
80 */ 81 */
81 82
82 public class RequestHandler extends BaseRequestHandler 83 public class RequestHandler extends BaseRequestHandler
83 { 84 {
84 private final static Pattern RE_HTTP = Pattern.compile("^https?:");
85
86 private AdblockPlus application; 85 private AdblockPlus application;
87 private String via; 86 private String via;
87 private static final Pattern RE_HTTP = Pattern.compile("^https?:");
88 88
89 @Override 89 @Override
90 public boolean init(final Server server, final String prefix) 90 public boolean init(final Server server, final String prefix)
91 { 91 {
92 super.init(server, prefix); 92 super.init(server, prefix);
93 93
94 this.application = AdblockPlus.getApplication(); 94 application = AdblockPlus.getApplication();
95 this.via = " " + server.hostName + ":" + server.listen.getLocalPort() + " (" + server.name + ")"; 95 via = " " + server.hostName + ":" + server.listen.getLocalPort() + " (" + se rver.name + ")";
96 96
97 return true; 97 return true;
98 } 98 }
99 99
100 @Override 100 @Override
101 public boolean respond(final Request request) throws IOException 101 public boolean respond(final Request request) throws IOException
102 { 102 {
103 boolean block = false; 103 boolean block = false;
104 104
105 try 105 try
106 { 106 {
107 block = this.application.matches(request.url, request.query, request.getRe questHeader("referer"), request.getRequestHeader("accept")); 107 block = application.matches(request.url, request.query, request.getRequest Header("referer"), request.getRequestHeader("accept"));
108 } 108 }
109 catch (final Exception e) 109 catch (final Exception e)
110 { 110 {
111 Log.e(this.prefix, "Filter error", e); 111 Log.e(prefix, "Filter error", e);
112 } 112 }
113 113
114 request.log(Server.LOG_LOG, this.prefix, block + ": " + request.url); 114 request.log(Server.LOG_LOG, prefix, block + ": " + request.url);
115 115
116 int count = request.server.requestCount; 116 int count = request.server.requestCount;
117 if (this.shouldLogHeaders) 117 if (shouldLogHeaders)
118 { 118 {
119 System.err.println(dumpHeaders(count, request, request.headers, true)); 119 System.err.println(dumpHeaders(count, request, request.headers, true));
120 } 120 }
121 121
122 if (block) 122 if (block)
123 { 123 {
124 request.sendHeaders(204, null, 0); 124 request.sendHeaders(204, null, 0);
125 return true; 125 return true;
126 } 126 }
127 127
128 // Do not further process non-http requests 128 // Do not further process non-http requests
129 if (!RE_HTTP.matcher(request.url).find()) 129 if (!RE_HTTP.matcher(request.url).find())
130 { 130 {
131 return false; 131 return false;
132 } 132 }
133 133
134 String url = request.url; 134 String url = request.url;
135 135
136 if ((request.query != null) && (request.query.length() > 0)) 136 if ((request.query != null) && (request.query.length() > 0))
137 { 137 {
138 url += "?" + request.query; 138 url += "?" + request.query;
139 } 139 }
140 140
141 /* 141 /*
142 * "Proxy-Connection" may be used (instead of just "Connection") to keep 142 * "Proxy-Connection" may be used (instead of just "Connection")
143 * alive a connection between a client and this proxy. 143 * to keep alive a connection between a client and this proxy.
144 */ 144 */
145 final String pc = request.headers.get("Proxy-Connection"); 145 final String pc = request.headers.get("Proxy-Connection");
146 if (pc != null) 146 if (pc != null)
147 { 147 {
148 request.connectionHeader = "Proxy-Connection"; 148 request.connectionHeader = "Proxy-Connection";
149 request.keepAlive = pc.equalsIgnoreCase("Keep-Alive"); 149 request.keepAlive = pc.equalsIgnoreCase("Keep-Alive");
150 } 150 }
151 151
152 HttpRequest.removePointToPointHeaders(request.headers, false); 152 HttpRequest.removePointToPointHeaders(request.headers, false);
153 153
154 final HttpRequest target = new HttpRequest(url); 154 final HttpRequest target = new HttpRequest(url);
155 try 155 try
156 { 156 {
157 target.setMethod(request.method); 157 target.setMethod(request.method);
158 request.headers.copyTo(target.requestHeaders); 158 request.headers.copyTo(target.requestHeaders);
159 159
160 if (this.proxyHost != null) 160 if (proxyHost != null)
161 { 161 {
162 target.setProxy(this.proxyHost, this.proxyPort); 162 target.setProxy(proxyHost, proxyPort);
163 if (this.auth != null) 163 if (auth != null)
164 { 164 {
165 target.requestHeaders.add("Proxy-Authorization", this.auth); 165 target.requestHeaders.add("Proxy-Authorization", auth);
166 } 166 }
167 } 167 }
168 168
169 if (request.postData != null) 169 if (request.postData != null)
170 { 170 {
171 final OutputStream out = target.getOutputStream(); 171 final OutputStream out = target.getOutputStream();
172 out.write(request.postData); 172 out.write(request.postData);
173 out.close(); 173 out.close();
174 } 174 }
175 else 175 else
176 { 176 {
177 target.setHttpInputStream(request.in); 177 target.setHttpInputStream(request.in);
178 } 178 }
179 target.connect(); 179 target.connect();
180 180
181 if (this.shouldLogHeaders) 181 if (shouldLogHeaders)
182 { 182 {
183 System.err.println(" " + target.status + "\n" + dumpHeaders(count, request, target.responseHeaders, false)); 183 System.err.println(" " + target.status + "\n" + dumpHeaders(count, request, target.responseHeaders, false));
184 } 184 }
185 HttpRequest.removePointToPointHeaders(target.responseHeaders, true); 185 HttpRequest.removePointToPointHeaders(target.responseHeaders, true);
186 186
187 request.setStatus(target.getResponseCode()); 187 request.setStatus(target.getResponseCode());
188 target.responseHeaders.copyTo(request.responseHeaders); 188 target.responseHeaders.copyTo(request.responseHeaders);
189 try 189 try
190 { 190 {
191 request.responseHeaders.add("Via", target.status.substring(0, 8) + this. via); 191 request.responseHeaders.add("Via", target.status.substring(0, 8) + via);
192 } 192 }
193 catch (final StringIndexOutOfBoundsException e) 193 catch (final StringIndexOutOfBoundsException e)
194 { 194 {
195 request.responseHeaders.add("Via", this.via); 195 request.responseHeaders.add("Via", via);
196 } 196 }
197 197
198 // Detect if we need to add ElemHide filters 198 // Detect if we need to add ElemHide filters
199 final String type = request.responseHeaders.get("Content-Type"); 199 final String type = request.responseHeaders.get("Content-Type");
200 200
201 String[] selectors = null; 201 String[] selectors = null;
202 if (type != null && type.toLowerCase().startsWith("text/html")) 202 if (type != null && type.toLowerCase().startsWith("text/html"))
203 { 203 {
204 String reqHost = ""; 204 String reqHost = "";
205 205
206 try 206 try
207 { 207 {
208 reqHost = (new URL(request.url)).getHost(); 208 reqHost = (new URL(request.url)).getHost();
209 } 209 }
210 catch (final MalformedURLException e) 210 catch (final MalformedURLException e)
211 { 211 {
212 // We are transparent, it's not our deal if it's malformed. 212 // We are transparent, it's not our deal if it's malformed.
213 } 213 }
214 214
215 selectors = this.application.getSelectorsForDomain(reqHost); 215 selectors = application.getSelectorsForDomain(reqHost);
216 } 216 }
217 // If no filters are applicable just pass through the response 217 // If no filters are applicable just pass through the response
218 if (selectors == null || target.getResponseCode() != 200) 218 if (selectors == null || target.getResponseCode() != 200)
219 { 219 {
220 final int contentLength = target.getContentLength(); 220 final int contentLength = target.getContentLength();
221 if (contentLength == 0) 221 if (contentLength == 0)
222 { 222 {
223 // we do not use request.sendResponse to avoid arbitrary 223 // we do not use request.sendResponse to avoid arbitrary
224 // 200 -> 204 response code conversion 224 // 200 -> 204 response code conversion
225 request.sendHeaders(-1, null, -1); 225 request.sendHeaders(-1, null, -1);
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 if (matcher.matches()) 285 if (matcher.matches())
286 { 286 {
287 try 287 try
288 { 288 {
289 final String extractedCharsetName = matcher.group(0); 289 final String extractedCharsetName = matcher.group(0);
290 Charset.forName(extractedCharsetName); 290 Charset.forName(extractedCharsetName);
291 charsetName = extractedCharsetName; 291 charsetName = extractedCharsetName;
292 } 292 }
293 catch (final IllegalArgumentException e) 293 catch (final IllegalArgumentException e)
294 { 294 {
295 Log.e(this.prefix, "Unsupported site charset, falling back to " + charsetName, e); 295 Log.e(prefix, "Unsupported site charset, falling back to " + chars etName, e);
296 } 296 }
297 } 297 }
298 } 298 }
299 299
300 request.sendHeaders(-1, null, -1); 300 request.sendHeaders(-1, null, -1);
301 301
302 final byte[] buf = new byte[Math.min(4096, size)]; 302 final byte[] buf = new byte[Math.min(4096, size)];
303 303
304 boolean sent = selectors == null; 304 boolean sent = selectors == null;
305 final BoyerMoore matcher = new BoyerMoore("<html".getBytes()); 305 final BoyerMoore matcher = new BoyerMoore("<html".getBytes());
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 } 337 }
338 catch (final IOException e) 338 catch (final IOException e)
339 { 339 {
340 break; 340 break;
341 } 341 }
342 } 342 }
343 // The correct way would be to close ChunkedOutputStream 343 // The correct way would be to close ChunkedOutputStream
344 // but we can not do it because underlying output stream is 344 // but we can not do it because underlying output stream is
345 // used later in caller code. So we use this ugly hack: 345 // used later in caller code. So we use this ugly hack:
346 if (out instanceof ChunkedOutputStream) 346 if (out instanceof ChunkedOutputStream)
347 { 347 ((ChunkedOutputStream) out).writeFinalChunk();
348 ((ChunkedOutputStream)out).writeFinalChunk();
349 }
350 } 348 }
351 } 349 }
352 catch (final InterruptedIOException e) 350 catch (final InterruptedIOException e)
353 { 351 {
354 /* 352 /*
355 * Read timeout while reading from the remote side. We use a read timeout 353 * Read timeout while reading from the remote side. We use a
356 * in case the target never responds. 354 * read timeout in case the target never responds.
357 */ 355 */
358 request.sendError(408, "Timeout / No response"); 356 request.sendError(408, "Timeout / No response");
359 } 357 }
360 catch (final EOFException e) 358 catch (final EOFException e)
361 { 359 {
362 request.sendError(500, "No response"); 360 request.sendError(500, "No response");
363 } 361 }
364 catch (final UnknownHostException e) 362 catch (final UnknownHostException e)
365 { 363 {
366 request.sendError(500, "Unknown host"); 364 request.sendError(500, "Unknown host");
367 } 365 }
368 catch (final ConnectException e) 366 catch (final ConnectException e)
369 { 367 {
370 request.sendError(500, "Connection refused"); 368 request.sendError(500, "Connection refused");
371 } 369 }
372 catch (final IOException e) 370 catch (final IOException e)
373 { 371 {
374 /* 372 /*
375 * An IOException will happen if we can't communicate with the target or 373 * An IOException will happen if we can't communicate with the
376 * the client. Rather than attempting to discriminate, just send an error 374 * target or the client. Rather than attempting to discriminate,
377 * message to the client, and let the send fail if the client was the one 375 * just send an error message to the client, and let the send
378 * that was in error. 376 * fail if the client was the one that was in error.
379 */ 377 */
380 378
381 String msg = "Error from proxy"; 379 String msg = "Error from proxy";
382 if (e.getMessage() != null) 380 if (e.getMessage() != null)
383 { 381 {
384 msg += ": " + e.getMessage(); 382 msg += ": " + e.getMessage();
385 } 383 }
386 request.sendError(500, msg); 384 request.sendError(500, msg);
387 Log.e(this.prefix, msg, e); 385 Log.e(prefix, msg, e);
388 } 386 }
389 finally 387 finally
390 { 388 {
391 target.close(); 389 target.close();
392 } 390 }
393 return true; 391 return true;
394 } 392 }
395 } 393 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld