Skip to content

Commit

Permalink
[core-http] Establish standard PipelineOptions pattern in core-http (#…
Browse files Browse the repository at this point in the history
…5669)

* Extract NewPipelineOptions from keyvault-keys into core-http

* Move keyvault-certificates to new PipelineOptions model

* Move keyvault-secrets to new PipelineOptions model

* Remove unused imports in ServiceClient

* Remove userAgentHeaderName from UserAgentOptions

* Remove the need for min retry interval

* Add RetryMode to RetryOptions

* Add InternalPipelineOptions for configuring internal options

* Narrow KeyVault client constructor options to PipelineOptions type

* Add LoggingOptions to propagate AzureLogger with LogPolicyOptions

* Add requestPolicyFilter to PipelineOptions

* Fix LoggerOptions logger propagation and KeyVault configuration

* Simplify UserAgentOptions handling

* Remove unused pipeline related artifacts in keyvault

* Merge remote-tracking branch 'origin/master' into pr/daviwil/5669

* Revert "Merge remote-tracking branch 'origin/master' into pr/daviwil/5669"

This reverts commit 126f6f5.

* Remove unused pipeline related artifacts in keyvault certificates

* Remove KeepAliveOptions.maxSockets (to be added back in the future)

* Remove unused isPipelineOptions

* Remove unused DefaultLogPolicyOptions

* Rename userAgentPrefix local var

* Alias ProxySettings as ProxyOptions

* Rename PipelineOptions.requestPolicyFilter to updatePipelinePolicies
  • Loading branch information
daviwil authored Oct 22, 2019
1 parent 27bf79b commit 2f973f5
Show file tree
Hide file tree
Showing 19 changed files with 566 additions and 631 deletions.
14 changes: 9 additions & 5 deletions sdk/core/core-http/lib/coreHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,33 @@ export {
ServiceClient,
ServiceClientOptions,
flattenResponse,
ProxySettings
createPipelineFromOptions,
ProxySettings,
ProxyOptions
} from "./serviceClient";
export { PipelineOptions, InternalPipelineOptions } from "./pipelineOptions";
export { QueryCollectionFormat } from "./queryCollectionFormat";
export { Constants } from "./util/constants";
export {
BearerTokenAuthenticationPolicy,
bearerTokenAuthenticationPolicy
} from "./policies/bearerTokenAuthenticationPolicy";
export { logPolicy } from "./policies/logPolicy";
export { LogPolicyOptions, LoggingOptions, logPolicy } from "./policies/logPolicy";
export {
BaseRequestPolicy,
RequestPolicy,
RequestPolicyFactory,
RequestPolicyOptions
} from "./policies/requestPolicy";
export { generateClientRequestIdPolicy } from "./policies/generateClientRequestIdPolicy";
export { exponentialRetryPolicy } from "./policies/exponentialRetryPolicy";
export { exponentialRetryPolicy, RetryOptions, RetryMode } from "./policies/exponentialRetryPolicy";
export { systemErrorRetryPolicy } from "./policies/systemErrorRetryPolicy";
export { throttlingRetryPolicy } from "./policies/throttlingRetryPolicy";
export { getDefaultProxySettings, proxyPolicy } from "./policies/proxyPolicy";
export { redirectPolicy } from "./policies/redirectPolicy";
export { redirectPolicy, RedirectOptions } from "./policies/redirectPolicy";
export { keepAlivePolicy, KeepAliveOptions } from "./policies/keepAlivePolicy";
export { signingPolicy } from "./policies/signingPolicy";
export { userAgentPolicy, getDefaultUserAgentValue } from "./policies/userAgentPolicy";
export { userAgentPolicy, getDefaultUserAgentValue, UserAgentOptions } from "./policies/userAgentPolicy";
export { deserializationPolicy, deserializeResponseBody } from "./policies/deserializationPolicy";
export { tracingPolicy } from "./policies/tracingPolicy";
export {
Expand Down
75 changes: 75 additions & 0 deletions sdk/core/core-http/lib/pipelineOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { HttpClient } from "./httpClient";
import { RetryOptions } from './policies/exponentialRetryPolicy';
import { KeepAliveOptions } from './policies/keepAlivePolicy';
import { RedirectOptions } from './policies/redirectPolicy';
import { ProxyOptions } from './serviceClient';
import { UserAgentOptions } from './policies/userAgentPolicy';
import { DeserializationOptions } from './policies/deserializationPolicy';
import { LoggingOptions } from './policies/logPolicy';
import { RequestPolicyFactory } from './policies/requestPolicy';

/**
* Defines options that are used to configure the HTTP pipeline for
* an SDK client.
*/
export interface PipelineOptions {
/**
* The HttpClient implementation to use for outgoing HTTP requests. Defaults
* to DefaultHttpClient.
*/
httpClient?: HttpClient;

/**
* Options that control how to retry failed requests.
*/
retryOptions?: RetryOptions;

/**
* Options to configure a proxy for outgoing requests.
*/
proxyOptions?: ProxyOptions;

/*
* Options for how HTTP connections should be maintained for future
* requests.
*/
keepAliveOptions?: KeepAliveOptions;

/**
* Options for how redirect responses are handled.
*/
redirectOptions?: RedirectOptions;

/**
* Options for adding user agent details to outgoing requests.
*/
userAgentOptions?: UserAgentOptions;

/**
* A function that accepts the array of RequestPolicyFactory created for
* this PipelineOptions instance and can return modified list of policies.
* This is useful for adding, inserting, or removing policies in special
* case scenarios. If the function does not modify the array of
* RequestPolicyFactory, it must return the original array it was given.
*/
updatePipelinePolicies?: (requestPolicyFactories: RequestPolicyFactory[]) => RequestPolicyFactory[];
}

/**
* Defines options that are used to configure internal options of
* the HTTP pipeline for an SDK client.
*/
export interface InternalPipelineOptions extends PipelineOptions {
/**
* Options to configure API response deserialization.
*/
deserializationOptions?: DeserializationOptions;

/**
* Options to configure request/response logging.
*/
loggingOptions?: LoggingOptions;
}
18 changes: 18 additions & 0 deletions sdk/core/core-http/lib/policies/deserializationPolicy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ import {
RequestPolicyOptions
} from "./requestPolicy";

/**
* Options to configure API response deserialization.
*/
export interface DeserializationOptions {
/**
* Configures the expected content types for the deserialization of
* JSON and XML response bodies.
*/
expectedContentTypes: DeserializationContentTypes;
}

/**
* The content-types that will indicate that an operation response should be deserialized in a
* particular way.
Expand Down Expand Up @@ -51,6 +62,13 @@ export function deserializationPolicy(
export const defaultJsonContentTypes = ["application/json", "text/json", "text/plain"];
export const defaultXmlContentTypes = ["application/xml", "application/atom+xml"];

export const DefaultDeserializationOptions: DeserializationOptions = {
expectedContentTypes: {
json: defaultJsonContentTypes,
xml: defaultXmlContentTypes
}
};

/**
* A RequestPolicy that will deserialize HTTP response bodies and headers as they pass through the
* HTTP pipeline.
Expand Down
55 changes: 43 additions & 12 deletions sdk/core/core-http/lib/policies/exponentialRetryPolicy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export interface RetryError extends Error {
export function exponentialRetryPolicy(
retryCount?: number,
retryInterval?: number,
minRetryInterval?: number,
maxRetryInterval?: number
): RequestPolicyFactory {
return {
Expand All @@ -38,7 +37,6 @@ export function exponentialRetryPolicy(
options,
retryCount,
retryInterval,
minRetryInterval,
maxRetryInterval
);
}
Expand All @@ -48,7 +46,48 @@ export function exponentialRetryPolicy(
const DEFAULT_CLIENT_RETRY_INTERVAL = 1000 * 30;
const DEFAULT_CLIENT_RETRY_COUNT = 3;
const DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 90;
const DEFAULT_CLIENT_MIN_RETRY_INTERVAL = 1000 * 3;

/**
* Describes the Retry Mode type. Currently supporting only Exponential.
* @enum RetryMode
*/
export enum RetryMode {
Exponential
}

/**
* Options that control how to retry failed requests.
*/
export interface RetryOptions {
/**
* The maximum number of retry attempts. Defaults to 3.
*/
maxRetries?: number;

/**
* The amount of delay in milliseconds between retry attempts. Defaults to 30000
* (30 seconds). The delay increases exponentially with each retry up to a maximum
* specified by maxRetryDelayInMs.
*/
retryDelayInMs?: number;

/**
* The maximum delay in milliseconds allowed before retrying an operation. Defaults
* to 90000 (90 seconds).
*/
maxRetryDelayInMs?: number;

/**
* Currently supporting only Exponential mode.
*/
mode?: RetryMode;
}

export const DefaultRetryOptions: RetryOptions = {
maxRetries: DEFAULT_CLIENT_RETRY_COUNT,
retryDelayInMs: DEFAULT_CLIENT_RETRY_INTERVAL,
maxRetryDelayInMs: DEFAULT_CLIENT_MAX_RETRY_INTERVAL
}

/**
* @class
Expand All @@ -63,10 +102,6 @@ export class ExponentialRetryPolicy extends BaseRequestPolicy {
* The client retry interval in milliseconds.
*/
retryInterval: number;
/**
* The minimum retry interval in milliseconds.
*/
minRetryInterval: number;
/**
* The maximum retry interval in milliseconds.
*/
Expand All @@ -86,7 +121,6 @@ export class ExponentialRetryPolicy extends BaseRequestPolicy {
options: RequestPolicyOptions,
retryCount?: number,
retryInterval?: number,
minRetryInterval?: number,
maxRetryInterval?: number
) {
super(nextPolicy, options);
Expand All @@ -95,9 +129,6 @@ export class ExponentialRetryPolicy extends BaseRequestPolicy {
}
this.retryCount = isNumber(retryCount) ? retryCount : DEFAULT_CLIENT_RETRY_COUNT;
this.retryInterval = isNumber(retryInterval) ? retryInterval : DEFAULT_CLIENT_RETRY_INTERVAL;
this.minRetryInterval = isNumber(minRetryInterval)
? minRetryInterval
: DEFAULT_CLIENT_MIN_RETRY_INTERVAL;
this.maxRetryInterval = isNumber(maxRetryInterval)
? maxRetryInterval
: DEFAULT_CLIENT_MAX_RETRY_INTERVAL;
Expand Down Expand Up @@ -181,7 +212,7 @@ function updateRetryData(
incrementDelta *= boundedRandDelta;

retryData.retryInterval = Math.min(
policy.minRetryInterval + incrementDelta,
incrementDelta,
policy.maxRetryInterval
);

Expand Down
62 changes: 62 additions & 0 deletions sdk/core/core-http/lib/policies/keepAlivePolicy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { BaseRequestPolicy, RequestPolicy, RequestPolicyOptions } from './requestPolicy';
import { WebResource } from '../webResource';
import { HttpOperationResponse } from '../httpOperationResponse';

/**
* Options for how HTTP connections should be maintained for future
* requests.
*/
export interface KeepAliveOptions {
/*
* When true, connections will be kept alive for multiple requests.
* Defaults to true.
*/
enable: boolean;
}

export const DefaultKeepAliveOptions: KeepAliveOptions = {
enable: true
}

export function keepAlivePolicy(keepAliveOptions?: KeepAliveOptions) {
return {
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => {
return new KeepAlivePolicy(nextPolicy, options, keepAliveOptions || DefaultKeepAliveOptions);
}
};
}

/**
* KeepAlivePolicy is a policy used to control keep alive settings for every request.
*/
export class KeepAlivePolicy extends BaseRequestPolicy {
/**
* Creates an instance of KeepAlivePolicy.
*
* @param {RequestPolicy} nextPolicy
* @param {RequestPolicyOptions} options
* @param {KeepAliveOptions} [keepAliveOptions]
*/
constructor(
nextPolicy: RequestPolicy,
options: RequestPolicyOptions,
private readonly keepAliveOptions: KeepAliveOptions
) {
super(nextPolicy, options);
}

/**
* Sends out request.
*
* @param {WebResource} request
* @returns {Promise<HttpOperationResponse>}
* @memberof KeepAlivePolicy
*/
public async sendRequest(request: WebResource): Promise<HttpOperationResponse> {
request.keepAlive = this.keepAliveOptions.enable;
return this._nextPolicy.sendRequest(request);
}
}
24 changes: 24 additions & 0 deletions sdk/core/core-http/lib/policies/logPolicy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
RequestPolicyFactory,
RequestPolicyOptions
} from "./requestPolicy";
import { Debugger } from "@azure/logger";
import { logger as coreLogger, logger } from "../log";

export interface LogPolicyOptions {
Expand All @@ -28,6 +29,21 @@ export interface LogPolicyOptions {
allowedQueryParameters?: string[];
}

/**
* Options to configure request/response logging.
*/
export interface LoggingOptions {
/**
* The Debugger (logger) instance to use for writing pipeline logs.
*/
logger?: Debugger,

/**
* Options to pass to the logPolicy factory.
*/
logPolicyOptions?: LogPolicyOptions
}

const RedactedString = "REDACTED";

const defaultAllowedHeaderNames = [
Expand Down Expand Up @@ -60,6 +76,14 @@ const defaultAllowedQueryParameters: string[] = [
"api-version"
];

export const DefaultLoggingOptions: LoggingOptions = {
logger: undefined,
logPolicyOptions: {
allowedHeaderNames: [], // These are empty lists because they are additive to
allowedQueryParameters: [] // the real defaultAllowed[HeaderNames|QueryParameters].
}
}

export function logPolicy(
logger: any = coreLogger.info.bind(coreLogger),
logOptions: LogPolicyOptions = {}
Expand Down
21 changes: 21 additions & 0 deletions sdk/core/core-http/lib/policies/redirectPolicy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@ import {
RequestPolicyOptions
} from "./requestPolicy";

/**
* Options for how redirect responses are handled.
*/
export interface RedirectOptions {
/*
* When true, redirect responses are followed. Defaults to true.
*/
handleRedirects: boolean;

/*
* The maximum number of times the redirect URL will be tried before
* failing. Defaults to 20.
*/
maxRetries?: number;
}

export const DefaultRedirectOptions: RedirectOptions = {
handleRedirects: true,
maxRetries: 20
}

export function redirectPolicy(maximumRetries = 20): RequestPolicyFactory {
return {
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptions) => {
Expand Down
Loading

0 comments on commit 2f973f5

Please sign in to comment.