From 744a9f929990090087feba7b0c825a81b8c5340c Mon Sep 17 00:00:00 2001 From: Jeremy Meng Date: Thu, 16 Jan 2025 14:16:41 -0800 Subject: [PATCH 1/2] [core] Add optional `agent` option to WebResourceLike and add plubming to pass it to core-rest-pipeline. Also add agent and tlsSettings to PipelineRequestOptions. --- .../review/core-http-compat.api.md | 10 +++++ sdk/core/core-http-compat/src/index.ts | 1 + sdk/core/core-http-compat/src/util.ts | 38 +++++++++++++++++++ .../review/core-rest-pipeline.api.md | 2 + .../core-rest-pipeline/src/pipelineRequest.ts | 18 ++++++++- 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/sdk/core/core-http-compat/review/core-http-compat.api.md b/sdk/core/core-http-compat/review/core-http-compat.api.md index d7e2511dad3e..8a2b9ee111f6 100644 --- a/sdk/core/core-http-compat/review/core-http-compat.api.md +++ b/sdk/core/core-http-compat/review/core-http-compat.api.md @@ -17,6 +17,15 @@ import type { ProxySettings } from '@azure/core-rest-pipeline'; import { ServiceClient } from '@azure/core-client'; import type { ServiceClientOptions } from '@azure/core-client'; +// @public +export interface Agent { + destroy(): void; + maxFreeSockets: number; + maxSockets: number; + requests: unknown; + sockets: unknown; +} + // @public export interface CompatResponse extends Omit { headers: HttpHeadersLike; @@ -134,6 +143,7 @@ export type TransferProgressEvent = { // @public export interface WebResourceLike { abortSignal?: AbortSignalLike; + agent?: Agent; body?: any; clone(): WebResourceLike; decompressResponse?: boolean; diff --git a/sdk/core/core-http-compat/src/index.ts b/sdk/core/core-http-compat/src/index.ts index 3eb742db0165..93879b80a08f 100644 --- a/sdk/core/core-http-compat/src/index.ts +++ b/sdk/core/core-http-compat/src/index.ts @@ -26,6 +26,7 @@ export { RedirectOptions } from "./policies/redirectOptions.js"; export { disableKeepAlivePolicyName } from "./policies/disableKeepAlivePolicy.js"; export { convertHttpClient } from "./httpClientAdapter.js"; export { + Agent, WebResourceLike, HttpHeadersLike, RawHttpHeaders, diff --git a/sdk/core/core-http-compat/src/util.ts b/sdk/core/core-http-compat/src/util.ts index 23bbbea80286..df0ce398259a 100644 --- a/sdk/core/core-http-compat/src/util.ts +++ b/sdk/core/core-http-compat/src/util.ts @@ -47,6 +47,7 @@ export function toPipelineRequest( onUploadProgress: webResource.onUploadProgress, proxySettings: webResource.proxySettings, streamResponseStatusCodes: webResource.streamResponseStatusCodes, + agent: webResource.agent, }); if (options.originalRequest) { (newRequest as PipelineRequestWithOriginal)[originalClientRequestSymbol] = @@ -76,6 +77,7 @@ export function toWebResourceLike( onUploadProgress: request.onUploadProgress, proxySettings: request.proxySettings, streamResponseStatusCodes: request.streamResponseStatusCodes, + agent: request.agent, clone(): WebResourceLike { throw new Error("Cannot clone a non-proxied WebResourceLike"); }, @@ -361,6 +363,34 @@ export class HttpHeaders implements HttpHeadersLike { } } +/** + * An interface compatible with NodeJS's `http.Agent`. + * We want to avoid publicly re-exporting the actual interface, + * since it might vary across runtime versions. + */ +export interface Agent { + /** + * Destroy any sockets that are currently in use by the agent. + */ + destroy(): void; + /** + * For agents with keepAlive enabled, this sets the maximum number of sockets that will be left open in the free state. + */ + maxFreeSockets: number; + /** + * Determines how many concurrent sockets the agent can have open per origin. + */ + maxSockets: number; + /** + * An object which contains queues of requests that have not yet been assigned to sockets. + */ + requests: unknown; + /** + * An object which contains arrays of sockets currently in use by the agent. + */ + sockets: unknown; +} + /** * A description of a HTTP request to be made to a remote server. */ @@ -437,6 +467,14 @@ export interface WebResourceLike { /** Callback which fires upon download progress. */ onDownloadProgress?: (progress: TransferProgressEvent) => void; + /** + * NODEJS ONLY + * + * A Node-only option to provide a custom `http.Agent`/`https.Agent`. + * Does nothing when running in the browser. + */ + agent?: Agent; + /** * Clone this request object. */ diff --git a/sdk/core/core-rest-pipeline/review/core-rest-pipeline.api.md b/sdk/core/core-rest-pipeline/review/core-rest-pipeline.api.md index a8784c0cea6e..982a982bc8f8 100644 --- a/sdk/core/core-rest-pipeline/review/core-rest-pipeline.api.md +++ b/sdk/core/core-rest-pipeline/review/core-rest-pipeline.api.md @@ -283,6 +283,7 @@ export interface PipelineRequest { // @public export interface PipelineRequestOptions { abortSignal?: AbortSignalLike; + agent?: Agent; allowInsecureConnection?: boolean; body?: RequestBodyType; disableKeepAlive?: boolean; @@ -297,6 +298,7 @@ export interface PipelineRequestOptions { requestId?: string; streamResponseStatusCodes?: Set; timeout?: number; + tlsSettings?: TlsSettings; tracingOptions?: OperationTracingOptions; url: string; withCredentials?: boolean; diff --git a/sdk/core/core-rest-pipeline/src/pipelineRequest.ts b/sdk/core/core-rest-pipeline/src/pipelineRequest.ts index 8d1648ddb031..6783f9eccdaf 100644 --- a/sdk/core/core-rest-pipeline/src/pipelineRequest.ts +++ b/sdk/core/core-rest-pipeline/src/pipelineRequest.ts @@ -2,12 +2,14 @@ // Licensed under the MIT License. import type { + Agent, FormDataMap, HttpHeaders, MultipartRequestBody, PipelineRequest, ProxySettings, RequestBodyType, + TlsSettings, TransferProgressEvent, } from "./interfaces.js"; import { createHttpHeaders } from "./httpHeaders.js"; @@ -74,6 +76,14 @@ export interface PipelineRequestOptions { */ streamResponseStatusCodes?: Set; + /** + * NODEJS ONLY + * + * A Node-only option to provide a custom `http.Agent`/`https.Agent`. + * Does nothing when running in the browser. + */ + agent?: Agent; + /** * BROWSER ONLY * @@ -85,6 +95,9 @@ export interface PipelineRequestOptions { */ enableBrowserStreams?: boolean; + /** Settings for configuring TLS authentication */ + tlsSettings?: TlsSettings; + /** * Proxy configuration. */ @@ -128,7 +141,6 @@ class PipelineRequestImpl implements PipelineRequest { public formData?: FormDataMap; public streamResponseStatusCodes?: Set; public enableBrowserStreams: boolean; - public proxySettings?: ProxySettings; public disableKeepAlive: boolean; public abortSignal?: AbortSignalLike; @@ -137,6 +149,8 @@ class PipelineRequestImpl implements PipelineRequest { public allowInsecureConnection?: boolean; public onUploadProgress?: (progress: TransferProgressEvent) => void; public onDownloadProgress?: (progress: TransferProgressEvent) => void; + public agent?: Agent; + public tlsSettings?: TlsSettings; constructor(options: PipelineRequestOptions) { this.url = options.url; @@ -157,6 +171,8 @@ class PipelineRequestImpl implements PipelineRequest { this.requestId = options.requestId || randomUUID(); this.allowInsecureConnection = options.allowInsecureConnection ?? false; this.enableBrowserStreams = options.enableBrowserStreams ?? false; + this.agent = options.agent; + this.tlsSettings = options.tlsSettings; } } From 70c1e53de4584c823a726fcd6c3365c001c2307a Mon Sep 17 00:00:00 2001 From: Jeremy Meng Date: Thu, 16 Jan 2025 17:45:34 -0800 Subject: [PATCH 2/2] pass "agent" through proxy --- sdk/core/core-http-compat/src/util.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/core/core-http-compat/src/util.ts b/sdk/core/core-http-compat/src/util.ts index df0ce398259a..b15afe984293 100644 --- a/sdk/core/core-http-compat/src/util.ts +++ b/sdk/core/core-http-compat/src/util.ts @@ -121,6 +121,7 @@ export function toWebResourceLike( "onUploadProgress", "proxySettings", "streamResponseStatusCodes", + "agent", ]; if (typeof prop === "string" && passThroughProps.includes(prop)) {