From ae27a8068719b6b238e33127b8925cdcf0aa1d15 Mon Sep 17 00:00:00 2001 From: Gneev Roland Date: Tue, 3 Jul 2018 11:33:45 +0300 Subject: [PATCH 1/8] Added withCredentials in xhrHttpClient --- lib/xhrHttpClient.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/xhrHttpClient.ts b/lib/xhrHttpClient.ts index 15c677c02d08..d3acafbc1c0e 100644 --- a/lib/xhrHttpClient.ts +++ b/lib/xhrHttpClient.ts @@ -60,6 +60,7 @@ export class XhrHttpClient implements HttpClient { } } + xhr.withCredentials = true; xhr.open(request.method, request.url); for (const header of request.headers.headersArray()) { xhr.setRequestHeader(header.name, header.value); @@ -91,9 +92,9 @@ export class XhrHttpClient implements HttpClient { } else { return new Promise(function(resolve, reject) { xhr.addEventListener("load", () => resolve({ - request, - status: xhr.status, - headers: parseHeaders(xhr), + request, + status: xhr.status, + headers: parseHeaders(xhr), bodyAsText: xhr.responseText })); rejectOnTerminalEvent(request, xhr, reject); @@ -105,7 +106,7 @@ export class XhrHttpClient implements HttpClient { function addProgressListener(xhr: XMLHttpRequestEventTarget, listener?: (progress: TransferProgressEvent) => void) { if (listener) { xhr.addEventListener("progress", rawEvent => listener({ - loadedBytes: rawEvent.loaded, + loadedBytes: rawEvent.loaded, totalBytes: rawEvent.lengthComputable ? rawEvent.total : undefined })); } From 07aa96612b401f60ac21a399c30df190575a689c Mon Sep 17 00:00:00 2001 From: Gneev Roland Date: Wed, 4 Jul 2018 11:27:26 +0300 Subject: [PATCH 2/8] Revert whitespace changes --- lib/xhrHttpClient.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/xhrHttpClient.ts b/lib/xhrHttpClient.ts index d3acafbc1c0e..1c4a60b775c8 100644 --- a/lib/xhrHttpClient.ts +++ b/lib/xhrHttpClient.ts @@ -92,9 +92,9 @@ export class XhrHttpClient implements HttpClient { } else { return new Promise(function(resolve, reject) { xhr.addEventListener("load", () => resolve({ - request, - status: xhr.status, - headers: parseHeaders(xhr), + request, + status: xhr.status, + headers: parseHeaders(xhr), bodyAsText: xhr.responseText })); rejectOnTerminalEvent(request, xhr, reject); @@ -106,7 +106,7 @@ export class XhrHttpClient implements HttpClient { function addProgressListener(xhr: XMLHttpRequestEventTarget, listener?: (progress: TransferProgressEvent) => void) { if (listener) { xhr.addEventListener("progress", rawEvent => listener({ - loadedBytes: rawEvent.loaded, + loadedBytes: rawEvent.loaded, totalBytes: rawEvent.lengthComputable ? rawEvent.total : undefined })); } From 98107b1ebd6200fe9fe4aec9b9dc78f3b4acce2c Mon Sep 17 00:00:00 2001 From: Gneev Roland Date: Fri, 6 Jul 2018 14:16:28 +0300 Subject: [PATCH 3/8] withCredentials option in WebResource --- lib/serviceClient.ts | 5 +++++ lib/webResource.ts | 4 ++++ lib/xhrHttpClient.ts | 2 +- test/shared/defaultHttpClientTests.ts | 8 ++++---- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/serviceClient.ts b/lib/serviceClient.ts index 771e85de148d..5febb84bebfc 100644 --- a/lib/serviceClient.ts +++ b/lib/serviceClient.ts @@ -95,6 +95,7 @@ export class ServiceClient { private readonly _requestPolicyOptions: RequestPolicyOptions; private readonly _requestPolicyCreators: RequestPolicyCreator[]; + private readonly _requestOptions: RequestInit; /** * The ServiceClient constructor @@ -111,6 +112,7 @@ export class ServiceClient { if (!options.requestOptions) { options.requestOptions = {}; } + this._requestOptions = options.requestOptions; this.userAgentInfo = { value: [] }; @@ -281,6 +283,9 @@ export class ServiceClient { httpRequest.onDownloadProgress = operationArguments.onDownloadProgress; } + if (this._requestOptions.credentials === "include") + httpRequest.withCredentials = true; + serializeRequestBody(httpRequest, operationArguments, operationSpec); if (operationSpec.responses) { diff --git a/lib/webResource.ts b/lib/webResource.ts index 0a6002fdaee4..2339c50003f6 100644 --- a/lib/webResource.ts +++ b/lib/webResource.ts @@ -52,6 +52,7 @@ export class WebResource { formData?: any; query?: { [key: string]: any; }; operationSpec?: OperationSpec; + withCredentials: boolean; abortSignal?: AbortSignalLike; @@ -68,6 +69,7 @@ export class WebResource { query?: { [key: string]: any; }, headers?: { [key: string]: any; } | HttpHeaders, rawResponse = false, + withCredentials = false, abortSignal?: AbortSignalLike, onUploadProgress?: (progress: TransferProgressEvent) => void, onDownloadProgress?: (progress: TransferProgressEvent) => void) { @@ -79,6 +81,7 @@ export class WebResource { this.body = body; this.query = query; this.formData = undefined; + this.withCredentials = withCredentials; this.abortSignal = abortSignal; this.onUploadProgress = onUploadProgress; this.onDownloadProgress = onDownloadProgress; @@ -285,6 +288,7 @@ export class WebResource { this.query, this.headers && this.headers.clone(), this.rawResponse, + this.withCredentials, this.abortSignal, this.onUploadProgress, this.onDownloadProgress); diff --git a/lib/xhrHttpClient.ts b/lib/xhrHttpClient.ts index 1c4a60b775c8..18e87330ef83 100644 --- a/lib/xhrHttpClient.ts +++ b/lib/xhrHttpClient.ts @@ -60,7 +60,7 @@ export class XhrHttpClient implements HttpClient { } } - xhr.withCredentials = true; + xhr.withCredentials = request.withCredentials; xhr.open(request.method, request.url); for (const header of request.headers.headersArray()) { xhr.setRequestHeader(header.name, header.value); diff --git a/test/shared/defaultHttpClientTests.ts b/test/shared/defaultHttpClientTests.ts index 53a346e4a6c0..fe27ffe0ecaa 100644 --- a/test/shared/defaultHttpClientTests.ts +++ b/test/shared/defaultHttpClientTests.ts @@ -98,7 +98,7 @@ describe("defaultHttpClient", () => { it("should allow canceling requests", async function () { const controller = getAbortController(); - const request = new WebResource(`${baseURL}/fileupload`, "POST", new Uint8Array(1024 * 1024 * 10), undefined, undefined, true, controller.signal); + const request = new WebResource(`${baseURL}/fileupload`, "POST", new Uint8Array(1024 * 1024 * 10), undefined, undefined, true, undefined, controller.signal); const client = new DefaultHttpClient(); const promise = client.sendRequest(request); controller.abort(); @@ -134,8 +134,8 @@ describe("defaultHttpClient", () => { const controller = getAbortController(); const buf = new Uint8Array(1024 * 1024 * 1); const requests = [ - new WebResource(`${baseURL}/fileupload`, "POST", buf, undefined, undefined, true, controller.signal), - new WebResource(`${baseURL}/fileupload`, "POST", buf, undefined, undefined, true, controller.signal) + new WebResource(`${baseURL}/fileupload`, "POST", buf, undefined, undefined, true, undefined, controller.signal), + new WebResource(`${baseURL}/fileupload`, "POST", buf, undefined, undefined, true, undefined, controller.signal) ]; const client = new DefaultHttpClient(); const promises = requests.map(r => client.sendRequest(r)); @@ -160,7 +160,7 @@ describe("defaultHttpClient", () => { let downloadNotified = false; const buf = new Uint8Array(1024 * 1024 * 1); - const request = new WebResource(`${baseURL}/fileupload`, "POST", buf, undefined, undefined, true, undefined, + const request = new WebResource(`${baseURL}/fileupload`, "POST", buf, undefined, undefined, true, undefined, undefined, ev => { uploadNotified = true; ev.should.not.be.instanceof(ProgressEvent); From aa3a31f1750cd7b6ba2236912dcd52d22abbd253 Mon Sep 17 00:00:00 2001 From: Gneev Roland Date: Fri, 6 Jul 2018 14:23:22 +0300 Subject: [PATCH 4/8] Test actualization --- test/shared/logFilterTests.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/shared/logFilterTests.ts b/test/shared/logFilterTests.ts index 6375c670234f..6ad66c118ce0 100644 --- a/test/shared/logFilterTests.ts +++ b/test/shared/logFilterTests.ts @@ -26,7 +26,8 @@ describe("Log filter", () => { }, "body": { "a": 1 - } + }, + "withCredentials": false } >> Response status code: 200 >> Body: null From af0d5c70455312db0b842c2b0165260ce70213d4 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Fri, 6 Jul 2018 12:02:33 -0700 Subject: [PATCH 5/8] Use withCredentials flag instead of requestInit --- lib/serviceClient.ts | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/lib/serviceClient.ts b/lib/serviceClient.ts index 5febb84bebfc..5199fe988dcb 100644 --- a/lib/serviceClient.ts +++ b/lib/serviceClient.ts @@ -30,11 +30,6 @@ import { RequestPrepareOptions, WebResource } from "./webResource"; * Options to be provided while creating the client. */ export interface ServiceClientOptions { - /** - * @property {RequestInit} [requestOptions] The request options. Detailed info can be found - * here https://github.github.io/fetch/#Request - */ - requestOptions?: RequestInit; /** * @property {Array} [requestPolicyCreators] An array of functions that will be * invoked to create the RequestPolicy pipeline that will be used to send a HTTP request on the @@ -63,6 +58,10 @@ export interface ServiceClientOptions { * Whether or not to generate a client request ID header for each HTTP request. */ generateClientRequestIdHeader?: boolean; + /** + * Whether to include credentials in CORS requests in the browser. + */ + withCredentials?: boolean; /** * If specified, a GenerateRequestIdPolicy will be added to the HTTP pipeline that will add a * header to all outgoing requests with this header name and a random UUID as the request ID. @@ -95,7 +94,7 @@ export class ServiceClient { private readonly _requestPolicyOptions: RequestPolicyOptions; private readonly _requestPolicyCreators: RequestPolicyCreator[]; - private readonly _requestOptions: RequestInit; + private readonly _withCredentials: boolean; /** * The ServiceClient constructor @@ -109,11 +108,6 @@ export class ServiceClient { options = {}; } - if (!options.requestOptions) { - options.requestOptions = {}; - } - this._requestOptions = options.requestOptions; - this.userAgentInfo = { value: [] }; if (credentials && !credentials.signRequest) { @@ -128,6 +122,7 @@ export class ServiceClient { // do nothing } + this._withCredentials = options.withCredentials || false; this._httpClient = options.httpClient || new DefaultHttpClient(); this._requestPolicyOptions = new RequestPolicyOptions(options.httpPipelineLogger); @@ -283,8 +278,7 @@ export class ServiceClient { httpRequest.onDownloadProgress = operationArguments.onDownloadProgress; } - if (this._requestOptions.credentials === "include") - httpRequest.withCredentials = true; + httpRequest.withCredentials = this._withCredentials; serializeRequestBody(httpRequest, operationArguments, operationSpec); @@ -435,4 +429,4 @@ function getOperationArgumentValueFromParameterPath(operationArguments: Operatio } } return value; -} \ No newline at end of file +} From 3739084a17ae7cd8ae0ca583c2fb2e2aa39d35d7 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Fri, 6 Jul 2018 12:12:03 -0700 Subject: [PATCH 6/8] Bump to v0.15.x --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 58fa1dbce8d2..4d495dd2c7cb 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "email": "azsdkteam@microsoft.com", "url": "https://github.com/Azure/ms-rest-js" }, - "version": "0.14.0", + "version": "0.15.0", "description": "Isomorphic client Runtime for Typescript/node.js/browser javascript client libraries generated using AutoRest", "tags": [ "isomorphic", From a16d3dd725b21260899ffcb6ac4c285593f445ef Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Fri, 6 Jul 2018 12:22:05 -0700 Subject: [PATCH 7/8] Add test to ServiceClient --- test/shared/serviceClientTests.ts | 41 ++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/test/shared/serviceClientTests.ts b/test/shared/serviceClientTests.ts index aa1d84df884c..2b55b1cb1f74 100644 --- a/test/shared/serviceClientTests.ts +++ b/test/shared/serviceClientTests.ts @@ -1,4 +1,4 @@ -import { ServiceClient, WebResource, Serializer, HttpOperationResponse, DictionaryMapper, QueryCollectionFormat, SequenceMapper } from "../../lib/msRest"; +import { ServiceClient, WebResource, Serializer, HttpOperationResponse, DictionaryMapper, QueryCollectionFormat, SequenceMapper, HttpClient } from "../../lib/msRest"; import * as assert from "assert"; describe("ServiceClient", function () { @@ -66,6 +66,7 @@ describe("ServiceClient", function () { assert(request!); assert.deepStrictEqual(request!.headers.toJson(), expected); }); + it("Should serialize collection:multi query parameters", async function () { const expected = "?q=1&q=2&q=3"; @@ -117,4 +118,42 @@ describe("ServiceClient", function () { assert(request!); assert(request!.url.endsWith(expected), `"${request!.url}" does not end with "${expected}"`); }); + + it("should apply withCredentials to requests", async function() { + let request: WebResource; + const httpClient: HttpClient = { + sendRequest: req => { + request = req; + return Promise.resolve({} as HttpOperationResponse); + } + }; + + const client1 = new ServiceClient(undefined, { + httpClient, + requestPolicyCreators: [] + }); + await client1.sendOperationRequest({ arguments: {} }, + { + serializer: new Serializer(), + httpMethod: "GET", + baseUrl: "httpbin.org", + responses: { 200: {} } + }); + + assert.strictEqual(request!.withCredentials, false); + + const client2 = new ServiceClient(undefined, { + httpClient, + requestPolicyCreators: [], + withCredentials: true + }); + await client2.sendOperationRequest({ arguments: {} }, + { + serializer: new Serializer(), + httpMethod: "GET", + baseUrl: "httpbin.org", + responses: { 200: {} } + }); + assert.strictEqual(request!.withCredentials, true); + }); }); \ No newline at end of file From 0ace3050d7a8d0093d6d82df1f8c576a518af7b6 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Fri, 6 Jul 2018 13:05:48 -0700 Subject: [PATCH 8/8] Link to mdn docs for withCredentials --- lib/serviceClient.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/serviceClient.ts b/lib/serviceClient.ts index 5199fe988dcb..d413206e5a5e 100644 --- a/lib/serviceClient.ts +++ b/lib/serviceClient.ts @@ -60,6 +60,7 @@ export interface ServiceClientOptions { generateClientRequestIdHeader?: boolean; /** * Whether to include credentials in CORS requests in the browser. + * See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials for more information. */ withCredentials?: boolean; /**