OLD | NEW |
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-2016 Eyeo GmbH | 3 * Copyright (C) 2006-2016 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 10 matching lines...) Expand all Loading... |
21 import java.io.BufferedOutputStream; | 21 import java.io.BufferedOutputStream; |
22 import java.io.BufferedReader; | 22 import java.io.BufferedReader; |
23 import java.io.DataInputStream; | 23 import java.io.DataInputStream; |
24 import java.io.DataOutputStream; | 24 import java.io.DataOutputStream; |
25 import java.io.File; | 25 import java.io.File; |
26 import java.io.FileInputStream; | 26 import java.io.FileInputStream; |
27 import java.io.FileOutputStream; | 27 import java.io.FileOutputStream; |
28 import java.io.IOException; | 28 import java.io.IOException; |
29 import java.io.StringReader; | 29 import java.io.StringReader; |
30 import java.net.URL; | 30 import java.net.URL; |
| 31 import java.nio.charset.StandardCharsets; |
31 import java.security.MessageDigest; | 32 import java.security.MessageDigest; |
32 import java.security.NoSuchAlgorithmException; | 33 import java.security.NoSuchAlgorithmException; |
33 import java.util.ArrayList; | 34 import java.util.ArrayList; |
34 import java.util.Collection; | 35 import java.util.Collection; |
35 import java.util.Collections; | 36 import java.util.Collections; |
36 import java.util.HashMap; | 37 import java.util.HashMap; |
37 import java.util.HashSet; | 38 import java.util.HashSet; |
38 import java.util.List; | 39 import java.util.List; |
39 import java.util.Locale; | 40 import java.util.Locale; |
40 import java.util.Map; | 41 import java.util.Map; |
(...skipping 18 matching lines...) Expand all Loading... |
59 public static final String KEY_UPDATE_TIMESTAMP = "_update_timestamp"; | 60 public static final String KEY_UPDATE_TIMESTAMP = "_update_timestamp"; |
60 public static final String KEY_TRIED_UPDATE_TIMESTAMP = "_tried_update_timesta
mp"; | 61 public static final String KEY_TRIED_UPDATE_TIMESTAMP = "_tried_update_timesta
mp"; |
61 public static final String KEY_DOWNLOAD_COUNT = "_download_count"; | 62 public static final String KEY_DOWNLOAD_COUNT = "_download_count"; |
62 public static final String KEY_ENABLED = "_enabled"; | 63 public static final String KEY_ENABLED = "_enabled"; |
63 public static final String KEY_HAS_FILTERS = "_has_filters"; | 64 public static final String KEY_HAS_FILTERS = "_has_filters"; |
64 public static final String KEY_META_HASH = "_meta_hash"; | 65 public static final String KEY_META_HASH = "_meta_hash"; |
65 | 66 |
66 public static final long MINIMAL_DOWNLOAD_INTERVAL = Engine.MILLIS_PER_HOUR /
4; | 67 public static final long MINIMAL_DOWNLOAD_INTERVAL = Engine.MILLIS_PER_HOUR /
4; |
67 public static final long DOWNLOAD_RETRY_INTERVAL = Engine.MILLIS_PER_HOUR; | 68 public static final long DOWNLOAD_RETRY_INTERVAL = Engine.MILLIS_PER_HOUR; |
68 | 69 |
69 private static final HashSet<String> ALLOWED_META_KEYS = new HashSet<String>()
; | 70 private static final HashSet<String> ALLOWED_META_KEYS = new HashSet<>(); |
70 private static final Locale LOCALE_EN = Locale.ENGLISH; | 71 private static final Locale LOCALE_EN = Locale.ENGLISH; |
71 | 72 |
72 private final long updateInterval = Engine.MILLIS_PER_DAY | 73 private final long updateInterval = Engine.MILLIS_PER_DAY |
73 + (long) (Engine.MILLIS_PER_HOUR * 8. * Math.random()); | 74 + (long) (Engine.MILLIS_PER_HOUR * 8. * Math.random()); |
74 | 75 |
75 /** | 76 /** |
76 * List of meta keys that are allowed to import from a downloaded | 77 * List of meta keys that are allowed to import from a downloaded |
77 * subscription. | 78 * subscription. |
78 */ | 79 */ |
79 private static final String[] ALLOWED_META_KEYS_ARRAY = | 80 private static final String[] ALLOWED_META_KEYS_ARRAY = |
80 { | 81 { |
81 "checksum", KEY_VERSION, KEY_TITLE, "last modified", "expires", "homepage"
, "licence" | 82 "checksum", KEY_VERSION, KEY_TITLE, "last modified", "expires", "homepage"
, "licence" |
82 }; | 83 }; |
83 | 84 |
84 private final URL url; | 85 private final URL url; |
85 private final Type type; | 86 private final Type type; |
86 private final HashMap<String, String> meta = new HashMap<String, String>(); | 87 private final HashMap<String, String> meta = new HashMap<>(); |
87 private final HashSet<String> filters = new HashSet<String>(); | 88 private final HashSet<String> filters = new HashSet<>(); |
88 | 89 |
89 private boolean metaDataValid = true; | 90 private boolean metaDataValid = true; |
90 private boolean filtersValid = true; | 91 private boolean filtersValid = true; |
91 | 92 |
92 static | 93 static |
93 { | 94 { |
94 for (final String s : ALLOWED_META_KEYS_ARRAY) | 95 for (final String s : ALLOWED_META_KEYS_ARRAY) |
95 { | 96 { |
96 ALLOWED_META_KEYS.add(s); | 97 ALLOWED_META_KEYS.add(s); |
97 } | 98 } |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 { | 365 { |
365 sb.append('0'); | 366 sb.append('0'); |
366 } | 367 } |
367 sb.append(Integer.toHexString(value)); | 368 sb.append(Integer.toHexString(value)); |
368 } | 369 } |
369 return sb.toString(); | 370 return sb.toString(); |
370 } | 371 } |
371 | 372 |
372 private static String createMetaDataHash(final HashMap<String, String> meta) t
hrows IOException | 373 private static String createMetaDataHash(final HashMap<String, String> meta) t
hrows IOException |
373 { | 374 { |
374 final ArrayList<String> keyValues = new ArrayList<String>(); | 375 final ArrayList<String> keyValues = new ArrayList<>(); |
375 for (final Entry<String, String> e : meta.entrySet()) | 376 for (final Entry<String, String> e : meta.entrySet()) |
376 { | 377 { |
377 if (!KEY_META_HASH.equals(e.getKey())) | 378 if (!KEY_META_HASH.equals(e.getKey())) |
378 { | 379 { |
379 keyValues.add(e.getKey() + ":" + e.getValue()); | 380 keyValues.add(e.getKey() + ":" + e.getValue()); |
380 } | 381 } |
381 } | 382 } |
382 return createFilterHash(keyValues); | 383 return createFilterHash(keyValues); |
383 } | 384 } |
384 | 385 |
385 private static String createFilterHash(List<String> filters) throws IOExceptio
n | 386 private static String createFilterHash(List<String> filters) throws IOExceptio
n |
386 { | 387 { |
387 try | 388 try |
388 { | 389 { |
389 final MessageDigest md5 = MessageDigest.getInstance("MD5"); | 390 final MessageDigest md5 = MessageDigest.getInstance("MD5"); |
390 Collections.sort(filters); | 391 Collections.sort(filters); |
391 for (final String filter : filters) | 392 for (final String filter : filters) |
392 { | 393 { |
393 md5.update(filter.getBytes(Engine.CHARSET_UTF_8)); | 394 md5.update(filter.getBytes(StandardCharsets.UTF_8)); |
394 } | 395 } |
395 return byteArrayToHexString(md5.digest()); | 396 return byteArrayToHexString(md5.digest()); |
396 } | 397 } |
397 catch (final NoSuchAlgorithmException e) | 398 catch (final NoSuchAlgorithmException e) |
398 { | 399 { |
399 throw new IOException("MD5 is unavailable: " + e.getMessage(), e); | 400 throw new IOException("MD5 is unavailable: " + e.getMessage(), e); |
400 } | 401 } |
401 } | 402 } |
402 | 403 |
403 public void serializeMetaData(final File metaFile) throws IOException | 404 public void serializeMetaData(final File metaFile) throws IOException |
404 { | 405 { |
405 this.putMeta(KEY_META_HASH, createMetaDataHash(this.meta)); | 406 this.putMeta(KEY_META_HASH, createMetaDataHash(this.meta)); |
406 final DataOutputStream metaOut = new DataOutputStream(new GZIPOutputStream( | 407 try (final DataOutputStream metaOut = new DataOutputStream(new GZIPOutputStr
eam( |
407 new BufferedOutputStream(new FileOutputStream(metaFile)))); | 408 new BufferedOutputStream(new FileOutputStream(metaFile))))) |
408 try | |
409 { | 409 { |
410 metaOut.writeUTF(this.url != null ? this.url.toString() : ""); | 410 metaOut.writeUTF(this.url != null ? this.url.toString() : ""); |
411 metaOut.writeInt(this.meta.size()); | 411 metaOut.writeInt(this.meta.size()); |
412 for (final Entry<String, String> e : this.meta.entrySet()) | 412 for (final Entry<String, String> e : this.meta.entrySet()) |
413 { | 413 { |
414 metaOut.writeUTF(e.getKey()); | 414 metaOut.writeUTF(e.getKey()); |
415 metaOut.writeUTF(e.getValue()); | 415 metaOut.writeUTF(e.getValue()); |
416 } | 416 } |
417 } | 417 } |
418 finally | |
419 { | |
420 metaOut.close(); | |
421 } | |
422 } | 418 } |
423 | 419 |
424 public void serializeFilters(final File filtersFile) throws IOException | 420 public void serializeFilters(final File filtersFile) throws IOException |
425 { | 421 { |
426 final DataOutputStream filtersOut = new DataOutputStream(new GZIPOutputStrea
m( | 422 try (final DataOutputStream filtersOut = new DataOutputStream(new GZIPOutput
Stream( |
427 new BufferedOutputStream(new FileOutputStream(filtersFile)))); | 423 new BufferedOutputStream(new FileOutputStream(filtersFile))))) |
428 try | |
429 { | 424 { |
430 filtersOut.writeInt(this.filters.size()); | 425 filtersOut.writeInt(this.filters.size()); |
431 filtersOut.writeUTF(createFilterHash(new ArrayList<String>(this.filters)))
; | 426 filtersOut.writeUTF(createFilterHash(new ArrayList<String>(this.filters)))
; |
432 for (final String s : this.filters) | 427 for (final String s : this.filters) |
433 { | 428 { |
434 final byte[] b = s.getBytes(Engine.CHARSET_UTF_8); | 429 final byte[] b = s.getBytes(StandardCharsets.UTF_8); |
435 filtersOut.writeInt(b.length); | 430 filtersOut.writeInt(b.length); |
436 filtersOut.write(b); | 431 filtersOut.write(b); |
437 } | 432 } |
438 } | 433 } |
439 finally | |
440 { | |
441 filtersOut.close(); | |
442 } | |
443 } | 434 } |
444 | 435 |
445 public void serializeSubscription(final File metaFile, final File filtersFile)
throws IOException | 436 public void serializeSubscription(final File metaFile, final File filtersFile)
throws IOException |
446 { | 437 { |
447 this.serializeMetaData(metaFile); | 438 this.serializeMetaData(metaFile); |
448 this.serializeFilters(filtersFile); | 439 this.serializeFilters(filtersFile); |
449 } | 440 } |
450 | 441 |
451 public static Subscription deserializeSubscription(final File metaFile) | 442 public static Subscription deserializeSubscription(final File metaFile) |
452 { | 443 { |
453 Subscription sub = null; | 444 Subscription sub = null; |
454 DataInputStream in = null; | 445 try (final DataInputStream in = new DataInputStream(new GZIPInputStream(new
BufferedInputStream( |
455 try | 446 new FileInputStream(metaFile))))) |
456 { | 447 { |
457 in = new DataInputStream(new GZIPInputStream(new BufferedInputStream( | |
458 new FileInputStream(metaFile)))); | |
459 final String urlString = in.readUTF(); | 448 final String urlString = in.readUTF(); |
460 sub = new Subscription(!TextUtils.isEmpty(urlString) ? new URL(urlString)
: null); | 449 sub = new Subscription(!TextUtils.isEmpty(urlString) ? new URL(urlString)
: null); |
461 sub.metaDataValid = false; | 450 sub.metaDataValid = false; |
462 final int numMetaEntries = in.readInt(); | 451 final int numMetaEntries = in.readInt(); |
463 for (int i = 0; i < numMetaEntries; i++) | 452 for (int i = 0; i < numMetaEntries; i++) |
464 { | 453 { |
465 final String key = in.readUTF(); | 454 final String key = in.readUTF(); |
466 final String value = in.readUTF(); | 455 final String value = in.readUTF(); |
467 sub.meta.put(key, value); | 456 sub.meta.put(key, value); |
468 } | 457 } |
469 sub.metaDataValid = createMetaDataHash(sub.meta).equals(sub.getMeta(KEY_ME
TA_HASH)); | 458 sub.metaDataValid = createMetaDataHash(sub.meta).equals(sub.getMeta(KEY_ME
TA_HASH)); |
470 } | 459 } |
471 catch (Throwable t) | 460 catch (Throwable t) |
472 { | 461 { |
473 // We catch Throwable here in order to return whatever we could retrieve f
rom the meta file | 462 // We catch Throwable here in order to return whatever we could retrieve f
rom the meta file |
474 } | 463 } |
475 finally | |
476 { | |
477 if (in != null) | |
478 { | |
479 try | |
480 { | |
481 in.close(); | |
482 } | |
483 catch (IOException e) | |
484 { | |
485 // Ignored | |
486 } | |
487 } | |
488 } | |
489 return sub; | 464 return sub; |
490 } | 465 } |
491 | 466 |
492 public void deserializeFilters(final File filtersFile) | 467 public void deserializeFilters(final File filtersFile) |
493 { | 468 { |
494 this.clearFilters(); | 469 this.clearFilters(); |
495 this.filtersValid = false; | 470 this.filtersValid = false; |
496 DataInputStream in = null; | 471 try (final DataInputStream in = new DataInputStream(new GZIPInputStream(new
BufferedInputStream( |
497 try | 472 new FileInputStream(filtersFile))))) |
498 { | 473 { |
499 in = new DataInputStream(new GZIPInputStream(new BufferedInputStream( | |
500 new FileInputStream(filtersFile)))); | |
501 final int numFilters = in.readInt(); | 474 final int numFilters = in.readInt(); |
502 final String filtersHash = in.readUTF(); | 475 final String filtersHash = in.readUTF(); |
503 for (int i = 0; i < numFilters; i++) | 476 for (int i = 0; i < numFilters; i++) |
504 { | 477 { |
505 final int length = in.readInt(); | 478 final int length = in.readInt(); |
506 final byte[] b = new byte[length]; | 479 final byte[] b = new byte[length]; |
507 in.readFully(b); | 480 in.readFully(b); |
508 this.filters.add(new String(b, Engine.CHARSET_UTF_8)); | 481 this.filters.add(new String(b, StandardCharsets.UTF_8)); |
509 } | 482 } |
510 this.filtersValid = createFilterHash(new ArrayList<String>(this.filters)).
equals( | 483 this.filtersValid = createFilterHash(new ArrayList<String>(this.filters)).
equals( |
511 filtersHash); | 484 filtersHash); |
512 Log.d(TAG, "Filters valid: " + this.filtersValid); | 485 Log.d(TAG, "Filters valid: " + this.filtersValid); |
513 } | 486 } |
514 catch (Throwable t) | 487 catch (Throwable t) |
515 { | 488 { |
516 // We catch Throwable here in order to load whatever we could retrieve fro
m the filters file | 489 // We catch Throwable here in order to load whatever we could retrieve fro
m the filters file |
517 } | 490 } |
518 finally | |
519 { | |
520 if (in != null) | |
521 { | |
522 try | |
523 { | |
524 in.close(); | |
525 } | |
526 catch (IOException e) | |
527 { | |
528 // Ignored | |
529 } | |
530 } | |
531 } | |
532 } | 491 } |
533 | 492 |
534 /** | 493 /** |
535 * Adds the given string, which should be a single filter to this | 494 * Adds the given string, which should be a single filter to this |
536 * subscription. | 495 * subscription. |
537 * | 496 * |
538 * @param input | 497 * @param input |
539 */ | 498 */ |
540 public Subscription parseLine(String input) | 499 public Subscription parseLine(String input) |
541 { | 500 { |
(...skipping 30 matching lines...) Expand all Loading... |
572 { | 531 { |
573 for (String line : lines) | 532 for (String line : lines) |
574 { | 533 { |
575 this.parseLine(line); | 534 this.parseLine(line); |
576 } | 535 } |
577 return this; | 536 return this; |
578 } | 537 } |
579 | 538 |
580 public Subscription parseText(final String string) | 539 public Subscription parseText(final String string) |
581 { | 540 { |
582 final BufferedReader r = new BufferedReader(new StringReader(string)); | 541 try (final BufferedReader r = new BufferedReader(new StringReader(string))) |
583 try | |
584 { | 542 { |
585 for (String line = r.readLine(); line != null; line = r.readLine()) | 543 for (String line = r.readLine(); line != null; line = r.readLine()) |
586 { | 544 { |
587 this.parseLine(line); | 545 this.parseLine(line); |
588 } | 546 } |
589 r.close(); | |
590 } | 547 } |
591 catch (final IOException e) | 548 catch (final IOException e) |
592 { | 549 { |
593 // ignored ... we're reading from a String | 550 // ignored ... we're reading from a String |
594 } | 551 } |
595 return this; | 552 return this; |
596 } | 553 } |
597 | 554 |
598 boolean updateSubscription(final int responseCode, final String text, | 555 boolean updateSubscription(final int responseCode, final String text, |
599 final Map<String, String> httpHeaders, final File metaFile, final File fil
tersFile) | 556 final Map<String, String> httpHeaders, final File metaFile, final File fil
tersFile) |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
650 this.serializeMetaData(metaFile); | 607 this.serializeMetaData(metaFile); |
651 if (filtersChanged) | 608 if (filtersChanged) |
652 { | 609 { |
653 this.serializeFilters(filtersFile); | 610 this.serializeFilters(filtersFile); |
654 this.clearFilters(); | 611 this.clearFilters(); |
655 } | 612 } |
656 | 613 |
657 return filtersChanged; | 614 return filtersChanged; |
658 } | 615 } |
659 } | 616 } |
OLD | NEW |