You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
6.2 KiB

  1. /*******************************************************************************
  2. uMatrix - a browser extension to block requests.
  3. Copyright (C) 2017-present Raymond Hill
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see {http://www.gnu.org/licenses/}.
  14. Home: https://github.com/gorhill/uMatrix
  15. */
  16. // For background page
  17. 'use strict';
  18. /******************************************************************************/
  19. (( ) => {
  20. // https://github.com/uBlockOrigin/uBlock-issues/issues/407
  21. if ( vAPI.webextFlavor.soup.has('chromium') === false ) { return; }
  22. const extToTypeMap = new Map([
  23. ['eot','font'],['otf','font'],['svg','font'],['ttf','font'],['woff','font'],['woff2','font'],
  24. ['mp3','media'],['mp4','media'],['webm','media'],
  25. ['gif','image'],['ico','image'],['jpeg','image'],['jpg','image'],['png','image'],['webp','image']
  26. ]);
  27. const headerValue = (headers, name) => {
  28. let i = headers.length;
  29. while ( i-- ) {
  30. if ( headers[i].name.toLowerCase() === name ) {
  31. return headers[i].value.trim();
  32. }
  33. }
  34. return '';
  35. };
  36. const parsedURL = new URL('https://www.example.org/');
  37. // Extend base class to normalize as per platform.
  38. vAPI.Net = class extends vAPI.Net {
  39. constructor() {
  40. super();
  41. this.suspendedTabIds = new Set();
  42. }
  43. normalizeDetails(details) {
  44. // Chromium 63+ supports the `initiator` property, which contains
  45. // the URL of the origin from which the network request was made.
  46. if (
  47. typeof details.initiator === 'string' &&
  48. details.initiator !== 'null'
  49. ) {
  50. details.documentUrl = details.initiator;
  51. }
  52. let type = details.type;
  53. if ( type === 'imageset' ) {
  54. details.type = 'image';
  55. return;
  56. }
  57. // The rest of the function code is to normalize type
  58. if ( type !== 'other' ) { return; }
  59. // Try to map known "extension" part of URL to request type.
  60. parsedURL.href = details.url;
  61. const path = parsedURL.pathname,
  62. pos = path.indexOf('.', path.length - 6);
  63. if ( pos !== -1 && (type = extToTypeMap.get(path.slice(pos + 1))) ) {
  64. details.type = type;
  65. return;
  66. }
  67. // Try to extract type from response headers if present.
  68. if ( details.responseHeaders ) {
  69. type = headerValue(details.responseHeaders, 'content-type');
  70. if ( type.startsWith('font/') ) {
  71. details.type = 'font';
  72. return;
  73. }
  74. if ( type.startsWith('image/') ) {
  75. details.type = 'image';
  76. return;
  77. }
  78. if ( type.startsWith('audio/') || type.startsWith('video/') ) {
  79. details.type = 'media';
  80. return;
  81. }
  82. }
  83. }
  84. // https://www.reddit.com/r/uBlockOrigin/comments/9vcrk3/
  85. // Some types can be mapped from 'other', thus include 'other' if and
  86. // only if the caller is interested in at least one of those types.
  87. denormalizeTypes(types) {
  88. if ( types.length === 0 ) {
  89. return Array.from(this.validTypes);
  90. }
  91. const out = new Set();
  92. for ( const type of types ) {
  93. if ( this.validTypes.has(type) ) {
  94. out.add(type);
  95. }
  96. }
  97. if ( out.has('other') === false ) {
  98. for ( const type of extToTypeMap.values() ) {
  99. if ( out.has(type) ) {
  100. out.add('other');
  101. break;
  102. }
  103. }
  104. }
  105. return Array.from(out);
  106. }
  107. suspendOneRequest(details) {
  108. this.suspendedTabIds.add(details.tabId);
  109. return { cancel: true };
  110. }
  111. unsuspendAllRequests() {
  112. for ( const tabId of this.suspendedTabIds ) {
  113. vAPI.tabs.reload(tabId);
  114. }
  115. this.suspendedTabIds.clear();
  116. }
  117. };
  118. })();
  119. /******************************************************************************/
  120. // https://github.com/uBlockOrigin/uBlock-issues/issues/548
  121. // Use `X-DNS-Prefetch-Control` to workaround Chromium's disregard of the
  122. // setting "Predict network actions to improve page load performance".
  123. vAPI.prefetching = (( ) => {
  124. // https://github.com/uBlockOrigin/uBlock-issues/issues/407
  125. if ( vAPI.webextFlavor.soup.has('chromium') === false ) { return; }
  126. let listening = false;
  127. const onHeadersReceived = function(details) {
  128. details.responseHeaders.push({
  129. name: 'X-DNS-Prefetch-Control',
  130. value: 'off'
  131. });
  132. return { responseHeaders: details.responseHeaders };
  133. };
  134. return state => {
  135. const wr = chrome.webRequest;
  136. if ( state && listening ) {
  137. wr.onHeadersReceived.removeListener(onHeadersReceived);
  138. listening = false;
  139. } else if ( !state && !listening ) {
  140. wr.onHeadersReceived.addListener(
  141. onHeadersReceived,
  142. {
  143. urls: [ 'http://*/*', 'https://*/*' ],
  144. types: [ 'main_frame', 'sub_frame' ]
  145. },
  146. [ 'blocking', 'responseHeaders' ]
  147. );
  148. listening = true;
  149. }
  150. };
  151. })();
  152. /******************************************************************************/