UNPKG

3.2 kBJavaScriptView Raw
1import { HttpResponse } from "@aws-sdk/protocol-http";
2import { buildQueryString } from "@aws-sdk/querystring-builder";
3import { requestTimeout } from "./request-timeout";
4export class FetchHttpHandler {
5 constructor(options) {
6 if (typeof options === "function") {
7 this.configProvider = options().then((opts) => opts || {});
8 }
9 else {
10 this.config = options ?? {};
11 this.configProvider = Promise.resolve(this.config);
12 }
13 }
14 destroy() {
15 }
16 async handle(request, { abortSignal } = {}) {
17 if (!this.config) {
18 this.config = await this.configProvider;
19 }
20 const requestTimeoutInMs = this.config.requestTimeout;
21 if (abortSignal?.aborted) {
22 const abortError = new Error("Request aborted");
23 abortError.name = "AbortError";
24 return Promise.reject(abortError);
25 }
26 let path = request.path;
27 if (request.query) {
28 const queryString = buildQueryString(request.query);
29 if (queryString) {
30 path += `?${queryString}`;
31 }
32 }
33 const { port, method } = request;
34 const url = `${request.protocol}//${request.hostname}${port ? `:${port}` : ""}${path}`;
35 const body = method === "GET" || method === "HEAD" ? undefined : request.body;
36 const requestOptions = {
37 body,
38 headers: new Headers(request.headers),
39 method: method,
40 };
41 if (typeof AbortController !== "undefined") {
42 requestOptions["signal"] = abortSignal;
43 }
44 const fetchRequest = new Request(url, requestOptions);
45 const raceOfPromises = [
46 fetch(fetchRequest).then((response) => {
47 const fetchHeaders = response.headers;
48 const transformedHeaders = {};
49 for (const pair of fetchHeaders.entries()) {
50 transformedHeaders[pair[0]] = pair[1];
51 }
52 const hasReadableStream = response.body != undefined;
53 if (!hasReadableStream) {
54 return response.blob().then((body) => ({
55 response: new HttpResponse({
56 headers: transformedHeaders,
57 statusCode: response.status,
58 body,
59 }),
60 }));
61 }
62 return {
63 response: new HttpResponse({
64 headers: transformedHeaders,
65 statusCode: response.status,
66 body: response.body,
67 }),
68 };
69 }),
70 requestTimeout(requestTimeoutInMs),
71 ];
72 if (abortSignal) {
73 raceOfPromises.push(new Promise((resolve, reject) => {
74 abortSignal.onabort = () => {
75 const abortError = new Error("Request aborted");
76 abortError.name = "AbortError";
77 reject(abortError);
78 };
79 }));
80 }
81 return Promise.race(raceOfPromises);
82 }
83}