diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts index c08f3fa1d..0c05ddb2e 100644 --- a/packages/taler-harness/src/harness/harness.ts +++ b/packages/taler-harness/src/harness/harness.ts @@ -931,7 +931,7 @@ export class FakebankService ); await this.pingUntilAvailable(); for (const acc of this.accounts) { - await BankApi.registerAccount(this, acc.accountName, acc.accountPassword); + await BankApi.registerAccount(this, acc.accountName, acc.accountPassword, {}); } } diff --git a/packages/taler-harness/src/integrationtests/test-bank-api.ts b/packages/taler-harness/src/integrationtests/test-bank-api.ts index 5e3448625..a0e1c2085 100644 --- a/packages/taler-harness/src/integrationtests/test-bank-api.ts +++ b/packages/taler-harness/src/integrationtests/test-bank-api.ts @@ -100,12 +100,12 @@ export async function runBankApiTest(t: GlobalTestState) { console.log("setup done!"); - const bankUser = await BankApi.registerAccount(bank, "user1", "pw1"); + const bankUser = await BankApi.registerAccount(bank, "user1", "pw1", {}); // Make sure that registering twice results in a 409 Conflict { const e = await t.assertThrowsTalerErrorAsync(async () => { - await BankApi.registerAccount(bank, "user1", "pw2"); + await BankApi.registerAccount(bank, "user1", "pw2", {}); }); t.assertTrue(e.errorDetail.httpStatusCode === 409); } diff --git a/packages/web-util/src/utils/http-impl.browser.ts b/packages/web-util/src/utils/http-impl.browser.ts index 2b6ca019c..3bc5bb141 100644 --- a/packages/web-util/src/utils/http-impl.browser.ts +++ b/packages/web-util/src/utils/http-impl.browser.ts @@ -29,6 +29,8 @@ import { HttpRequestOptions, HttpResponse, Headers, + getDefaultHeaders, + encodeBody, } from "@gnu-taler/taler-util/http"; const logger = new Logger("browserHttpLib"); @@ -47,6 +49,8 @@ export class BrowserHttpLib implements HttpRequestLibrary { ): Promise { const requestMethod = options?.method ?? "GET"; const requestBody = options?.body; + const requestHeader = options?.headers; + const requestTimeout = options?.timeout ?? { d_ms: 2 * 1000 }; if (this.throttlingEnabled && this.throttle.applyThrottle(requestUrl)) { const parsedUrl = new URL(requestUrl); @@ -61,28 +65,18 @@ export class BrowserHttpLib implements HttpRequestLibrary { ); } + let myBody: ArrayBuffer | undefined = + requestMethod === "POST" || requestMethod === "PUT" + ? encodeBody(requestBody) + : undefined; + + const requestHeadersMap = { + ...getDefaultHeaders(requestMethod), + ...requestHeader, + }; + return new Promise((resolve, reject) => { const myRequest = new XMLHttpRequest(); - myRequest.open(requestMethod, requestUrl); - if (options?.headers) { - for (const headerName in options.headers) { - myRequest.setRequestHeader(headerName, options.headers[headerName]); - } - } - myRequest.responseType = "arraybuffer"; - if (requestBody) { - if (requestBody instanceof ArrayBuffer) { - myRequest.send(requestBody); - } else if (ArrayBuffer.isView(requestBody)) { - myRequest.send(requestBody); - } else if (typeof requestBody === "string") { - myRequest.send(requestBody); - } else { - myRequest.send(JSON.stringify(requestBody)); - } - } else { - myRequest.send(); - } myRequest.onerror = (e) => { logger.error("http request error"); @@ -98,6 +92,29 @@ export class BrowserHttpLib implements HttpRequestLibrary { ); }; + myRequest.open(requestMethod, requestUrl); + + let timeoutId: any | undefined; + if (requestTimeout.d_ms !== "forever") { + timeoutId = setTimeout(() => { + myRequest.abort(); + reject( + TalerError.fromDetail( + TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT, + {}, + `request to ${requestUrl} timed out`, + ), + ); + }, requestTimeout.d_ms); + } + + for (const headerName in Object.keys(requestHeadersMap)) { + myRequest.setRequestHeader(headerName, requestHeadersMap[headerName]); + } + + myRequest.responseType = "arraybuffer"; + myRequest.send(myBody); + myRequest.addEventListener("readystatechange", (e) => { if (myRequest.readyState === XMLHttpRequest.DONE) { if (myRequest.status === 0) { diff --git a/packages/web-util/src/utils/http-impl.sw.ts b/packages/web-util/src/utils/http-impl.sw.ts index 921acd63b..59bef1775 100644 --- a/packages/web-util/src/utils/http-impl.sw.ts +++ b/packages/web-util/src/utils/http-impl.sw.ts @@ -28,6 +28,8 @@ import { HttpRequestLibrary, HttpRequestOptions, HttpResponse, + encodeBody, + getDefaultHeaders, } from "@gnu-taler/taler-util/http"; /** @@ -60,20 +62,13 @@ export class ServiceWorkerHttpLib implements HttpRequestLibrary { ); } - let myBody: BodyInit | undefined = undefined; - if (requestBody != null) { - if (typeof requestBody === "string") { - myBody = requestBody; - } else if (requestBody instanceof ArrayBuffer) { - myBody = requestBody; - } else if (ArrayBuffer.isView(requestBody)) { - myBody = requestBody; - } else if (typeof requestBody === "object") { - myBody = JSON.stringify(requestBody); - } else { - throw Error("unsupported request body type"); - } - } + let myBody: ArrayBuffer | undefined = + requestMethod === "POST" ? encodeBody(requestBody) : undefined; + + const requestHeadersMap = { + ...getDefaultHeaders(requestMethod), + ...requestHeader, + }; const controller = new AbortController(); let timeoutId: any | undefined; @@ -85,7 +80,7 @@ export class ServiceWorkerHttpLib implements HttpRequestLibrary { try { const response = await fetch(requestUrl, { - headers: requestHeader, + headers: requestHeadersMap, body: myBody, method: requestMethod, signal: controller.signal,