2022-07-12 09:00:22 +02:00

214 lines
12 KiB
JavaScript

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import { __assign, __awaiter, __generator } from "tslib";
import AbortController from "abort-controller";
import FormData from "form-data";
import { HttpHeaders } from "./httpHeaders";
import { RestError } from "./restError";
import { Transform } from "stream";
var FetchHttpClient = /** @class */ (function () {
function FetchHttpClient() {
}
FetchHttpClient.prototype.sendRequest = function (httpRequest) {
return __awaiter(this, void 0, void 0, function () {
var abortController, abortListener, formData, requestForm_1, appendFormValue, _i, _a, formKey, formValue, j, contentType, body, loadedBytes_1, uploadReportStream, platformSpecificRequestInit, requestInit, operationResponse, response, headers, _b, _c, onDownloadProgress_1, responseBody, loadedBytes_2, downloadReportStream, length_1, error_1, fetchError, uploadStreamDone, downloadStreamDone;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
if (!httpRequest && typeof httpRequest !== "object") {
throw new Error("'httpRequest' (WebResource) cannot be null or undefined and must be of type object.");
}
abortController = new AbortController();
if (httpRequest.abortSignal) {
if (httpRequest.abortSignal.aborted) {
throw new RestError("The request was aborted", RestError.REQUEST_ABORTED_ERROR, undefined, httpRequest);
}
abortListener = function (event) {
if (event.type === "abort") {
abortController.abort();
}
};
httpRequest.abortSignal.addEventListener("abort", abortListener);
}
if (httpRequest.timeout) {
setTimeout(function () {
abortController.abort();
}, httpRequest.timeout);
}
if (httpRequest.formData) {
formData = httpRequest.formData;
requestForm_1 = new FormData();
appendFormValue = function (key, value) {
// value function probably returns a stream so we can provide a fresh stream on each retry
if (typeof value === "function") {
value = value();
}
if (value && value.hasOwnProperty("value") && value.hasOwnProperty("options")) {
requestForm_1.append(key, value.value, value.options);
}
else {
requestForm_1.append(key, value);
}
};
for (_i = 0, _a = Object.keys(formData); _i < _a.length; _i++) {
formKey = _a[_i];
formValue = formData[formKey];
if (Array.isArray(formValue)) {
for (j = 0; j < formValue.length; j++) {
appendFormValue(formKey, formValue[j]);
}
}
else {
appendFormValue(formKey, formValue);
}
}
httpRequest.body = requestForm_1;
httpRequest.formData = undefined;
contentType = httpRequest.headers.get("Content-Type");
if (contentType && contentType.indexOf("multipart/form-data") !== -1) {
if (typeof requestForm_1.getBoundary === "function") {
httpRequest.headers.set("Content-Type", "multipart/form-data; boundary=" + requestForm_1.getBoundary());
}
else {
// browser will automatically apply a suitable content-type header
httpRequest.headers.remove("Content-Type");
}
}
}
body = httpRequest.body
? typeof httpRequest.body === "function"
? httpRequest.body()
: httpRequest.body
: undefined;
if (httpRequest.onUploadProgress && httpRequest.body) {
loadedBytes_1 = 0;
uploadReportStream = new Transform({
transform: function (chunk, _encoding, callback) {
loadedBytes_1 += chunk.length;
httpRequest.onUploadProgress({ loadedBytes: loadedBytes_1 });
callback(undefined, chunk);
},
});
if (isReadableStream(body)) {
body.pipe(uploadReportStream);
}
else {
uploadReportStream.end(body);
}
body = uploadReportStream;
}
return [4 /*yield*/, this.prepareRequest(httpRequest)];
case 1:
platformSpecificRequestInit = _d.sent();
requestInit = __assign({ body: body, headers: httpRequest.headers.rawHeaders(), method: httpRequest.method, signal: abortController.signal, redirect: "manual" }, platformSpecificRequestInit);
_d.label = 2;
case 2:
_d.trys.push([2, 8, 9, 10]);
return [4 /*yield*/, this.fetch(httpRequest.url, requestInit)];
case 3:
response = _d.sent();
headers = parseHeaders(response.headers);
_b = {
headers: headers,
request: httpRequest,
status: response.status,
readableStreamBody: httpRequest.streamResponseBody
? response.body
: undefined
};
if (!!httpRequest.streamResponseBody) return [3 /*break*/, 5];
return [4 /*yield*/, response.text()];
case 4:
_c = _d.sent();
return [3 /*break*/, 6];
case 5:
_c = undefined;
_d.label = 6;
case 6:
operationResponse = (_b.bodyAsText = _c,
_b.redirected = response.redirected,
_b.url = response.url,
_b);
onDownloadProgress_1 = httpRequest.onDownloadProgress;
if (onDownloadProgress_1) {
responseBody = response.body || undefined;
if (isReadableStream(responseBody)) {
loadedBytes_2 = 0;
downloadReportStream = new Transform({
transform: function (chunk, _encoding, callback) {
loadedBytes_2 += chunk.length;
onDownloadProgress_1({ loadedBytes: loadedBytes_2 });
callback(undefined, chunk);
},
});
responseBody.pipe(downloadReportStream);
operationResponse.readableStreamBody = downloadReportStream;
}
else {
length_1 = parseInt(headers.get("Content-Length")) || undefined;
if (length_1) {
// Calling callback for non-stream response for consistency with browser
onDownloadProgress_1({ loadedBytes: length_1 });
}
}
}
return [4 /*yield*/, this.processRequest(operationResponse)];
case 7:
_d.sent();
return [2 /*return*/, operationResponse];
case 8:
error_1 = _d.sent();
fetchError = error_1;
if (fetchError.code === "ENOTFOUND") {
throw new RestError(fetchError.message, RestError.REQUEST_SEND_ERROR, undefined, httpRequest);
}
else if (fetchError.type === "aborted") {
throw new RestError("The request was aborted", RestError.REQUEST_ABORTED_ERROR, undefined, httpRequest);
}
throw fetchError;
case 9:
// clean up event listener
if (httpRequest.abortSignal && abortListener) {
uploadStreamDone = Promise.resolve();
if (isReadableStream(body)) {
uploadStreamDone = isStreamComplete(body);
}
downloadStreamDone = Promise.resolve();
if (isReadableStream(operationResponse === null || operationResponse === void 0 ? void 0 : operationResponse.readableStreamBody)) {
downloadStreamDone = isStreamComplete(operationResponse.readableStreamBody);
}
Promise.all([uploadStreamDone, downloadStreamDone])
.then(function () {
var _a;
(_a = httpRequest.abortSignal) === null || _a === void 0 ? void 0 : _a.removeEventListener("abort", abortListener);
return;
})
.catch(function (_e) { });
}
return [7 /*endfinally*/];
case 10: return [2 /*return*/];
}
});
});
};
return FetchHttpClient;
}());
export { FetchHttpClient };
function isReadableStream(body) {
return body && typeof body.pipe === "function";
}
function isStreamComplete(stream) {
return new Promise(function (resolve) {
stream.on("close", resolve);
stream.on("end", resolve);
stream.on("error", resolve);
});
}
export function parseHeaders(headers) {
var httpHeaders = new HttpHeaders();
headers.forEach(function (value, key) {
httpHeaders.set(key, value);
});
return httpHeaders;
}
//# sourceMappingURL=fetchHttpClient.js.map