aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-06-30 16:20:47 -0300
committerSebastian <sebasjm@gmail.com>2024-06-30 23:46:46 -0300
commit3bb3d4c82535e4c3bc946355967d40683a15fd1c (patch)
treed4011169559d3da4d11cfe000570417b425398b2
parentd768a1c75efc8c6fefc2b9fff644f63657d9e6c8 (diff)
downloadwallet-core-3bb3d4c82535e4c3bc946355967d40683a15fd1c.tar.xz
fix double reading http response
-rw-r--r--packages/taler-util/src/http-impl.node.ts2
-rw-r--r--packages/web-util/src/utils/http-impl.sw.ts126
2 files changed, 88 insertions, 40 deletions
diff --git a/packages/taler-util/src/http-impl.node.ts b/packages/taler-util/src/http-impl.node.ts
index d27fd878d..fc5fe5e98 100644
--- a/packages/taler-util/src/http-impl.node.ts
+++ b/packages/taler-util/src/http-impl.node.ts
@@ -237,7 +237,7 @@ export class HttpLibImpl implements HttpRequestLibrary {
};
doCleanup();
if (SHOW_CURL_HTTP_REQUEST) {
- console.log(`TALER_API_DEBUG: ${textDecoder.decode(data)}`)
+ console.log(`TALER_API_DEBUG: ${res.statusCode} ${textDecoder.decode(data)}`)
}
resolve(resp);
});
diff --git a/packages/web-util/src/utils/http-impl.sw.ts b/packages/web-util/src/utils/http-impl.sw.ts
index 9c820bb4b..7b168b739 100644
--- a/packages/web-util/src/utils/http-impl.sw.ts
+++ b/packages/web-util/src/utils/http-impl.sw.ts
@@ -21,7 +21,7 @@ import {
Duration,
RequestThrottler,
TalerError,
- TalerErrorCode
+ TalerErrorCode,
} from "@gnu-taler/taler-util";
import {
@@ -85,7 +85,9 @@ export class BrowserFetchHttpLib implements HttpRequestLibrary {
}
const myBody: ArrayBuffer | undefined =
- requestMethod === "POST" || requestMethod === "PUT" || requestMethod === "PATCH"
+ requestMethod === "POST" ||
+ requestMethod === "PUT" ||
+ requestMethod === "PATCH"
? encodeBody(requestBody)
: undefined;
@@ -93,8 +95,8 @@ export class BrowserFetchHttpLib implements HttpRequestLibrary {
if (requestHeader) {
Object.entries(requestHeader).forEach(([key, value]) => {
if (value === undefined) return;
- requestHeadersMap[key] = value
- })
+ requestHeadersMap[key] = value;
+ });
}
const controller = new AbortController();
@@ -106,7 +108,7 @@ export class BrowserFetchHttpLib implements HttpRequestLibrary {
}
if (requestCancel) {
requestCancel.onCancelled(() => {
- controller.abort(TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR)
+ controller.abort(TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR);
});
}
@@ -116,7 +118,7 @@ export class BrowserFetchHttpLib implements HttpRequestLibrary {
body: myBody,
method: requestMethod,
signal: controller.signal,
- redirect: requestRedirect
+ redirect: requestRedirect,
});
if (timeoutId) {
@@ -127,13 +129,15 @@ export class BrowserFetchHttpLib implements HttpRequestLibrary {
response.headers.forEach((value, key) => {
headerMap.set(key, value);
});
+ const text = makeTextHandler(response, requestUrl, requestMethod);
+ const json = makeJsonHandler(response, requestUrl, requestMethod, text);
return {
headers: headerMap,
status: response.status,
requestMethod,
requestUrl,
- json: makeJsonHandler(response, requestUrl, requestMethod),
- text: makeTextHandler(response, requestUrl, requestMethod),
+ json,
+ text,
bytes: async () => (await response.blob()).arrayBuffer(),
};
} catch (e) {
@@ -143,7 +147,8 @@ export class BrowserFetchHttpLib implements HttpRequestLibrary {
{
requestUrl,
requestMethod,
- timeoutMs: requestTimeout.d_ms === "forever" ? 0 : requestTimeout.d_ms
+ timeoutMs:
+ requestTimeout.d_ms === "forever" ? 0 : requestTimeout.d_ms,
},
`HTTP request failed.`,
);
@@ -151,7 +156,6 @@ export class BrowserFetchHttpLib implements HttpRequestLibrary {
throw e;
}
}
-
}
function makeTextHandler(
@@ -159,20 +163,29 @@ function makeTextHandler(
requestUrl: string,
requestMethod: string,
) {
- return async function getTextFromResponse(): Promise<any> {
- let respText;
- try {
- respText = await response.text();
- } catch (e) {
- throw TalerError.fromDetail(
- TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
- {
- requestUrl,
- requestMethod,
- httpStatusCode: response.status,
- },
- "Invalid text from HTTP response",
- );
+ let firstTime = true;
+ let respText: string;
+ let error: TalerError | undefined;
+ return async function getTextFromResponse(): Promise<string> {
+ if (firstTime) {
+ firstTime = false;
+ try {
+ respText = await response.text();
+ } catch (e) {
+ error = TalerError.fromDetail(
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ {
+ requestUrl,
+ requestMethod,
+ httpStatusCode: response.status,
+ validationError: e instanceof Error ? e.message : String(e),
+ },
+ "Invalid text from HTTP response",
+ );
+ }
+ }
+ if (error !== undefined) {
+ throw error;
}
return respText;
};
@@ -182,35 +195,70 @@ function makeJsonHandler(
response: Response,
requestUrl: string,
requestMethod: string,
+ readTextHandler: () => Promise<string>,
) {
- let responseJson: unknown = undefined;
+ let firstTime = true;
+ let responseJson: string | undefined = undefined;
+ let error: TalerError | undefined;
return async function getJsonFromResponse(): Promise<any> {
- if (responseJson === undefined) {
+ if (firstTime) {
+ let responseText: string;
try {
- responseJson = await response.json();
+ responseText = await readTextHandler();
} catch (e) {
- const message = e instanceof Error ? `Invalid JSON from HTTP response: ${e.message}` : "Invalid JSON from HTTP response"
- throw TalerError.fromDetail(
+ const message =
+ e instanceof Error
+ ? `Couldn't read HTTP response: ${e.message}`
+ : "Couldn't read HTTP response";
+ error = TalerError.fromDetail(
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
{
requestUrl,
requestMethod,
httpStatusCode: response.status,
+ validationError: e instanceof Error ? e.message : String(e),
},
message,
);
}
+ if (!error) {
+ try {
+ // @ts-expect-error no error then text is initialized
+ responseJson = JSON.parse(responseText);
+ } catch (e) {
+ const message =
+ e instanceof Error
+ ? `Invalid JSON from HTTP response: ${e.message}`
+ : "Invalid JSON from HTTP response";
+ error = TalerError.fromDetail(
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ {
+ requestUrl,
+ requestMethod,
+ // @ts-expect-error no error then text is initialized
+ response: responseText,
+ httpStatusCode: response.status,
+ validationError: e instanceof Error ? e.message : String(e),
+ },
+ message,
+ );
+ }
+ if (responseJson === null || typeof responseJson !== "object") {
+ error = TalerError.fromDetail(
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ {
+ requestUrl,
+ requestMethod,
+ response: JSON.stringify(responseJson),
+ httpStatusCode: response.status,
+ },
+ "Invalid JSON from HTTP response: null or not object",
+ );
+ }
+ }
}
- if (responseJson === null || typeof responseJson !== "object") {
- throw TalerError.fromDetail(
- TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
- {
- requestUrl,
- requestMethod,
- httpStatusCode: response.status,
- },
- "Invalid JSON from HTTP response: null or not object",
- );
+ if (error !== undefined) {
+ throw error;
}
return responseJson;
};