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.

194 lines
6.5 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. (function() {
  20. const extToTypeMap = new Map([
  21. ['eot','font'],['otf','font'],['svg','font'],['ttf','font'],['woff','font'],['woff2','font'],
  22. ['mp3','media'],['mp4','media'],['webm','media'],
  23. ['gif','image'],['ico','image'],['jpeg','image'],['jpg','image'],['png','image'],['webp','image']
  24. ]);
  25. // https://www.reddit.com/r/uBlockOrigin/comments/9vcrk3/bug_in_ubo_1173_betas_when_saving_files_hosted_on/
  26. // Some types can be mapped from 'other', thus include 'other' if and
  27. // only if the caller is interested in at least one of those types.
  28. const denormalizeTypes = function(aa) {
  29. if ( aa.length === 0 ) {
  30. return Array.from(vAPI.net.validTypes);
  31. }
  32. const out = new Set();
  33. let i = aa.length;
  34. while ( i-- ) {
  35. const type = aa[i];
  36. if ( vAPI.net.validTypes.has(type) ) {
  37. out.add(type);
  38. }
  39. }
  40. if ( out.has('other') === false ) {
  41. for ( const type of extToTypeMap.values() ) {
  42. if ( out.has(type) ) {
  43. out.add('other');
  44. break;
  45. }
  46. }
  47. }
  48. return Array.from(out);
  49. };
  50. const headerValue = function(headers, name) {
  51. let i = headers.length;
  52. while ( i-- ) {
  53. if ( headers[i].name.toLowerCase() === name ) {
  54. return headers[i].value.trim();
  55. }
  56. }
  57. return '';
  58. };
  59. const parsedURL = new URL('https://www.example.org/');
  60. vAPI.net.normalizeDetails = function(details) {
  61. // Chromium 63+ supports the `initiator` property, which contains
  62. // the URL of the origin from which the network request was made.
  63. if (
  64. typeof details.initiator === 'string' &&
  65. details.initiator !== 'null'
  66. ) {
  67. details.documentUrl = details.initiator;
  68. }
  69. let type = details.type;
  70. // https://github.com/gorhill/uBlock/issues/1493
  71. // Chromium 49+/WebExtensions support a new request type: `ping`,
  72. // which is fired as a result of using `navigator.sendBeacon`.
  73. if ( type === 'ping' ) {
  74. details.type = 'beacon';
  75. return;
  76. }
  77. if ( type === 'imageset' ) {
  78. details.type = 'image';
  79. return;
  80. }
  81. // The rest of the function code is to normalize type
  82. if ( type !== 'other' ) { return; }
  83. // Try to map known "extension" part of URL to request type.
  84. parsedURL.href = details.url;
  85. const path = parsedURL.pathname,
  86. pos = path.indexOf('.', path.length - 6);
  87. if ( pos !== -1 && (type = extToTypeMap.get(path.slice(pos + 1))) ) {
  88. details.type = type;
  89. return;
  90. }
  91. // Try to extract type from response headers if present.
  92. if ( details.responseHeaders ) {
  93. type = headerValue(details.responseHeaders, 'content-type');
  94. if ( type.startsWith('font/') ) {
  95. details.type = 'font';
  96. return;
  97. }
  98. if ( type.startsWith('image/') ) {
  99. details.type = 'image';
  100. return;
  101. }
  102. if ( type.startsWith('audio/') || type.startsWith('video/') ) {
  103. details.type = 'media';
  104. return;
  105. }
  106. }
  107. };
  108. vAPI.net.denormalizeFilters = function(filters) {
  109. const urls = filters.urls || [ '<all_urls>' ];
  110. let types = filters.types;
  111. if ( Array.isArray(types) ) {
  112. types = denormalizeTypes(types);
  113. }
  114. if (
  115. (vAPI.net.validTypes.has('websocket')) &&
  116. (types === undefined || types.indexOf('websocket') !== -1) &&
  117. (urls.indexOf('<all_urls>') === -1)
  118. ) {
  119. if ( urls.indexOf('ws://*/*') === -1 ) {
  120. urls.push('ws://*/*');
  121. }
  122. if ( urls.indexOf('wss://*/*') === -1 ) {
  123. urls.push('wss://*/*');
  124. }
  125. }
  126. return { types, urls };
  127. };
  128. })();
  129. /******************************************************************************/
  130. // https://github.com/gorhill/uBlock/issues/2067
  131. // Experimental: Block everything until uBO is fully ready.
  132. vAPI.net.onBeforeReady = (function() {
  133. let pendings;
  134. const handler = function(details) {
  135. if ( pendings === undefined ) { return; }
  136. if ( details.tabId < 0 ) { return; }
  137. pendings.add(details.tabId);
  138. //console.log(`Aborting tab ${details.tabId}: ${details.type} ${details.url}`);
  139. return { cancel: true };
  140. };
  141. return {
  142. experimental: true,
  143. start: function() {
  144. pendings = new Set();
  145. browser.webRequest.onBeforeRequest.addListener(
  146. handler,
  147. { urls: [ 'http://*/*', 'https://*/*' ] },
  148. [ 'blocking' ]
  149. );
  150. },
  151. // https://github.com/gorhill/uBlock/issues/2067
  152. // Force-reload tabs for which network requests were blocked
  153. // during launch. This can happen only if tabs were "suspended".
  154. stop: function() {
  155. if ( pendings === undefined ) { return; }
  156. browser.webRequest.onBeforeRequest.removeListener(handler);
  157. for ( const tabId of pendings ) {
  158. //console.log(`Reloading tab ${tabId}`);
  159. vAPI.tabs.reload(tabId);
  160. }
  161. pendings = undefined;
  162. },
  163. };
  164. })();
  165. /******************************************************************************/