fetch.js 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /*
  2. * Copyright 2010-2019 Gildas Lormeau
  3. * contact : gildas.lormeau <at> gmail.com
  4. *
  5. * This file is part of SingleFile.
  6. *
  7. * SingleFile is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * SingleFile is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with SingleFile. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /* global browser, XMLHttpRequest */
  21. (() => {
  22. const responses = new Map();
  23. let requestId = 1;
  24. browser.runtime.onMessage.addListener(request => {
  25. if (request.method && request.method.startsWith("fetch")) {
  26. return new Promise(resolve => {
  27. onRequest(request)
  28. .then(resolve)
  29. .catch(error => resolve({ error: error.toString() }));
  30. });
  31. }
  32. });
  33. async function onRequest(request) {
  34. if (request.method == "fetch") {
  35. const responseId = requestId;
  36. requestId = requestId + 1;
  37. const response = await superFetch(request.url);
  38. responses.set(responseId, response);
  39. response.responseId = responseId;
  40. return { responseId, headers: response.headers };
  41. } else if (request.method == "fetch.array") {
  42. const response = responses.get(request.requestId);
  43. responses.delete(response.requestId);
  44. return new Promise((resolve, reject) => {
  45. response.xhrRequest.onerror = event => reject(new Error(event.detail));
  46. if (response.xhrRequest.readyState == XMLHttpRequest.DONE) {
  47. resolve(getResponse(response.xhrRequest));
  48. } else {
  49. response.xhrRequest.onload = () => resolve(getResponse(response.xhrRequest));
  50. }
  51. });
  52. }
  53. }
  54. function getResponse(xhrRequest) {
  55. return { array: Array.from(new Uint8Array(xhrRequest.response)) };
  56. }
  57. async function superFetch(url) {
  58. return new Promise((resolve, reject) => {
  59. const xhrRequest = new XMLHttpRequest();
  60. xhrRequest.withCredentials = true;
  61. xhrRequest.responseType = "arraybuffer";
  62. xhrRequest.onerror = event => reject(new Error(event.detail));
  63. xhrRequest.onreadystatechange = () => {
  64. if (xhrRequest.readyState == XMLHttpRequest.HEADERS_RECEIVED) {
  65. const headers = {};
  66. headers["content-type"] = xhrRequest.getResponseHeader("Content-Type");
  67. resolve({ xhrRequest, headers, status: xhrRequest.status });
  68. }
  69. };
  70. xhrRequest.open("GET", url, true);
  71. xhrRequest.send();
  72. });
  73. }
  74. })();