From a4ffee2193889ddf8e408a247b66cfe4c37df53a Mon Sep 17 00:00:00 2001 From: Michel Kaporin Date: Mon, 17 Jan 2022 15:53:06 +0100 Subject: [PATCH] fix: do not expect specific error for clients without IPv6 (#120) --- src/constants.ts | 1 - src/http.ts | 2 +- src/needle.ts | 8 ++++++-- tests/analysis.spec.ts | 2 +- tests/http.spec.ts | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 tests/http.spec.ts diff --git a/src/constants.ts b/src/constants.ts index d350dc6b..f572b60b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -48,7 +48,6 @@ export const NETWORK_ERRORS = { ECONNRESET: ErrorCodes.connectionRefused, ENETUNREACH: ErrorCodes.connectionRefused, ENOTFOUND: ErrorCodes.dnsNotFound, - EADDRNOTAVAIL: ErrorCodes.dnsNotFound, // happens when DNS cannot resolve the IPv6 }; export const DEFAULT_ERROR_MESSAGES: { [P in ErrorCodes]: string } = { diff --git a/src/http.ts b/src/http.ts index 405bfca8..7962b42d 100644 --- a/src/http.ts +++ b/src/http.ts @@ -100,7 +100,7 @@ export async function getIpFamily(authHost: string): Promise { 0, ); - const ipv6Incompatible = (res).errorCode === ErrorCodes.dnsNotFound; + const ipv6Incompatible = (res).error; return ipv6Incompatible ? undefined : family; } diff --git a/src/needle.ts b/src/needle.ts index 05dc3ef4..cc6cb02e 100644 --- a/src/needle.ts +++ b/src/needle.ts @@ -47,6 +47,7 @@ interface SuccessResponse { export type FailedResponse = { success: false; errorCode: number; + error: Error | undefined; }; export async function makeRequest( @@ -83,8 +84,10 @@ export async function makeRequest( }; emitter.apiRequestLog(`=> HTTP ${method?.toUpperCase()} ${url} ${data ?? ''}`.slice(0, 399)); + do { let errorCode: number | undefined; + let error: Error | undefined; let response: needle.NeedleResponse | undefined; try { response = await needle(method, url, data, options); @@ -93,6 +96,7 @@ export async function makeRequest( if (success) return { success, body: response.body as T }; errorCode = response.statusCode; } catch (err) { + error = err; // do not swallow the error, pass further to the caller instead errorCode = NETWORK_ERRORS[err.code || err.errno]; emitter.apiRequestLog(`Requested url --> ${url} | error --> ${err}`); } @@ -114,9 +118,9 @@ export async function makeRequest( await sleep(REQUEST_RETRY_DELAY); } else { attempts = 0; - return { success: false, errorCode }; + return { success: false, errorCode, error }; } } while (attempts > 0); - return { success: false, errorCode: ErrorCodes.serviceUnavailable }; + return { success: false, errorCode: ErrorCodes.serviceUnavailable, error: undefined }; } diff --git a/tests/analysis.spec.ts b/tests/analysis.spec.ts index 845b77e3..d318d140 100644 --- a/tests/analysis.spec.ts +++ b/tests/analysis.spec.ts @@ -248,7 +248,7 @@ describe('Functional test of analysis', () => { const sarifResults = extendedBundle.analysisResults.sarif; - expect(sarifResults.runs[0].tool.driver.rules).toHaveLength(7); + expect(sarifResults.runs[0].tool.driver.rules).toHaveLength(8); expect(sarifResults.runs[0].results).toHaveLength(15); const getRes = (path: string) => sarifResults.runs[0].results!.find( diff --git a/tests/http.spec.ts b/tests/http.spec.ts new file mode 100644 index 00000000..66931988 --- /dev/null +++ b/tests/http.spec.ts @@ -0,0 +1,33 @@ +import needle from 'needle'; + +describe('HTTP', () => { + const authHost = 'https://dev.snyk.io'; + + beforeEach(() => { + jest.resetModuleRegistry(); + }) + + it('should respolve IPv6, if http request succeeds', async () => { + jest.mock('needle', () => jest.fn(() => ({ + response: { + statusCode: 401, + body: {} + } + }))); + + const http = await import('../src'); + const family = await http.getIpFamily(authHost); + + expect(family).toBe(6); + }); + + it('shouldn not resolve IPv6, if http request throws an error', async () => { + const errorFn = () => { throw new Error(); }; + jest.mock('needle', () => jest.fn(errorFn)); + + const http = await import('../src'); + const family = await http.getIpFamily(authHost); + + expect(family).toBe(undefined); + }); +});