diff --git a/lib/axiosHttpClient.ts b/lib/axiosHttpClient.ts index 335ae3d..e7b7068 100644 --- a/lib/axiosHttpClient.ts +++ b/lib/axiosHttpClient.ts @@ -85,8 +85,9 @@ export class AxiosHttpClient implements HttpClient { throw new RestError("The request was aborted", "REQUEST_ABORTED_ERROR", undefined, httpRequest); } + let abortListener: (() => void) | undefined; const cancelToken = abortSignal && new axios.CancelToken(canceler => { - abortSignal.addEventListener("abort", () => canceler()); + abortSignal.addEventListener("abort", abortListener = () => canceler()); }); const rawHeaders: { [headerName: string]: string } = httpRequest.headers.rawHeaders(); @@ -115,6 +116,10 @@ export class AxiosHttpClient implements HttpClient { const axiosErr = err as AxiosError; throw new RestError(axiosErr.message, "REQUEST_SEND_ERROR", undefined, httpRequest); } + } finally { + if (abortSignal && abortListener) { + abortSignal.removeEventListener("abort", abortListener); + } } const headers = new HttpHeaders(res.headers); diff --git a/lib/operationArguments.ts b/lib/operationArguments.ts index 1961ac3..01428c7 100644 --- a/lib/operationArguments.ts +++ b/lib/operationArguments.ts @@ -15,4 +15,9 @@ export interface OperationArguments { * header arguments are added. */ customHeaders?: { [headerName: string]: string }; + + /** + * The signal which can be used to abort requests. + */ + abortSignal?: AbortSignal; } \ No newline at end of file diff --git a/lib/serviceClient.ts b/lib/serviceClient.ts index de02ede..4517314 100644 --- a/lib/serviceClient.ts +++ b/lib/serviceClient.ts @@ -256,6 +256,10 @@ export class ServiceClient { } } + if (operationArguments.abortSignal) { + httpRequest.abortSignal = operationArguments.abortSignal; + } + return this.sendRequest(httpRequest); } } diff --git a/lib/webResource.ts b/lib/webResource.ts index 18ca3dd..960851b 100644 --- a/lib/webResource.ts +++ b/lib/webResource.ts @@ -326,5 +326,11 @@ export interface RequestOptionsBase { * will be applied before the request is sent. */ customHeaders?: { [key: string]: string }; + + /** + * The signal which can be used to abort requests. + */ + abortSignal?: AbortSignal; + [key: string]: any; } \ No newline at end of file diff --git a/test/shared/axiosHttpClientTests.ts b/test/shared/axiosHttpClientTests.ts index 8cc0df9..4d45307 100644 --- a/test/shared/axiosHttpClientTests.ts +++ b/test/shared/axiosHttpClientTests.ts @@ -5,7 +5,17 @@ import * as should from "should"; import { AxiosHttpClient } from "../../lib/axiosHttpClient"; import { baseURL } from "../testUtils"; import { WebResource } from "../../lib/webResource"; -import { isNode } from "../../lib/util/utils"; + +function getAbortController(): AbortController { + let controller: AbortController; + if (typeof AbortController === "function") { + controller = new AbortController(); + } else { + const AbortControllerPonyfill = require("abortcontroller-polyfill/dist/cjs-ponyfill").AbortController; + controller = new AbortControllerPonyfill(); + } + return controller; +} describe("axiosHttpClient", () => { it("should send HTTP requests", async () => { @@ -89,13 +99,7 @@ describe("axiosHttpClient", () => { // ensure that a large upload is actually cancelled this.timeout(2000); - let controller: AbortController; - if (isNode) { - const AbortControllerPonyfill = require("abortcontroller-polyfill/dist/cjs-ponyfill").AbortController; - controller = new AbortControllerPonyfill(); - } else { - controller = new AbortController(); - } + const controller = getAbortController(); const request = new WebResource(`${baseURL}/fileupload`, "POST", new Uint8Array(1024*1024*100), undefined, undefined, true, controller.signal); const client = new AxiosHttpClient(); const promise = client.sendRequest(request); @@ -117,14 +121,7 @@ describe("axiosHttpClient", () => { // ensure that a large upload is actually cancelled this.timeout(4000); - let controller: AbortController; - if (isNode) { - const AbortControllerPonyfill = require("abortcontroller-polyfill/dist/cjs-ponyfill").AbortController; - controller = new AbortControllerPonyfill(); - } else { - controller = new AbortController(); - } - + const controller = getAbortController(); const buf = new Uint8Array(1024*1024*100); const requests = [ new WebResource(`${baseURL}/fileupload`, "POST", buf, undefined, undefined, true, controller.signal),