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.

198 lines
6.7 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. let type = details.type;
  62. // https://github.com/uBlockOrigin/uMatrix-issues/issues/156#issuecomment-494427094
  63. if ( type === 'main_frame' ) {
  64. details.documentUrl = details.url;
  65. }
  66. // Chromium 63+ supports the `initiator` property, which contains
  67. // the URL of the origin from which the network request was made.
  68. else if (
  69. typeof details.initiator === 'string' &&
  70. details.initiator !== 'null'
  71. ) {
  72. details.documentUrl = details.initiator;
  73. }
  74. // https://github.com/gorhill/uBlock/issues/1493
  75. // Chromium 49+/WebExtensions support a new request type: `ping`,
  76. // which is fired as a result of using `navigator.sendBeacon`.
  77. if ( type === 'ping' ) {
  78. details.type = 'beacon';
  79. return;
  80. }
  81. if ( type === 'imageset' ) {
  82. details.type = 'image';
  83. return;
  84. }
  85. // The rest of the function code is to normalize type
  86. if ( type !== 'other' ) { return; }
  87. // Try to map known "extension" part of URL to request type.
  88. parsedURL.href = details.url;
  89. const path = parsedURL.pathname,
  90. pos = path.indexOf('.', path.length - 6);
  91. if ( pos !== -1 && (type = extToTypeMap.get(path.slice(pos + 1))) ) {
  92. details.type = type;
  93. return;
  94. }
  95. // Try to extract type from response headers if present.
  96. if ( details.responseHeaders ) {
  97. type = headerValue(details.responseHeaders, 'content-type');
  98. if ( type.startsWith('font/') ) {
  99. details.type = 'font';
  100. return;
  101. }
  102. if ( type.startsWith('image/') ) {
  103. details.type = 'image';
  104. return;
  105. }
  106. if ( type.startsWith('audio/') || type.startsWith('video/') ) {
  107. details.type = 'media';
  108. return;
  109. }
  110. }
  111. };
  112. vAPI.net.denormalizeFilters = function(filters) {
  113. const urls = filters.urls || [ '<all_urls>' ];
  114. let types = filters.types;
  115. if ( Array.isArray(types) ) {
  116. types = denormalizeTypes(types);
  117. }
  118. if (
  119. (vAPI.net.validTypes.has('websocket')) &&
  120. (types === undefined || types.indexOf('websocket') !== -1) &&
  121. (urls.indexOf('<all_urls>') === -1)
  122. ) {
  123. if ( urls.indexOf('ws://*/*') === -1 ) {
  124. urls.push('ws://*/*');
  125. }
  126. if ( urls.indexOf('wss://*/*') === -1 ) {
  127. urls.push('wss://*/*');
  128. }
  129. }
  130. return { types, urls };
  131. };
  132. })();
  133. /******************************************************************************/
  134. // https://github.com/gorhill/uBlock/issues/2067
  135. // Experimental: Block everything until uBO is fully ready.
  136. vAPI.net.onBeforeReady = (function() {
  137. let pendings;
  138. const handler = function(details) {
  139. if ( pendings === undefined ) { return; }
  140. if ( details.tabId < 0 ) { return; }
  141. pendings.add(details.tabId);
  142. //console.log(`Aborting tab ${details.tabId}: ${details.type} ${details.url}`);
  143. return { cancel: true };
  144. };
  145. return {
  146. experimental: true,
  147. start: function() {
  148. pendings = new Set();
  149. browser.webRequest.onBeforeRequest.addListener(
  150. handler,
  151. { urls: [ 'http://*/*', 'https://*/*' ] },
  152. [ 'blocking' ]
  153. );
  154. },
  155. // https://github.com/gorhill/uBlock/issues/2067
  156. // Force-reload tabs for which network requests were blocked
  157. // during launch. This can happen only if tabs were "suspended".
  158. stop: function() {
  159. if ( pendings === undefined ) { return; }
  160. browser.webRequest.onBeforeRequest.removeListener(handler);
  161. for ( const tabId of pendings ) {
  162. //console.log(`Reloading tab ${tabId}`);
  163. vAPI.tabs.reload(tabId);
  164. }
  165. pendings = undefined;
  166. },
  167. };
  168. })();
  169. /******************************************************************************/