Left: | ||
Right: |
LEFT | RIGHT |
---|---|
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-2013 Eyeo GmbH | 3 * Copyright (C) 2006-2013 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 |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
16 */ | 16 */ |
17 | 17 |
18 package org.adblockplus.android; | 18 package org.adblockplus.android; |
19 | 19 |
20 import java.io.BufferedReader; | 20 import java.io.BufferedReader; |
21 import java.io.File; | 21 import java.io.File; |
22 import java.io.FileNotFoundException; | 22 import java.io.FileNotFoundException; |
23 import java.io.IOException; | 23 import java.io.IOException; |
24 import java.io.InputStream; | 24 import java.io.InputStream; |
25 import java.io.InputStreamReader; | 25 import java.io.InputStreamReader; |
26 import java.util.ArrayList; | 26 import java.util.ArrayList; |
27 import java.util.Calendar; | 27 import java.util.Calendar; |
28 import java.util.Collections; | 28 import java.util.LinkedHashMap; |
29 import java.util.HashMap; | |
30 import java.util.HashSet; | |
31 import java.util.List; | 29 import java.util.List; |
32 import java.util.Map; | 30 import java.util.Map; |
33 import java.util.Set; | |
34 import java.util.TimeZone; | 31 import java.util.TimeZone; |
35 import java.util.regex.Pattern; | 32 import java.util.regex.Pattern; |
36 | 33 |
37 import org.adblockplus.android.updater.AlarmReceiver; | 34 import org.adblockplus.android.updater.AlarmReceiver; |
38 | 35 |
39 import android.app.ActivityManager; | 36 import android.app.ActivityManager; |
40 import android.app.ActivityManager.RunningServiceInfo; | 37 import android.app.ActivityManager.RunningServiceInfo; |
41 import android.app.AlarmManager; | 38 import android.app.AlarmManager; |
42 import android.app.Application; | 39 import android.app.Application; |
43 import android.app.PendingIntent; | 40 import android.app.PendingIntent; |
44 import android.content.Context; | 41 import android.content.Context; |
45 import android.content.Intent; | 42 import android.content.Intent; |
43 import android.content.SharedPreferences; | |
44 import android.content.SharedPreferences.Editor; | |
46 import android.content.pm.PackageInfo; | 45 import android.content.pm.PackageInfo; |
47 import android.content.pm.PackageManager; | 46 import android.content.pm.PackageManager; |
48 import android.content.pm.PackageManager.NameNotFoundException; | 47 import android.content.pm.PackageManager.NameNotFoundException; |
49 import android.net.ConnectivityManager; | 48 import android.net.ConnectivityManager; |
50 import android.net.NetworkInfo; | 49 import android.net.NetworkInfo; |
51 import android.net.Uri; | 50 import android.net.Uri; |
52 import android.os.Build; | 51 import android.os.Build; |
52 import android.preference.PreferenceManager; | |
53 import android.provider.Settings; | 53 import android.provider.Settings; |
54 import android.util.Log; | 54 import android.util.Log; |
55 | 55 |
56 public class AdblockPlus extends Application | 56 public class AdblockPlus extends Application |
57 { | 57 { |
58 private final static String TAG = "Application"; | 58 private final static String TAG = "Application"; |
59 | 59 |
60 private final static Pattern RE_JS = Pattern.compile(".*\\.js$", Pattern.CASE_ INSENSITIVE); | 60 private final static Pattern RE_JS = Pattern.compile(".*\\.js$", Pattern.CASE_ INSENSITIVE); |
61 private final static Pattern RE_CSS = Pattern.compile(".*\\.css$", Pattern.CAS E_INSENSITIVE); | 61 private final static Pattern RE_CSS = Pattern.compile(".*\\.css$", Pattern.CAS E_INSENSITIVE); |
62 private final static Pattern RE_IMAGE = Pattern.compile(".*\\.(?:gif|png|jpe?g |bmp|ico)$", Pattern.CASE_INSENSITIVE); | 62 private final static Pattern RE_IMAGE = Pattern.compile(".*\\.(?:gif|png|jpe?g |bmp|ico)$", Pattern.CASE_INSENSITIVE); |
(...skipping 18 matching lines...) Expand all Loading... | |
81 private Subscription[] subscriptions; | 81 private Subscription[] subscriptions; |
82 | 82 |
83 /** | 83 /** |
84 * Indicates whether filtering is enabled or not. | 84 * Indicates whether filtering is enabled or not. |
85 */ | 85 */ |
86 private boolean filteringEnabled = false; | 86 private boolean filteringEnabled = false; |
87 | 87 |
88 private ABPEngine abpEngine; | 88 private ABPEngine abpEngine; |
89 | 89 |
90 private static AdblockPlus instance; | 90 private static AdblockPlus instance; |
91 | 91 |
92 private Map<String, Set<String>> referrerMapping = new HashMap<String, Set<Str ing>>(); | 92 private static class ReferrerMappingCache extends LinkedHashMap<String, String > |
93 { | |
94 private static final long serialVersionUID = 1L; | |
95 private static final int MAX_SIZE = 5000; | |
96 | |
97 public ReferrerMappingCache() | |
98 { | |
99 super(MAX_SIZE + 1, 0.75f, true); | |
100 } | |
101 | |
102 @Override | |
103 protected boolean removeEldestEntry(Map.Entry<String, String> eldest) | |
104 { | |
105 return size() > MAX_SIZE; | |
106 } | |
107 }; | |
108 | |
109 private ReferrerMappingCache referrerMapping = new ReferrerMappingCache(); | |
93 | 110 |
94 /** | 111 /** |
95 * Returns pointer to itself (singleton pattern). | 112 * Returns pointer to itself (singleton pattern). |
96 */ | 113 */ |
97 public static AdblockPlus getApplication() | 114 public static AdblockPlus getApplication() |
98 { | 115 { |
99 return instance; | 116 return instance; |
100 } | 117 } |
101 | 118 |
102 public int getBuildNumber() | 119 public int getBuildNumber() |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
284 abpEngine.actualizeSubscriptionStatus(url); | 301 abpEngine.actualizeSubscriptionStatus(url); |
285 } | 302 } |
286 | 303 |
287 | 304 |
288 /** | 305 /** |
289 * Enables or disables Acceptable Ads | 306 * Enables or disables Acceptable Ads |
290 */ | 307 */ |
291 public void setAcceptableAdsEnabled(boolean enabled) | 308 public void setAcceptableAdsEnabled(boolean enabled) |
292 { | 309 { |
293 abpEngine.setAcceptableAdsEnabled(enabled); | 310 abpEngine.setAcceptableAdsEnabled(enabled); |
311 } | |
312 | |
313 public String getAcceptableAdsUrl() | |
314 { | |
315 final String documentationLink = abpEngine.getDocumentationLink(); | |
316 final String locale = getResources().getConfiguration().locale.toString().re place("_", "-"); | |
317 return documentationLink.replace("%LINK%", "acceptable_ads").replace("%LANG% ", locale); | |
318 } | |
319 | |
320 public void setNotifiedAboutAcceptableAds(boolean notified) | |
321 { | |
322 final SharedPreferences preferences = PreferenceManager.getDefaultSharedPref erences(this); | |
323 final Editor editor = preferences.edit(); | |
324 editor.putBoolean("notified_about_acceptable_ads", notified); | |
325 editor.commit(); | |
326 } | |
327 | |
328 public boolean isNotifiedAboutAcceptableAds() | |
329 { | |
330 final SharedPreferences preferences = PreferenceManager.getDefaultSharedPref erences(this); | |
331 return preferences.getBoolean("notified_about_acceptable_ads", false); | |
294 } | 332 } |
295 | 333 |
296 /** | 334 /** |
297 * Returns ElemHide selectors for domain. | 335 * Returns ElemHide selectors for domain. |
298 * | 336 * |
299 * @param domain The domain | 337 * @param domain The domain |
300 * @return A list of CSS selectors | 338 * @return A list of CSS selectors |
301 */ | 339 */ |
302 public String[] getSelectorsForDomain(final String domain) | 340 public String[] getSelectorsForDomain(final String domain) |
303 { | 341 { |
(...skipping 13 matching lines...) Expand all Loading... | |
317 * @param referrer | 355 * @param referrer |
318 * Request referrer header | 356 * Request referrer header |
319 * @param accept | 357 * @param accept |
320 * Request accept header | 358 * Request accept header |
321 * @return true if matched filter was found | 359 * @return true if matched filter was found |
322 * @throws Exception | 360 * @throws Exception |
323 */ | 361 */ |
324 public boolean matches(String url, String query, String referrer, String accep t) | 362 public boolean matches(String url, String query, String referrer, String accep t) |
325 { | 363 { |
326 if (referrer != null) | 364 if (referrer != null) |
327 recordReferrer(url, referrer); | 365 referrerMapping.put(url, referrer); |
328 | 366 |
329 if (!filteringEnabled) | 367 if (!filteringEnabled) |
330 return false; | 368 return false; |
331 | 369 |
332 String contentType = null; | 370 String contentType = null; |
333 | 371 |
334 if (accept != null) | 372 if (accept != null) |
335 { | 373 { |
336 if (accept.contains("text/css")) | 374 if (accept.contains("text/css")) |
337 contentType = "STYLESHEET"; | 375 contentType = "STYLESHEET"; |
(...skipping 11 matching lines...) Expand all Loading... | |
349 contentType = "IMAGE"; | 387 contentType = "IMAGE"; |
350 else if (RE_FONT.matcher(url).matches()) | 388 else if (RE_FONT.matcher(url).matches()) |
351 contentType = "FONT"; | 389 contentType = "FONT"; |
352 } | 390 } |
353 if (contentType == null) | 391 if (contentType == null) |
354 contentType = "OTHER"; | 392 contentType = "OTHER"; |
355 | 393 |
356 if (!"".equals(query)) | 394 if (!"".equals(query)) |
357 url = url + "?" + query; | 395 url = url + "?" + query; |
358 | 396 |
359 final List<List<String>> referrerChains = referrer != null | 397 final List<String> referrerChain = buildReferrerChain(referrer); |
360 ? buildReferrerChains(referrer) | 398 Log.d("Referrer chain", url + ": " + referrerChain.toString()); |
361 : Collections.singletonList(Collections.<String>emptyList()); | 399 String[] referrerChainArray = referrerChain.toArray(new String[referrerChain .size()]); |
362 for (List<String> referrerChain : referrerChains) | 400 return abpEngine.matches(url, contentType, referrerChainArray); |
363 { | 401 } |
364 Log.d("Referrer chain", url + ": " + referrerChain.toString()); | 402 |
365 String[] referrerChainArray = referrerChain.toArray(new String[referrerCha in.size()]); | 403 private List<String> buildReferrerChain(String url) |
366 if (abpEngine.matches(url, contentType, referrerChainArray)) | 404 { |
367 return true; | 405 final List<String> referrerChain = new ArrayList<String>(); |
368 } | 406 // We need to limit the chain length to ensure we don't block indefinitely i f there's |
369 return false; | 407 // a referrer loop. |
370 } | 408 final int maxChainLength = 10; |
371 | 409 for (int i = 0; i < maxChainLength && url != null; i++) |
372 private void recordReferrer(String url, String referrer) | 410 { |
373 { | |
374 // TODO: Garbage collect the mapping - currently it will grow out of control . | |
375 // In addition, we might have to persist mappings, because clients are | |
376 // likely to cache some requests in the chain. | |
377 if (!referrerMapping.containsKey(url)) | |
378 referrerMapping.put(url, new HashSet<String>()); | |
379 Set<String> referrers = referrerMapping.get(url); | |
380 referrers.add(referrer); | |
Wladimir Palant
2013/11/25 10:24:41
Do you think that this is really necessary? We are
Felix Dahlke
2013/11/27 12:19:32
Yes, I think it makes sense to not have a single c
Wladimir Palant
2013/11/27 12:59:01
Not with the same parameters - they have to know s
Felix Dahlke
2013/11/27 13:38:59
Alright, didn't think of that. Makes the code much
| |
381 } | |
382 | |
383 private List<List<String>> buildReferrerChains(String url) | |
384 { | |
385 List<List<String>> referrerChains = new ArrayList<List<String>>(); | |
386 Set<String> referrers = referrerMapping.get(url); | |
387 if (referrers == null) | |
388 { | |
389 List<String> referrerChain = new ArrayList<String>(); | |
390 referrerChain.add(url); | 411 referrerChain.add(url); |
391 referrerChains.add(referrerChain); | 412 url = referrerMapping.get(url); |
392 return referrerChains; | 413 } |
393 } | 414 return referrerChain; |
394 | |
395 for (String referrer : referrers) { | |
396 List<List<String>> currentReferrerChains = buildReferrerChains(referrer); | |
397 for (List<String> referrerChain : currentReferrerChains) | |
398 { | |
399 referrerChain.add(0, url); | |
400 referrerChains.add(referrerChain); | |
401 } | |
402 } | |
403 return referrerChains; | |
404 } | 415 } |
405 | 416 |
406 /** | 417 /** |
407 * Checks if filtering is enabled. | 418 * Checks if filtering is enabled. |
408 */ | 419 */ |
409 public boolean isFilteringEnabled() | 420 public boolean isFilteringEnabled() |
410 { | 421 { |
411 return filteringEnabled; | 422 return filteringEnabled; |
412 } | 423 } |
413 | 424 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
528 Log.e(TAG, e.getMessage(), e); | 539 Log.e(TAG, e.getMessage(), e); |
529 } | 540 } |
530 | 541 |
531 // Set crash handler | 542 // Set crash handler |
532 Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(this)); | 543 Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(this)); |
533 | 544 |
534 // Initiate update check | 545 // Initiate update check |
535 scheduleUpdater(0); | 546 scheduleUpdater(0); |
536 } | 547 } |
537 } | 548 } |
LEFT | RIGHT |