geturl-browser.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import { assert, makeError } from "./errors.js";
  2. import type {
  3. FetchGetUrlFunc, FetchRequest, FetchCancelSignal, GetUrlResponse
  4. } from "./fetch.js";
  5. export function createGetUrl(options?: Record<string, any>): FetchGetUrlFunc {
  6. async function getUrl(req: FetchRequest, _signal?: FetchCancelSignal): Promise<GetUrlResponse> {
  7. assert(_signal == null || !_signal.cancelled, "request cancelled before sending", "CANCELLED");
  8. const protocol = req.url.split(":")[0].toLowerCase();
  9. assert(protocol === "http" || protocol === "https", `unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
  10. info: { protocol },
  11. operation: "request"
  12. });
  13. assert(protocol === "https" || !req.credentials || req.allowInsecureAuthentication, "insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
  14. operation: "request"
  15. });
  16. let error: null | Error = null;
  17. const controller = new AbortController();
  18. const timer = setTimeout(() => {
  19. error = makeError("request timeout", "TIMEOUT");
  20. controller.abort();
  21. }, req.timeout);
  22. if (_signal) {
  23. _signal.addListener(() => {
  24. error = makeError("request cancelled", "CANCELLED");
  25. controller.abort();
  26. });
  27. }
  28. const init = {
  29. method: req.method,
  30. headers: new Headers(Array.from(req)),
  31. body: req.body || undefined,
  32. signal: controller.signal
  33. };
  34. let resp: Awaited<ReturnType<typeof fetch>>;
  35. try {
  36. resp = await fetch(req.url, init);
  37. } catch (_error) {
  38. clearTimeout(timer);
  39. if (error) { throw error; }
  40. throw _error;
  41. }
  42. clearTimeout(timer);
  43. const headers: Record<string, string> = { };
  44. resp.headers.forEach((value, key) => {
  45. headers[key.toLowerCase()] = value;
  46. });
  47. const respBody = await resp.arrayBuffer();
  48. const body = (respBody == null) ? null: new Uint8Array(respBody);
  49. return {
  50. statusCode: resp.status,
  51. statusMessage: resp.statusText,
  52. headers, body
  53. };
  54. }
  55. return getUrl;
  56. }
  57. // @TODO: remove in v7; provided for backwards compat
  58. const defaultGetUrl: FetchGetUrlFunc = createGetUrl({ });
  59. export async function getUrl(req: FetchRequest, _signal?: FetchCancelSignal): Promise<GetUrlResponse> {
  60. return defaultGetUrl(req, _signal);
  61. }