Merge pull request #403 from joshgummersall/master

Add HTTP agent settings and policy
This commit is contained in:
David Wilson 2020-10-08 13:08:13 -07:00 коммит произвёл GitHub
Родитель 01cfc78e2f 2e999a39e6
Коммит abc4f8f58e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 217 добавлений и 8 удалений

Просмотреть файл

@ -1,4 +1,8 @@
# Changelog
## 2.1.0 - 2020-10-08
- Add support for custom http/https agent (PR [#403](https://github.com/Azure/ms-rest-js/pull/403))
- Fix WebResource clone to include extra settings (Issue [#405](https://github.com/Azure/ms-rest-js/issue/403))
## 2.0.8 - 2020-07-23
- [BugFix] - Fixed loading of proxyPolicy.browser.js in the HTML files.(PR [#397](https://github.com/Azure/ms-rest-js/pull/397))
@ -7,7 +11,7 @@
- Replace public usage of `RequestPolicyOptions` to an interface `RequestPolicyOptionsLike` to avoid compatibility issues with private members.
- Fix issue with null/undefined values in array and tabs/space delimiter arrays during sendOperationRequest. [PR #390](https://github.com/Azure/ms-rest-js/pull/390)
- Fix in flattenResponse when expecting an array, checking for parsedBody to be an array before proceeding with flattening. (PR [#385](https://github.com/Azure/ms-rest-js/pull/385))
## 2.0.6 - 2020-04-15
- A new interface `WebResourceLike` was introduced to avoid a direct dependency on the class `WebResource` in public interfaces. `HttpHeadersLike` was also added to replace references to `HttpHeaders`. This change was added to improve compatibility between `@azure/core-http` and `@azure/ms-rest-nodeauth`.

Просмотреть файл

@ -22,6 +22,7 @@ export { generateClientRequestIdPolicy } from "./policies/generateClientRequestI
export { exponentialRetryPolicy } from "./policies/exponentialRetryPolicy";
export { systemErrorRetryPolicy } from "./policies/systemErrorRetryPolicy";
export { throttlingRetryPolicy } from "./policies/throttlingRetryPolicy";
export { agentPolicy } from "./policies/agentPolicy";
export { getDefaultProxySettings, proxyPolicy } from "./policies/proxyPolicy";
export { redirectPolicy } from "./policies/redirectPolicy";
export { signingPolicy } from "./policies/signingPolicy";

Просмотреть файл

@ -46,7 +46,14 @@ export class NodeFetchHttpClient extends FetchHttpClient {
httpRequest.headers.set("Cookie", cookieString);
}
if (httpRequest.proxySettings) {
if (httpRequest.agentSettings) {
const {http: httpAgent, https: httpsAgent} = httpRequest.agentSettings;
if (httpsAgent && httpRequest.url.startsWith("https")) {
requestInit.agent = httpsAgent;
} else if (httpAgent) {
requestInit.agent = httpAgent;
}
} else if (httpRequest.proxySettings) {
const tunnel: ProxyAgent = createProxyAgent(httpRequest.url, httpRequest.proxySettings, httpRequest.headers);
requestInit.agent = tunnel.agent;
}

Просмотреть файл

@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import { AgentSettings } from "../serviceClient";
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
import { HttpOperationResponse } from "../httpOperationResponse";
import { WebResourceLike } from "../webResource";
const agentNotSupportedInBrowser = new Error("AgentPolicy is not supported in browser environment");
export function agentPolicy(_agentSettings?: AgentSettings): RequestPolicyFactory {
return {
create: (_nextPolicy: RequestPolicy, _options: RequestPolicyOptionsLike) => {
throw agentNotSupportedInBrowser;
}
};
}
export class AgentPolicy extends BaseRequestPolicy {
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) {
super(nextPolicy, options);
throw agentNotSupportedInBrowser;
}
public sendRequest(_request: WebResourceLike): Promise<HttpOperationResponse> {
throw agentNotSupportedInBrowser;
}
}

Просмотреть файл

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import { AgentSettings } from "../serviceClient";
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
import { HttpOperationResponse } from "../httpOperationResponse";
import { WebResourceLike } from "../webResource";
export function agentPolicy(agentSettings?: AgentSettings): RequestPolicyFactory {
return {
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
return new AgentPolicy(nextPolicy, options, agentSettings!);
}
};
}
export class AgentPolicy extends BaseRequestPolicy {
agentSettings: AgentSettings;
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike, agentSettings: AgentSettings) {
super(nextPolicy, options);
this.agentSettings = agentSettings;
}
public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
if (!request.agentSettings) {
request.agentSettings = this.agentSettings;
}
return this._nextPolicy.sendRequest(request);
}
}

Просмотреть файл

@ -26,8 +26,10 @@ import { stringifyXML } from "./util/xml";
import { RequestOptionsBase, RequestPrepareOptions, WebResourceLike, isWebResourceLike, WebResource } from "./webResource";
import { OperationResponse } from "./operationResponse";
import { ServiceCallback } from "./util/utils";
import { agentPolicy } from "./policies/agentPolicy";
import { proxyPolicy, getDefaultProxySettings } from "./policies/proxyPolicy";
import { throttlingRetryPolicy } from "./policies/throttlingRetryPolicy";
import { Agent } from "http";
/**
@ -40,6 +42,14 @@ export interface ProxySettings {
password?: string;
}
/**
* HTTP and HTTPS agents (Node.js only)
*/
export interface AgentSettings {
http: Agent;
https: Agent;
}
/**
* Options to be provided while creating the client.
*/
@ -99,6 +109,10 @@ export interface ServiceClientOptions {
* Proxy settings which will be used for every HTTP request (Node.js only).
*/
proxySettings?: ProxySettings;
/**
* HTTP and HTTPS agents which will be used for every HTTP request (Node.js only).
*/
agentSettings?: AgentSettings;
}
/**
@ -434,6 +448,10 @@ function createDefaultRequestPolicyFactories(credentials: ServiceClientCredentia
factories.push(proxyPolicy(proxySettings));
}
if (options.agentSettings) {
factories.push(agentPolicy(options.agentSettings));
}
return factories;
}

Просмотреть файл

@ -7,7 +7,7 @@ export const Constants = {
* @const
* @type {string}
*/
msRestVersion: "2.0.8",
msRestVersion: "2.1.0",
/**
* Specifies HTTP.

Просмотреть файл

@ -7,7 +7,7 @@ import { Mapper, Serializer } from "./serializer";
import { generateUuid } from "./util/utils";
import { HttpOperationResponse } from "./httpOperationResponse";
import { OperationResponse } from "./operationResponse";
import { ProxySettings } from "./serviceClient";
import { AgentSettings, ProxySettings } from "./serviceClient";
export type HttpMethods = "GET" | "PUT" | "POST" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS" | "TRACE";
export type HttpRequestBody = Blob | string | ArrayBuffer | ArrayBufferView | (() => NodeJS.ReadableStream);
@ -94,6 +94,10 @@ export interface WebResourceLike {
* Proxy configuration.
*/
proxySettings?: ProxySettings;
/**
* HTTP(S) agent configuration.
*/
agentSettings?: AgentSettings;
/**
* If the connection should be reused.
*/
@ -182,6 +186,7 @@ export class WebResource {
timeout: number;
proxySettings?: ProxySettings;
keepAlive?: boolean;
agentSettings?: AgentSettings;
abortSignal?: AbortSignalLike;
@ -204,7 +209,8 @@ export class WebResource {
onUploadProgress?: (progress: TransferProgressEvent) => void,
onDownloadProgress?: (progress: TransferProgressEvent) => void,
proxySettings?: ProxySettings,
keepAlive?: boolean) {
keepAlive?: boolean,
agentSettings?: AgentSettings) {
this.streamResponseBody = streamResponseBody;
this.url = url || "";
@ -220,6 +226,7 @@ export class WebResource {
this.onDownloadProgress = onDownloadProgress;
this.proxySettings = proxySettings;
this.keepAlive = keepAlive;
this.agentSettings = agentSettings;
}
/**
@ -427,7 +434,10 @@ export class WebResource {
this.abortSignal,
this.timeout,
this.onUploadProgress,
this.onDownloadProgress);
this.onDownloadProgress,
this.proxySettings,
this.keepAlive,
this.agentSettings);
if (this.formData) {
result.formData = this.formData;

Просмотреть файл

@ -14,6 +14,10 @@ export class XhrHttpClient implements HttpClient {
public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
const xhr = new XMLHttpRequest();
if (request.agentSettings) {
throw new Error("HTTP agent settings not supported in browser environment");
}
if (request.proxySettings) {
throw new Error("HTTP proxy is not supported in browser environment");
}

Просмотреть файл

@ -5,7 +5,7 @@
"email": "azsdkteam@microsoft.com",
"url": "https://github.com/Azure/ms-rest-js"
},
"version": "2.0.8",
"version": "2.1.0",
"description": "Isomorphic client Runtime for Typescript/node.js/browser javascript client libraries generated using AutoRest",
"tags": [
"isomorphic",
@ -42,6 +42,7 @@
],
"browser": {
"./es/lib/policies/msRestUserAgentPolicy.js": "./es/lib/policies/msRestUserAgentPolicy.browser.js",
"./es/lib/policies/agentPolicy.js": "./es/lib/policies/agentPolicy.browser.js",
"./es/lib/policies/proxyPolicy.js": "./es/lib/policies/proxyPolicy.browser.js",
"./es/lib/util/base64.js": "./es/lib/util/base64.browser.js",
"./es/lib/util/xml.js": "./es/lib/util/xml.browser.js",

Просмотреть файл

@ -0,0 +1,95 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import "chai/register-should";
import { AgentSettings } from "../../lib/serviceClient";
import { RequestPolicyOptions } from "../../lib/policies/requestPolicy";
import { WebResource, WebResourceLike } from "../../lib/webResource";
import { HttpHeaders } from "../../lib/httpHeaders";
import { agentPolicy, AgentPolicy } from "../../lib/policies/agentPolicy";
import { nodeDescribe, browserDescribe } from "../msAssert";
describe("AgentPolicy", function () {
const emptyRequestPolicy = {
sendRequest: (_: WebResourceLike) =>
Promise.resolve({
request: new WebResource(),
status: 404,
headers: new HttpHeaders(undefined),
}),
};
const emptyPolicyOptions = new RequestPolicyOptions();
nodeDescribe("for Node.js", function () {
const http = require("http");
const https = require("https");
const agentSettings: AgentSettings = {
http: new http.Agent(),
https: new https.Agent(),
};
it("factory passes correct agent settings", function () {
const factory = agentPolicy(agentSettings);
const policy = factory.create(
emptyRequestPolicy,
emptyPolicyOptions
) as AgentPolicy;
policy.agentSettings.should.be.deep.equal(agentSettings);
});
it("sets correct agent settings through constructor", function () {
const policy = new AgentPolicy(
emptyRequestPolicy,
emptyPolicyOptions,
agentSettings
);
policy.agentSettings.should.be.deep.equal(agentSettings);
});
it("should assign agent settings to the web request", async function () {
const policy = new AgentPolicy(
emptyRequestPolicy,
emptyPolicyOptions,
agentSettings
);
const request = new WebResource();
await policy.sendRequest(request);
request.agentSettings!.should.be.deep.equal(agentSettings);
});
it("should not override agent settings to the web request", async function () {
const policy = new AgentPolicy(
emptyRequestPolicy,
emptyPolicyOptions,
agentSettings
);
const request = new WebResource();
const requestSpecificAgentSettings = {
http: new http.Agent({keepAlive: true}),
https: new http.Agent({keepAlive: true}),
};
request.agentSettings = requestSpecificAgentSettings;
await policy.sendRequest(request);
request.agentSettings!.should.be.deep.equal(requestSpecificAgentSettings);
});
});
browserDescribe("for browser", () => {
it("should throw an Error while constructing object", () => {
const agentSettings = {} as AgentSettings;
const construct = () =>
new AgentPolicy(emptyRequestPolicy, emptyPolicyOptions, agentSettings);
construct.should.throw();
});
});
});

Просмотреть файл

@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import { AgentSettings } from "../lib/serviceClient";
import { WebResource } from "../lib/webResource";
import { assert } from "chai";
import { parseHeaders, XhrHttpClient } from "../lib/xhrHttpClient";
import { WebResource } from "../lib/webResource";
describe("XhrHttpClient", function() {
it("parses headers", function() {
@ -38,4 +39,12 @@ describe("XhrHttpClient", function() {
const client = new XhrHttpClient();
assert.throws(() => { client.sendRequest(request); }, Error);
});
it("throws when agent settings are passed", function() {
const request = new WebResource();
request.agentSettings = {} as AgentSettings;
const client = new XhrHttpClient();
assert.throws(() => { client.sendRequest(request); }, Error);
});
});

Просмотреть файл

@ -31,6 +31,7 @@ const config: webpack.Configuration = {
new webpack.NormalModuleReplacementPlugin(/(\.).+util\/xml/, path.resolve(__dirname, "./lib/util/xml.browser.ts")),
new webpack.NormalModuleReplacementPlugin(/(\.).+defaultHttpClient/, path.resolve(__dirname, "./lib/defaultHttpClient.browser.ts")),
new webpack.NormalModuleReplacementPlugin(/(\.).+msRestUserAgentPolicy/, path.resolve(__dirname, "./lib/policies/msRestUserAgentPolicy.browser.ts")),
new webpack.NormalModuleReplacementPlugin(/(\.).+agentPolicy/, path.resolve(__dirname, "./lib/policies/agentPolicy.browser.ts")),
new webpack.NormalModuleReplacementPlugin(/(\.).+proxyPolicy/, path.resolve(__dirname, "./lib/policies/proxyPolicy.browser.ts"))
],
module: {