http auth: improve status code handling

This commit is contained in:
Koushik Dutta
2024-07-15 11:56:39 -07:00
parent 0050624880
commit 90bca27bde
5 changed files with 33 additions and 18 deletions

View File

@@ -91,20 +91,26 @@ export function createAuthFetch<B, M>(
const initialResponse = await h({
...options,
signal: controller.signal,
ignoreStatusCode: true,
// need to intercept the status code to check for 401.
// all other status codes will be handled according to the initial request options.
checkStatusCode(statusCode) {
// can handle a 401 if an credential is provided.
// however, not providing a credential is also valid, and should
// fall through to the normal response handling which may be interested
// in the 401 response.
if (statusCode === 401 && options.credential)
return true;
if (options?.checkStatusCode === undefined || options?.checkStatusCode) {
const checker = typeof options?.checkStatusCode === 'function' ? options.checkStatusCode : checkStatus;
return checker(statusCode);
}
return true;
},
responseType: 'readable',
});
if (initialResponse.statusCode !== 401 || !options.credential) {
if (!options?.ignoreStatusCode) {
try {
checkStatus(initialResponse.statusCode);
}
catch (e) {
controller.abort('Invalid status code');
throw e;
}
}
// if it's not a 401, just return the response.
if (initialResponse.statusCode !== 401) {
return {
...initialResponse,
body: await parser(initialResponse.body, options.responseType),

View File

@@ -5,7 +5,7 @@ export async function getDeviceInfo(credential: AuthFetchCredentialState, addres
const response = await authHttpFetch({
credential,
url: `http://${address}/ISAPI/System/deviceInfo`,
ignoreStatusCode: true,
checkStatusCode: false,
responseType: 'text',
rejectUnauthorized: false,
});

View File

@@ -30,7 +30,7 @@ export class TapoAPI {
const response = await authHttpFetch({
credential: undefined,
url: url,
ignoreStatusCode: true,
checkStatusCode: false,
method: 'POST',
headers: {
'Content-Type': 'multipart/mixed; boundary=--client-stream-boundary--',

View File

@@ -122,9 +122,12 @@ export async function httpFetch<T extends HttpFetchOptions<Readable>>(options: T
try {
const [response] = await once(request, 'response') as [IncomingMessage];
if (!options?.ignoreStatusCode) {
if (options?.checkStatusCode === undefined || options?.checkStatusCode) {
try {
checkStatus(response.statusCode);
const checker = typeof options?.checkStatusCode === 'function' ? options.checkStatusCode : checkStatus;
if (!checker(response.statusCode))
throw new Error(`http response statusCode ${response.statusCode}`);
}
catch (e) {
readMessageBuffer(response).catch(() => { });

View File

@@ -7,7 +7,10 @@ export interface HttpFetchOptionsBase<B> {
signal?: AbortSignal,
timeout?: number;
rejectUnauthorized?: boolean;
ignoreStatusCode?: boolean;
/**
* Checks the status code. Defaults to true.
*/
checkStatusCode?: boolean | ((statusCode: number) => boolean);
body?: B | string | ArrayBufferView | any;
withCredentials?: boolean;
}
@@ -40,6 +43,7 @@ export function fetchStatusCodeOk(statusCode: number) {
export function checkStatus(statusCode: number) {
if (!fetchStatusCodeOk(statusCode))
throw new Error(`http response statusCode ${statusCode}`);
return true;
}
export function getFetchMethod(options: HttpFetchOptions<any>) {
@@ -190,9 +194,11 @@ export async function domFetch<T extends HttpFetchOptions<BodyInit>>(options: T)
body,
});
if (!options?.ignoreStatusCode) {
if (options?.checkStatusCode === undefined || options?.checkStatusCode) {
try {
checkStatus(response.status);
const checker = typeof options?.checkStatusCode === 'function' ? options.checkStatusCode : checkStatus;
if (!checker(response.status))
throw new Error(`http response statusCode ${response.status}`);
}
catch (e) {
response.arrayBuffer().catch(() => { });