aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-util
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-02-16 00:30:25 +0100
committerFlorian Dold <florian@dold.me>2024-02-16 00:30:25 +0100
commitc909d6fc0657002a2e5d117e98b9685f7a04a9d4 (patch)
treed03d65354a12c5946025b04c939b04b49328b425 /packages/taler-util
parent490ef893e04d0515c3093a5a3e1cf14e707f3ea6 (diff)
downloadwallet-core-c909d6fc0657002a2e5d117e98b9685f7a04a9d4.tar.xz
taler-util: cancellation and timeouts on qjs
Diffstat (limited to 'packages/taler-util')
-rw-r--r--packages/taler-util/src/http-impl.qtart.ts80
-rw-r--r--packages/taler-util/src/index.ts1
2 files changed, 77 insertions, 4 deletions
diff --git a/packages/taler-util/src/http-impl.qtart.ts b/packages/taler-util/src/http-impl.qtart.ts
index a37029d6e..0be9f2c23 100644
--- a/packages/taler-util/src/http-impl.qtart.ts
+++ b/packages/taler-util/src/http-impl.qtart.ts
@@ -19,9 +19,9 @@
/**
* Imports.
*/
-import { Logger } from "@gnu-taler/taler-util";
+import { Logger, openPromise } from "@gnu-taler/taler-util";
import { TalerError } from "./errors.js";
-import { encodeBody, getDefaultHeaders, HttpLibArgs } from "./http-common.js";
+import { HttpLibArgs, encodeBody, getDefaultHeaders } from "./http-common.js";
import {
Headers,
HttpRequestLibrary,
@@ -29,12 +29,26 @@ import {
HttpResponse,
} from "./http.js";
import { RequestThrottler, TalerErrorCode, URL } from "./index.js";
-import { qjsOs } from "./qtart.js";
+import { QjsHttpResp, qjsOs } from "./qtart.js";
const logger = new Logger("http-impl.qtart.ts");
const textDecoder = new TextDecoder();
+export class RequestTimeoutError extends Error {
+ public constructor() {
+ super("Request timed out");
+ Object.setPrototypeOf(this, RequestTimeoutError.prototype);
+ }
+}
+
+export class RequestCancelledError extends Error {
+ public constructor() {
+ super("Request cancelled");
+ Object.setPrototypeOf(this, RequestCancelledError.prototype);
+ }
+}
+
/**
* Implementation of the HTTP request library interface for node.
*/
@@ -92,12 +106,70 @@ export class HttpLibImpl implements HttpRequestLibrary {
if (method === "POST") {
data = encodeBody(opt?.body);
}
- const res = await qjsOs.fetchHttp(url, {
+
+ const cancelPromCap = openPromise<QjsHttpResp>();
+
+ // Just like WHATWG fetch(), the qjs http client doesn't
+ // really support cancellation, so cancellation here just
+ // means that the result is ignored!
+ const fetchProm = qjsOs.fetchHttp(url, {
method,
data,
headers: headersList,
});
+ let timeoutHandle: any = undefined;
+ let cancelCancelledHandler: (() => void) | undefined = undefined;
+
+ if (opt?.timeout && opt.timeout.d_ms !== "forever") {
+ timeoutHandle = setTimeout(() => {
+ cancelPromCap.reject(new RequestTimeoutError());
+ }, opt.timeout.d_ms);
+ }
+
+ if (opt?.cancellationToken) {
+ cancelCancelledHandler = opt.cancellationToken.onCancelled(() => {
+ cancelPromCap.reject(new RequestCancelledError());
+ });
+ }
+
+ let res: QjsHttpResp;
+ try {
+ res = await Promise.race([fetchProm, cancelPromCap.promise]);
+ } catch (e) {
+ if (e instanceof RequestCancelledError) {
+ throw TalerError.fromDetail(
+ TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
+ {
+ requestUrl: url,
+ requestMethod: method,
+ httpStatusCode: 0,
+ },
+ `Request cancelled`,
+ );
+ }
+ if (e instanceof RequestTimeoutError) {
+ throw TalerError.fromDetail(
+ TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
+ {
+ requestUrl: url,
+ requestMethod: method,
+ httpStatusCode: 0,
+ },
+ `Request timed out`,
+ );
+ }
+ throw e;
+ }
+
+ if (timeoutHandle != null) {
+ clearTimeout(timeoutHandle);
+ }
+
+ if (cancelCancelledHandler != null) {
+ cancelCancelledHandler();
+ }
+
const headers: Headers = new Headers();
if (res.headers) {
diff --git a/packages/taler-util/src/index.ts b/packages/taler-util/src/index.ts
index 2045a4717..edc9c4ff2 100644
--- a/packages/taler-util/src/index.ts
+++ b/packages/taler-util/src/index.ts
@@ -44,6 +44,7 @@ export {
export * from "./notifications.js";
export * from "./operation.js";
export * from "./payto.js";
+export * from "./promises.js";
export * from "./rfc3548.js";
export * from "./taler-crypto.js";
export * from "./taler-types.js";