зеркало из https://github.com/Azure/ms-rest-js.git
Add Prettier and format code (#415)
* Add prettier and configs * npm run format * Fix tslint error - Prettier broke lines but the // tslint:disable-next-line comments remains in the old position. They should be before the applicable lines. - Enforce `SwitchCase` indentation level of 1 to match prettier behavior.
This commit is contained in:
Родитель
43a03bc758
Коммит
4208098ab1
|
@ -0,0 +1,2 @@
|
|||
typings/
|
||||
**/*.d.ts
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"arrowParens": "always",
|
||||
"bracketSpacing": true,
|
||||
"endOfLine": "lf",
|
||||
"printWidth": 100,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"tabWidth": 2
|
||||
}
|
|
@ -1,4 +1,11 @@
|
|||
import { findPackageJsonFileSync, PackageJson, readPackageJsonFileSync, getParentFolderPath, joinPath, fileExistsSync } from "@ts-common/azure-js-dev-tools";
|
||||
import {
|
||||
findPackageJsonFileSync,
|
||||
PackageJson,
|
||||
readPackageJsonFileSync,
|
||||
getParentFolderPath,
|
||||
joinPath,
|
||||
fileExistsSync,
|
||||
} from "@ts-common/azure-js-dev-tools";
|
||||
import { readFileSync } from "fs";
|
||||
import { Logger, getDefaultLogger } from "@azure/logger-js";
|
||||
|
||||
|
@ -21,20 +28,29 @@ export function checkConstantsVersion(): number {
|
|||
error(`Could not find a version property in ${packageJsonFilePath}.`);
|
||||
} else {
|
||||
const repositoryRootFolderPath: string = getParentFolderPath(packageJsonFilePath);
|
||||
const constantsTsFilePath: string = joinPath(repositoryRootFolderPath, "lib/util/constants.ts");
|
||||
const constantsTsFilePath: string = joinPath(
|
||||
repositoryRootFolderPath,
|
||||
"lib/util/constants.ts"
|
||||
);
|
||||
if (!fileExistsSync(constantsTsFilePath)) {
|
||||
error(`${constantsTsFilePath} doesn't exist anymore. Where'd it go?`);
|
||||
} else {
|
||||
const constantsTsFileContents: string = readFileSync(constantsTsFilePath, { encoding: "utf8" });
|
||||
const constantsTsFileContents: string = readFileSync(constantsTsFilePath, {
|
||||
encoding: "utf8",
|
||||
});
|
||||
const regularExpressionString = `msRestVersion: "(.*)"`;
|
||||
const regularExpression = new RegExp(regularExpressionString);
|
||||
const match: RegExpMatchArray | null = constantsTsFileContents.match(regularExpression);
|
||||
if (!match) {
|
||||
error(`${constantsTsFilePath} doesn't contain a match for ${regularExpressionString}.`);
|
||||
} else if (match[1] !== packageVersion) {
|
||||
error(`Expected ${constantsTsFilePath} to contain an msRestVersion property with the value "${packageVersion}", but it was "${match[1]}" instead.`);
|
||||
error(
|
||||
`Expected ${constantsTsFilePath} to contain an msRestVersion property with the value "${packageVersion}", but it was "${match[1]}" instead.`
|
||||
);
|
||||
} else {
|
||||
logger.logInfo(`${constantsTsFilePath} contained the correct value for msRestVersion ("${packageVersion}").`);
|
||||
logger.logInfo(
|
||||
`${constantsTsFilePath} contained the correct value for msRestVersion ("${packageVersion}").`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,6 @@ import { checkConstantsVersion } from "./checkConstantsVersion";
|
|||
checkEverything({
|
||||
additionalChecks: {
|
||||
name: "Constants.ts Version",
|
||||
check: checkConstantsVersion
|
||||
}
|
||||
check: checkConstantsVersion,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import path from "path";
|
||||
import { run, RunResult, RunOptions, Command, commandToString } from "@ts-common/azure-js-dev-tools";
|
||||
import {
|
||||
run,
|
||||
RunResult,
|
||||
RunOptions,
|
||||
Command,
|
||||
commandToString,
|
||||
} from "@ts-common/azure-js-dev-tools";
|
||||
|
||||
async function execAndLog(executable: string, args?: string[], options?: RunOptions): Promise<any> {
|
||||
const command: Command = {
|
||||
|
@ -16,7 +22,11 @@ async function execAndLog(executable: string, args?: string[], options?: RunOpti
|
|||
showResult: true,
|
||||
});
|
||||
|
||||
console.log(`\nResult of "${commandToString(command)}" [Exit code: ${result.exitCode}]:\n` + result.stdout + "\n");
|
||||
console.log(
|
||||
`\nResult of "${commandToString(command)}" [Exit code: ${result.exitCode}]:\n` +
|
||||
result.stdout +
|
||||
"\n"
|
||||
);
|
||||
|
||||
if (result.exitCode) {
|
||||
console.error(`Error while running "${commandToString(command)}": ${result.error}`);
|
||||
|
@ -29,19 +39,21 @@ async function execAndLog(executable: string, args?: string[], options?: RunOpti
|
|||
async function cloneRepository(projectName: string, projectDirectory: string) {
|
||||
const gitHubUrl = `https://github.com/Azure/${projectName}.git`;
|
||||
await execAndLog(`git`, ["clone", gitHubUrl, projectDirectory, "--recursive"]);
|
||||
await execAndLog(`npm`, [ "install" ], { executionFolderPath: projectDirectory });
|
||||
await execAndLog(`npm`, ["install"], { executionFolderPath: projectDirectory });
|
||||
}
|
||||
|
||||
async function buildAndTest(projectDirectory: string) {
|
||||
await execAndLog(`npm`, [ "run", "build" ], { executionFolderPath: projectDirectory });
|
||||
await execAndLog(`npm`, [ "run", "test" ], { executionFolderPath: projectDirectory });
|
||||
await execAndLog(`npm`, ["run", "build"], { executionFolderPath: projectDirectory });
|
||||
await execAndLog(`npm`, ["run", "test"], { executionFolderPath: projectDirectory });
|
||||
}
|
||||
|
||||
async function cloneAndRunTest(msRestJsDirectory: string, projectName: string) {
|
||||
const projectDirectory = path.join(msRestJsDirectory, `../.tmp/${projectName}`);
|
||||
await cloneRepository(projectName, projectDirectory);
|
||||
|
||||
await execAndLog(`npm`, [ "install", msRestJsDirectory ], { executionFolderPath: projectDirectory });
|
||||
await execAndLog(`npm`, ["install", msRestJsDirectory], {
|
||||
executionFolderPath: projectDirectory,
|
||||
});
|
||||
|
||||
const additionalCommands: string[] = process.argv.slice(3);
|
||||
for (const command of additionalCommands) {
|
||||
|
@ -49,7 +61,7 @@ async function cloneAndRunTest(msRestJsDirectory: string, projectName: string) {
|
|||
}
|
||||
|
||||
await buildAndTest(projectDirectory);
|
||||
await execAndLog(`rm`, [ "-rf", projectDirectory ]);
|
||||
await execAndLog(`rm`, ["-rf", projectDirectory]);
|
||||
}
|
||||
|
||||
(async () => {
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
const defaults = {
|
||||
port: 9876
|
||||
port: 9876,
|
||||
};
|
||||
|
||||
module.exports = function (config: any) {
|
||||
config.set({
|
||||
plugins: [
|
||||
"karma-mocha",
|
||||
"karma-chrome-launcher",
|
||||
"karma-firefox-launcher"
|
||||
],
|
||||
plugins: ["karma-mocha", "karma-chrome-launcher", "karma-firefox-launcher"],
|
||||
|
||||
// frameworks to use
|
||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||
|
@ -19,7 +15,7 @@ module.exports = function (config: any) {
|
|||
{ pattern: "dist/msRest.browser.js" },
|
||||
{ pattern: "dist/msRest.browser.js.map", included: false },
|
||||
{ pattern: "test/msRest.browser.test.js" },
|
||||
{ pattern: "test/msRest.browser.test.js.map", included: false }
|
||||
{ pattern: "test/msRest.browser.test.js.map", included: false },
|
||||
],
|
||||
|
||||
// test results reporter to use
|
||||
|
@ -52,16 +48,20 @@ module.exports = function (config: any) {
|
|||
customLaunchers: {
|
||||
ChromeNoSecurity: {
|
||||
base: "ChromeHeadless",
|
||||
flags: ["--disable-web-security"]
|
||||
flags: ["--disable-web-security"],
|
||||
},
|
||||
ChromeDebugging: {
|
||||
base: "Chrome",
|
||||
flags: [`http://localhost:${defaults.port}/debug.html`, "--auto-open-devtools-for-tabs", "--disable-web-security"]
|
||||
flags: [
|
||||
`http://localhost:${defaults.port}/debug.html`,
|
||||
"--auto-open-devtools-for-tabs",
|
||||
"--disable-web-security",
|
||||
],
|
||||
},
|
||||
FirefoxDebugging: {
|
||||
base: "Firefox",
|
||||
flags: ["-url", `http://localhost:${defaults.port}/debug.html`, "-devtools"]
|
||||
}
|
||||
flags: ["-url", `http://localhost:${defaults.port}/debug.html`, "-devtools"],
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -39,7 +39,9 @@ export class ApiKeyCredentials implements ServiceClientCredentials {
|
|||
*/
|
||||
constructor(options: ApiKeyCredentialOptions) {
|
||||
if (!options || (options && !options.inHeader && !options.inQuery)) {
|
||||
throw new Error(`options cannot be null or undefined. Either "inHeader" or "inQuery" property of the options object needs to be provided.`);
|
||||
throw new Error(
|
||||
`options cannot be null or undefined. Either "inHeader" or "inQuery" property of the options object needs to be provided.`
|
||||
);
|
||||
}
|
||||
this.inHeader = options.inHeader;
|
||||
this.inQuery = options.inQuery;
|
||||
|
@ -53,7 +55,9 @@ export class ApiKeyCredentials implements ServiceClientCredentials {
|
|||
*/
|
||||
signRequest(webResource: WebResourceLike): Promise<WebResourceLike> {
|
||||
if (!webResource) {
|
||||
return Promise.reject(new Error(`webResource cannot be null or undefined and must be of type "object".`));
|
||||
return Promise.reject(
|
||||
new Error(`webResource cannot be null or undefined and must be of type "object".`)
|
||||
);
|
||||
}
|
||||
|
||||
if (this.inHeader) {
|
||||
|
|
|
@ -14,8 +14,7 @@ const DEFAULT_AUTHORIZATION_SCHEME = "Bearer";
|
|||
* This class provides a simple extension to use {@link TokenCredential} from `@azure/identity` library to
|
||||
* use with legacy Azure SDKs that accept {@link ServiceClientCredentials} family of credentials for authentication.
|
||||
*/
|
||||
export class AzureIdentityCredentialAdapter
|
||||
implements ServiceClientCredentials {
|
||||
export class AzureIdentityCredentialAdapter implements ServiceClientCredentials {
|
||||
private azureTokenCredential: TokenCredential;
|
||||
private scopes: string | string[];
|
||||
constructor(
|
||||
|
|
|
@ -22,7 +22,11 @@ export class BasicAuthenticationCredentials implements ServiceClientCredentials
|
|||
* @param {string} password Password.
|
||||
* @param {string} [authorizationScheme] The authorization scheme.
|
||||
*/
|
||||
constructor(userName: string, password: string, authorizationScheme: string = DEFAULT_AUTHORIZATION_SCHEME) {
|
||||
constructor(
|
||||
userName: string,
|
||||
password: string,
|
||||
authorizationScheme: string = DEFAULT_AUTHORIZATION_SCHEME
|
||||
) {
|
||||
if (userName === null || userName === undefined || typeof userName.valueOf() !== "string") {
|
||||
throw new Error("userName cannot be null or undefined and must be of type string.");
|
||||
}
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
import { ApiKeyCredentials, ApiKeyCredentialOptions } from "./apiKeyCredentials";
|
||||
|
||||
export class DomainCredentials extends ApiKeyCredentials {
|
||||
/**
|
||||
* Creates a new EventGrid DomainCredentials object.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} domainKey The EventGrid domain key
|
||||
*/
|
||||
/**
|
||||
* Creates a new EventGrid DomainCredentials object.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} domainKey The EventGrid domain key
|
||||
*/
|
||||
constructor(domainKey: string) {
|
||||
if (!domainKey || (domainKey && typeof domainKey !== "string")) {
|
||||
throw new Error("domainKey cannot be null or undefined and must be of type string.");
|
||||
}
|
||||
const options: ApiKeyCredentialOptions = {
|
||||
inHeader: {
|
||||
"aeg-sas-key": domainKey
|
||||
}
|
||||
"aeg-sas-key": domainKey,
|
||||
},
|
||||
};
|
||||
super(options);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,10 @@ export class TokenCredentials implements ServiceClientCredentials {
|
|||
*/
|
||||
signRequest(webResource: WebResourceLike) {
|
||||
if (!webResource.headers) webResource.headers = new HttpHeaders();
|
||||
webResource.headers.set(HeaderConstants.AUTHORIZATION, `${this.authorizationScheme} ${this.token}`);
|
||||
webResource.headers.set(
|
||||
HeaderConstants.AUTHORIZATION,
|
||||
`${this.authorizationScheme} ${this.token}`
|
||||
);
|
||||
return Promise.resolve(webResource);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
import { ApiKeyCredentials, ApiKeyCredentialOptions } from "./apiKeyCredentials";
|
||||
|
||||
export class TopicCredentials extends ApiKeyCredentials {
|
||||
/**
|
||||
* Creates a new EventGrid TopicCredentials object.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} topicKey The EventGrid topic key
|
||||
*/
|
||||
/**
|
||||
* Creates a new EventGrid TopicCredentials object.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} topicKey The EventGrid topic key
|
||||
*/
|
||||
constructor(topicKey: string) {
|
||||
if (!topicKey || (topicKey && typeof topicKey !== "string")) {
|
||||
throw new Error("topicKey cannot be null or undefined and must be of type string.");
|
||||
}
|
||||
const options: ApiKeyCredentialOptions = {
|
||||
inHeader: {
|
||||
"aeg-sas-key": topicKey
|
||||
}
|
||||
"aeg-sas-key": topicKey,
|
||||
},
|
||||
};
|
||||
super(options);
|
||||
}
|
||||
|
|
|
@ -20,13 +20,20 @@ interface FetchError extends Error {
|
|||
export abstract class FetchHttpClient implements HttpClient {
|
||||
async sendRequest(httpRequest: WebResourceLike): Promise<HttpOperationResponse> {
|
||||
if (!httpRequest && typeof httpRequest !== "object") {
|
||||
throw new Error("'httpRequest' (WebResource) cannot be null or undefined and must be of type object.");
|
||||
throw new Error(
|
||||
"'httpRequest' (WebResource) cannot be null or undefined and must be of type object."
|
||||
);
|
||||
}
|
||||
|
||||
const abortController = new AbortController();
|
||||
if (httpRequest.abortSignal) {
|
||||
if (httpRequest.abortSignal.aborted) {
|
||||
throw new RestError("The request was aborted", RestError.REQUEST_ABORTED_ERROR, undefined, httpRequest);
|
||||
throw new RestError(
|
||||
"The request was aborted",
|
||||
RestError.REQUEST_ABORTED_ERROR,
|
||||
undefined,
|
||||
httpRequest
|
||||
);
|
||||
}
|
||||
|
||||
httpRequest.abortSignal.addEventListener("abort", (event: Event) => {
|
||||
|
@ -46,7 +53,7 @@ export abstract class FetchHttpClient implements HttpClient {
|
|||
const formData: any = httpRequest.formData;
|
||||
const requestForm = new FormData();
|
||||
const appendFormValue = (key: string, value: any) => {
|
||||
// value function probably returns a stream so we can provide a fresh stream on each retry
|
||||
// value function probably returns a stream so we can provide a fresh stream on each retry
|
||||
if (typeof value === "function") {
|
||||
value = value();
|
||||
}
|
||||
|
@ -72,7 +79,10 @@ export abstract class FetchHttpClient implements HttpClient {
|
|||
const contentType = httpRequest.headers.get("Content-Type");
|
||||
if (contentType && contentType.indexOf("multipart/form-data") !== -1) {
|
||||
if (typeof requestForm.getBoundary === "function") {
|
||||
httpRequest.headers.set("Content-Type", `multipart/form-data; boundary=${requestForm.getBoundary()}`);
|
||||
httpRequest.headers.set(
|
||||
"Content-Type",
|
||||
`multipart/form-data; boundary=${requestForm.getBoundary()}`
|
||||
);
|
||||
} else {
|
||||
// browser will automatically apply a suitable content-type header
|
||||
httpRequest.headers.remove("Content-Type");
|
||||
|
@ -81,8 +91,10 @@ export abstract class FetchHttpClient implements HttpClient {
|
|||
}
|
||||
|
||||
let body = httpRequest.body
|
||||
? (typeof httpRequest.body === "function" ? httpRequest.body() : httpRequest.body)
|
||||
: undefined;
|
||||
? typeof httpRequest.body === "function"
|
||||
? httpRequest.body()
|
||||
: httpRequest.body
|
||||
: undefined;
|
||||
if (httpRequest.onUploadProgress && httpRequest.body) {
|
||||
let loadedBytes = 0;
|
||||
const uploadReportStream = new Transform({
|
||||
|
@ -90,7 +102,7 @@ export abstract class FetchHttpClient implements HttpClient {
|
|||
loadedBytes += chunk.length;
|
||||
httpRequest.onUploadProgress!({ loadedBytes });
|
||||
callback(undefined, chunk);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (isReadableStream(body)) {
|
||||
|
@ -102,14 +114,16 @@ export abstract class FetchHttpClient implements HttpClient {
|
|||
body = uploadReportStream;
|
||||
}
|
||||
|
||||
const platformSpecificRequestInit: Partial<RequestInit> = await this.prepareRequest(httpRequest);
|
||||
const platformSpecificRequestInit: Partial<RequestInit> = await this.prepareRequest(
|
||||
httpRequest
|
||||
);
|
||||
|
||||
const requestInit: RequestInit = {
|
||||
body: body,
|
||||
headers: httpRequest.headers.rawHeaders(),
|
||||
method: httpRequest.method,
|
||||
signal: abortController.signal,
|
||||
...platformSpecificRequestInit
|
||||
...platformSpecificRequestInit,
|
||||
};
|
||||
|
||||
try {
|
||||
|
@ -120,12 +134,14 @@ export abstract class FetchHttpClient implements HttpClient {
|
|||
headers: headers,
|
||||
request: httpRequest,
|
||||
status: response.status,
|
||||
readableStreamBody: httpRequest.streamResponseBody ? (response.body as unknown) as NodeJS.ReadableStream : undefined,
|
||||
readableStreamBody: httpRequest.streamResponseBody
|
||||
? ((response.body as unknown) as NodeJS.ReadableStream)
|
||||
: undefined,
|
||||
bodyAsText: !httpRequest.streamResponseBody ? await response.text() : undefined,
|
||||
};
|
||||
|
||||
const onDownloadProgress = httpRequest.onDownloadProgress;
|
||||
if (onDownloadProgress) {
|
||||
if (onDownloadProgress) {
|
||||
const responseBody: ReadableStream<Uint8Array> | undefined = response.body || undefined;
|
||||
|
||||
if (isReadableStream(responseBody)) {
|
||||
|
@ -135,7 +151,7 @@ export abstract class FetchHttpClient implements HttpClient {
|
|||
loadedBytes += chunk.length;
|
||||
onDownloadProgress({ loadedBytes });
|
||||
callback(undefined, chunk);
|
||||
}
|
||||
},
|
||||
});
|
||||
responseBody.pipe(downloadReportStream);
|
||||
operationResponse.readableStreamBody = downloadReportStream;
|
||||
|
@ -154,9 +170,19 @@ export abstract class FetchHttpClient implements HttpClient {
|
|||
} catch (error) {
|
||||
const fetchError: FetchError = error;
|
||||
if (fetchError.code === "ENOTFOUND") {
|
||||
throw new RestError(fetchError.message, RestError.REQUEST_SEND_ERROR, undefined, httpRequest);
|
||||
throw new RestError(
|
||||
fetchError.message,
|
||||
RestError.REQUEST_SEND_ERROR,
|
||||
undefined,
|
||||
httpRequest
|
||||
);
|
||||
} else if (fetchError.type === "aborted") {
|
||||
throw new RestError("The request was aborted", RestError.REQUEST_ABORTED_ERROR, undefined, httpRequest);
|
||||
throw new RestError(
|
||||
"The request was aborted",
|
||||
RestError.REQUEST_ABORTED_ERROR,
|
||||
undefined,
|
||||
httpRequest
|
||||
);
|
||||
}
|
||||
|
||||
throw fetchError;
|
||||
|
|
|
@ -6,5 +6,4 @@ import { RequestPolicy } from "./policies/requestPolicy";
|
|||
/**
|
||||
* An interface that can send HttpRequests and receive promised HttpResponses.
|
||||
*/
|
||||
export interface HttpClient extends RequestPolicy {
|
||||
}
|
||||
export interface HttpClient extends RequestPolicy {}
|
||||
|
|
|
@ -126,7 +126,10 @@ export class HttpHeaders {
|
|||
* @param headerValue The value of the header to set.
|
||||
*/
|
||||
public set(headerName: string, headerValue: string | number): void {
|
||||
this._headersMap[getHeaderKey(headerName)] = { name: headerName, value: headerValue.toString() };
|
||||
this._headersMap[getHeaderKey(headerName)] = {
|
||||
name: headerName,
|
||||
value: headerValue.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,5 +23,5 @@ export enum HttpPipelineLogLevel {
|
|||
/**
|
||||
* An information log.
|
||||
*/
|
||||
INFO
|
||||
INFO,
|
||||
}
|
|
@ -29,8 +29,7 @@ export class ConsoleHttpPipelineLogger implements HttpPipelineLogger {
|
|||
* Create a new ConsoleHttpPipelineLogger.
|
||||
* @param minimumLogLevel The log level threshold for what logs will be logged.
|
||||
*/
|
||||
constructor(public minimumLogLevel: HttpPipelineLogLevel) {
|
||||
}
|
||||
constructor(public minimumLogLevel: HttpPipelineLogLevel) {}
|
||||
|
||||
/**
|
||||
* Log the provided message.
|
||||
|
@ -40,17 +39,17 @@ export class ConsoleHttpPipelineLogger implements HttpPipelineLogger {
|
|||
log(logLevel: HttpPipelineLogLevel, message: string): void {
|
||||
const logMessage = `${HttpPipelineLogLevel[logLevel]}: ${message}`;
|
||||
switch (logLevel) {
|
||||
case HttpPipelineLogLevel.ERROR:
|
||||
console.error(logMessage);
|
||||
break;
|
||||
case HttpPipelineLogLevel.ERROR:
|
||||
console.error(logMessage);
|
||||
break;
|
||||
|
||||
case HttpPipelineLogLevel.WARNING:
|
||||
console.warn(logMessage);
|
||||
break;
|
||||
case HttpPipelineLogLevel.WARNING:
|
||||
console.warn(logMessage);
|
||||
break;
|
||||
|
||||
case HttpPipelineLogLevel.INFO:
|
||||
console.log(logMessage);
|
||||
break;
|
||||
case HttpPipelineLogLevel.INFO:
|
||||
console.log(logMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,17 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
export { WebResource, WebResourceLike, HttpRequestBody, RequestPrepareOptions, HttpMethods, ParameterValue, RequestOptionsBase, TransferProgressEvent, AbortSignalLike } from "./webResource";
|
||||
export {
|
||||
WebResource,
|
||||
WebResourceLike,
|
||||
HttpRequestBody,
|
||||
RequestPrepareOptions,
|
||||
HttpMethods,
|
||||
ParameterValue,
|
||||
RequestOptionsBase,
|
||||
TransferProgressEvent,
|
||||
AbortSignalLike,
|
||||
} from "./webResource";
|
||||
export { DefaultHttpClient } from "./defaultHttpClient";
|
||||
export { HttpClient } from "./httpClient";
|
||||
export { HttpHeaders, HttpHeadersLike } from "./httpHeaders";
|
||||
|
@ -10,14 +20,24 @@ export { HttpPipelineLogger } from "./httpPipelineLogger";
|
|||
export { HttpPipelineLogLevel } from "./httpPipelineLogLevel";
|
||||
export { RestError } from "./restError";
|
||||
export { OperationArguments } from "./operationArguments";
|
||||
export { OperationParameter, OperationQueryParameter, OperationURLParameter } from "./operationParameter";
|
||||
export {
|
||||
OperationParameter,
|
||||
OperationQueryParameter,
|
||||
OperationURLParameter,
|
||||
} from "./operationParameter";
|
||||
export { OperationResponse } from "./operationResponse";
|
||||
export { OperationSpec } from "./operationSpec";
|
||||
export { ServiceClient, ServiceClientOptions, flattenResponse } from "./serviceClient";
|
||||
export { QueryCollectionFormat } from "./queryCollectionFormat";
|
||||
export { Constants } from "./util/constants";
|
||||
export { logPolicy } from "./policies/logPolicy";
|
||||
export { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptions, RequestPolicyOptionsLike } from "./policies/requestPolicy";
|
||||
export {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptions,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./policies/requestPolicy";
|
||||
export { generateClientRequestIdPolicy } from "./policies/generateClientRequestIdPolicy";
|
||||
export { exponentialRetryPolicy } from "./policies/exponentialRetryPolicy";
|
||||
export { systemErrorRetryPolicy } from "./policies/systemErrorRetryPolicy";
|
||||
|
@ -29,16 +49,38 @@ export { signingPolicy } from "./policies/signingPolicy";
|
|||
export { userAgentPolicy, getDefaultUserAgentValue } from "./policies/userAgentPolicy";
|
||||
export { deserializationPolicy, deserializeResponseBody } from "./policies/deserializationPolicy";
|
||||
export {
|
||||
MapperType, SimpleMapperType, CompositeMapperType, DictionaryMapperType, SequenceMapperType, EnumMapperType,
|
||||
Mapper, BaseMapper, CompositeMapper, SequenceMapper, DictionaryMapper, EnumMapper,
|
||||
MapperConstraints, PolymorphicDiscriminator,
|
||||
Serializer, UrlParameterValue, serializeObject
|
||||
MapperType,
|
||||
SimpleMapperType,
|
||||
CompositeMapperType,
|
||||
DictionaryMapperType,
|
||||
SequenceMapperType,
|
||||
EnumMapperType,
|
||||
Mapper,
|
||||
BaseMapper,
|
||||
CompositeMapper,
|
||||
SequenceMapper,
|
||||
DictionaryMapper,
|
||||
EnumMapper,
|
||||
MapperConstraints,
|
||||
PolymorphicDiscriminator,
|
||||
Serializer,
|
||||
UrlParameterValue,
|
||||
serializeObject,
|
||||
} from "./serializer";
|
||||
export {
|
||||
stripRequest, stripResponse, delay,
|
||||
executePromisesSequentially, generateUuid, encodeUri, ServiceCallback,
|
||||
promiseToCallback, promiseToServiceCallback, isValidUuid,
|
||||
applyMixins, isNode, isDuration
|
||||
stripRequest,
|
||||
stripResponse,
|
||||
delay,
|
||||
executePromisesSequentially,
|
||||
generateUuid,
|
||||
encodeUri,
|
||||
ServiceCallback,
|
||||
promiseToCallback,
|
||||
promiseToServiceCallback,
|
||||
isValidUuid,
|
||||
applyMixins,
|
||||
isNode,
|
||||
isDuration,
|
||||
} from "./util/utils";
|
||||
export { URLBuilder, URLQuery } from "./url";
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ if (typeof globalWithFetch.fetch !== "function") {
|
|||
globalWithFetch.fetch = fetch;
|
||||
}
|
||||
|
||||
|
||||
export class NodeFetchHttpClient extends FetchHttpClient {
|
||||
private readonly cookieJar = new tough.CookieJar(undefined, { looseMode: true });
|
||||
|
||||
|
@ -47,14 +46,18 @@ export class NodeFetchHttpClient extends FetchHttpClient {
|
|||
}
|
||||
|
||||
if (httpRequest.agentSettings) {
|
||||
const {http: httpAgent, https: httpsAgent} = 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);
|
||||
const tunnel: ProxyAgent = createProxyAgent(
|
||||
httpRequest.url,
|
||||
httpRequest.proxySettings,
|
||||
httpRequest.headers
|
||||
);
|
||||
requestInit.agent = tunnel.agent;
|
||||
}
|
||||
|
||||
|
@ -63,7 +66,9 @@ export class NodeFetchHttpClient extends FetchHttpClient {
|
|||
requestInit.agent.keepAlive = true;
|
||||
} else {
|
||||
const options: http.AgentOptions | https.AgentOptions = { keepAlive: true };
|
||||
const agent = httpRequest.url.startsWith("https") ? new https.Agent(options) : new http.Agent(options);
|
||||
const agent = httpRequest.url.startsWith("https")
|
||||
? new https.Agent(options)
|
||||
: new http.Agent(options);
|
||||
requestInit.agent = agent;
|
||||
}
|
||||
}
|
||||
|
@ -80,13 +85,14 @@ export class NodeFetchHttpClient extends FetchHttpClient {
|
|||
setCookieHeader,
|
||||
operationResponse.request.url,
|
||||
{ ignoreError: true },
|
||||
err => {
|
||||
(err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,10 @@ export function getPathStringFromParameter(parameter: OperationParameter): strin
|
|||
return getPathStringFromParameterPath(parameter.parameterPath, parameter.mapper);
|
||||
}
|
||||
|
||||
export function getPathStringFromParameterPath(parameterPath: ParameterPath, mapper: Mapper): string {
|
||||
export function getPathStringFromParameterPath(
|
||||
parameterPath: ParameterPath,
|
||||
mapper: Mapper
|
||||
): string {
|
||||
let result: string;
|
||||
if (typeof parameterPath === "string") {
|
||||
result = parameterPath;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
import { OperationParameter, OperationQueryParameter, OperationURLParameter } from "./operationParameter";
|
||||
import {
|
||||
OperationParameter,
|
||||
OperationQueryParameter,
|
||||
OperationURLParameter,
|
||||
} from "./operationParameter";
|
||||
import { OperationResponse } from "./operationResponse";
|
||||
import { MapperType, Serializer } from "./serializer";
|
||||
import { HttpMethods } from "./webResource";
|
||||
|
@ -82,7 +86,10 @@ export function isStreamOperation(operationSpec: OperationSpec): boolean {
|
|||
let result = false;
|
||||
for (const statusCode in operationSpec.responses) {
|
||||
const operationResponse: OperationResponse = operationSpec.responses[statusCode];
|
||||
if (operationResponse.bodyMapper && operationResponse.bodyMapper.type.name === MapperType.Stream) {
|
||||
if (
|
||||
operationResponse.bodyMapper &&
|
||||
operationResponse.bodyMapper.type.name === MapperType.Stream
|
||||
) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,12 @@
|
|||
// 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 {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
|
||||
|
@ -12,7 +17,7 @@ export function agentPolicy(_agentSettings?: AgentSettings): RequestPolicyFactor
|
|||
return {
|
||||
create: (_nextPolicy: RequestPolicy, _options: RequestPolicyOptionsLike) => {
|
||||
throw agentNotSupportedInBrowser;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,12 @@
|
|||
// 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 {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
|
||||
|
@ -10,14 +15,18 @@ 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) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptionsLike,
|
||||
agentSettings: AgentSettings
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
this.agentSettings = agentSettings;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,12 @@ import { Mapper, MapperType } from "../serializer";
|
|||
import * as utils from "../util/utils";
|
||||
import { parseXML } from "../util/xml";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
|
||||
/**
|
||||
* The content-types that will indicate that an operation response should be deserialized in a
|
||||
|
@ -33,11 +38,13 @@ export interface DeserializationContentTypes {
|
|||
* Create a new serialization RequestPolicyCreator that will serialized HTTP request bodies as they
|
||||
* pass through the HTTP pipeline.
|
||||
*/
|
||||
export function deserializationPolicy(deserializationContentTypes?: DeserializationContentTypes): RequestPolicyFactory {
|
||||
export function deserializationPolicy(
|
||||
deserializationContentTypes?: DeserializationContentTypes
|
||||
): RequestPolicyFactory {
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new DeserializationPolicy(nextPolicy, deserializationContentTypes, options);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -52,24 +59,41 @@ export class DeserializationPolicy extends BaseRequestPolicy {
|
|||
public readonly jsonContentTypes: string[];
|
||||
public readonly xmlContentTypes: string[];
|
||||
|
||||
constructor(nextPolicy: RequestPolicy, deserializationContentTypes: DeserializationContentTypes | undefined, options: RequestPolicyOptionsLike) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
deserializationContentTypes: DeserializationContentTypes | undefined,
|
||||
options: RequestPolicyOptionsLike
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
|
||||
this.jsonContentTypes = deserializationContentTypes && deserializationContentTypes.json || defaultJsonContentTypes;
|
||||
this.xmlContentTypes = deserializationContentTypes && deserializationContentTypes.xml || defaultXmlContentTypes;
|
||||
this.jsonContentTypes =
|
||||
(deserializationContentTypes && deserializationContentTypes.json) || defaultJsonContentTypes;
|
||||
this.xmlContentTypes =
|
||||
(deserializationContentTypes && deserializationContentTypes.xml) || defaultXmlContentTypes;
|
||||
}
|
||||
|
||||
public async sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
|
||||
return this._nextPolicy.sendRequest(request).then((response: HttpOperationResponse) => deserializeResponseBody(this.jsonContentTypes, this.xmlContentTypes, response));
|
||||
return this._nextPolicy
|
||||
.sendRequest(request)
|
||||
.then((response: HttpOperationResponse) =>
|
||||
deserializeResponseBody(this.jsonContentTypes, this.xmlContentTypes, response)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getOperationResponse(parsedResponse: HttpOperationResponse): undefined | OperationResponse {
|
||||
function getOperationResponse(
|
||||
parsedResponse: HttpOperationResponse
|
||||
): undefined | OperationResponse {
|
||||
let result: OperationResponse | undefined;
|
||||
const request: WebResourceLike = parsedResponse.request;
|
||||
const operationSpec: OperationSpec | undefined = request.operationSpec;
|
||||
if (operationSpec) {
|
||||
const operationResponseGetter: undefined | ((operationSpec: OperationSpec, response: HttpOperationResponse) => (undefined | OperationResponse)) = request.operationResponseGetter;
|
||||
const operationResponseGetter:
|
||||
| undefined
|
||||
| ((
|
||||
operationSpec: OperationSpec,
|
||||
response: HttpOperationResponse
|
||||
) => undefined | OperationResponse) = request.operationResponseGetter;
|
||||
if (!operationResponseGetter) {
|
||||
result = operationSpec.responses[parsedResponse.status];
|
||||
} else {
|
||||
|
@ -80,7 +104,8 @@ function getOperationResponse(parsedResponse: HttpOperationResponse): undefined
|
|||
}
|
||||
|
||||
function shouldDeserializeResponse(parsedResponse: HttpOperationResponse): boolean {
|
||||
const shouldDeserialize: undefined | boolean | ((response: HttpOperationResponse) => boolean) = parsedResponse.request.shouldDeserialize;
|
||||
const shouldDeserialize: undefined | boolean | ((response: HttpOperationResponse) => boolean) =
|
||||
parsedResponse.request.shouldDeserialize;
|
||||
let result: boolean;
|
||||
if (shouldDeserialize === undefined) {
|
||||
result = true;
|
||||
|
@ -92,8 +117,12 @@ function shouldDeserializeResponse(parsedResponse: HttpOperationResponse): boole
|
|||
return result;
|
||||
}
|
||||
|
||||
export function deserializeResponseBody(jsonContentTypes: string[], xmlContentTypes: string[], response: HttpOperationResponse): Promise<HttpOperationResponse> {
|
||||
return parse(jsonContentTypes, xmlContentTypes, response).then(parsedResponse => {
|
||||
export function deserializeResponseBody(
|
||||
jsonContentTypes: string[],
|
||||
xmlContentTypes: string[],
|
||||
response: HttpOperationResponse
|
||||
): Promise<HttpOperationResponse> {
|
||||
return parse(jsonContentTypes, xmlContentTypes, response).then((parsedResponse) => {
|
||||
const shouldDeserialize: boolean = shouldDeserializeResponse(parsedResponse);
|
||||
if (shouldDeserialize) {
|
||||
const operationSpec: OperationSpec | undefined = parsedResponse.request.operationSpec;
|
||||
|
@ -102,17 +131,21 @@ export function deserializeResponseBody(jsonContentTypes: string[], xmlContentTy
|
|||
|
||||
const expectedStatusCodes: string[] = Object.keys(operationSpec.responses);
|
||||
|
||||
const hasNoExpectedStatusCodes: boolean = (expectedStatusCodes.length === 0 || (expectedStatusCodes.length === 1 && expectedStatusCodes[0] === "default"));
|
||||
const hasNoExpectedStatusCodes: boolean =
|
||||
expectedStatusCodes.length === 0 ||
|
||||
(expectedStatusCodes.length === 1 && expectedStatusCodes[0] === "default");
|
||||
|
||||
const responseSpec: OperationResponse | undefined = getOperationResponse(parsedResponse);
|
||||
|
||||
const isExpectedStatusCode: boolean = hasNoExpectedStatusCodes ? (200 <= statusCode && statusCode < 300) : !!responseSpec;
|
||||
const isExpectedStatusCode: boolean = hasNoExpectedStatusCodes
|
||||
? 200 <= statusCode && statusCode < 300
|
||||
: !!responseSpec;
|
||||
if (!isExpectedStatusCode) {
|
||||
const defaultResponseSpec: OperationResponse = operationSpec.responses.default;
|
||||
if (defaultResponseSpec) {
|
||||
const initialErrorMessage: string = isStreamOperation(operationSpec)
|
||||
? `Unexpected status code: ${statusCode}`
|
||||
: parsedResponse.bodyAsText as string;
|
||||
: (parsedResponse.bodyAsText as string);
|
||||
|
||||
const error = new RestError(initialErrorMessage);
|
||||
error.statusCode = statusCode;
|
||||
|
@ -122,8 +155,12 @@ export function deserializeResponseBody(jsonContentTypes: string[], xmlContentTy
|
|||
let parsedErrorResponse: { [key: string]: any } = parsedResponse.parsedBody;
|
||||
try {
|
||||
if (parsedErrorResponse) {
|
||||
const defaultResponseBodyMapper: Mapper | undefined = defaultResponseSpec.bodyMapper;
|
||||
if (defaultResponseBodyMapper && defaultResponseBodyMapper.serializedName === "CloudError") {
|
||||
const defaultResponseBodyMapper: Mapper | undefined =
|
||||
defaultResponseSpec.bodyMapper;
|
||||
if (
|
||||
defaultResponseBodyMapper &&
|
||||
defaultResponseBodyMapper.serializedName === "CloudError"
|
||||
) {
|
||||
if (parsedErrorResponse.error) {
|
||||
parsedErrorResponse = parsedErrorResponse.error;
|
||||
}
|
||||
|
@ -147,12 +184,20 @@ export function deserializeResponseBody(jsonContentTypes: string[], xmlContentTy
|
|||
|
||||
if (defaultResponseBodyMapper) {
|
||||
let valueToDeserialize: any = parsedErrorResponse;
|
||||
if (operationSpec.isXML && defaultResponseBodyMapper.type.name === MapperType.Sequence) {
|
||||
valueToDeserialize = typeof parsedErrorResponse === "object"
|
||||
? parsedErrorResponse[defaultResponseBodyMapper.xmlElementName!]
|
||||
: [];
|
||||
if (
|
||||
operationSpec.isXML &&
|
||||
defaultResponseBodyMapper.type.name === MapperType.Sequence
|
||||
) {
|
||||
valueToDeserialize =
|
||||
typeof parsedErrorResponse === "object"
|
||||
? parsedErrorResponse[defaultResponseBodyMapper.xmlElementName!]
|
||||
: [];
|
||||
}
|
||||
error.body = operationSpec.serializer.deserialize(defaultResponseBodyMapper, valueToDeserialize, "error.body");
|
||||
error.body = operationSpec.serializer.deserialize(
|
||||
defaultResponseBodyMapper,
|
||||
valueToDeserialize,
|
||||
"error.body"
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (defaultError) {
|
||||
|
@ -164,12 +209,21 @@ export function deserializeResponseBody(jsonContentTypes: string[], xmlContentTy
|
|||
if (responseSpec.bodyMapper) {
|
||||
let valueToDeserialize: any = parsedResponse.parsedBody;
|
||||
if (operationSpec.isXML && responseSpec.bodyMapper.type.name === MapperType.Sequence) {
|
||||
valueToDeserialize = typeof valueToDeserialize === "object" ? valueToDeserialize[responseSpec.bodyMapper.xmlElementName!] : [];
|
||||
valueToDeserialize =
|
||||
typeof valueToDeserialize === "object"
|
||||
? valueToDeserialize[responseSpec.bodyMapper.xmlElementName!]
|
||||
: [];
|
||||
}
|
||||
try {
|
||||
parsedResponse.parsedBody = operationSpec.serializer.deserialize(responseSpec.bodyMapper, valueToDeserialize, "operationRes.parsedBody");
|
||||
parsedResponse.parsedBody = operationSpec.serializer.deserialize(
|
||||
responseSpec.bodyMapper,
|
||||
valueToDeserialize,
|
||||
"operationRes.parsedBody"
|
||||
);
|
||||
} catch (error) {
|
||||
const restError = new RestError(`Error ${error} occurred in deserializing the responseBody - ${parsedResponse.bodyAsText}`);
|
||||
const restError = new RestError(
|
||||
`Error ${error} occurred in deserializing the responseBody - ${parsedResponse.bodyAsText}`
|
||||
);
|
||||
restError.request = utils.stripRequest(parsedResponse.request);
|
||||
restError.response = utils.stripResponse(parsedResponse);
|
||||
return Promise.reject(restError);
|
||||
|
@ -180,7 +234,11 @@ export function deserializeResponseBody(jsonContentTypes: string[], xmlContentTy
|
|||
}
|
||||
|
||||
if (responseSpec.headersMapper) {
|
||||
parsedResponse.parsedHeaders = operationSpec.serializer.deserialize(responseSpec.headersMapper, parsedResponse.headers.rawHeaders(), "operationRes.parsedHeaders");
|
||||
parsedResponse.parsedHeaders = operationSpec.serializer.deserialize(
|
||||
responseSpec.headersMapper,
|
||||
parsedResponse.headers.rawHeaders(),
|
||||
"operationRes.parsedHeaders"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,26 +247,42 @@ export function deserializeResponseBody(jsonContentTypes: string[], xmlContentTy
|
|||
});
|
||||
}
|
||||
|
||||
function parse(jsonContentTypes: string[], xmlContentTypes: string[], operationResponse: HttpOperationResponse): Promise<HttpOperationResponse> {
|
||||
function parse(
|
||||
jsonContentTypes: string[],
|
||||
xmlContentTypes: string[],
|
||||
operationResponse: HttpOperationResponse
|
||||
): Promise<HttpOperationResponse> {
|
||||
const errorHandler = (err: Error & { code: string }) => {
|
||||
const msg = `Error "${err}" occurred while parsing the response body - ${operationResponse.bodyAsText}.`;
|
||||
const errCode = err.code || RestError.PARSE_ERROR;
|
||||
const e = new RestError(msg, errCode, operationResponse.status, operationResponse.request, operationResponse, operationResponse.bodyAsText);
|
||||
const e = new RestError(
|
||||
msg,
|
||||
errCode,
|
||||
operationResponse.status,
|
||||
operationResponse.request,
|
||||
operationResponse,
|
||||
operationResponse.bodyAsText
|
||||
);
|
||||
return Promise.reject(e);
|
||||
};
|
||||
|
||||
if (!operationResponse.request.streamResponseBody && operationResponse.bodyAsText) {
|
||||
const text = operationResponse.bodyAsText;
|
||||
const contentType: string = operationResponse.headers.get("Content-Type") || "";
|
||||
const contentComponents: string[] = !contentType ? [] : contentType.split(";").map(component => component.toLowerCase());
|
||||
if (contentComponents.length === 0 || contentComponents.some(component => jsonContentTypes.indexOf(component) !== -1)) {
|
||||
return new Promise<HttpOperationResponse>(resolve => {
|
||||
const contentComponents: string[] = !contentType
|
||||
? []
|
||||
: contentType.split(";").map((component) => component.toLowerCase());
|
||||
if (
|
||||
contentComponents.length === 0 ||
|
||||
contentComponents.some((component) => jsonContentTypes.indexOf(component) !== -1)
|
||||
) {
|
||||
return new Promise<HttpOperationResponse>((resolve) => {
|
||||
operationResponse.parsedBody = JSON.parse(text);
|
||||
resolve(operationResponse);
|
||||
}).catch(errorHandler);
|
||||
} else if (contentComponents.some(component => xmlContentTypes.indexOf(component) !== -1)) {
|
||||
} else if (contentComponents.some((component) => xmlContentTypes.indexOf(component) !== -1)) {
|
||||
return parseXML(text)
|
||||
.then(body => {
|
||||
.then((body) => {
|
||||
operationResponse.parsedBody = body;
|
||||
return operationResponse;
|
||||
})
|
||||
|
|
|
@ -4,7 +4,12 @@
|
|||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import * as utils from "../util/utils";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
import { RestError } from "../restError";
|
||||
|
||||
export interface RetryData {
|
||||
|
@ -19,11 +24,23 @@ export interface RetryError extends Error {
|
|||
innerError?: RetryError;
|
||||
}
|
||||
|
||||
export function exponentialRetryPolicy(retryCount?: number, retryInterval?: number, minRetryInterval?: number, maxRetryInterval?: number): RequestPolicyFactory {
|
||||
export function exponentialRetryPolicy(
|
||||
retryCount?: number,
|
||||
retryInterval?: number,
|
||||
minRetryInterval?: number,
|
||||
maxRetryInterval?: number
|
||||
): RequestPolicyFactory {
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new ExponentialRetryPolicy(nextPolicy, options, retryCount, retryInterval, minRetryInterval, maxRetryInterval);
|
||||
}
|
||||
return new ExponentialRetryPolicy(
|
||||
nextPolicy,
|
||||
options,
|
||||
retryCount,
|
||||
retryInterval,
|
||||
minRetryInterval,
|
||||
maxRetryInterval
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -63,19 +80,33 @@ export class ExponentialRetryPolicy extends BaseRequestPolicy {
|
|||
* @param {number} [minRetryInterval] The minimum retry interval, in milliseconds.
|
||||
* @param {number} [maxRetryInterval] The maximum retry interval, in milliseconds.
|
||||
*/
|
||||
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike, retryCount?: number, retryInterval?: number, minRetryInterval?: number, maxRetryInterval?: number) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptionsLike,
|
||||
retryCount?: number,
|
||||
retryInterval?: number,
|
||||
minRetryInterval?: number,
|
||||
maxRetryInterval?: number
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
function isNumber(n: any): n is number { return typeof n === "number"; }
|
||||
function isNumber(n: any): n is number {
|
||||
return typeof n === "number";
|
||||
}
|
||||
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;
|
||||
this.minRetryInterval = isNumber(minRetryInterval)
|
||||
? minRetryInterval
|
||||
: DEFAULT_CLIENT_MIN_RETRY_INTERVAL;
|
||||
this.maxRetryInterval = isNumber(maxRetryInterval)
|
||||
? maxRetryInterval
|
||||
: DEFAULT_CLIENT_MAX_RETRY_INTERVAL;
|
||||
}
|
||||
|
||||
public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
|
||||
return this._nextPolicy.sendRequest(request.clone())
|
||||
.then(response => retry(this, request, response))
|
||||
.catch(error => retry(this, request, error.response, undefined, error));
|
||||
return this._nextPolicy
|
||||
.sendRequest(request.clone())
|
||||
.then((response) => retry(this, request, response))
|
||||
.catch((error) => retry(this, request, error.response, undefined, error));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,8 +118,17 @@ export class ExponentialRetryPolicy extends BaseRequestPolicy {
|
|||
* @param {RetryData} retryData The retry data.
|
||||
* @return {boolean} True if the operation qualifies for a retry; false otherwise.
|
||||
*/
|
||||
function shouldRetry(policy: ExponentialRetryPolicy, statusCode: number | undefined, retryData: RetryData): boolean {
|
||||
if (statusCode == undefined || (statusCode < 500 && statusCode !== 408) || statusCode === 501 || statusCode === 505) {
|
||||
function shouldRetry(
|
||||
policy: ExponentialRetryPolicy,
|
||||
statusCode: number | undefined,
|
||||
retryData: RetryData
|
||||
): boolean {
|
||||
if (
|
||||
statusCode == undefined ||
|
||||
(statusCode < 500 && statusCode !== 408) ||
|
||||
statusCode === 501 ||
|
||||
statusCode === 505
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -96,10 +136,10 @@ function shouldRetry(policy: ExponentialRetryPolicy, statusCode: number | undefi
|
|||
if (!retryData) {
|
||||
throw new Error("retryData for the ExponentialRetryPolicyFilter cannot be null.");
|
||||
} else {
|
||||
currentCount = (retryData && retryData.retryCount);
|
||||
currentCount = retryData && retryData.retryCount;
|
||||
}
|
||||
|
||||
return (currentCount < policy.retryCount);
|
||||
return currentCount < policy.retryCount;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,11 +149,15 @@ function shouldRetry(policy: ExponentialRetryPolicy, statusCode: number | undefi
|
|||
* @param {RetryData} retryData The retry data.
|
||||
* @param {RetryError} [err] The operation"s error, if any.
|
||||
*/
|
||||
function updateRetryData(policy: ExponentialRetryPolicy, retryData?: RetryData, err?: RetryError): RetryData {
|
||||
function updateRetryData(
|
||||
policy: ExponentialRetryPolicy,
|
||||
retryData?: RetryData,
|
||||
err?: RetryError
|
||||
): RetryData {
|
||||
if (!retryData) {
|
||||
retryData = {
|
||||
retryCount: 0,
|
||||
retryInterval: 0
|
||||
retryInterval: 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -130,32 +174,45 @@ function updateRetryData(policy: ExponentialRetryPolicy, retryData?: RetryData,
|
|||
|
||||
// Adjust retry interval
|
||||
let incrementDelta = Math.pow(2, retryData.retryCount) - 1;
|
||||
const boundedRandDelta = policy.retryInterval * 0.8 +
|
||||
const boundedRandDelta =
|
||||
policy.retryInterval * 0.8 +
|
||||
Math.floor(Math.random() * (policy.retryInterval * 1.2 - policy.retryInterval * 0.8));
|
||||
incrementDelta *= boundedRandDelta;
|
||||
|
||||
retryData.retryInterval = Math.min(policy.minRetryInterval + incrementDelta, policy.maxRetryInterval);
|
||||
retryData.retryInterval = Math.min(
|
||||
policy.minRetryInterval + incrementDelta,
|
||||
policy.maxRetryInterval
|
||||
);
|
||||
|
||||
return retryData;
|
||||
}
|
||||
|
||||
function retry(policy: ExponentialRetryPolicy, request: WebResourceLike, response?: HttpOperationResponse, retryData?: RetryData, requestError?: RetryError): Promise<HttpOperationResponse> {
|
||||
function retry(
|
||||
policy: ExponentialRetryPolicy,
|
||||
request: WebResourceLike,
|
||||
response?: HttpOperationResponse,
|
||||
retryData?: RetryData,
|
||||
requestError?: RetryError
|
||||
): Promise<HttpOperationResponse> {
|
||||
retryData = updateRetryData(policy, retryData, requestError);
|
||||
const isAborted: boolean | undefined = request.abortSignal && request.abortSignal.aborted;
|
||||
if (!isAborted && shouldRetry(policy, response && response.status, retryData)) {
|
||||
return utils.delay(retryData.retryInterval)
|
||||
return utils
|
||||
.delay(retryData.retryInterval)
|
||||
.then(() => policy._nextPolicy.sendRequest(request.clone()))
|
||||
.then(res => retry(policy, request, res, retryData, undefined))
|
||||
.catch(err => retry(policy, request, response, retryData, err));
|
||||
.then((res) => retry(policy, request, res, retryData, undefined))
|
||||
.catch((err) => retry(policy, request, response, retryData, err));
|
||||
} else if (isAborted || requestError || !response) {
|
||||
// If the operation failed in the end, return all errors instead of just the last one
|
||||
const err = retryData.error ||
|
||||
const err =
|
||||
retryData.error ||
|
||||
new RestError(
|
||||
"Failed to send the request.",
|
||||
RestError.REQUEST_SEND_ERROR,
|
||||
response && response.status,
|
||||
response && response.request,
|
||||
response);
|
||||
response
|
||||
);
|
||||
return Promise.reject(err);
|
||||
} else {
|
||||
return Promise.resolve(response);
|
||||
|
|
|
@ -4,18 +4,29 @@
|
|||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import * as utils from "../util/utils";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
|
||||
export function generateClientRequestIdPolicy(requestIdHeaderName = "x-ms-client-request-id"): RequestPolicyFactory {
|
||||
export function generateClientRequestIdPolicy(
|
||||
requestIdHeaderName = "x-ms-client-request-id"
|
||||
): RequestPolicyFactory {
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new GenerateClientRequestIdPolicy(nextPolicy, options, requestIdHeaderName);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class GenerateClientRequestIdPolicy extends BaseRequestPolicy {
|
||||
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike, private _requestIdHeaderName: string) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptionsLike,
|
||||
private _requestIdHeaderName: string
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,30 +3,42 @@
|
|||
|
||||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
|
||||
export function logPolicy(logger: any = console.log): RequestPolicyFactory {
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new LogPolicy(nextPolicy, options, logger);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class LogPolicy extends BaseRequestPolicy {
|
||||
logger?: any;
|
||||
|
||||
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike, logger: any = console.log) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptionsLike,
|
||||
logger: any = console.log
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
|
||||
return this._nextPolicy.sendRequest(request).then(response => logResponse(this, response));
|
||||
return this._nextPolicy.sendRequest(request).then((response) => logResponse(this, response));
|
||||
}
|
||||
}
|
||||
|
||||
function logResponse(policy: LogPolicy, response: HttpOperationResponse): Promise<HttpOperationResponse> {
|
||||
function logResponse(
|
||||
policy: LogPolicy,
|
||||
response: HttpOperationResponse
|
||||
): Promise<HttpOperationResponse> {
|
||||
policy.logger(`>> Request: ${JSON.stringify(response.request, undefined, 2)}`);
|
||||
policy.logger(`>> Response status code: ${response.status}`);
|
||||
const responseBody = response.bodyAsText;
|
||||
|
|
|
@ -21,7 +21,7 @@ export function getPlatformSpecificData(): TelemetryInfo[] {
|
|||
const navigator = window.navigator as NavigatorEx;
|
||||
const osInfo = {
|
||||
key: "OS",
|
||||
value: (navigator.oscpu || navigator.platform).replace(" ", "")
|
||||
value: (navigator.oscpu || navigator.platform).replace(" ", ""),
|
||||
};
|
||||
|
||||
return [osInfo];
|
||||
|
|
|
@ -12,12 +12,12 @@ export function getDefaultUserAgentKey(): string {
|
|||
export function getPlatformSpecificData(): TelemetryInfo[] {
|
||||
const runtimeInfo = {
|
||||
key: "Node",
|
||||
value: process.version
|
||||
value: process.version,
|
||||
};
|
||||
|
||||
const osInfo = {
|
||||
key: "OS",
|
||||
value: `(${os.arch()}-${os.type()}-${os.release()})`
|
||||
value: `(${os.arch()}-${os.type()}-${os.release()})`,
|
||||
};
|
||||
|
||||
return [runtimeInfo, osInfo];
|
||||
|
|
|
@ -2,7 +2,12 @@
|
|||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
import { ProxySettings } from "../serviceClient";
|
||||
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
|
||||
|
@ -16,7 +21,7 @@ export function proxyPolicy(_proxySettings?: ProxySettings): RequestPolicyFactor
|
|||
return {
|
||||
create: (_nextPolicy: RequestPolicy, _options: RequestPolicyOptionsLike) => {
|
||||
throw proxyNotSupportedInBrowser;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import { ProxySettings } from "../serviceClient";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
|
@ -37,23 +42,26 @@ export function getDefaultProxySettings(proxyUrl?: string): ProxySettings | unde
|
|||
const parsedUrl = URLBuilder.parse(proxyUrl);
|
||||
return {
|
||||
host: parsedUrl.getScheme() + "://" + parsedUrl.getHost(),
|
||||
port: Number.parseInt(parsedUrl.getPort() || "80")
|
||||
port: Number.parseInt(parsedUrl.getPort() || "80"),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function proxyPolicy(proxySettings?: ProxySettings): RequestPolicyFactory {
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new ProxyPolicy(nextPolicy, options, proxySettings!);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class ProxyPolicy extends BaseRequestPolicy {
|
||||
proxySettings: ProxySettings;
|
||||
|
||||
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike, proxySettings: ProxySettings) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptionsLike,
|
||||
proxySettings: ProxySettings
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
this.proxySettings = proxySettings;
|
||||
}
|
||||
|
|
|
@ -4,33 +4,49 @@
|
|||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import { URLBuilder } from "../url";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
|
||||
export function redirectPolicy(maximumRetries = 20): RequestPolicyFactory {
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new RedirectPolicy(nextPolicy, options, maximumRetries);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class RedirectPolicy extends BaseRequestPolicy {
|
||||
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike, readonly maxRetries = 20) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptionsLike,
|
||||
readonly maxRetries = 20
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
}
|
||||
|
||||
public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
|
||||
return this._nextPolicy.sendRequest(request).then(response => handleRedirect(this, response, 0));
|
||||
return this._nextPolicy
|
||||
.sendRequest(request)
|
||||
.then((response) => handleRedirect(this, response, 0));
|
||||
}
|
||||
}
|
||||
|
||||
function handleRedirect(policy: RedirectPolicy, response: HttpOperationResponse, currentRetries: number): Promise<HttpOperationResponse> {
|
||||
function handleRedirect(
|
||||
policy: RedirectPolicy,
|
||||
response: HttpOperationResponse,
|
||||
currentRetries: number
|
||||
): Promise<HttpOperationResponse> {
|
||||
const { request, status } = response;
|
||||
const locationHeader = response.headers.get("location");
|
||||
if (locationHeader &&
|
||||
if (
|
||||
locationHeader &&
|
||||
(status === 300 || status === 307 || (status === 303 && request.method === "POST")) &&
|
||||
(!policy.maxRetries || currentRetries < policy.maxRetries)) {
|
||||
|
||||
(!policy.maxRetries || currentRetries < policy.maxRetries)
|
||||
) {
|
||||
const builder = URLBuilder.parse(request.url);
|
||||
builder.setPath(locationHeader);
|
||||
request.url = builder.toString();
|
||||
|
@ -41,8 +57,9 @@ function handleRedirect(policy: RedirectPolicy, response: HttpOperationResponse,
|
|||
request.method = "GET";
|
||||
}
|
||||
|
||||
return policy._nextPolicy.sendRequest(request)
|
||||
.then(res => handleRedirect(policy, res, currentRetries + 1));
|
||||
return policy._nextPolicy
|
||||
.sendRequest(request)
|
||||
.then((res) => handleRedirect(policy, res, currentRetries + 1));
|
||||
}
|
||||
|
||||
return Promise.resolve(response);
|
||||
|
|
|
@ -10,7 +10,7 @@ import { WebResourceLike } from "../webResource";
|
|||
* Creates a new RequestPolicy per-request that uses the provided nextPolicy.
|
||||
*/
|
||||
export type RequestPolicyFactory = {
|
||||
create(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike): RequestPolicy
|
||||
create(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike): RequestPolicy;
|
||||
};
|
||||
|
||||
export interface RequestPolicy {
|
||||
|
@ -18,8 +18,10 @@ export interface RequestPolicy {
|
|||
}
|
||||
|
||||
export abstract class BaseRequestPolicy implements RequestPolicy {
|
||||
protected constructor(readonly _nextPolicy: RequestPolicy, readonly _options: RequestPolicyOptionsLike) {
|
||||
}
|
||||
protected constructor(
|
||||
readonly _nextPolicy: RequestPolicy,
|
||||
readonly _options: RequestPolicyOptionsLike
|
||||
) {}
|
||||
|
||||
public abstract sendRequest(webResource: WebResourceLike): Promise<HttpOperationResponse>;
|
||||
|
||||
|
@ -67,8 +69,7 @@ export interface RequestPolicyOptionsLike {
|
|||
* Optional properties that can be used when creating a RequestPolicy.
|
||||
*/
|
||||
export class RequestPolicyOptions implements RequestPolicyOptionsLike {
|
||||
constructor(private _logger?: HttpPipelineLogger) {
|
||||
}
|
||||
constructor(private _logger?: HttpPipelineLogger) {}
|
||||
|
||||
/**
|
||||
* Get whether or not a log with the provided log level should be logged.
|
||||
|
@ -76,9 +77,11 @@ export class RequestPolicyOptions implements RequestPolicyOptionsLike {
|
|||
* @returns Whether or not a log with the provided log level should be logged.
|
||||
*/
|
||||
public shouldLog(logLevel: HttpPipelineLogLevel): boolean {
|
||||
return !!this._logger &&
|
||||
return (
|
||||
!!this._logger &&
|
||||
logLevel !== HttpPipelineLogLevel.OFF &&
|
||||
logLevel <= this._logger.minimumLogLevel;
|
||||
logLevel <= this._logger.minimumLogLevel
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,47 +3,62 @@
|
|||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import * as utils from "../util/utils";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
|
||||
export function rpRegistrationPolicy(retryTimeout = 30): RequestPolicyFactory {
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new RPRegistrationPolicy(nextPolicy, options, retryTimeout);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class RPRegistrationPolicy extends BaseRequestPolicy {
|
||||
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike, readonly _retryTimeout = 30) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptionsLike,
|
||||
readonly _retryTimeout = 30
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
}
|
||||
|
||||
public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
|
||||
return this._nextPolicy.sendRequest(request.clone())
|
||||
.then(response => registerIfNeeded(this, request, response));
|
||||
return this._nextPolicy
|
||||
.sendRequest(request.clone())
|
||||
.then((response) => registerIfNeeded(this, request, response));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function registerIfNeeded(policy: RPRegistrationPolicy, request: WebResourceLike, response: HttpOperationResponse): Promise<HttpOperationResponse> {
|
||||
function registerIfNeeded(
|
||||
policy: RPRegistrationPolicy,
|
||||
request: WebResourceLike,
|
||||
response: HttpOperationResponse
|
||||
): Promise<HttpOperationResponse> {
|
||||
if (response.status === 409) {
|
||||
const rpName = checkRPNotRegisteredError(response.bodyAsText as string);
|
||||
if (rpName) {
|
||||
const urlPrefix = extractSubscriptionUrl(request.url);
|
||||
return registerRP(policy, urlPrefix, rpName, request)
|
||||
// Autoregistration of ${provider} failed for some reason. We will not return this error
|
||||
// instead will return the initial response with 409 status code back to the user.
|
||||
// do nothing here as we are returning the original response at the end of this method.
|
||||
.catch(() => false)
|
||||
.then(registrationStatus => {
|
||||
if (registrationStatus) {
|
||||
// Retry the original request. We have to change the x-ms-client-request-id
|
||||
// otherwise Azure endpoint will return the initial 409 (cached) response.
|
||||
request.headers.set("x-ms-client-request-id", utils.generateUuid());
|
||||
return policy._nextPolicy.sendRequest(request.clone());
|
||||
}
|
||||
return response;
|
||||
});
|
||||
return (
|
||||
registerRP(policy, urlPrefix, rpName, request)
|
||||
// Autoregistration of ${provider} failed for some reason. We will not return this error
|
||||
// instead will return the initial response with 409 status code back to the user.
|
||||
// do nothing here as we are returning the original response at the end of this method.
|
||||
.catch(() => false)
|
||||
.then((registrationStatus) => {
|
||||
if (registrationStatus) {
|
||||
// Retry the original request. We have to change the x-ms-client-request-id
|
||||
// otherwise Azure endpoint will return the initial 409 (cached) response.
|
||||
request.headers.set("x-ms-client-request-id", utils.generateUuid());
|
||||
return policy._nextPolicy.sendRequest(request.clone());
|
||||
}
|
||||
return response;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +71,10 @@ function registerIfNeeded(policy: RPRegistrationPolicy, request: WebResourceLike
|
|||
* @param {boolean} reuseUrlToo Should the url from the original request be reused as well. Default false.
|
||||
* @returns {object} A new request object with desired headers.
|
||||
*/
|
||||
function getRequestEssentials(originalRequest: WebResourceLike, reuseUrlToo = false): WebResourceLike {
|
||||
function getRequestEssentials(
|
||||
originalRequest: WebResourceLike,
|
||||
reuseUrlToo = false
|
||||
): WebResourceLike {
|
||||
const reqOptions: WebResourceLike = originalRequest.clone();
|
||||
if (reuseUrlToo) {
|
||||
reqOptions.url = originalRequest.url;
|
||||
|
@ -86,8 +104,13 @@ function checkRPNotRegisteredError(body: string): string {
|
|||
} catch (err) {
|
||||
// do nothing;
|
||||
}
|
||||
if (responseBody && responseBody.error && responseBody.error.message &&
|
||||
responseBody.error.code && responseBody.error.code === "MissingSubscriptionRegistration") {
|
||||
if (
|
||||
responseBody &&
|
||||
responseBody.error &&
|
||||
responseBody.error.message &&
|
||||
responseBody.error.code &&
|
||||
responseBody.error.code === "MissingSubscriptionRegistration"
|
||||
) {
|
||||
const matchRes = responseBody.error.message.match(/.*'(.*)'/i);
|
||||
if (matchRes) {
|
||||
result = matchRes.pop();
|
||||
|
@ -105,7 +128,7 @@ function checkRPNotRegisteredError(body: string): string {
|
|||
*/
|
||||
function extractSubscriptionUrl(url: string): string {
|
||||
let result;
|
||||
const matchRes = url.match(/.*\/subscriptions\/[a-f0-9-]+\//ig);
|
||||
const matchRes = url.match(/.*\/subscriptions\/[a-f0-9-]+\//gi);
|
||||
if (matchRes && matchRes[0]) {
|
||||
result = matchRes[0];
|
||||
} else {
|
||||
|
@ -123,20 +146,24 @@ function extractSubscriptionUrl(url: string): string {
|
|||
* with a message that the provider is not registered.
|
||||
* @param {registrationCallback} callback The callback that handles the RP registration
|
||||
*/
|
||||
function registerRP(policy: RPRegistrationPolicy, urlPrefix: string, provider: string, originalRequest: WebResourceLike): Promise<boolean> {
|
||||
function registerRP(
|
||||
policy: RPRegistrationPolicy,
|
||||
urlPrefix: string,
|
||||
provider: string,
|
||||
originalRequest: WebResourceLike
|
||||
): Promise<boolean> {
|
||||
const postUrl = `${urlPrefix}providers/${provider}/register?api-version=2016-02-01`;
|
||||
const getUrl = `${urlPrefix}providers/${provider}?api-version=2016-02-01`;
|
||||
const reqOptions = getRequestEssentials(originalRequest);
|
||||
reqOptions.method = "POST";
|
||||
reqOptions.url = postUrl;
|
||||
|
||||
return policy._nextPolicy.sendRequest(reqOptions)
|
||||
.then(response => {
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`Autoregistration of ${provider} failed. Please try registering manually.`);
|
||||
}
|
||||
return getRegistrationStatus(policy, getUrl, originalRequest);
|
||||
});
|
||||
return policy._nextPolicy.sendRequest(reqOptions).then((response) => {
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`Autoregistration of ${provider} failed. Please try registering manually.`);
|
||||
}
|
||||
return getRegistrationStatus(policy, getUrl, originalRequest);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,17 +175,23 @@ function registerRP(policy: RPRegistrationPolicy, urlPrefix: string, provider: s
|
|||
* with a message that the provider is not registered.
|
||||
* @returns {Promise<boolean>} True if RP Registration is successful.
|
||||
*/
|
||||
function getRegistrationStatus(policy: RPRegistrationPolicy, url: string, originalRequest: WebResourceLike): Promise<boolean> {
|
||||
function getRegistrationStatus(
|
||||
policy: RPRegistrationPolicy,
|
||||
url: string,
|
||||
originalRequest: WebResourceLike
|
||||
): Promise<boolean> {
|
||||
const reqOptions: any = getRequestEssentials(originalRequest);
|
||||
reqOptions.url = url;
|
||||
reqOptions.method = "GET";
|
||||
|
||||
return policy._nextPolicy.sendRequest(reqOptions).then(res => {
|
||||
const obj = (res.parsedBody as any);
|
||||
return policy._nextPolicy.sendRequest(reqOptions).then((res) => {
|
||||
const obj = res.parsedBody as any;
|
||||
if (res.parsedBody && obj.registrationState && obj.registrationState === "Registered") {
|
||||
return true;
|
||||
} else {
|
||||
return utils.delay(policy._retryTimeout * 1000).then(() => getRegistrationStatus(policy, url, originalRequest));
|
||||
return utils
|
||||
.delay(policy._retryTimeout * 1000)
|
||||
.then(() => getRegistrationStatus(policy, url, originalRequest));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,19 +4,29 @@
|
|||
import { ServiceClientCredentials } from "../credentials/serviceClientCredentials";
|
||||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
import { BaseRequestPolicy, RequestPolicyFactory, RequestPolicy, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicy,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
|
||||
export function signingPolicy(authenticationProvider: ServiceClientCredentials): RequestPolicyFactory {
|
||||
export function signingPolicy(
|
||||
authenticationProvider: ServiceClientCredentials
|
||||
): RequestPolicyFactory {
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new SigningPolicy(nextPolicy, options, authenticationProvider);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class SigningPolicy extends BaseRequestPolicy {
|
||||
|
||||
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike, public authenticationProvider: ServiceClientCredentials) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptionsLike,
|
||||
public authenticationProvider: ServiceClientCredentials
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
}
|
||||
|
||||
|
@ -25,6 +35,8 @@ export class SigningPolicy extends BaseRequestPolicy {
|
|||
}
|
||||
|
||||
public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
|
||||
return this.signRequest(request).then(nextRequest => this._nextPolicy.sendRequest(nextRequest));
|
||||
return this.signRequest(request).then((nextRequest) =>
|
||||
this._nextPolicy.sendRequest(nextRequest)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,12 @@
|
|||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import * as utils from "../util/utils";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
|
||||
export interface RetryData {
|
||||
retryCount: number;
|
||||
|
@ -18,11 +23,23 @@ export interface RetryError extends Error {
|
|||
innerError?: RetryError;
|
||||
}
|
||||
|
||||
export function systemErrorRetryPolicy(retryCount?: number, retryInterval?: number, minRetryInterval?: number, maxRetryInterval?: number): RequestPolicyFactory {
|
||||
export function systemErrorRetryPolicy(
|
||||
retryCount?: number,
|
||||
retryInterval?: number,
|
||||
minRetryInterval?: number,
|
||||
maxRetryInterval?: number
|
||||
): RequestPolicyFactory {
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new SystemErrorRetryPolicy(nextPolicy, options, retryCount, retryInterval, minRetryInterval, maxRetryInterval);
|
||||
}
|
||||
return new SystemErrorRetryPolicy(
|
||||
nextPolicy,
|
||||
options,
|
||||
retryCount,
|
||||
retryInterval,
|
||||
minRetryInterval,
|
||||
maxRetryInterval
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -46,16 +63,32 @@ export class SystemErrorRetryPolicy extends BaseRequestPolicy {
|
|||
DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 90;
|
||||
DEFAULT_CLIENT_MIN_RETRY_INTERVAL = 1000 * 3;
|
||||
|
||||
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike, retryCount?: number, retryInterval?: number, minRetryInterval?: number, maxRetryInterval?: number) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptionsLike,
|
||||
retryCount?: number,
|
||||
retryInterval?: number,
|
||||
minRetryInterval?: number,
|
||||
maxRetryInterval?: number
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
this.retryCount = typeof retryCount === "number" ? retryCount : this.DEFAULT_CLIENT_RETRY_COUNT;
|
||||
this.retryInterval = typeof retryInterval === "number" ? retryInterval : this.DEFAULT_CLIENT_RETRY_INTERVAL;
|
||||
this.minRetryInterval = typeof minRetryInterval === "number" ? minRetryInterval : this.DEFAULT_CLIENT_MIN_RETRY_INTERVAL;
|
||||
this.maxRetryInterval = typeof maxRetryInterval === "number" ? maxRetryInterval : this.DEFAULT_CLIENT_MAX_RETRY_INTERVAL;
|
||||
this.retryInterval =
|
||||
typeof retryInterval === "number" ? retryInterval : this.DEFAULT_CLIENT_RETRY_INTERVAL;
|
||||
this.minRetryInterval =
|
||||
typeof minRetryInterval === "number"
|
||||
? minRetryInterval
|
||||
: this.DEFAULT_CLIENT_MIN_RETRY_INTERVAL;
|
||||
this.maxRetryInterval =
|
||||
typeof maxRetryInterval === "number"
|
||||
? maxRetryInterval
|
||||
: this.DEFAULT_CLIENT_MAX_RETRY_INTERVAL;
|
||||
}
|
||||
|
||||
public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
|
||||
return this._nextPolicy.sendRequest(request.clone()).then(response => retry(this, request, response));
|
||||
return this._nextPolicy
|
||||
.sendRequest(request.clone())
|
||||
.then((response) => retry(this, request, response));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,9 +104,9 @@ function shouldRetry(policy: SystemErrorRetryPolicy, retryData: RetryData): bool
|
|||
if (!retryData) {
|
||||
throw new Error("retryData for the SystemErrorRetryPolicyFilter cannot be null.");
|
||||
} else {
|
||||
currentCount = (retryData && retryData.retryCount);
|
||||
currentCount = retryData && retryData.retryCount;
|
||||
}
|
||||
return (currentCount < policy.retryCount);
|
||||
return currentCount < policy.retryCount;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,11 +115,15 @@ function shouldRetry(policy: SystemErrorRetryPolicy, retryData: RetryData): bool
|
|||
* @param {RetryData} retryData The retry data.
|
||||
* @param {object} err The operation"s error, if any.
|
||||
*/
|
||||
function updateRetryData(policy: SystemErrorRetryPolicy, retryData?: RetryData, err?: RetryError): RetryData {
|
||||
function updateRetryData(
|
||||
policy: SystemErrorRetryPolicy,
|
||||
retryData?: RetryData,
|
||||
err?: RetryError
|
||||
): RetryData {
|
||||
if (!retryData) {
|
||||
retryData = {
|
||||
retryCount: 0,
|
||||
retryInterval: 0
|
||||
retryInterval: 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -103,25 +140,43 @@ function updateRetryData(policy: SystemErrorRetryPolicy, retryData?: RetryData,
|
|||
|
||||
// Adjust retry interval
|
||||
let incrementDelta = Math.pow(2, retryData.retryCount) - 1;
|
||||
const boundedRandDelta = policy.retryInterval * 0.8 +
|
||||
const boundedRandDelta =
|
||||
policy.retryInterval * 0.8 +
|
||||
Math.floor(Math.random() * (policy.retryInterval * 1.2 - policy.retryInterval * 0.8));
|
||||
incrementDelta *= boundedRandDelta;
|
||||
|
||||
retryData.retryInterval = Math.min(policy.minRetryInterval + incrementDelta, policy.maxRetryInterval);
|
||||
retryData.retryInterval = Math.min(
|
||||
policy.minRetryInterval + incrementDelta,
|
||||
policy.maxRetryInterval
|
||||
);
|
||||
|
||||
return retryData;
|
||||
}
|
||||
|
||||
function retry(policy: SystemErrorRetryPolicy, request: WebResourceLike, operationResponse: HttpOperationResponse, retryData?: RetryData, err?: RetryError): Promise<HttpOperationResponse> {
|
||||
function retry(
|
||||
policy: SystemErrorRetryPolicy,
|
||||
request: WebResourceLike,
|
||||
operationResponse: HttpOperationResponse,
|
||||
retryData?: RetryData,
|
||||
err?: RetryError
|
||||
): Promise<HttpOperationResponse> {
|
||||
retryData = updateRetryData(policy, retryData, err);
|
||||
if (err && err.code && shouldRetry(policy, retryData) &&
|
||||
(err.code === "ETIMEDOUT" || err.code === "ESOCKETTIMEDOUT" || err.code === "ECONNREFUSED" ||
|
||||
err.code === "ECONNRESET" || err.code === "ENOENT")) {
|
||||
if (
|
||||
err &&
|
||||
err.code &&
|
||||
shouldRetry(policy, retryData) &&
|
||||
(err.code === "ETIMEDOUT" ||
|
||||
err.code === "ESOCKETTIMEDOUT" ||
|
||||
err.code === "ECONNREFUSED" ||
|
||||
err.code === "ECONNRESET" ||
|
||||
err.code === "ENOENT")
|
||||
) {
|
||||
// If previous operation ended with an error and the policy allows a retry, do that
|
||||
return utils.delay(retryData.retryInterval)
|
||||
.then(() => policy._nextPolicy.sendRequest(request.clone()))
|
||||
.then(res => retry(policy, request, res, retryData, err))
|
||||
.catch(err => retry(policy, request, operationResponse, retryData, err));
|
||||
return utils
|
||||
.delay(retryData.retryInterval)
|
||||
.then(() => policy._nextPolicy.sendRequest(request.clone()))
|
||||
.then((res) => retry(policy, request, res, retryData, err))
|
||||
.catch((err) => retry(policy, request, operationResponse, retryData, err));
|
||||
} else {
|
||||
if (err != undefined) {
|
||||
// If the operation failed in the end, return all errors instead of just the last one
|
||||
|
|
|
@ -1,20 +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 { BaseRequestPolicy, RequestPolicy, RequestPolicyOptionsLike, RequestPolicyFactory } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyOptionsLike,
|
||||
RequestPolicyFactory,
|
||||
} from "./requestPolicy";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
import { HttpOperationResponse } from "../httpOperationResponse";
|
||||
import { Constants } from "../util/constants";
|
||||
import { delay } from "../util/utils";
|
||||
|
||||
type ResponseHandler = (httpRequest: WebResourceLike, response: HttpOperationResponse) => Promise<HttpOperationResponse>;
|
||||
type ResponseHandler = (
|
||||
httpRequest: WebResourceLike,
|
||||
response: HttpOperationResponse
|
||||
) => Promise<HttpOperationResponse>;
|
||||
const StatusCodes = Constants.HttpConstants.StatusCodes;
|
||||
|
||||
export function throttlingRetryPolicy(): RequestPolicyFactory {
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new ThrottlingRetryPolicy(nextPolicy, options);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -27,13 +35,17 @@ export function throttlingRetryPolicy(): RequestPolicyFactory {
|
|||
export class ThrottlingRetryPolicy extends BaseRequestPolicy {
|
||||
private _handleResponse: ResponseHandler;
|
||||
|
||||
constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike, _handleResponse?: ResponseHandler) {
|
||||
constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptionsLike,
|
||||
_handleResponse?: ResponseHandler
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
this._handleResponse = _handleResponse || this._defaultResponseHandler;
|
||||
}
|
||||
|
||||
public async sendRequest(httpRequest: WebResourceLike): Promise<HttpOperationResponse> {
|
||||
return this._nextPolicy.sendRequest(httpRequest.clone()).then(response => {
|
||||
return this._nextPolicy.sendRequest(httpRequest.clone()).then((response) => {
|
||||
if (response.status !== StatusCodes.TooManyRequests) {
|
||||
return response;
|
||||
} else {
|
||||
|
@ -42,11 +54,18 @@ export class ThrottlingRetryPolicy extends BaseRequestPolicy {
|
|||
});
|
||||
}
|
||||
|
||||
private async _defaultResponseHandler(httpRequest: WebResourceLike, httpResponse: HttpOperationResponse): Promise<HttpOperationResponse> {
|
||||
const retryAfterHeader: string | undefined = httpResponse.headers.get(Constants.HeaderConstants.RETRY_AFTER);
|
||||
private async _defaultResponseHandler(
|
||||
httpRequest: WebResourceLike,
|
||||
httpResponse: HttpOperationResponse
|
||||
): Promise<HttpOperationResponse> {
|
||||
const retryAfterHeader: string | undefined = httpResponse.headers.get(
|
||||
Constants.HeaderConstants.RETRY_AFTER
|
||||
);
|
||||
|
||||
if (retryAfterHeader) {
|
||||
const delayInMs: number | undefined = ThrottlingRetryPolicy.parseRetryAfterHeader(retryAfterHeader);
|
||||
const delayInMs: number | undefined = ThrottlingRetryPolicy.parseRetryAfterHeader(
|
||||
retryAfterHeader
|
||||
);
|
||||
if (delayInMs) {
|
||||
return delay(delayInMs).then((_: any) => this._nextPolicy.sendRequest(httpRequest));
|
||||
}
|
||||
|
|
|
@ -6,24 +6,35 @@ import { HttpOperationResponse } from "../httpOperationResponse";
|
|||
import { Constants } from "../util/constants";
|
||||
import { WebResourceLike } from "../webResource";
|
||||
import { getDefaultUserAgentKey, getPlatformSpecificData } from "./msRestUserAgentPolicy";
|
||||
import { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptionsLike } from "./requestPolicy";
|
||||
import {
|
||||
BaseRequestPolicy,
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./requestPolicy";
|
||||
|
||||
export type TelemetryInfo = { key?: string; value?: string };
|
||||
|
||||
function getRuntimeInfo(): TelemetryInfo[] {
|
||||
const msRestRuntime = {
|
||||
key: "ms-rest-js",
|
||||
value: Constants.msRestVersion
|
||||
value: Constants.msRestVersion,
|
||||
};
|
||||
|
||||
return [msRestRuntime];
|
||||
}
|
||||
|
||||
function getUserAgentString(telemetryInfo: TelemetryInfo[], keySeparator = " ", valueSeparator = "/"): string {
|
||||
return telemetryInfo.map(info => {
|
||||
const value = info.value ? `${valueSeparator}${info.value}` : "";
|
||||
return `${info.key}${value}`;
|
||||
}).join(keySeparator);
|
||||
function getUserAgentString(
|
||||
telemetryInfo: TelemetryInfo[],
|
||||
keySeparator = " ",
|
||||
valueSeparator = "/"
|
||||
): string {
|
||||
return telemetryInfo
|
||||
.map((info) => {
|
||||
const value = info.value ? `${valueSeparator}${info.value}` : "";
|
||||
return `${info.key}${value}`;
|
||||
})
|
||||
.join(keySeparator);
|
||||
}
|
||||
|
||||
export const getDefaultUserAgentHeaderName = getDefaultUserAgentKey;
|
||||
|
@ -36,18 +47,27 @@ export function getDefaultUserAgentValue(): string {
|
|||
}
|
||||
|
||||
export function userAgentPolicy(userAgentData?: TelemetryInfo): RequestPolicyFactory {
|
||||
const key: string = (!userAgentData || userAgentData.key == undefined) ? getDefaultUserAgentKey() : userAgentData.key;
|
||||
const value: string = (!userAgentData || userAgentData.value == undefined) ? getDefaultUserAgentValue() : userAgentData.value;
|
||||
const key: string =
|
||||
!userAgentData || userAgentData.key == undefined ? getDefaultUserAgentKey() : userAgentData.key;
|
||||
const value: string =
|
||||
!userAgentData || userAgentData.value == undefined
|
||||
? getDefaultUserAgentValue()
|
||||
: userAgentData.value;
|
||||
|
||||
return {
|
||||
create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
|
||||
return new UserAgentPolicy(nextPolicy, options, key, value);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class UserAgentPolicy extends BaseRequestPolicy {
|
||||
constructor(readonly _nextPolicy: RequestPolicy, readonly _options: RequestPolicyOptionsLike, protected headerKey: string, protected headerValue: string) {
|
||||
constructor(
|
||||
readonly _nextPolicy: RequestPolicy,
|
||||
readonly _options: RequestPolicyOptionsLike,
|
||||
protected headerKey: string,
|
||||
protected headerValue: string
|
||||
) {
|
||||
super(_nextPolicy, _options);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,16 +10,20 @@ import { URLBuilder } from "./url";
|
|||
import { HttpHeadersLike } from "./httpHeaders";
|
||||
|
||||
export type ProxyAgent = { isHttps: boolean; agent: http.Agent | https.Agent };
|
||||
export function createProxyAgent(requestUrl: string, proxySettings: ProxySettings, headers?: HttpHeadersLike): ProxyAgent {
|
||||
export function createProxyAgent(
|
||||
requestUrl: string,
|
||||
proxySettings: ProxySettings,
|
||||
headers?: HttpHeadersLike
|
||||
): ProxyAgent {
|
||||
const tunnelOptions: tunnel.HttpsOverHttpsOptions = {
|
||||
proxy: {
|
||||
host: URLBuilder.parse(proxySettings.host).getHost() as string,
|
||||
port: proxySettings.port,
|
||||
headers: (headers && headers.rawHeaders()) || {}
|
||||
}
|
||||
headers: (headers && headers.rawHeaders()) || {},
|
||||
},
|
||||
};
|
||||
|
||||
if ((proxySettings.username && proxySettings.password)) {
|
||||
if (proxySettings.username && proxySettings.password) {
|
||||
tunnelOptions.proxy!.proxyAuth = `${proxySettings.username}:${proxySettings.password}`;
|
||||
}
|
||||
|
||||
|
@ -30,13 +34,17 @@ export function createProxyAgent(requestUrl: string, proxySettings: ProxySetting
|
|||
|
||||
const proxyAgent = {
|
||||
isHttps: isRequestHttps,
|
||||
agent: createTunnel(isRequestHttps, isProxyHttps, tunnelOptions)
|
||||
agent: createTunnel(isRequestHttps, isProxyHttps, tunnelOptions),
|
||||
};
|
||||
|
||||
return proxyAgent;
|
||||
}
|
||||
|
||||
export function createTunnel(isRequestHttps: boolean, isProxyHttps: boolean, tunnelOptions: tunnel.HttpsOverHttpsOptions): http.Agent | https.Agent {
|
||||
export function createTunnel(
|
||||
isRequestHttps: boolean,
|
||||
isProxyHttps: boolean,
|
||||
tunnelOptions: tunnel.HttpsOverHttpsOptions
|
||||
): http.Agent | https.Agent {
|
||||
if (isRequestHttps && isProxyHttps) {
|
||||
return tunnel.httpsOverHttps(tunnelOptions);
|
||||
} else if (isRequestHttps && !isProxyHttps) {
|
||||
|
|
|
@ -14,7 +14,14 @@ export class RestError extends Error {
|
|||
request?: WebResourceLike;
|
||||
response?: HttpOperationResponse;
|
||||
body?: any;
|
||||
constructor(message: string, code?: string, statusCode?: number, request?: WebResourceLike, response?: HttpOperationResponse, body?: any) {
|
||||
constructor(
|
||||
message: string,
|
||||
code?: string,
|
||||
statusCode?: number,
|
||||
request?: WebResourceLike,
|
||||
response?: HttpOperationResponse,
|
||||
body?: any
|
||||
) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.statusCode = statusCode;
|
||||
|
|
|
@ -5,13 +5,18 @@ import * as base64 from "./util/base64";
|
|||
import * as utils from "./util/utils";
|
||||
|
||||
export class Serializer {
|
||||
constructor(public readonly modelMappers: { [key: string]: any } = {}, public readonly isXML?: boolean) { }
|
||||
constructor(
|
||||
public readonly modelMappers: { [key: string]: any } = {},
|
||||
public readonly isXML?: boolean
|
||||
) {}
|
||||
|
||||
validateConstraints(mapper: Mapper, value: any, objectName: string): void {
|
||||
const failValidation = (constraintName: keyof MapperConstraints, constraintValue: any) => {
|
||||
throw new Error(`"${objectName}" with value "${value}" should satisfy the constraint "${constraintName}": ${constraintValue}.`);
|
||||
throw new Error(
|
||||
`"${objectName}" with value "${value}" should satisfy the constraint "${constraintName}": ${constraintValue}.`
|
||||
);
|
||||
};
|
||||
if (mapper.constraints && (value != undefined)) {
|
||||
if (mapper.constraints && value != undefined) {
|
||||
const {
|
||||
ExclusiveMaximum,
|
||||
ExclusiveMinimum,
|
||||
|
@ -23,7 +28,7 @@ export class Serializer {
|
|||
MinLength,
|
||||
MultipleOf,
|
||||
Pattern,
|
||||
UniqueItems
|
||||
UniqueItems,
|
||||
} = mapper.constraints;
|
||||
if (ExclusiveMaximum != undefined && value >= ExclusiveMaximum) {
|
||||
failValidation("ExclusiveMaximum", ExclusiveMaximum);
|
||||
|
@ -54,11 +59,14 @@ export class Serializer {
|
|||
}
|
||||
if (Pattern) {
|
||||
const pattern: RegExp = typeof Pattern === "string" ? new RegExp(Pattern) : Pattern;
|
||||
if ((typeof value !== "string") || (value.match(pattern) === null)) {
|
||||
if (typeof value !== "string" || value.match(pattern) === null) {
|
||||
failValidation("Pattern", Pattern);
|
||||
}
|
||||
}
|
||||
if (UniqueItems && value.some((item: any, i: number, ar: Array<any>) => ar.indexOf(item) !== i)) {
|
||||
if (
|
||||
UniqueItems &&
|
||||
value.some((item: any, i: number, ar: Array<any>) => ar.indexOf(item) !== i)
|
||||
) {
|
||||
failValidation("UniqueItems", UniqueItems);
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +89,7 @@ export class Serializer {
|
|||
if (!objectName) {
|
||||
objectName = mapper.serializedName!;
|
||||
}
|
||||
if (mapperType.match(/^Sequence$/ig) !== null) {
|
||||
if (mapperType.match(/^Sequence$/gi) !== null) {
|
||||
payload = [];
|
||||
}
|
||||
|
||||
|
@ -116,24 +124,26 @@ export class Serializer {
|
|||
} else {
|
||||
// Validate Constraints if any
|
||||
this.validateConstraints(mapper, object, objectName);
|
||||
if (mapperType.match(/^any$/ig) !== null) {
|
||||
if (mapperType.match(/^any$/gi) !== null) {
|
||||
payload = object;
|
||||
} else if (mapperType.match(/^(Number|String|Boolean|Object|Stream|Uuid)$/ig) !== null) {
|
||||
} else if (mapperType.match(/^(Number|String|Boolean|Object|Stream|Uuid)$/gi) !== null) {
|
||||
payload = serializeBasicTypes(mapperType, objectName, object);
|
||||
} else if (mapperType.match(/^Enum$/ig) !== null) {
|
||||
} else if (mapperType.match(/^Enum$/gi) !== null) {
|
||||
const enumMapper: EnumMapper = mapper as EnumMapper;
|
||||
payload = serializeEnumType(objectName, enumMapper.type.allowedValues, object);
|
||||
} else if (mapperType.match(/^(Date|DateTime|TimeSpan|DateTimeRfc1123|UnixTime)$/ig) !== null) {
|
||||
} else if (
|
||||
mapperType.match(/^(Date|DateTime|TimeSpan|DateTimeRfc1123|UnixTime)$/gi) !== null
|
||||
) {
|
||||
payload = serializeDateTypes(mapperType, object, objectName);
|
||||
} else if (mapperType.match(/^ByteArray$/ig) !== null) {
|
||||
} else if (mapperType.match(/^ByteArray$/gi) !== null) {
|
||||
payload = serializeByteArrayType(objectName, object);
|
||||
} else if (mapperType.match(/^Base64Url$/ig) !== null) {
|
||||
} else if (mapperType.match(/^Base64Url$/gi) !== null) {
|
||||
payload = serializeBase64UrlType(objectName, object);
|
||||
} else if (mapperType.match(/^Sequence$/ig) !== null) {
|
||||
} else if (mapperType.match(/^Sequence$/gi) !== null) {
|
||||
payload = serializeSequenceType(this, mapper as SequenceMapper, object, objectName);
|
||||
} else if (mapperType.match(/^Dictionary$/ig) !== null) {
|
||||
} else if (mapperType.match(/^Dictionary$/gi) !== null) {
|
||||
payload = serializeDictionaryType(this, mapper as DictionaryMapper, object, objectName);
|
||||
} else if (mapperType.match(/^Composite$/ig) !== null) {
|
||||
} else if (mapperType.match(/^Composite$/gi) !== null) {
|
||||
payload = serializeCompositeType(this, mapper as CompositeMapper, object, objectName);
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +182,7 @@ export class Serializer {
|
|||
objectName = mapper.serializedName!;
|
||||
}
|
||||
|
||||
if (mapperType.match(/^Composite$/ig) !== null) {
|
||||
if (mapperType.match(/^Composite$/gi) !== null) {
|
||||
payload = deserializeCompositeType(this, mapper as CompositeMapper, responseBody, objectName);
|
||||
} else {
|
||||
if (this.isXML) {
|
||||
|
@ -186,12 +196,12 @@ export class Serializer {
|
|||
}
|
||||
}
|
||||
|
||||
if (mapperType.match(/^Number$/ig) !== null) {
|
||||
if (mapperType.match(/^Number$/gi) !== null) {
|
||||
payload = parseFloat(responseBody);
|
||||
if (isNaN(payload)) {
|
||||
payload = responseBody;
|
||||
}
|
||||
} else if (mapperType.match(/^Boolean$/ig) !== null) {
|
||||
} else if (mapperType.match(/^Boolean$/gi) !== null) {
|
||||
if (responseBody === "true") {
|
||||
payload = true;
|
||||
} else if (responseBody === "false") {
|
||||
|
@ -199,20 +209,25 @@ export class Serializer {
|
|||
} else {
|
||||
payload = responseBody;
|
||||
}
|
||||
} else if (mapperType.match(/^(String|Enum|Object|Stream|Uuid|TimeSpan|any)$/ig) !== null) {
|
||||
} else if (mapperType.match(/^(String|Enum|Object|Stream|Uuid|TimeSpan|any)$/gi) !== null) {
|
||||
payload = responseBody;
|
||||
} else if (mapperType.match(/^(Date|DateTime|DateTimeRfc1123)$/ig) !== null) {
|
||||
} else if (mapperType.match(/^(Date|DateTime|DateTimeRfc1123)$/gi) !== null) {
|
||||
payload = new Date(responseBody);
|
||||
} else if (mapperType.match(/^UnixTime$/ig) !== null) {
|
||||
} else if (mapperType.match(/^UnixTime$/gi) !== null) {
|
||||
payload = unixTimeToDate(responseBody);
|
||||
} else if (mapperType.match(/^ByteArray$/ig) !== null) {
|
||||
} else if (mapperType.match(/^ByteArray$/gi) !== null) {
|
||||
payload = base64.decodeString(responseBody);
|
||||
} else if (mapperType.match(/^Base64Url$/ig) !== null) {
|
||||
} else if (mapperType.match(/^Base64Url$/gi) !== null) {
|
||||
payload = base64UrlToByteArray(responseBody);
|
||||
} else if (mapperType.match(/^Sequence$/ig) !== null) {
|
||||
} else if (mapperType.match(/^Sequence$/gi) !== null) {
|
||||
payload = deserializeSequenceType(this, mapper as SequenceMapper, responseBody, objectName);
|
||||
} else if (mapperType.match(/^Dictionary$/ig) !== null) {
|
||||
payload = deserializeDictionaryType(this, mapper as DictionaryMapper, responseBody, objectName);
|
||||
} else if (mapperType.match(/^Dictionary$/gi) !== null) {
|
||||
payload = deserializeDictionaryType(
|
||||
this,
|
||||
mapper as DictionaryMapper,
|
||||
responseBody,
|
||||
objectName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,7 +241,7 @@ export class Serializer {
|
|||
|
||||
function trimEnd(str: string, ch: string) {
|
||||
let len = str.length;
|
||||
while ((len - 1) >= 0 && str[len - 1] === ch) {
|
||||
while (len - 1 >= 0 && str[len - 1] === ch) {
|
||||
--len;
|
||||
}
|
||||
return str.substr(0, len);
|
||||
|
@ -298,30 +313,36 @@ function unixTimeToDate(n: number): Date | undefined {
|
|||
|
||||
function serializeBasicTypes(typeName: string, objectName: string, value: any): any {
|
||||
if (value !== null && value !== undefined) {
|
||||
if (typeName.match(/^Number$/ig) !== null) {
|
||||
if (typeName.match(/^Number$/gi) !== null) {
|
||||
if (typeof value !== "number") {
|
||||
throw new Error(`${objectName} with value ${value} must be of type number.`);
|
||||
}
|
||||
} else if (typeName.match(/^String$/ig) !== null) {
|
||||
} else if (typeName.match(/^String$/gi) !== null) {
|
||||
if (typeof value.valueOf() !== "string") {
|
||||
throw new Error(`${objectName} with value "${value}" must be of type string.`);
|
||||
}
|
||||
} else if (typeName.match(/^Uuid$/ig) !== null) {
|
||||
} else if (typeName.match(/^Uuid$/gi) !== null) {
|
||||
if (!(typeof value.valueOf() === "string" && utils.isValidUuid(value))) {
|
||||
throw new Error(`${objectName} with value "${value}" must be of type string and a valid uuid.`);
|
||||
throw new Error(
|
||||
`${objectName} with value "${value}" must be of type string and a valid uuid.`
|
||||
);
|
||||
}
|
||||
} else if (typeName.match(/^Boolean$/ig) !== null) {
|
||||
} else if (typeName.match(/^Boolean$/gi) !== null) {
|
||||
if (typeof value !== "boolean") {
|
||||
throw new Error(`${objectName} with value ${value} must be of type boolean.`);
|
||||
}
|
||||
} else if (typeName.match(/^Stream$/ig) !== null) {
|
||||
} else if (typeName.match(/^Stream$/gi) !== null) {
|
||||
const objectType = typeof value;
|
||||
if (objectType !== "string" &&
|
||||
if (
|
||||
objectType !== "string" &&
|
||||
objectType !== "function" &&
|
||||
!(value instanceof ArrayBuffer) &&
|
||||
!ArrayBuffer.isView(value) &&
|
||||
!(typeof Blob === "function" && value instanceof Blob)) {
|
||||
throw new Error(`${objectName} must be a string, Blob, ArrayBuffer, ArrayBufferView, or a function returning NodeJS.ReadableStream.`);
|
||||
!(typeof Blob === "function" && value instanceof Blob)
|
||||
) {
|
||||
throw new Error(
|
||||
`${objectName} must be a string, Blob, ArrayBuffer, ArrayBufferView, or a function returning NodeJS.ReadableStream.`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -330,7 +351,9 @@ function serializeBasicTypes(typeName: string, objectName: string, value: any):
|
|||
|
||||
function serializeEnumType(objectName: string, allowedValues: Array<any>, value: any): any {
|
||||
if (!allowedValues) {
|
||||
throw new Error(`Please provide a set of allowedValues to validate ${objectName} as an Enum Type.`);
|
||||
throw new Error(
|
||||
`Please provide a set of allowedValues to validate ${objectName} as an Enum Type.`
|
||||
);
|
||||
}
|
||||
const isPresent = allowedValues.some((item) => {
|
||||
if (typeof item.valueOf() === "string") {
|
||||
|
@ -339,7 +362,11 @@ function serializeEnumType(objectName: string, allowedValues: Array<any>, value:
|
|||
return item === value;
|
||||
});
|
||||
if (!isPresent) {
|
||||
throw new Error(`${value} is not a valid value for ${objectName}. The valid values are: ${JSON.stringify(allowedValues)}.`);
|
||||
throw new Error(
|
||||
`${value} is not a valid value for ${objectName}. The valid values are: ${JSON.stringify(
|
||||
allowedValues
|
||||
)}.`
|
||||
);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
@ -366,34 +393,57 @@ function serializeBase64UrlType(objectName: string, value: any): any {
|
|||
|
||||
function serializeDateTypes(typeName: string, value: any, objectName: string) {
|
||||
if (value != undefined) {
|
||||
if (typeName.match(/^Date$/ig) !== null) {
|
||||
if (!(value instanceof Date ||
|
||||
(typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) {
|
||||
if (typeName.match(/^Date$/gi) !== null) {
|
||||
if (
|
||||
!(
|
||||
value instanceof Date ||
|
||||
(typeof value.valueOf() === "string" && !isNaN(Date.parse(value)))
|
||||
)
|
||||
) {
|
||||
throw new Error(`${objectName} must be an instanceof Date or a string in ISO8601 format.`);
|
||||
}
|
||||
value = (value instanceof Date) ? value.toISOString().substring(0, 10) : new Date(value).toISOString().substring(0, 10);
|
||||
} else if (typeName.match(/^DateTime$/ig) !== null) {
|
||||
if (!(value instanceof Date ||
|
||||
(typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) {
|
||||
value =
|
||||
value instanceof Date
|
||||
? value.toISOString().substring(0, 10)
|
||||
: new Date(value).toISOString().substring(0, 10);
|
||||
} else if (typeName.match(/^DateTime$/gi) !== null) {
|
||||
if (
|
||||
!(
|
||||
value instanceof Date ||
|
||||
(typeof value.valueOf() === "string" && !isNaN(Date.parse(value)))
|
||||
)
|
||||
) {
|
||||
throw new Error(`${objectName} must be an instanceof Date or a string in ISO8601 format.`);
|
||||
}
|
||||
value = (value instanceof Date) ? value.toISOString() : new Date(value).toISOString();
|
||||
} else if (typeName.match(/^DateTimeRfc1123$/ig) !== null) {
|
||||
if (!(value instanceof Date ||
|
||||
(typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) {
|
||||
value = value instanceof Date ? value.toISOString() : new Date(value).toISOString();
|
||||
} else if (typeName.match(/^DateTimeRfc1123$/gi) !== null) {
|
||||
if (
|
||||
!(
|
||||
value instanceof Date ||
|
||||
(typeof value.valueOf() === "string" && !isNaN(Date.parse(value)))
|
||||
)
|
||||
) {
|
||||
throw new Error(`${objectName} must be an instanceof Date or a string in RFC-1123 format.`);
|
||||
}
|
||||
value = (value instanceof Date) ? value.toUTCString() : new Date(value).toUTCString();
|
||||
} else if (typeName.match(/^UnixTime$/ig) !== null) {
|
||||
if (!(value instanceof Date ||
|
||||
(typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) {
|
||||
throw new Error(`${objectName} must be an instanceof Date or a string in RFC-1123/ISO8601 format ` +
|
||||
`for it to be serialized in UnixTime/Epoch format.`);
|
||||
value = value instanceof Date ? value.toUTCString() : new Date(value).toUTCString();
|
||||
} else if (typeName.match(/^UnixTime$/gi) !== null) {
|
||||
if (
|
||||
!(
|
||||
value instanceof Date ||
|
||||
(typeof value.valueOf() === "string" && !isNaN(Date.parse(value)))
|
||||
)
|
||||
) {
|
||||
throw new Error(
|
||||
`${objectName} must be an instanceof Date or a string in RFC-1123/ISO8601 format ` +
|
||||
`for it to be serialized in UnixTime/Epoch format.`
|
||||
);
|
||||
}
|
||||
value = dateToUnixTime(value);
|
||||
} else if (typeName.match(/^TimeSpan$/ig) !== null) {
|
||||
} else if (typeName.match(/^TimeSpan$/gi) !== null) {
|
||||
if (!utils.isDuration(value)) {
|
||||
throw new Error(`${objectName} must be a string in ISO 8601 format. Instead was "${value}".`);
|
||||
throw new Error(
|
||||
`${objectName} must be a string in ISO 8601 format. Instead was "${value}".`
|
||||
);
|
||||
}
|
||||
value = value;
|
||||
}
|
||||
|
@ -401,14 +451,21 @@ function serializeDateTypes(typeName: string, value: any, objectName: string) {
|
|||
return value;
|
||||
}
|
||||
|
||||
function serializeSequenceType(serializer: Serializer, mapper: SequenceMapper, object: any, objectName: string) {
|
||||
function serializeSequenceType(
|
||||
serializer: Serializer,
|
||||
mapper: SequenceMapper,
|
||||
object: any,
|
||||
objectName: string
|
||||
) {
|
||||
if (!Array.isArray(object)) {
|
||||
throw new Error(`${objectName} must be of type Array.`);
|
||||
}
|
||||
const elementType = mapper.type.element;
|
||||
if (!elementType || typeof elementType !== "object") {
|
||||
throw new Error(`element" metadata for an Array must be defined in the ` +
|
||||
`mapper and it must of type "object" in ${objectName}.`);
|
||||
throw new Error(
|
||||
`element" metadata for an Array must be defined in the ` +
|
||||
`mapper and it must of type "object" in ${objectName}.`
|
||||
);
|
||||
}
|
||||
const tempArray = [];
|
||||
for (let i = 0; i < object.length; i++) {
|
||||
|
@ -417,14 +474,21 @@ function serializeSequenceType(serializer: Serializer, mapper: SequenceMapper, o
|
|||
return tempArray;
|
||||
}
|
||||
|
||||
function serializeDictionaryType(serializer: Serializer, mapper: DictionaryMapper, object: any, objectName: string) {
|
||||
function serializeDictionaryType(
|
||||
serializer: Serializer,
|
||||
mapper: DictionaryMapper,
|
||||
object: any,
|
||||
objectName: string
|
||||
) {
|
||||
if (typeof object !== "object") {
|
||||
throw new Error(`${objectName} must be of type object.`);
|
||||
}
|
||||
const valueType = mapper.type.value;
|
||||
if (!valueType || typeof valueType !== "object") {
|
||||
throw new Error(`"value" metadata for a Dictionary must be defined in the ` +
|
||||
`mapper and it must of type "object" in ${objectName}.`);
|
||||
throw new Error(
|
||||
`"value" metadata for a Dictionary must be defined in the ` +
|
||||
`mapper and it must of type "object" in ${objectName}.`
|
||||
);
|
||||
}
|
||||
const tempDictionary: { [key: string]: any } = {};
|
||||
for (const key of Object.keys(object)) {
|
||||
|
@ -438,12 +502,22 @@ function serializeDictionaryType(serializer: Serializer, mapper: DictionaryMappe
|
|||
* @param serializer the serializer containing the entire set of mappers
|
||||
* @param mapper the composite mapper to resolve
|
||||
*/
|
||||
function resolveModelProperties(serializer: Serializer, mapper: CompositeMapper, objectName: string): { [propertyName: string]: Mapper } {
|
||||
function resolveModelProperties(
|
||||
serializer: Serializer,
|
||||
mapper: CompositeMapper,
|
||||
objectName: string
|
||||
): { [propertyName: string]: Mapper } {
|
||||
let modelProps = mapper.type.modelProperties;
|
||||
if (!modelProps) {
|
||||
const className = mapper.type.className;
|
||||
if (!className) {
|
||||
throw new Error(`Class name for model "${objectName}" is not provided in the mapper "${JSON.stringify(mapper, undefined, 2)}".`);
|
||||
throw new Error(
|
||||
`Class name for model "${objectName}" is not provided in the mapper "${JSON.stringify(
|
||||
mapper,
|
||||
undefined,
|
||||
2
|
||||
)}".`
|
||||
);
|
||||
}
|
||||
|
||||
const modelMapper = serializer.modelMappers[className];
|
||||
|
@ -452,15 +526,24 @@ function resolveModelProperties(serializer: Serializer, mapper: CompositeMapper,
|
|||
}
|
||||
modelProps = modelMapper.type.modelProperties;
|
||||
if (!modelProps) {
|
||||
throw new Error(`modelProperties cannot be null or undefined in the ` +
|
||||
`mapper "${JSON.stringify(modelMapper)}" of type "${className}" for object "${objectName}".`);
|
||||
throw new Error(
|
||||
`modelProperties cannot be null or undefined in the ` +
|
||||
`mapper "${JSON.stringify(
|
||||
modelMapper
|
||||
)}" of type "${className}" for object "${objectName}".`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return modelProps;
|
||||
}
|
||||
|
||||
function serializeCompositeType(serializer: Serializer, mapper: CompositeMapper, object: any, objectName: string) {
|
||||
function serializeCompositeType(
|
||||
serializer: Serializer,
|
||||
mapper: CompositeMapper,
|
||||
object: any,
|
||||
objectName: string
|
||||
) {
|
||||
if (getPolymorphicDiscriminatorRecursively(serializer, mapper)) {
|
||||
mapper = getPolymorphicMapper(serializer, mapper, object, "clientName");
|
||||
}
|
||||
|
@ -488,7 +571,7 @@ function serializeCompositeType(serializer: Serializer, mapper: CompositeMapper,
|
|||
|
||||
for (const pathName of paths) {
|
||||
const childObject = parentObject[pathName];
|
||||
if ((childObject == undefined) && (object[key] != undefined)) {
|
||||
if (childObject == undefined && object[key] != undefined) {
|
||||
parentObject[pathName] = {};
|
||||
}
|
||||
parentObject = parentObject[pathName];
|
||||
|
@ -496,17 +579,26 @@ function serializeCompositeType(serializer: Serializer, mapper: CompositeMapper,
|
|||
}
|
||||
|
||||
if (parentObject != undefined) {
|
||||
const propertyObjectName = propertyMapper.serializedName !== ""
|
||||
? objectName + "." + propertyMapper.serializedName
|
||||
: objectName;
|
||||
const propertyObjectName =
|
||||
propertyMapper.serializedName !== ""
|
||||
? objectName + "." + propertyMapper.serializedName
|
||||
: objectName;
|
||||
|
||||
let toSerialize = object[key];
|
||||
const polymorphicDiscriminator = getPolymorphicDiscriminatorRecursively(serializer, mapper);
|
||||
if (polymorphicDiscriminator && polymorphicDiscriminator.clientName === key && toSerialize == undefined) {
|
||||
if (
|
||||
polymorphicDiscriminator &&
|
||||
polymorphicDiscriminator.clientName === key &&
|
||||
toSerialize == undefined
|
||||
) {
|
||||
toSerialize = mapper.serializedName;
|
||||
}
|
||||
|
||||
const serializedValue = serializer.serialize(propertyMapper, toSerialize, propertyObjectName);
|
||||
const serializedValue = serializer.serialize(
|
||||
propertyMapper,
|
||||
toSerialize,
|
||||
propertyObjectName
|
||||
);
|
||||
if (serializedValue !== undefined && propName != undefined) {
|
||||
if (propertyMapper.xmlIsAttribute) {
|
||||
// $ is the key attributes are kept under in xml2js.
|
||||
|
@ -527,9 +619,13 @@ function serializeCompositeType(serializer: Serializer, mapper: CompositeMapper,
|
|||
if (additionalPropertiesMapper) {
|
||||
const propNames = Object.keys(modelProps);
|
||||
for (const clientPropName in object) {
|
||||
const isAdditionalProperty = propNames.every(pn => pn !== clientPropName);
|
||||
const isAdditionalProperty = propNames.every((pn) => pn !== clientPropName);
|
||||
if (isAdditionalProperty) {
|
||||
payload[clientPropName] = serializer.serialize(additionalPropertiesMapper, object[clientPropName], objectName + '["' + clientPropName + '"]');
|
||||
payload[clientPropName] = serializer.serialize(
|
||||
additionalPropertiesMapper,
|
||||
object[clientPropName],
|
||||
objectName + '["' + clientPropName + '"]'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -543,7 +639,12 @@ function isSpecialXmlProperty(propertyName: string): boolean {
|
|||
return ["$", "_"].includes(propertyName);
|
||||
}
|
||||
|
||||
function deserializeCompositeType(serializer: Serializer, mapper: CompositeMapper, responseBody: any, objectName: string): any {
|
||||
function deserializeCompositeType(
|
||||
serializer: Serializer,
|
||||
mapper: CompositeMapper,
|
||||
responseBody: any,
|
||||
objectName: string
|
||||
): any {
|
||||
if (getPolymorphicDiscriminatorRecursively(serializer, mapper)) {
|
||||
mapper = getPolymorphicMapper(serializer, mapper, responseBody, "serializedName");
|
||||
}
|
||||
|
@ -567,7 +668,11 @@ function deserializeCompositeType(serializer: Serializer, mapper: CompositeMappe
|
|||
const dictionary: any = {};
|
||||
for (const headerKey of Object.keys(responseBody)) {
|
||||
if (headerKey.startsWith(headerCollectionPrefix)) {
|
||||
dictionary[headerKey.substring(headerCollectionPrefix.length)] = serializer.deserialize((propertyMapper as DictionaryMapper).type.value, responseBody[headerKey], propertyObjectName);
|
||||
dictionary[headerKey.substring(headerCollectionPrefix.length)] = serializer.deserialize(
|
||||
(propertyMapper as DictionaryMapper).type.value,
|
||||
responseBody[headerKey],
|
||||
propertyObjectName
|
||||
);
|
||||
}
|
||||
|
||||
handledPropertyNames.push(headerKey);
|
||||
|
@ -575,7 +680,11 @@ function deserializeCompositeType(serializer: Serializer, mapper: CompositeMappe
|
|||
instance[key] = dictionary;
|
||||
} else if (serializer.isXML) {
|
||||
if (propertyMapper.xmlIsAttribute && responseBody.$) {
|
||||
instance[key] = serializer.deserialize(propertyMapper, responseBody.$[xmlName!], propertyObjectName);
|
||||
instance[key] = serializer.deserialize(
|
||||
propertyMapper,
|
||||
responseBody.$[xmlName!],
|
||||
propertyObjectName
|
||||
);
|
||||
} else {
|
||||
const propertyName = xmlElementName || xmlName || serializedName;
|
||||
let unwrappedProperty = responseBody[propertyName!];
|
||||
|
@ -588,7 +697,11 @@ function deserializeCompositeType(serializer: Serializer, mapper: CompositeMappe
|
|||
unwrappedProperty = [];
|
||||
}
|
||||
}
|
||||
instance[key] = serializer.deserialize(propertyMapper, unwrappedProperty, propertyObjectName);
|
||||
instance[key] = serializer.deserialize(
|
||||
propertyMapper,
|
||||
unwrappedProperty,
|
||||
propertyObjectName
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// deserialize the property if it is present in the provided responseBody instance
|
||||
|
@ -610,7 +723,11 @@ function deserializeCompositeType(serializer: Serializer, mapper: CompositeMappe
|
|||
// the clientName transformation of the polymorphicDiscriminator (ex: "fishtype") and
|
||||
// the transformation of model property name (ex: "fishtype") is done consistently.
|
||||
// Hence, it is a safer bet to rely on the clientName of the polymorphicDiscriminator.
|
||||
if (polymorphicDiscriminator && key === polymorphicDiscriminator.clientName && propertyInstance == undefined) {
|
||||
if (
|
||||
polymorphicDiscriminator &&
|
||||
key === polymorphicDiscriminator.clientName &&
|
||||
propertyInstance == undefined
|
||||
) {
|
||||
propertyInstance = mapper.serializedName;
|
||||
}
|
||||
|
||||
|
@ -620,7 +737,11 @@ function deserializeCompositeType(serializer: Serializer, mapper: CompositeMappe
|
|||
propertyInstance = responseBody[key];
|
||||
instance = serializer.deserialize(propertyMapper, propertyInstance, propertyObjectName);
|
||||
} else if (propertyInstance !== undefined || propertyMapper.defaultValue !== undefined) {
|
||||
serializedValue = serializer.deserialize(propertyMapper, propertyInstance, propertyObjectName);
|
||||
serializedValue = serializer.deserialize(
|
||||
propertyMapper,
|
||||
propertyInstance,
|
||||
propertyObjectName
|
||||
);
|
||||
instance[key] = serializedValue;
|
||||
}
|
||||
}
|
||||
|
@ -640,12 +761,20 @@ function deserializeCompositeType(serializer: Serializer, mapper: CompositeMappe
|
|||
|
||||
for (const responsePropName in responseBody) {
|
||||
if (isAdditionalProperty(responsePropName)) {
|
||||
instance[responsePropName] = serializer.deserialize(additionalPropertiesMapper, responseBody[responsePropName], objectName + '["' + responsePropName + '"]');
|
||||
instance[responsePropName] = serializer.deserialize(
|
||||
additionalPropertiesMapper,
|
||||
responseBody[responsePropName],
|
||||
objectName + '["' + responsePropName + '"]'
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (responseBody) {
|
||||
for (const key of Object.keys(responseBody)) {
|
||||
if (instance[key] === undefined && !handledPropertyNames.includes(key) && !isSpecialXmlProperty(key)) {
|
||||
if (
|
||||
instance[key] === undefined &&
|
||||
!handledPropertyNames.includes(key) &&
|
||||
!isSpecialXmlProperty(key)
|
||||
) {
|
||||
instance[key] = responseBody[key];
|
||||
}
|
||||
}
|
||||
|
@ -654,12 +783,19 @@ function deserializeCompositeType(serializer: Serializer, mapper: CompositeMappe
|
|||
return instance;
|
||||
}
|
||||
|
||||
function deserializeDictionaryType(serializer: Serializer, mapper: DictionaryMapper, responseBody: any, objectName: string): any {
|
||||
function deserializeDictionaryType(
|
||||
serializer: Serializer,
|
||||
mapper: DictionaryMapper,
|
||||
responseBody: any,
|
||||
objectName: string
|
||||
): any {
|
||||
/*jshint validthis: true */
|
||||
const value = mapper.type.value;
|
||||
if (!value || typeof value !== "object") {
|
||||
throw new Error(`"value" metadata for a Dictionary must be defined in the ` +
|
||||
`mapper and it must of type "object" in ${objectName}`);
|
||||
throw new Error(
|
||||
`"value" metadata for a Dictionary must be defined in the ` +
|
||||
`mapper and it must of type "object" in ${objectName}`
|
||||
);
|
||||
}
|
||||
if (responseBody) {
|
||||
const tempDictionary: { [key: string]: any } = {};
|
||||
|
@ -671,12 +807,19 @@ function deserializeDictionaryType(serializer: Serializer, mapper: DictionaryMap
|
|||
return responseBody;
|
||||
}
|
||||
|
||||
function deserializeSequenceType(serializer: Serializer, mapper: SequenceMapper, responseBody: any, objectName: string): any {
|
||||
function deserializeSequenceType(
|
||||
serializer: Serializer,
|
||||
mapper: SequenceMapper,
|
||||
responseBody: any,
|
||||
objectName: string
|
||||
): any {
|
||||
/*jshint validthis: true */
|
||||
const element = mapper.type.element;
|
||||
if (!element || typeof element !== "object") {
|
||||
throw new Error(`element" metadata for an Array must be defined in the ` +
|
||||
`mapper and it must of type "object" in ${objectName}`);
|
||||
throw new Error(
|
||||
`element" metadata for an Array must be defined in the ` +
|
||||
`mapper and it must of type "object" in ${objectName}`
|
||||
);
|
||||
}
|
||||
if (responseBody) {
|
||||
if (!Array.isArray(responseBody)) {
|
||||
|
@ -693,7 +836,12 @@ function deserializeSequenceType(serializer: Serializer, mapper: SequenceMapper,
|
|||
return responseBody;
|
||||
}
|
||||
|
||||
function getPolymorphicMapper(serializer: Serializer, mapper: CompositeMapper, object: any, polymorphicPropertyName: "clientName" | "serializedName"): CompositeMapper {
|
||||
function getPolymorphicMapper(
|
||||
serializer: Serializer,
|
||||
mapper: CompositeMapper,
|
||||
object: any,
|
||||
polymorphicPropertyName: "clientName" | "serializedName"
|
||||
): CompositeMapper {
|
||||
const polymorphicDiscriminator = getPolymorphicDiscriminatorRecursively(serializer, mapper);
|
||||
if (polymorphicDiscriminator) {
|
||||
const discriminatorName = polymorphicDiscriminator[polymorphicPropertyName];
|
||||
|
@ -701,9 +849,10 @@ function getPolymorphicMapper(serializer: Serializer, mapper: CompositeMapper, o
|
|||
const discriminatorValue = object[discriminatorName];
|
||||
if (discriminatorValue != undefined) {
|
||||
const typeName = mapper.type.uberParent || mapper.type.className;
|
||||
const indexDiscriminator = discriminatorValue === typeName
|
||||
? discriminatorValue
|
||||
: typeName + "." + discriminatorValue;
|
||||
const indexDiscriminator =
|
||||
discriminatorValue === typeName
|
||||
? discriminatorValue
|
||||
: typeName + "." + discriminatorValue;
|
||||
const polymorphicMapper = serializer.modelMappers.discriminators[indexDiscriminator];
|
||||
if (polymorphicMapper) {
|
||||
mapper = polymorphicMapper;
|
||||
|
@ -714,14 +863,23 @@ function getPolymorphicMapper(serializer: Serializer, mapper: CompositeMapper, o
|
|||
return mapper;
|
||||
}
|
||||
|
||||
function getPolymorphicDiscriminatorRecursively(serializer: Serializer, mapper: CompositeMapper): PolymorphicDiscriminator | undefined {
|
||||
return mapper.type.polymorphicDiscriminator
|
||||
|| getPolymorphicDiscriminatorSafely(serializer, mapper.type.uberParent)
|
||||
|| getPolymorphicDiscriminatorSafely(serializer, mapper.type.className);
|
||||
function getPolymorphicDiscriminatorRecursively(
|
||||
serializer: Serializer,
|
||||
mapper: CompositeMapper
|
||||
): PolymorphicDiscriminator | undefined {
|
||||
return (
|
||||
mapper.type.polymorphicDiscriminator ||
|
||||
getPolymorphicDiscriminatorSafely(serializer, mapper.type.uberParent) ||
|
||||
getPolymorphicDiscriminatorSafely(serializer, mapper.type.className)
|
||||
);
|
||||
}
|
||||
|
||||
function getPolymorphicDiscriminatorSafely(serializer: Serializer, typeName?: string) {
|
||||
return (typeName && serializer.modelMappers[typeName] && serializer.modelMappers[typeName].type.polymorphicDiscriminator);
|
||||
return (
|
||||
typeName &&
|
||||
serializer.modelMappers[typeName] &&
|
||||
serializer.modelMappers[typeName].type.polymorphicDiscriminator
|
||||
);
|
||||
}
|
||||
|
||||
export interface MapperConstraints {
|
||||
|
@ -738,23 +896,29 @@ export interface MapperConstraints {
|
|||
MultipleOf?: number;
|
||||
}
|
||||
|
||||
export type MapperType = SimpleMapperType | CompositeMapperType | SequenceMapperType | DictionaryMapperType | EnumMapperType;
|
||||
export type MapperType =
|
||||
| SimpleMapperType
|
||||
| CompositeMapperType
|
||||
| SequenceMapperType
|
||||
| DictionaryMapperType
|
||||
| EnumMapperType;
|
||||
|
||||
export interface SimpleMapperType {
|
||||
name: "Base64Url"
|
||||
| "Boolean"
|
||||
| "ByteArray"
|
||||
| "Date"
|
||||
| "DateTime"
|
||||
| "DateTimeRfc1123"
|
||||
| "Object"
|
||||
| "Stream"
|
||||
| "String"
|
||||
| "TimeSpan"
|
||||
| "UnixTime"
|
||||
| "Uuid"
|
||||
| "Number"
|
||||
| "any";
|
||||
name:
|
||||
| "Base64Url"
|
||||
| "Boolean"
|
||||
| "ByteArray"
|
||||
| "Date"
|
||||
| "DateTime"
|
||||
| "DateTimeRfc1123"
|
||||
| "Object"
|
||||
| "Stream"
|
||||
| "String"
|
||||
| "TimeSpan"
|
||||
| "UnixTime"
|
||||
| "Uuid"
|
||||
| "Number"
|
||||
| "any";
|
||||
}
|
||||
|
||||
export interface CompositeMapperType {
|
||||
|
@ -838,11 +1002,9 @@ export function serializeObject(toSerialize: any): any {
|
|||
if (toSerialize instanceof Uint8Array) {
|
||||
toSerialize = base64.encodeByteArray(toSerialize);
|
||||
return toSerialize;
|
||||
}
|
||||
else if (toSerialize instanceof Date) {
|
||||
} else if (toSerialize instanceof Date) {
|
||||
return toSerialize.toISOString();
|
||||
}
|
||||
else if (Array.isArray(toSerialize)) {
|
||||
} else if (Array.isArray(toSerialize)) {
|
||||
const array = [];
|
||||
for (let i = 0; i < toSerialize.length; i++) {
|
||||
array.push(serializeObject(toSerialize[i]));
|
||||
|
@ -885,5 +1047,5 @@ export const MapperType = strEnum([
|
|||
"String",
|
||||
"Stream",
|
||||
"TimeSpan",
|
||||
"UnixTime"
|
||||
"UnixTime",
|
||||
]);
|
||||
|
|
|
@ -8,14 +8,31 @@ import { HttpClient } from "./httpClient";
|
|||
import { HttpOperationResponse, RestResponse } from "./httpOperationResponse";
|
||||
import { HttpPipelineLogger } from "./httpPipelineLogger";
|
||||
import { OperationArguments } from "./operationArguments";
|
||||
import { getPathStringFromParameter, getPathStringFromParameterPath, OperationParameter, ParameterPath } from "./operationParameter";
|
||||
import {
|
||||
getPathStringFromParameter,
|
||||
getPathStringFromParameterPath,
|
||||
OperationParameter,
|
||||
ParameterPath,
|
||||
} from "./operationParameter";
|
||||
import { isStreamOperation, OperationSpec } from "./operationSpec";
|
||||
import { deserializationPolicy, DeserializationContentTypes } from "./policies/deserializationPolicy";
|
||||
import {
|
||||
deserializationPolicy,
|
||||
DeserializationContentTypes,
|
||||
} from "./policies/deserializationPolicy";
|
||||
import { exponentialRetryPolicy } from "./policies/exponentialRetryPolicy";
|
||||
import { generateClientRequestIdPolicy } from "./policies/generateClientRequestIdPolicy";
|
||||
import { userAgentPolicy, getDefaultUserAgentHeaderName, getDefaultUserAgentValue } from "./policies/userAgentPolicy";
|
||||
import {
|
||||
userAgentPolicy,
|
||||
getDefaultUserAgentHeaderName,
|
||||
getDefaultUserAgentValue,
|
||||
} from "./policies/userAgentPolicy";
|
||||
import { redirectPolicy } from "./policies/redirectPolicy";
|
||||
import { RequestPolicy, RequestPolicyFactory, RequestPolicyOptions, RequestPolicyOptionsLike } from "./policies/requestPolicy";
|
||||
import {
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptions,
|
||||
RequestPolicyOptionsLike,
|
||||
} from "./policies/requestPolicy";
|
||||
import { rpRegistrationPolicy } from "./policies/rpRegistrationPolicy";
|
||||
import { signingPolicy } from "./policies/signingPolicy";
|
||||
import { systemErrorRetryPolicy } from "./policies/systemErrorRetryPolicy";
|
||||
|
@ -24,7 +41,13 @@ import { CompositeMapper, DictionaryMapper, Mapper, MapperType, Serializer } fro
|
|||
import { URLBuilder } from "./url";
|
||||
import * as utils from "./util/utils";
|
||||
import { stringifyXML } from "./util/xml";
|
||||
import { RequestOptionsBase, RequestPrepareOptions, WebResourceLike, isWebResourceLike, WebResource } from "./webResource";
|
||||
import {
|
||||
RequestOptionsBase,
|
||||
RequestPrepareOptions,
|
||||
WebResourceLike,
|
||||
isWebResourceLike,
|
||||
WebResource,
|
||||
} from "./webResource";
|
||||
import { OperationResponse } from "./operationResponse";
|
||||
import { ServiceCallback } from "./util/utils";
|
||||
import { agentPolicy } from "./policies/agentPolicy";
|
||||
|
@ -33,7 +56,6 @@ import { throttlingRetryPolicy } from "./policies/throttlingRetryPolicy";
|
|||
import { Agent } from "http";
|
||||
import { AzureIdentityCredentialAdapter } from "./credentials/azureIdentityTokenCredentialAdapter";
|
||||
|
||||
|
||||
/**
|
||||
* HTTP proxy settings (Node.js only)
|
||||
*/
|
||||
|
@ -61,7 +83,9 @@ export interface ServiceClientOptions {
|
|||
* request on the wire, or a function that takes in the defaultRequestPolicyFactories and returns
|
||||
* the requestPolicyFactories that will be used.
|
||||
*/
|
||||
requestPolicyFactories?: RequestPolicyFactory[] | ((defaultRequestPolicyFactories: RequestPolicyFactory[]) => (void | RequestPolicyFactory[]));
|
||||
requestPolicyFactories?:
|
||||
| RequestPolicyFactory[]
|
||||
| ((defaultRequestPolicyFactories: RequestPolicyFactory[]) => void | RequestPolicyFactory[]);
|
||||
/**
|
||||
* The HttpClient that will be used to send HTTP requests.
|
||||
*/
|
||||
|
@ -134,7 +158,6 @@ export class ServiceClient {
|
|||
*/
|
||||
protected requestContentType?: string;
|
||||
|
||||
|
||||
/**
|
||||
* The HTTP client that will be used to send requests.
|
||||
*/
|
||||
|
@ -150,7 +173,10 @@ export class ServiceClient {
|
|||
* @param {ServiceClientCredentials} [credentials] The credentials object used for authentication.
|
||||
* @param {ServiceClientOptions} [options] The service client options that govern the behavior of the client.
|
||||
*/
|
||||
constructor(credentials?: ServiceClientCredentials | TokenCredential, options?: ServiceClientOptions) {
|
||||
constructor(
|
||||
credentials?: ServiceClientCredentials | TokenCredential,
|
||||
options?: ServiceClientOptions
|
||||
) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
@ -162,7 +188,6 @@ export class ServiceClient {
|
|||
serviceClientCredentials = credentials;
|
||||
}
|
||||
|
||||
|
||||
if (serviceClientCredentials && !serviceClientCredentials.signRequest) {
|
||||
throw new Error("credentials argument needs to implement signRequest method");
|
||||
}
|
||||
|
@ -175,9 +200,14 @@ export class ServiceClient {
|
|||
if (Array.isArray(options.requestPolicyFactories)) {
|
||||
requestPolicyFactories = options.requestPolicyFactories;
|
||||
} else {
|
||||
requestPolicyFactories = createDefaultRequestPolicyFactories(serviceClientCredentials, options);
|
||||
requestPolicyFactories = createDefaultRequestPolicyFactories(
|
||||
serviceClientCredentials,
|
||||
options
|
||||
);
|
||||
if (options.requestPolicyFactories) {
|
||||
const newRequestPolicyFactories: void | RequestPolicyFactory[] = options.requestPolicyFactories(requestPolicyFactories);
|
||||
const newRequestPolicyFactories:
|
||||
| void
|
||||
| RequestPolicyFactory[] = options.requestPolicyFactories(requestPolicyFactories);
|
||||
if (newRequestPolicyFactories) {
|
||||
requestPolicyFactories = newRequestPolicyFactories;
|
||||
}
|
||||
|
@ -210,7 +240,10 @@ export class ServiceClient {
|
|||
let httpPipeline: RequestPolicy = this._httpClient;
|
||||
if (this._requestPolicyFactories && this._requestPolicyFactories.length > 0) {
|
||||
for (let i = this._requestPolicyFactories.length - 1; i >= 0; --i) {
|
||||
httpPipeline = this._requestPolicyFactories[i].create(httpPipeline, this._requestPolicyOptions);
|
||||
httpPipeline = this._requestPolicyFactories[i].create(
|
||||
httpPipeline,
|
||||
this._requestPolicyOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
return httpPipeline.sendRequest(httpRequest);
|
||||
|
@ -222,7 +255,11 @@ export class ServiceClient {
|
|||
* @param {OperationSpec} operationSpec The OperationSpec to use to populate the httpRequest.
|
||||
* @param {ServiceCallback} callback The callback to call when the response is received.
|
||||
*/
|
||||
sendOperationRequest(operationArguments: OperationArguments, operationSpec: OperationSpec, callback?: ServiceCallback<any>): Promise<RestResponse> {
|
||||
sendOperationRequest(
|
||||
operationArguments: OperationArguments,
|
||||
operationSpec: OperationSpec,
|
||||
callback?: ServiceCallback<any>
|
||||
): Promise<RestResponse> {
|
||||
if (typeof operationArguments.options === "function") {
|
||||
callback = operationArguments.options;
|
||||
operationArguments.options = undefined;
|
||||
|
@ -234,7 +271,9 @@ export class ServiceClient {
|
|||
try {
|
||||
const baseUri: string | undefined = operationSpec.baseUrl || this.baseUri;
|
||||
if (!baseUri) {
|
||||
throw new Error("If operationSpec.baseUrl is not specified, then the ServiceClient must have a baseUri string property that contains the base URL to use.");
|
||||
throw new Error(
|
||||
"If operationSpec.baseUrl is not specified, then the ServiceClient must have a baseUri string property that contains the base URL to use."
|
||||
);
|
||||
}
|
||||
|
||||
httpRequest.method = operationSpec.httpMethod;
|
||||
|
@ -246,19 +285,40 @@ export class ServiceClient {
|
|||
}
|
||||
if (operationSpec.urlParameters && operationSpec.urlParameters.length > 0) {
|
||||
for (const urlParameter of operationSpec.urlParameters) {
|
||||
let urlParameterValue: string = getOperationArgumentValueFromParameter(this, operationArguments, urlParameter, operationSpec.serializer);
|
||||
urlParameterValue = operationSpec.serializer.serialize(urlParameter.mapper, urlParameterValue, getPathStringFromParameter(urlParameter));
|
||||
let urlParameterValue: string = getOperationArgumentValueFromParameter(
|
||||
this,
|
||||
operationArguments,
|
||||
urlParameter,
|
||||
operationSpec.serializer
|
||||
);
|
||||
urlParameterValue = operationSpec.serializer.serialize(
|
||||
urlParameter.mapper,
|
||||
urlParameterValue,
|
||||
getPathStringFromParameter(urlParameter)
|
||||
);
|
||||
if (!urlParameter.skipEncoding) {
|
||||
urlParameterValue = encodeURIComponent(urlParameterValue);
|
||||
}
|
||||
requestUrl.replaceAll(`{${urlParameter.mapper.serializedName || getPathStringFromParameter(urlParameter)}}`, urlParameterValue);
|
||||
requestUrl.replaceAll(
|
||||
`{${urlParameter.mapper.serializedName || getPathStringFromParameter(urlParameter)}}`,
|
||||
urlParameterValue
|
||||
);
|
||||
}
|
||||
}
|
||||
if (operationSpec.queryParameters && operationSpec.queryParameters.length > 0) {
|
||||
for (const queryParameter of operationSpec.queryParameters) {
|
||||
let queryParameterValue: any = getOperationArgumentValueFromParameter(this, operationArguments, queryParameter, operationSpec.serializer);
|
||||
let queryParameterValue: any = getOperationArgumentValueFromParameter(
|
||||
this,
|
||||
operationArguments,
|
||||
queryParameter,
|
||||
operationSpec.serializer
|
||||
);
|
||||
if (queryParameterValue != undefined) {
|
||||
queryParameterValue = operationSpec.serializer.serialize(queryParameter.mapper, queryParameterValue, getPathStringFromParameter(queryParameter));
|
||||
queryParameterValue = operationSpec.serializer.serialize(
|
||||
queryParameter.mapper,
|
||||
queryParameterValue,
|
||||
getPathStringFromParameter(queryParameter)
|
||||
);
|
||||
if (queryParameter.collectionFormat != undefined) {
|
||||
if (queryParameter.collectionFormat === QueryCollectionFormat.Multi) {
|
||||
if (queryParameterValue.length === 0) {
|
||||
|
@ -269,26 +329,39 @@ export class ServiceClient {
|
|||
queryParameterValue[index] = item == undefined ? "" : item.toString();
|
||||
}
|
||||
}
|
||||
} else if (queryParameter.collectionFormat === QueryCollectionFormat.Ssv || queryParameter.collectionFormat === QueryCollectionFormat.Tsv) {
|
||||
} else if (
|
||||
queryParameter.collectionFormat === QueryCollectionFormat.Ssv ||
|
||||
queryParameter.collectionFormat === QueryCollectionFormat.Tsv
|
||||
) {
|
||||
queryParameterValue = queryParameterValue.join(queryParameter.collectionFormat);
|
||||
}
|
||||
}
|
||||
if (!queryParameter.skipEncoding) {
|
||||
if (Array.isArray(queryParameterValue)) {
|
||||
for (const index in queryParameterValue) {
|
||||
if (queryParameterValue[index] !== undefined && queryParameterValue[index] !== null) {
|
||||
if (
|
||||
queryParameterValue[index] !== undefined &&
|
||||
queryParameterValue[index] !== null
|
||||
) {
|
||||
queryParameterValue[index] = encodeURIComponent(queryParameterValue[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
queryParameterValue = encodeURIComponent(queryParameterValue);
|
||||
}
|
||||
}
|
||||
if (queryParameter.collectionFormat != undefined && queryParameter.collectionFormat !== QueryCollectionFormat.Multi && queryParameter.collectionFormat !== QueryCollectionFormat.Ssv && queryParameter.collectionFormat !== QueryCollectionFormat.Tsv) {
|
||||
if (
|
||||
queryParameter.collectionFormat != undefined &&
|
||||
queryParameter.collectionFormat !== QueryCollectionFormat.Multi &&
|
||||
queryParameter.collectionFormat !== QueryCollectionFormat.Ssv &&
|
||||
queryParameter.collectionFormat !== QueryCollectionFormat.Tsv
|
||||
) {
|
||||
queryParameterValue = queryParameterValue.join(queryParameter.collectionFormat);
|
||||
}
|
||||
requestUrl.setQueryParameter(queryParameter.mapper.serializedName || getPathStringFromParameter(queryParameter), queryParameterValue);
|
||||
requestUrl.setQueryParameter(
|
||||
queryParameter.mapper.serializedName || getPathStringFromParameter(queryParameter),
|
||||
queryParameterValue
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -301,16 +374,30 @@ export class ServiceClient {
|
|||
|
||||
if (operationSpec.headerParameters) {
|
||||
for (const headerParameter of operationSpec.headerParameters) {
|
||||
let headerValue: any = getOperationArgumentValueFromParameter(this, operationArguments, headerParameter, operationSpec.serializer);
|
||||
let headerValue: any = getOperationArgumentValueFromParameter(
|
||||
this,
|
||||
operationArguments,
|
||||
headerParameter,
|
||||
operationSpec.serializer
|
||||
);
|
||||
if (headerValue != undefined) {
|
||||
headerValue = operationSpec.serializer.serialize(headerParameter.mapper, headerValue, getPathStringFromParameter(headerParameter));
|
||||
const headerCollectionPrefix = (headerParameter.mapper as DictionaryMapper).headerCollectionPrefix;
|
||||
headerValue = operationSpec.serializer.serialize(
|
||||
headerParameter.mapper,
|
||||
headerValue,
|
||||
getPathStringFromParameter(headerParameter)
|
||||
);
|
||||
const headerCollectionPrefix = (headerParameter.mapper as DictionaryMapper)
|
||||
.headerCollectionPrefix;
|
||||
if (headerCollectionPrefix) {
|
||||
for (const key of Object.keys(headerValue)) {
|
||||
httpRequest.headers.set(headerCollectionPrefix + key, headerValue[key]);
|
||||
}
|
||||
} else {
|
||||
httpRequest.headers.set(headerParameter.mapper.serializedName || getPathStringFromParameter(headerParameter), headerValue);
|
||||
httpRequest.headers.set(
|
||||
headerParameter.mapper.serializedName ||
|
||||
getPathStringFromParameter(headerParameter),
|
||||
headerValue
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -349,8 +436,9 @@ export class ServiceClient {
|
|||
httpRequest.streamResponseBody = isStreamOperation(operationSpec);
|
||||
}
|
||||
|
||||
result = this.sendRequest(httpRequest)
|
||||
.then(res => flattenResponse(res, operationSpec.responses[res.status]));
|
||||
result = this.sendRequest(httpRequest).then((res) =>
|
||||
flattenResponse(res, operationSpec.responses[res.status])
|
||||
);
|
||||
} catch (error) {
|
||||
result = Promise.reject(error);
|
||||
}
|
||||
|
@ -359,47 +447,86 @@ export class ServiceClient {
|
|||
if (cb) {
|
||||
result
|
||||
// tslint:disable-next-line:no-null-keyword
|
||||
.then(res => cb(null, res._response.parsedBody, res._response.request, res._response))
|
||||
.catch(err => cb(err));
|
||||
.then((res) => cb(null, res._response.parsedBody, res._response.request, res._response))
|
||||
.catch((err) => cb(err));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export function serializeRequestBody(serviceClient: ServiceClient, httpRequest: WebResourceLike, operationArguments: OperationArguments, operationSpec: OperationSpec): void {
|
||||
export function serializeRequestBody(
|
||||
serviceClient: ServiceClient,
|
||||
httpRequest: WebResourceLike,
|
||||
operationArguments: OperationArguments,
|
||||
operationSpec: OperationSpec
|
||||
): void {
|
||||
if (operationSpec.requestBody && operationSpec.requestBody.mapper) {
|
||||
httpRequest.body = getOperationArgumentValueFromParameter(serviceClient, operationArguments, operationSpec.requestBody, operationSpec.serializer);
|
||||
httpRequest.body = getOperationArgumentValueFromParameter(
|
||||
serviceClient,
|
||||
operationArguments,
|
||||
operationSpec.requestBody,
|
||||
operationSpec.serializer
|
||||
);
|
||||
|
||||
const bodyMapper = operationSpec.requestBody.mapper;
|
||||
const { required, xmlName, xmlElementName, serializedName } = bodyMapper;
|
||||
const typeName = bodyMapper.type.name;
|
||||
try {
|
||||
if (httpRequest.body != undefined || required) {
|
||||
const requestBodyParameterPathString: string = getPathStringFromParameter(operationSpec.requestBody);
|
||||
httpRequest.body = operationSpec.serializer.serialize(bodyMapper, httpRequest.body, requestBodyParameterPathString);
|
||||
const requestBodyParameterPathString: string = getPathStringFromParameter(
|
||||
operationSpec.requestBody
|
||||
);
|
||||
httpRequest.body = operationSpec.serializer.serialize(
|
||||
bodyMapper,
|
||||
httpRequest.body,
|
||||
requestBodyParameterPathString
|
||||
);
|
||||
const isStream = typeName === MapperType.Stream;
|
||||
if (operationSpec.isXML) {
|
||||
if (typeName === MapperType.Sequence) {
|
||||
httpRequest.body = stringifyXML(utils.prepareXMLRootList(httpRequest.body, xmlElementName || xmlName || serializedName!), { rootName: xmlName || serializedName });
|
||||
}
|
||||
else if (!isStream) {
|
||||
httpRequest.body = stringifyXML(httpRequest.body, { rootName: xmlName || serializedName });
|
||||
httpRequest.body = stringifyXML(
|
||||
utils.prepareXMLRootList(
|
||||
httpRequest.body,
|
||||
xmlElementName || xmlName || serializedName!
|
||||
),
|
||||
{ rootName: xmlName || serializedName }
|
||||
);
|
||||
} else if (!isStream) {
|
||||
httpRequest.body = stringifyXML(httpRequest.body, {
|
||||
rootName: xmlName || serializedName,
|
||||
});
|
||||
}
|
||||
} else if (!isStream) {
|
||||
httpRequest.body = JSON.stringify(httpRequest.body);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`Error "${error.message}" occurred in serializing the payload - ${JSON.stringify(serializedName, undefined, " ")}.`);
|
||||
throw new Error(
|
||||
`Error "${error.message}" occurred in serializing the payload - ${JSON.stringify(
|
||||
serializedName,
|
||||
undefined,
|
||||
" "
|
||||
)}.`
|
||||
);
|
||||
}
|
||||
} else if (operationSpec.formDataParameters && operationSpec.formDataParameters.length > 0) {
|
||||
httpRequest.formData = {};
|
||||
for (const formDataParameter of operationSpec.formDataParameters) {
|
||||
const formDataParameterValue: any = getOperationArgumentValueFromParameter(serviceClient, operationArguments, formDataParameter, operationSpec.serializer);
|
||||
const formDataParameterValue: any = getOperationArgumentValueFromParameter(
|
||||
serviceClient,
|
||||
operationArguments,
|
||||
formDataParameter,
|
||||
operationSpec.serializer
|
||||
);
|
||||
if (formDataParameterValue != undefined) {
|
||||
const formDataParameterPropertyName: string = formDataParameter.mapper.serializedName || getPathStringFromParameter(formDataParameter);
|
||||
httpRequest.formData[formDataParameterPropertyName] = operationSpec.serializer.serialize(formDataParameter.mapper, formDataParameterValue, getPathStringFromParameter(formDataParameter));
|
||||
const formDataParameterPropertyName: string =
|
||||
formDataParameter.mapper.serializedName || getPathStringFromParameter(formDataParameter);
|
||||
httpRequest.formData[formDataParameterPropertyName] = operationSpec.serializer.serialize(
|
||||
formDataParameter.mapper,
|
||||
formDataParameterValue,
|
||||
getPathStringFromParameter(formDataParameter)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -409,7 +536,10 @@ function isRequestPolicyFactory(instance: any): instance is RequestPolicyFactory
|
|||
return typeof instance.create === "function";
|
||||
}
|
||||
|
||||
function getValueOrFunctionResult(value: undefined | string | ((defaultValue: string) => string), defaultValueCreator: (() => string)): string {
|
||||
function getValueOrFunctionResult(
|
||||
value: undefined | string | ((defaultValue: string) => string),
|
||||
defaultValueCreator: () => string
|
||||
): string {
|
||||
let result: string;
|
||||
if (typeof value === "string") {
|
||||
result = value;
|
||||
|
@ -422,7 +552,10 @@ function getValueOrFunctionResult(value: undefined | string | ((defaultValue: st
|
|||
return result;
|
||||
}
|
||||
|
||||
function createDefaultRequestPolicyFactories(credentials: ServiceClientCredentials | RequestPolicyFactory | undefined, options: ServiceClientOptions): RequestPolicyFactory[] {
|
||||
function createDefaultRequestPolicyFactories(
|
||||
credentials: ServiceClientCredentials | RequestPolicyFactory | undefined,
|
||||
options: ServiceClientOptions
|
||||
): RequestPolicyFactory[] {
|
||||
const factories: RequestPolicyFactory[] = [];
|
||||
|
||||
if (options.generateClientRequestIdHeader) {
|
||||
|
@ -437,8 +570,14 @@ function createDefaultRequestPolicyFactories(credentials: ServiceClientCredentia
|
|||
}
|
||||
}
|
||||
|
||||
const userAgentHeaderName: string = getValueOrFunctionResult(options.userAgentHeaderName, getDefaultUserAgentHeaderName);
|
||||
const userAgentHeaderValue: string = getValueOrFunctionResult(options.userAgent, getDefaultUserAgentValue);
|
||||
const userAgentHeaderName: string = getValueOrFunctionResult(
|
||||
options.userAgentHeaderName,
|
||||
getDefaultUserAgentHeaderName
|
||||
);
|
||||
const userAgentHeaderValue: string = getValueOrFunctionResult(
|
||||
options.userAgent,
|
||||
getDefaultUserAgentValue
|
||||
);
|
||||
if (userAgentHeaderName && userAgentHeaderValue) {
|
||||
factories.push(userAgentPolicy({ key: userAgentHeaderName, value: userAgentHeaderValue }));
|
||||
}
|
||||
|
@ -485,11 +624,28 @@ export function getPropertyParent(parent: PropertyParent, propertyPath: string[]
|
|||
return parent;
|
||||
}
|
||||
|
||||
function getOperationArgumentValueFromParameter(serviceClient: ServiceClient, operationArguments: OperationArguments, parameter: OperationParameter, serializer: Serializer): any {
|
||||
return getOperationArgumentValueFromParameterPath(serviceClient, operationArguments, parameter.parameterPath, parameter.mapper, serializer);
|
||||
function getOperationArgumentValueFromParameter(
|
||||
serviceClient: ServiceClient,
|
||||
operationArguments: OperationArguments,
|
||||
parameter: OperationParameter,
|
||||
serializer: Serializer
|
||||
): any {
|
||||
return getOperationArgumentValueFromParameterPath(
|
||||
serviceClient,
|
||||
operationArguments,
|
||||
parameter.parameterPath,
|
||||
parameter.mapper,
|
||||
serializer
|
||||
);
|
||||
}
|
||||
|
||||
export function getOperationArgumentValueFromParameterPath(serviceClient: ServiceClient, operationArguments: OperationArguments, parameterPath: ParameterPath, parameterMapper: Mapper, serializer: Serializer): any {
|
||||
export function getOperationArgumentValueFromParameterPath(
|
||||
serviceClient: ServiceClient,
|
||||
operationArguments: OperationArguments,
|
||||
parameterPath: ParameterPath,
|
||||
parameterMapper: Mapper,
|
||||
serializer: Serializer
|
||||
): any {
|
||||
let value: any;
|
||||
if (typeof parameterPath === "string") {
|
||||
parameterPath = [parameterPath];
|
||||
|
@ -499,20 +655,28 @@ export function getOperationArgumentValueFromParameterPath(serviceClient: Servic
|
|||
if (parameterMapper.isConstant) {
|
||||
value = parameterMapper.defaultValue;
|
||||
} else {
|
||||
let propertySearchResult: PropertySearchResult = getPropertyFromParameterPath(operationArguments, parameterPath);
|
||||
let propertySearchResult: PropertySearchResult = getPropertyFromParameterPath(
|
||||
operationArguments,
|
||||
parameterPath
|
||||
);
|
||||
if (!propertySearchResult.propertyFound) {
|
||||
propertySearchResult = getPropertyFromParameterPath(serviceClient, parameterPath);
|
||||
}
|
||||
|
||||
let useDefaultValue = false;
|
||||
if (!propertySearchResult.propertyFound) {
|
||||
useDefaultValue = parameterMapper.required || (parameterPath[0] === "options" && parameterPath.length === 2);
|
||||
useDefaultValue =
|
||||
parameterMapper.required ||
|
||||
(parameterPath[0] === "options" && parameterPath.length === 2);
|
||||
}
|
||||
value = useDefaultValue ? parameterMapper.defaultValue : propertySearchResult.propertyValue;
|
||||
}
|
||||
|
||||
// Serialize just for validation purposes.
|
||||
const parameterPathString: string = getPathStringFromParameterPath(parameterPath, parameterMapper);
|
||||
const parameterPathString: string = getPathStringFromParameterPath(
|
||||
parameterPath,
|
||||
parameterMapper
|
||||
);
|
||||
serializer.serialize(parameterMapper, value, parameterPathString);
|
||||
}
|
||||
} else {
|
||||
|
@ -521,11 +685,22 @@ export function getOperationArgumentValueFromParameterPath(serviceClient: Servic
|
|||
}
|
||||
|
||||
for (const propertyName in parameterPath) {
|
||||
const propertyMapper: Mapper = (parameterMapper as CompositeMapper).type.modelProperties![propertyName];
|
||||
const propertyMapper: Mapper = (parameterMapper as CompositeMapper).type.modelProperties![
|
||||
propertyName
|
||||
];
|
||||
const propertyPath: ParameterPath = parameterPath[propertyName];
|
||||
const propertyValue: any = getOperationArgumentValueFromParameterPath(serviceClient, operationArguments, propertyPath, propertyMapper, serializer);
|
||||
const propertyValue: any = getOperationArgumentValueFromParameterPath(
|
||||
serviceClient,
|
||||
operationArguments,
|
||||
propertyPath,
|
||||
propertyMapper,
|
||||
serializer
|
||||
);
|
||||
// Serialize just for validation purposes.
|
||||
const propertyPathString: string = getPathStringFromParameterPath(propertyPath, propertyMapper);
|
||||
const propertyPathString: string = getPathStringFromParameterPath(
|
||||
propertyPath,
|
||||
propertyMapper
|
||||
);
|
||||
serializer.serialize(propertyMapper, propertyValue, propertyPathString);
|
||||
if (propertyValue !== undefined) {
|
||||
if (!value) {
|
||||
|
@ -543,7 +718,10 @@ interface PropertySearchResult {
|
|||
propertyFound: boolean;
|
||||
}
|
||||
|
||||
function getPropertyFromParameterPath(parent: { [parameterName: string]: any }, parameterPath: string[]): PropertySearchResult {
|
||||
function getPropertyFromParameterPath(
|
||||
parent: { [parameterName: string]: any },
|
||||
parameterPath: string[]
|
||||
): PropertySearchResult {
|
||||
const result: PropertySearchResult = { propertyFound: false };
|
||||
let i = 0;
|
||||
for (; i < parameterPath.length; ++i) {
|
||||
|
@ -562,13 +740,16 @@ function getPropertyFromParameterPath(parent: { [parameterName: string]: any },
|
|||
return result;
|
||||
}
|
||||
|
||||
export function flattenResponse(_response: HttpOperationResponse, responseSpec: OperationResponse | undefined): RestResponse {
|
||||
export function flattenResponse(
|
||||
_response: HttpOperationResponse,
|
||||
responseSpec: OperationResponse | undefined
|
||||
): RestResponse {
|
||||
const parsedHeaders = _response.parsedHeaders;
|
||||
const bodyMapper = responseSpec && responseSpec.bodyMapper;
|
||||
|
||||
const addOperationResponse = (obj: {}) =>
|
||||
Object.defineProperty(obj, "_response", {
|
||||
value: _response
|
||||
value: _response,
|
||||
});
|
||||
|
||||
if (bodyMapper) {
|
||||
|
@ -577,19 +758,19 @@ export function flattenResponse(_response: HttpOperationResponse, responseSpec:
|
|||
return addOperationResponse({
|
||||
...parsedHeaders,
|
||||
blobBody: _response.blobBody,
|
||||
readableStreamBody: _response.readableStreamBody
|
||||
readableStreamBody: _response.readableStreamBody,
|
||||
});
|
||||
}
|
||||
|
||||
const modelProperties = typeName === "Composite" && (bodyMapper as CompositeMapper).type.modelProperties || {};
|
||||
const isPageableResponse = Object.keys(modelProperties).some(k => modelProperties[k].serializedName === "");
|
||||
const modelProperties =
|
||||
(typeName === "Composite" && (bodyMapper as CompositeMapper).type.modelProperties) || {};
|
||||
const isPageableResponse = Object.keys(modelProperties).some(
|
||||
(k) => modelProperties[k].serializedName === ""
|
||||
);
|
||||
if (typeName === "Sequence" || isPageableResponse) {
|
||||
// We're expecting a sequece(array) make sure that the response body is in the
|
||||
// correct format, if not make it an empty array []
|
||||
const parsedBody =
|
||||
Array.isArray(_response.parsedBody)
|
||||
? _response.parsedBody
|
||||
: [];
|
||||
const parsedBody = Array.isArray(_response.parsedBody) ? _response.parsedBody : [];
|
||||
const arrayResponse = [...parsedBody] as RestResponse & any[];
|
||||
|
||||
for (const key of Object.keys(modelProperties)) {
|
||||
|
@ -610,21 +791,25 @@ export function flattenResponse(_response: HttpOperationResponse, responseSpec:
|
|||
if (typeName === "Composite" || typeName === "Dictionary") {
|
||||
return addOperationResponse({
|
||||
...parsedHeaders,
|
||||
..._response.parsedBody
|
||||
..._response.parsedBody,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (bodyMapper || _response.request.method === "HEAD" || utils.isPrimitiveType(_response.parsedBody)) {
|
||||
if (
|
||||
bodyMapper ||
|
||||
_response.request.method === "HEAD" ||
|
||||
utils.isPrimitiveType(_response.parsedBody)
|
||||
) {
|
||||
// primitive body types and HEAD booleans
|
||||
return addOperationResponse({
|
||||
...parsedHeaders,
|
||||
body: _response.parsedBody
|
||||
body: _response.parsedBody,
|
||||
});
|
||||
}
|
||||
|
||||
return addOperationResponse({
|
||||
...parsedHeaders,
|
||||
..._response.parsedBody
|
||||
..._response.parsedBody,
|
||||
});
|
||||
}
|
||||
|
|
155
lib/url.ts
155
lib/url.ts
|
@ -83,40 +83,40 @@ export class URLQuery {
|
|||
for (let i = 0; i < text.length; ++i) {
|
||||
const currentCharacter: string = text[i];
|
||||
switch (currentState) {
|
||||
case "ParameterName":
|
||||
switch (currentCharacter) {
|
||||
case "=":
|
||||
currentState = "ParameterValue";
|
||||
case "ParameterName":
|
||||
switch (currentCharacter) {
|
||||
case "=":
|
||||
currentState = "ParameterValue";
|
||||
break;
|
||||
|
||||
case "&":
|
||||
parameterName = "";
|
||||
parameterValue = "";
|
||||
break;
|
||||
|
||||
default:
|
||||
parameterName += currentCharacter;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case "&":
|
||||
parameterName = "";
|
||||
parameterValue = "";
|
||||
case "ParameterValue":
|
||||
switch (currentCharacter) {
|
||||
case "&":
|
||||
result.set(parameterName, parameterValue);
|
||||
parameterName = "";
|
||||
parameterValue = "";
|
||||
currentState = "ParameterName";
|
||||
break;
|
||||
|
||||
default:
|
||||
parameterValue += currentCharacter;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
parameterName += currentCharacter;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case "ParameterValue":
|
||||
switch (currentCharacter) {
|
||||
case "&":
|
||||
result.set(parameterName, parameterValue);
|
||||
parameterName = "";
|
||||
parameterValue = "";
|
||||
currentState = "ParameterName";
|
||||
break;
|
||||
|
||||
default:
|
||||
parameterValue += currentCharacter;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Unrecognized URLQuery parse state: " + currentState);
|
||||
throw new Error("Unrecognized URLQuery parse state: " + currentState);
|
||||
}
|
||||
}
|
||||
if (currentState === "ParameterValue") {
|
||||
|
@ -290,31 +290,31 @@ export class URLBuilder {
|
|||
const token: URLToken | undefined = tokenizer.current();
|
||||
if (token) {
|
||||
switch (token.type) {
|
||||
case "SCHEME":
|
||||
this._scheme = token.text || undefined;
|
||||
break;
|
||||
case "SCHEME":
|
||||
this._scheme = token.text || undefined;
|
||||
break;
|
||||
|
||||
case "HOST":
|
||||
this._host = token.text || undefined;
|
||||
break;
|
||||
case "HOST":
|
||||
this._host = token.text || undefined;
|
||||
break;
|
||||
|
||||
case "PORT":
|
||||
this._port = token.text || undefined;
|
||||
break;
|
||||
case "PORT":
|
||||
this._port = token.text || undefined;
|
||||
break;
|
||||
|
||||
case "PATH":
|
||||
const tokenPath: string | undefined = token.text || undefined;
|
||||
if (!this._path || this._path === "/" || tokenPath !== "/") {
|
||||
this._path = tokenPath;
|
||||
}
|
||||
break;
|
||||
case "PATH":
|
||||
const tokenPath: string | undefined = token.text || undefined;
|
||||
if (!this._path || this._path === "/" || tokenPath !== "/") {
|
||||
this._path = tokenPath;
|
||||
}
|
||||
break;
|
||||
|
||||
case "QUERY":
|
||||
this._query = URLQuery.parse(token.text);
|
||||
break;
|
||||
case "QUERY":
|
||||
this._query = URLQuery.parse(token.text);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unrecognized URLTokenType: ${token.type}`);
|
||||
default:
|
||||
throw new Error(`Unrecognized URLTokenType: ${token.type}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,8 +375,7 @@ type URLTokenizerState = "SCHEME" | "SCHEME_OR_HOST" | "HOST" | "PORT" | "PATH"
|
|||
type URLTokenType = "SCHEME" | "HOST" | "PORT" | "PATH" | "QUERY";
|
||||
|
||||
export class URLToken {
|
||||
public constructor(public readonly text: string, public readonly type: URLTokenType) {
|
||||
}
|
||||
public constructor(public readonly text: string, public readonly type: URLTokenType) {}
|
||||
|
||||
public static scheme(text: string): URLToken {
|
||||
return new URLToken(text, "SCHEME");
|
||||
|
@ -405,9 +404,11 @@ export class URLToken {
|
|||
*/
|
||||
export function isAlphaNumericCharacter(character: string): boolean {
|
||||
const characterCode: number = character.charCodeAt(0);
|
||||
return (48 /* '0' */ <= characterCode && characterCode <= 57 /* '9' */) ||
|
||||
(65 /* 'A' */ <= characterCode && characterCode <= 90 /* 'Z' */) ||
|
||||
(97 /* 'a' */ <= characterCode && characterCode <= 122 /* 'z' */);
|
||||
return (
|
||||
(48 /* '0' */ <= characterCode && characterCode <= 57) /* '9' */ ||
|
||||
(65 /* 'A' */ <= characterCode && characterCode <= 90) /* 'Z' */ ||
|
||||
(97 /* 'a' */ <= characterCode && characterCode <= 122) /* 'z' */
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -441,39 +442,38 @@ export class URLTokenizer {
|
|||
this._currentToken = undefined;
|
||||
} else {
|
||||
switch (this._currentState) {
|
||||
case "SCHEME":
|
||||
nextScheme(this);
|
||||
break;
|
||||
case "SCHEME":
|
||||
nextScheme(this);
|
||||
break;
|
||||
|
||||
case "SCHEME_OR_HOST":
|
||||
nextSchemeOrHost(this);
|
||||
break;
|
||||
case "SCHEME_OR_HOST":
|
||||
nextSchemeOrHost(this);
|
||||
break;
|
||||
|
||||
case "HOST":
|
||||
nextHost(this);
|
||||
break;
|
||||
case "HOST":
|
||||
nextHost(this);
|
||||
break;
|
||||
|
||||
case "PORT":
|
||||
nextPort(this);
|
||||
break;
|
||||
case "PORT":
|
||||
nextPort(this);
|
||||
break;
|
||||
|
||||
case "PATH":
|
||||
nextPath(this);
|
||||
break;
|
||||
case "PATH":
|
||||
nextPath(this);
|
||||
break;
|
||||
|
||||
case "QUERY":
|
||||
nextQuery(this);
|
||||
break;
|
||||
case "QUERY":
|
||||
nextQuery(this);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unrecognized URLTokenizerState: ${this._currentState}`);
|
||||
default:
|
||||
throw new Error(`Unrecognized URLTokenizerState: ${this._currentState}`);
|
||||
}
|
||||
}
|
||||
return !!this._currentToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the remaining characters from this Tokenizer's character stream.
|
||||
*/
|
||||
|
@ -558,7 +558,10 @@ function readWhileLetterOrDigit(tokenizer: URLTokenizer): string {
|
|||
* the end of the character stream is reached.
|
||||
*/
|
||||
function readUntilCharacter(tokenizer: URLTokenizer, ...terminatingCharacters: string[]): string {
|
||||
return readWhile(tokenizer, (character: string) => terminatingCharacters.indexOf(character) === -1);
|
||||
return readWhile(
|
||||
tokenizer,
|
||||
(character: string) => terminatingCharacters.indexOf(character) === -1
|
||||
);
|
||||
}
|
||||
|
||||
function nextScheme(tokenizer: URLTokenizer): void {
|
||||
|
|
|
@ -16,7 +16,7 @@ export function encodeString(value: string): string {
|
|||
export function encodeByteArray(value: Uint8Array): string {
|
||||
// Buffer.from accepts <ArrayBuffer> | <SharedArrayBuffer>-- the TypeScript definition is off here
|
||||
// https://nodejs.org/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length
|
||||
const bufferValue = (value instanceof Buffer) ? value : Buffer.from(value.buffer as ArrayBuffer);
|
||||
const bufferValue = value instanceof Buffer ? value : Buffer.from(value.buffer as ArrayBuffer);
|
||||
return bufferValue.toString("base64");
|
||||
}
|
||||
|
||||
|
|
|
@ -55,12 +55,12 @@ export const Constants = {
|
|||
POST: "POST",
|
||||
MERGE: "MERGE",
|
||||
HEAD: "HEAD",
|
||||
PATCH: "PATCH"
|
||||
PATCH: "PATCH",
|
||||
},
|
||||
|
||||
StatusCodes: {
|
||||
TooManyRequests: 429
|
||||
}
|
||||
TooManyRequests: 429,
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -93,6 +93,6 @@ export const Constants = {
|
|||
* @const
|
||||
* @type {string}
|
||||
*/
|
||||
USER_AGENT: "User-Agent"
|
||||
}
|
||||
USER_AGENT: "User-Agent",
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,7 +10,11 @@ import { Constants } from "./constants";
|
|||
/**
|
||||
* A constant that indicates whether the environment is node.js or browser based.
|
||||
*/
|
||||
export const isNode = (typeof process !== "undefined") && !!process.version && !!process.versions && !!process.versions.node;
|
||||
export const isNode =
|
||||
typeof process !== "undefined" &&
|
||||
!!process.version &&
|
||||
!!process.versions &&
|
||||
!!process.versions.node;
|
||||
|
||||
/**
|
||||
* Checks if a parsed URL is HTTPS
|
||||
|
@ -77,7 +81,10 @@ export function stripRequest(request: WebResourceLike): WebResourceLike {
|
|||
* @return {boolean} True if the uuid is valid; false otherwise.
|
||||
*/
|
||||
export function isValidUuid(uuid: string): boolean {
|
||||
const validUuidRegex = new RegExp("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", "ig");
|
||||
const validUuidRegex = new RegExp(
|
||||
"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
|
||||
"ig"
|
||||
);
|
||||
return validUuidRegex.test(uuid);
|
||||
}
|
||||
|
||||
|
@ -89,7 +96,7 @@ export function isValidUuid(uuid: string): boolean {
|
|||
*
|
||||
* @return {any[]} An array of values of the given object.
|
||||
*/
|
||||
export function objectValues(obj: { [key: string]: any; }): any[] {
|
||||
export function objectValues(obj: { [key: string]: any }): any[] {
|
||||
const result: any[] = [];
|
||||
if (obj && obj instanceof Object) {
|
||||
for (const key in obj) {
|
||||
|
@ -98,8 +105,13 @@ export function objectValues(obj: { [key: string]: any; }): any[] {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error(`The provided object ${JSON.stringify(obj, undefined, 2)} is not a valid object that can be ` +
|
||||
`enumerated to provide its values as an array.`);
|
||||
throw new Error(
|
||||
`The provided object ${JSON.stringify(
|
||||
obj,
|
||||
undefined,
|
||||
2
|
||||
)} is not a valid object that can be ` + `enumerated to provide its values as an array.`
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -140,7 +152,7 @@ export function executePromisesSequentially(promiseFactories: Array<any>, kickst
|
|||
*
|
||||
* @returns {object} Returns the merged target object.
|
||||
*/
|
||||
export function mergeObjects(source: { [key: string]: any; }, target: { [key: string]: any; }) {
|
||||
export function mergeObjects(source: { [key: string]: any }, target: { [key: string]: any }) {
|
||||
Object.keys(source).forEach((key) => {
|
||||
target[key] = source[key];
|
||||
});
|
||||
|
@ -168,7 +180,12 @@ export interface ServiceCallback<TResult> {
|
|||
* @param {WebResourceLike} [request] The raw/actual request sent to the server if an error did not occur.
|
||||
* @param {HttpOperationResponse} [response] The raw/actual response from the server if an error did not occur.
|
||||
*/
|
||||
(err: Error | RestError | null, result?: TResult, request?: WebResourceLike, response?: HttpOperationResponse): void;
|
||||
(
|
||||
err: Error | RestError | null,
|
||||
result?: TResult,
|
||||
request?: WebResourceLike,
|
||||
response?: HttpOperationResponse
|
||||
): void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,11 +199,14 @@ export function promiseToCallback(promise: Promise<any>): Function {
|
|||
throw new Error("The provided input is not a Promise.");
|
||||
}
|
||||
return (cb: Function): void => {
|
||||
promise.then((data: any) => {
|
||||
cb(undefined, data);
|
||||
}, (err: Error) => {
|
||||
cb(err);
|
||||
});
|
||||
promise.then(
|
||||
(data: any) => {
|
||||
cb(undefined, data);
|
||||
},
|
||||
(err: Error) => {
|
||||
cb(err);
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -200,11 +220,14 @@ export function promiseToServiceCallback<T>(promise: Promise<HttpOperationRespon
|
|||
throw new Error("The provided input is not a Promise.");
|
||||
}
|
||||
return (cb: ServiceCallback<T>): void => {
|
||||
promise.then((data: HttpOperationResponse) => {
|
||||
process.nextTick(cb, undefined, data.parsedBody as T, data.request, data);
|
||||
}, (err: Error) => {
|
||||
process.nextTick(cb, err);
|
||||
});
|
||||
promise.then(
|
||||
(data: HttpOperationResponse) => {
|
||||
process.nextTick(cb, undefined, data.parsedBody as T, data.request, data);
|
||||
},
|
||||
(err: Error) => {
|
||||
process.nextTick(cb, err);
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -221,8 +244,8 @@ export function prepareXMLRootList(obj: any, elementName: string) {
|
|||
* @param {Array<object>} sourceCtors An array of source objects from which the properties need to be taken.
|
||||
*/
|
||||
export function applyMixins(targetCtor: any, sourceCtors: any[]): void {
|
||||
sourceCtors.forEach(sourceCtors => {
|
||||
Object.getOwnPropertyNames(sourceCtors.prototype).forEach(name => {
|
||||
sourceCtors.forEach((sourceCtors) => {
|
||||
Object.getOwnPropertyNames(sourceCtors.prototype).forEach((name) => {
|
||||
targetCtor.prototype[name] = sourceCtors.prototype[name];
|
||||
});
|
||||
});
|
||||
|
@ -246,7 +269,11 @@ export function isDuration(value: string): boolean {
|
|||
* @param {string} replaceValue The value to replace searchValue with in the value argument.
|
||||
* @returns {string | undefined} The value where each instance of searchValue was replaced with replacedValue.
|
||||
*/
|
||||
export function replaceAll(value: string | undefined, searchValue: string, replaceValue: string): string | undefined {
|
||||
export function replaceAll(
|
||||
value: string | undefined,
|
||||
searchValue: string,
|
||||
replaceValue: string
|
||||
): string | undefined {
|
||||
return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || "");
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,8 @@ export function parseXML(str: string): Promise<any> {
|
|||
|
||||
let errorNS = "";
|
||||
try {
|
||||
errorNS = parser.parseFromString("INVALID", "text/xml").getElementsByTagName("parsererror")[0].namespaceURI!;
|
||||
errorNS = parser.parseFromString("INVALID", "text/xml").getElementsByTagName("parsererror")[0]
|
||||
.namespaceURI!;
|
||||
} catch (ignored) {
|
||||
// Most browsers will return a document containing <parsererror>, but IE will throw.
|
||||
}
|
||||
|
@ -48,7 +49,12 @@ function domToObject(node: Node): any {
|
|||
const childNodeCount: number = node.childNodes.length;
|
||||
|
||||
const firstChildNode: Node = node.childNodes[0];
|
||||
const onlyChildTextValue: string | undefined = (firstChildNode && childNodeCount === 1 && firstChildNode.nodeType === Node.TEXT_NODE && firstChildNode.nodeValue) || undefined;
|
||||
const onlyChildTextValue: string | undefined =
|
||||
(firstChildNode &&
|
||||
childNodeCount === 1 &&
|
||||
firstChildNode.nodeType === Node.TEXT_NODE &&
|
||||
firstChildNode.nodeValue) ||
|
||||
undefined;
|
||||
|
||||
const elementWithAttributes: Element | undefined = asElementWithAttributes(node);
|
||||
if (elementWithAttributes) {
|
||||
|
@ -93,12 +99,14 @@ const doc = document.implementation.createDocument(null, null, null);
|
|||
const serializer = new XMLSerializer();
|
||||
|
||||
export function stringifyXML(obj: any, opts?: { rootName?: string }) {
|
||||
const rootName = opts && opts.rootName || "root";
|
||||
const rootName = (opts && opts.rootName) || "root";
|
||||
const dom = buildNode(obj, rootName)[0];
|
||||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' + serializer.serializeToString(dom);
|
||||
return (
|
||||
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' + serializer.serializeToString(dom)
|
||||
);
|
||||
}
|
||||
|
||||
function buildAttributes(attrs: { [key: string]: { toString(): string; } }): Attr[] {
|
||||
function buildAttributes(attrs: { [key: string]: { toString(): string } }): Attr[] {
|
||||
const result = [];
|
||||
for (const key of Object.keys(attrs)) {
|
||||
const attr = doc.createAttribute(key);
|
||||
|
@ -113,8 +121,7 @@ function buildNode(obj: any, elementName: string): Node[] {
|
|||
const elem = doc.createElement(elementName);
|
||||
elem.textContent = obj.toString();
|
||||
return [elem];
|
||||
}
|
||||
else if (Array.isArray(obj)) {
|
||||
} else if (Array.isArray(obj)) {
|
||||
const result = [];
|
||||
for (const arrayElem of obj) {
|
||||
for (const child of buildNode(arrayElem, elementName)) {
|
||||
|
@ -136,8 +143,7 @@ function buildNode(obj: any, elementName: string): Node[] {
|
|||
}
|
||||
}
|
||||
return [elem];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw new Error(`Illegal value passed to buildObject: ${obj}`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ export function stringifyXML(obj: any, opts?: { rootName?: string }) {
|
|||
const builder = new xml2js.Builder({
|
||||
rootName: (opts || {}).rootName,
|
||||
renderOpts: {
|
||||
pretty: false
|
||||
}
|
||||
pretty: false,
|
||||
},
|
||||
});
|
||||
return builder.buildObject(obj);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export function parseXML(str: string): Promise<any> {
|
|||
const xmlParser = new xml2js.Parser({
|
||||
explicitArray: false,
|
||||
explicitCharkey: false,
|
||||
explicitRoot: false
|
||||
explicitRoot: false,
|
||||
});
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!str) {
|
||||
|
|
|
@ -9,8 +9,21 @@ import { HttpOperationResponse } from "./httpOperationResponse";
|
|||
import { OperationResponse } from "./operationResponse";
|
||||
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);
|
||||
export type HttpMethods =
|
||||
| "GET"
|
||||
| "PUT"
|
||||
| "POST"
|
||||
| "DELETE"
|
||||
| "PATCH"
|
||||
| "HEAD"
|
||||
| "OPTIONS"
|
||||
| "TRACE";
|
||||
export type HttpRequestBody =
|
||||
| Blob
|
||||
| string
|
||||
| ArrayBuffer
|
||||
| ArrayBufferView
|
||||
| (() => NodeJS.ReadableStream);
|
||||
|
||||
/**
|
||||
* Fired in response to upload or download progress.
|
||||
|
@ -19,7 +32,7 @@ export type TransferProgressEvent = {
|
|||
/**
|
||||
* The number of bytes loaded so far.
|
||||
*/
|
||||
loadedBytes: number
|
||||
loadedBytes: number;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -30,8 +43,16 @@ export interface AbortSignalLike {
|
|||
readonly aborted: boolean;
|
||||
dispatchEvent: (event: Event) => boolean;
|
||||
onabort: ((this: AbortSignalLike, ev: Event) => any) | null;
|
||||
addEventListener: (type: "abort", listener: (this: AbortSignalLike, ev: Event) => any, options?: any) => void;
|
||||
removeEventListener: (type: "abort", listener: (this: AbortSignalLike, ev: Event) => any, options?: any) => void;
|
||||
addEventListener: (
|
||||
type: "abort",
|
||||
listener: (this: AbortSignalLike, ev: Event) => any,
|
||||
options?: any
|
||||
) => void;
|
||||
removeEventListener: (
|
||||
type: "abort",
|
||||
listener: (this: AbortSignalLike, ev: Event) => any,
|
||||
options?: any
|
||||
) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,9 +199,12 @@ export class WebResource {
|
|||
* HttpOperationResponse combination. If this is undefined, then a simple status code lookup will
|
||||
* be used.
|
||||
*/
|
||||
operationResponseGetter?: (operationSpec: OperationSpec, response: HttpOperationResponse) => (undefined | OperationResponse);
|
||||
operationResponseGetter?: (
|
||||
operationSpec: OperationSpec,
|
||||
response: HttpOperationResponse
|
||||
) => undefined | OperationResponse;
|
||||
formData?: any;
|
||||
query?: { [key: string]: any; };
|
||||
query?: { [key: string]: any };
|
||||
operationSpec?: OperationSpec;
|
||||
withCredentials: boolean;
|
||||
timeout: number;
|
||||
|
@ -200,8 +224,8 @@ export class WebResource {
|
|||
url?: string,
|
||||
method?: HttpMethods,
|
||||
body?: any,
|
||||
query?: { [key: string]: any; },
|
||||
headers?: { [key: string]: any; } | HttpHeadersLike,
|
||||
query?: { [key: string]: any },
|
||||
headers?: { [key: string]: any } | HttpHeadersLike,
|
||||
streamResponseBody?: boolean,
|
||||
withCredentials?: boolean,
|
||||
abortSignal?: AbortSignalLike,
|
||||
|
@ -210,12 +234,12 @@ export class WebResource {
|
|||
onDownloadProgress?: (progress: TransferProgressEvent) => void,
|
||||
proxySettings?: ProxySettings,
|
||||
keepAlive?: boolean,
|
||||
agentSettings?: AgentSettings) {
|
||||
|
||||
agentSettings?: AgentSettings
|
||||
) {
|
||||
this.streamResponseBody = streamResponseBody;
|
||||
this.url = url || "";
|
||||
this.method = method || "GET";
|
||||
this.headers = (isHttpHeadersLike(headers) ? headers : new HttpHeaders(headers));
|
||||
this.headers = isHttpHeadersLike(headers) ? headers : new HttpHeaders(headers);
|
||||
this.body = body;
|
||||
this.query = query;
|
||||
this.formData = undefined;
|
||||
|
@ -258,18 +282,22 @@ export class WebResource {
|
|||
}
|
||||
|
||||
if (options.url && options.pathTemplate) {
|
||||
throw new Error("options.url and options.pathTemplate are mutually exclusive. Please provide exactly one of them.");
|
||||
throw new Error(
|
||||
"options.url and options.pathTemplate are mutually exclusive. Please provide exactly one of them."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if ((options.pathTemplate == undefined || typeof options.pathTemplate.valueOf() !== "string") && (options.url == undefined || typeof options.url.valueOf() !== "string")) {
|
||||
if (
|
||||
(options.pathTemplate == undefined || typeof options.pathTemplate.valueOf() !== "string") &&
|
||||
(options.url == undefined || typeof options.url.valueOf() !== "string")
|
||||
) {
|
||||
throw new Error("Please provide exactly one of options.pathTemplate or options.url.");
|
||||
}
|
||||
|
||||
// set the url if it is provided.
|
||||
if (options.url) {
|
||||
if (typeof options.url !== "string") {
|
||||
throw new Error("options.url must be of type \"string\".");
|
||||
throw new Error('options.url must be of type "string".');
|
||||
}
|
||||
this.url = options.url;
|
||||
}
|
||||
|
@ -278,35 +306,55 @@ export class WebResource {
|
|||
if (options.method) {
|
||||
const validMethods = ["GET", "PUT", "HEAD", "DELETE", "OPTIONS", "POST", "PATCH", "TRACE"];
|
||||
if (validMethods.indexOf(options.method.toUpperCase()) === -1) {
|
||||
throw new Error("The provided method \"" + options.method + "\" is invalid. Supported HTTP methods are: " + JSON.stringify(validMethods));
|
||||
throw new Error(
|
||||
'The provided method "' +
|
||||
options.method +
|
||||
'" is invalid. Supported HTTP methods are: ' +
|
||||
JSON.stringify(validMethods)
|
||||
);
|
||||
}
|
||||
}
|
||||
this.method = (options.method.toUpperCase() as HttpMethods);
|
||||
this.method = options.method.toUpperCase() as HttpMethods;
|
||||
|
||||
// construct the url if path template is provided
|
||||
if (options.pathTemplate) {
|
||||
const { pathTemplate, pathParameters } = options;
|
||||
if (typeof pathTemplate !== "string") {
|
||||
throw new Error("options.pathTemplate must be of type \"string\".");
|
||||
throw new Error('options.pathTemplate must be of type "string".');
|
||||
}
|
||||
if (!options.baseUrl) {
|
||||
options.baseUrl = "https://management.azure.com";
|
||||
}
|
||||
const baseUrl = options.baseUrl;
|
||||
let url = baseUrl + (baseUrl.endsWith("/") ? "" : "/") + (pathTemplate.startsWith("/") ? pathTemplate.slice(1) : pathTemplate);
|
||||
const segments = url.match(/({\w*\s*\w*})/ig);
|
||||
let url =
|
||||
baseUrl +
|
||||
(baseUrl.endsWith("/") ? "" : "/") +
|
||||
(pathTemplate.startsWith("/") ? pathTemplate.slice(1) : pathTemplate);
|
||||
const segments = url.match(/({\w*\s*\w*})/gi);
|
||||
if (segments && segments.length) {
|
||||
if (!pathParameters) {
|
||||
throw new Error(`pathTemplate: ${pathTemplate} has been provided. Hence, options.pathParameters must also be provided.`);
|
||||
throw new Error(
|
||||
`pathTemplate: ${pathTemplate} has been provided. Hence, options.pathParameters must also be provided.`
|
||||
);
|
||||
}
|
||||
segments.forEach(function (item) {
|
||||
const pathParamName = item.slice(1, -1);
|
||||
const pathParam = (pathParameters as { [key: string]: any })[pathParamName];
|
||||
if (pathParam === null || pathParam === undefined || !(typeof pathParam === "string" || typeof pathParam === "object")) {
|
||||
throw new Error(`pathTemplate: ${pathTemplate} contains the path parameter ${pathParamName}` +
|
||||
` however, it is not present in ${pathParameters} - ${JSON.stringify(pathParameters, undefined, 2)}.` +
|
||||
`The value of the path parameter can either be a "string" of the form { ${pathParamName}: "some sample value" } or ` +
|
||||
`it can be an "object" of the form { "${pathParamName}": { value: "some sample value", skipUrlEncoding: true } }.`);
|
||||
if (
|
||||
pathParam === null ||
|
||||
pathParam === undefined ||
|
||||
!(typeof pathParam === "string" || typeof pathParam === "object")
|
||||
) {
|
||||
throw new Error(
|
||||
`pathTemplate: ${pathTemplate} contains the path parameter ${pathParamName}` +
|
||||
` however, it is not present in ${pathParameters} - ${JSON.stringify(
|
||||
pathParameters,
|
||||
undefined,
|
||||
2
|
||||
)}.` +
|
||||
`The value of the path parameter can either be a "string" of the form { ${pathParamName}: "some sample value" } or ` +
|
||||
`it can be an "object" of the form { "${pathParamName}": { value: "some sample value", skipUrlEncoding: true } }.`
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof pathParam.valueOf() === "string") {
|
||||
|
@ -315,7 +363,9 @@ export class WebResource {
|
|||
|
||||
if (typeof pathParam.valueOf() === "object") {
|
||||
if (!pathParam.value) {
|
||||
throw new Error(`options.pathParameters[${pathParamName}] is of type "object" but it does not contain a "value" property.`);
|
||||
throw new Error(
|
||||
`options.pathParameters[${pathParamName}] is of type "object" but it does not contain a "value" property.`
|
||||
);
|
||||
}
|
||||
if (pathParam.skipUrlEncoding) {
|
||||
url = url.replace(item, pathParam.value);
|
||||
|
@ -332,9 +382,11 @@ export class WebResource {
|
|||
if (options.queryParameters) {
|
||||
const queryParameters = options.queryParameters;
|
||||
if (typeof queryParameters !== "object") {
|
||||
throw new Error(`options.queryParameters must be of type object. It should be a JSON object ` +
|
||||
`of "query-parameter-name" as the key and the "query-parameter-value" as the value. ` +
|
||||
`The "query-parameter-value" may be fo type "string" or an "object" of the form { value: "query-parameter-value", skipUrlEncoding: true }.`);
|
||||
throw new Error(
|
||||
`options.queryParameters must be of type object. It should be a JSON object ` +
|
||||
`of "query-parameter-name" as the key and the "query-parameter-value" as the value. ` +
|
||||
`The "query-parameter-value" may be fo type "string" or an "object" of the form { value: "query-parameter-value", skipUrlEncoding: true }.`
|
||||
);
|
||||
}
|
||||
// append question mark if it is not present in the url
|
||||
if (this.url && this.url.indexOf("?") === -1) {
|
||||
|
@ -350,10 +402,11 @@ export class WebResource {
|
|||
if (typeof queryParam === "string") {
|
||||
queryParams.push(queryParamName + "=" + encodeURIComponent(queryParam));
|
||||
this.query[queryParamName] = encodeURIComponent(queryParam);
|
||||
}
|
||||
else if (typeof queryParam === "object") {
|
||||
} else if (typeof queryParam === "object") {
|
||||
if (!queryParam.value) {
|
||||
throw new Error(`options.queryParameters[${queryParamName}] is of type "object" but it does not contain a "value" property.`);
|
||||
throw new Error(
|
||||
`options.queryParameters[${queryParamName}] is of type "object" but it does not contain a "value" property.`
|
||||
);
|
||||
}
|
||||
if (queryParam.skipUrlEncoding) {
|
||||
queryParams.push(queryParamName + "=" + queryParam.value);
|
||||
|
@ -364,7 +417,7 @@ export class WebResource {
|
|||
}
|
||||
}
|
||||
}
|
||||
}// end-of-for
|
||||
} // end-of-for
|
||||
// append the queryString
|
||||
this.url += queryParams.join("&");
|
||||
}
|
||||
|
@ -403,7 +456,11 @@ export class WebResource {
|
|||
}
|
||||
} else {
|
||||
if (options.serializationMapper) {
|
||||
this.body = new Serializer(options.mappers).serialize(options.serializationMapper, options.body, "requestBody");
|
||||
this.body = new Serializer(options.mappers).serialize(
|
||||
options.serializationMapper,
|
||||
options.body,
|
||||
"requestBody"
|
||||
);
|
||||
}
|
||||
if (!options.disableJsonStringifyOnBody) {
|
||||
this.body = JSON.stringify(options.body);
|
||||
|
@ -437,7 +494,8 @@ export class WebResource {
|
|||
this.onDownloadProgress,
|
||||
this.proxySettings,
|
||||
this.keepAlive,
|
||||
this.agentSettings);
|
||||
this.agentSettings
|
||||
);
|
||||
|
||||
if (this.formData) {
|
||||
result.formData = this.formData;
|
||||
|
|
|
@ -94,7 +94,7 @@ export class XhrHttpClient implements HttpClient {
|
|||
request,
|
||||
status: xhr.status,
|
||||
headers: parseHeaders(xhr),
|
||||
blobBody
|
||||
blobBody,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -102,30 +102,40 @@ export class XhrHttpClient implements HttpClient {
|
|||
});
|
||||
} else {
|
||||
return new Promise(function (resolve, reject) {
|
||||
xhr.addEventListener("load", () => resolve({
|
||||
request,
|
||||
status: xhr.status,
|
||||
headers: parseHeaders(xhr),
|
||||
bodyAsText: xhr.responseText
|
||||
}));
|
||||
xhr.addEventListener("load", () =>
|
||||
resolve({
|
||||
request,
|
||||
status: xhr.status,
|
||||
headers: parseHeaders(xhr),
|
||||
bodyAsText: xhr.responseText,
|
||||
})
|
||||
);
|
||||
rejectOnTerminalEvent(request, xhr, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addProgressListener(xhr: XMLHttpRequestEventTarget, listener?: (progress: TransferProgressEvent) => void) {
|
||||
function addProgressListener(
|
||||
xhr: XMLHttpRequestEventTarget,
|
||||
listener?: (progress: TransferProgressEvent) => void
|
||||
) {
|
||||
if (listener) {
|
||||
xhr.addEventListener("progress", rawEvent => listener({
|
||||
loadedBytes: rawEvent.loaded
|
||||
}));
|
||||
xhr.addEventListener("progress", (rawEvent) =>
|
||||
listener({
|
||||
loadedBytes: rawEvent.loaded,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// exported locally for testing
|
||||
export function parseHeaders(xhr: XMLHttpRequest) {
|
||||
const responseHeaders = new HttpHeaders();
|
||||
const headerLines = xhr.getAllResponseHeaders().trim().split(/[\r\n]+/);
|
||||
const headerLines = xhr
|
||||
.getAllResponseHeaders()
|
||||
.trim()
|
||||
.split(/[\r\n]+/);
|
||||
for (const line of headerLines) {
|
||||
const index = line.indexOf(":");
|
||||
const headerName = line.slice(0, index);
|
||||
|
@ -135,8 +145,34 @@ export function parseHeaders(xhr: XMLHttpRequest) {
|
|||
return responseHeaders;
|
||||
}
|
||||
|
||||
function rejectOnTerminalEvent(request: WebResourceLike, xhr: XMLHttpRequest, reject: (err: any) => void) {
|
||||
xhr.addEventListener("error", () => reject(new RestError(`Failed to send request to ${request.url}`, RestError.REQUEST_SEND_ERROR, undefined, request)));
|
||||
xhr.addEventListener("abort", () => reject(new RestError("The request was aborted", RestError.REQUEST_ABORTED_ERROR, undefined, request)));
|
||||
xhr.addEventListener("timeout", () => reject(new RestError(`timeout of ${xhr.timeout}ms exceeded`, RestError.REQUEST_SEND_ERROR, undefined, request)));
|
||||
function rejectOnTerminalEvent(
|
||||
request: WebResourceLike,
|
||||
xhr: XMLHttpRequest,
|
||||
reject: (err: any) => void
|
||||
) {
|
||||
xhr.addEventListener("error", () =>
|
||||
reject(
|
||||
new RestError(
|
||||
`Failed to send request to ${request.url}`,
|
||||
RestError.REQUEST_SEND_ERROR,
|
||||
undefined,
|
||||
request
|
||||
)
|
||||
)
|
||||
);
|
||||
xhr.addEventListener("abort", () =>
|
||||
reject(
|
||||
new RestError("The request was aborted", RestError.REQUEST_ABORTED_ERROR, undefined, request)
|
||||
)
|
||||
);
|
||||
xhr.addEventListener("timeout", () =>
|
||||
reject(
|
||||
new RestError(
|
||||
`timeout of ${xhr.timeout}ms exceeded`,
|
||||
RestError.REQUEST_SEND_ERROR,
|
||||
undefined,
|
||||
request
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@
|
|||
"mocha-multi-reporters": "^1.1.7",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"nyc": "^14.1.1",
|
||||
"prettier": "2.2.1",
|
||||
"rollup": "^1.16.6",
|
||||
"rollup-plugin-commonjs": "^10.0.1",
|
||||
"rollup-plugin-json": "^4.0.0",
|
||||
|
@ -139,6 +140,7 @@
|
|||
"build:rollup": "rollup -c rollup.config.ts",
|
||||
"build:minify-browser": "terser -c -m --comments --source-map \"content='./dist/msRest.browser.js.map'\" -o ./dist/msRest.browser.min.js ./dist/msRest.browser.js",
|
||||
"build:test-browser": "webpack --config webpack.testconfig.ts",
|
||||
"format": "prettier --write \"./**/*.ts\"",
|
||||
"test": "run-p test:tslint test:unit test:karma",
|
||||
"test:tslint": "tslint -p .",
|
||||
"test:unit": "nyc mocha",
|
||||
|
|
|
@ -37,7 +37,7 @@ const nodeConfig = {
|
|||
file: "./dist/msRest.node.js",
|
||||
format: "cjs",
|
||||
sourcemap: true,
|
||||
banner
|
||||
banner,
|
||||
},
|
||||
plugins: [
|
||||
nodeResolve({
|
||||
|
@ -48,9 +48,9 @@ const nodeConfig = {
|
|||
json(),
|
||||
visualizer({
|
||||
filename: "dist/node-stats.html",
|
||||
sourcemap: true
|
||||
})
|
||||
]
|
||||
sourcemap: true,
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -64,19 +64,19 @@ const browserConfig = {
|
|||
format: "umd",
|
||||
name: "msRest",
|
||||
sourcemap: true,
|
||||
banner
|
||||
banner,
|
||||
},
|
||||
plugins: [
|
||||
nodeResolve({
|
||||
mainFields: ["module", "main", "browser"]
|
||||
mainFields: ["module", "main", "browser"],
|
||||
}),
|
||||
commonjs(),
|
||||
sourcemaps(),
|
||||
visualizer({
|
||||
filename: "dist/browser-stats.html",
|
||||
sourcemap: true
|
||||
})
|
||||
]
|
||||
sourcemap: true,
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
export default [nodeConfig, browserConfig];
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as msRest from "../lib/msRest";
|
||||
const clientOptions: msRest.ServiceClientOptions = {
|
||||
// add log policy to list of default factories.
|
||||
requestPolicyFactories: (factories) => factories.concat([msRest.logPolicy()])
|
||||
requestPolicyFactories: (factories) => factories.concat([msRest.logPolicy()]),
|
||||
};
|
||||
|
||||
const subscriptionId = process.env["AZURE_SUBSCRIPTION_ID"] || "subscriptionId";
|
||||
|
@ -17,10 +17,9 @@ const creds = new msRest.TokenCredentials(token);
|
|||
const client = new msRest.ServiceClient(creds, clientOptions);
|
||||
const req: msRest.RequestPrepareOptions = {
|
||||
url: `https://management.azure.com/subscriptions/${subscriptionId}/providers/Microsoft.Storage/storageAccounts?api-version=2015-06-15`,
|
||||
method: "GET"
|
||||
method: "GET",
|
||||
};
|
||||
|
||||
client.sendRequest(req).then(function (res: msRest.HttpOperationResponse) {
|
||||
console.log(res.bodyAsText);
|
||||
});
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@ describe("Token credentials", () => {
|
|||
|
||||
creds.signRequest(request).then((signedRequest: msRest.WebResourceLike) => {
|
||||
signedRequest.headers.get("authorization")!.should.exist;
|
||||
signedRequest.headers.get("authorization")!.should.match(new RegExp("^Bearer\\s+" + dummyToken + "$"));
|
||||
signedRequest.headers
|
||||
.get("authorization")!
|
||||
.should.match(new RegExp("^Bearer\\s+" + dummyToken + "$"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -30,14 +32,15 @@ describe("Token credentials", () => {
|
|||
const request = new msRest.WebResource();
|
||||
creds.signRequest(request).then((signedRequest: msRest.WebResourceLike) => {
|
||||
signedRequest.headers.get("authorization")!.should.exist;
|
||||
signedRequest.headers.get("authorization")!.should.match(new RegExp("^" + fakeScheme + "\\s+" + dummyToken + "$"));
|
||||
signedRequest.headers
|
||||
.get("authorization")!
|
||||
.should.match(new RegExp("^" + fakeScheme + "\\s+" + dummyToken + "$"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("construction", () => {
|
||||
|
||||
it("should succeed with token", () => {
|
||||
(() => {
|
||||
new TokenCredentials(dummyToken);
|
||||
|
@ -66,7 +69,9 @@ describe("Basic Authentication credentials", () => {
|
|||
const request = new msRest.WebResource();
|
||||
creds.signRequest(request).then((signedRequest: msRest.WebResourceLike) => {
|
||||
signedRequest.headers.get("authorization")!.should.exist;
|
||||
signedRequest.headers.get("authorization")!.should.match(new RegExp("^Basic\\s+" + encodedCredentials + "$"));
|
||||
signedRequest.headers
|
||||
.get("authorization")!
|
||||
.should.match(new RegExp("^Basic\\s+" + encodedCredentials + "$"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -77,7 +82,9 @@ describe("Basic Authentication credentials", () => {
|
|||
|
||||
creds.signRequest(request).then((signedRequest: msRest.WebResourceLike) => {
|
||||
signedRequest.headers.get("authorization")!.should.exist;
|
||||
signedRequest.headers.get("authorization")!.should.match(new RegExp("^" + fakeScheme + "\\s+" + encodedCredentials + "$"));
|
||||
signedRequest.headers
|
||||
.get("authorization")!
|
||||
.should.match(new RegExp("^" + fakeScheme + "\\s+" + encodedCredentials + "$"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -94,7 +101,7 @@ describe("Basic Authentication credentials", () => {
|
|||
describe("ApiKey credentials", () => {
|
||||
describe("usage", function () {
|
||||
it("should set header parameters properly in request", async function () {
|
||||
const creds = new ApiKeyCredentials({inHeader: {"key1": "value1", "key2": "value2"}});
|
||||
const creds = new ApiKeyCredentials({ inHeader: { key1: "value1", key2: "value2" } });
|
||||
const request = new msRest.WebResource();
|
||||
request.headers = new msRest.HttpHeaders();
|
||||
|
||||
|
@ -107,10 +114,10 @@ describe("Basic Authentication credentials", () => {
|
|||
});
|
||||
|
||||
it("should set query parameters properly in the request url without any query parameters", async function () {
|
||||
const creds = new ApiKeyCredentials({inQuery: {"key1": "value1", "key2": "value2"}});
|
||||
const creds = new ApiKeyCredentials({ inQuery: { key1: "value1", key2: "value2" } });
|
||||
const request = {
|
||||
headers: {},
|
||||
url: "https://example.com"
|
||||
url: "https://example.com",
|
||||
} as msRest.WebResource;
|
||||
|
||||
await creds.signRequest(request);
|
||||
|
@ -118,10 +125,10 @@ describe("Basic Authentication credentials", () => {
|
|||
});
|
||||
|
||||
it("should set query parameters properly in the request url with existing query parameters", async function () {
|
||||
const creds = new ApiKeyCredentials({inQuery: {"key1": "value1", "key2": "value2"}});
|
||||
const creds = new ApiKeyCredentials({ inQuery: { key1: "value1", key2: "value2" } });
|
||||
const request = {
|
||||
headers: {},
|
||||
url: "https://example.com?q1=v2"
|
||||
url: "https://example.com?q1=v2",
|
||||
} as msRest.WebResource;
|
||||
|
||||
await creds.signRequest(request);
|
||||
|
@ -130,25 +137,24 @@ describe("Basic Authentication credentials", () => {
|
|||
});
|
||||
|
||||
describe("construction", function () {
|
||||
|
||||
it("should fail with options.inHeader and options.inQuery set to null or undefined", function (done) {
|
||||
(function () {
|
||||
new ApiKeyCredentials({ inHeader: undefined, inQuery: undefined } as any);
|
||||
}).should.throw();
|
||||
}.should.throw());
|
||||
done();
|
||||
});
|
||||
|
||||
it("should fail without options", function (done) {
|
||||
(function () {
|
||||
new (ApiKeyCredentials as any)();
|
||||
}).should.throw();
|
||||
}.should.throw());
|
||||
done();
|
||||
});
|
||||
|
||||
it("should fail with empty options", function (done) {
|
||||
(function () {
|
||||
new ApiKeyCredentials({});
|
||||
}).should.throw();
|
||||
}.should.throw());
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,29 +16,29 @@ internalMappers.Cat = {
|
|||
required: false,
|
||||
serializedName: "id",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
name: {
|
||||
required: false,
|
||||
serializedName: "name",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
pettype: {
|
||||
required: true,
|
||||
serializedName: "pet\\.type",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
color: {
|
||||
required: false,
|
||||
serializedName: "color",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
hates: {
|
||||
required: false,
|
||||
|
@ -50,13 +50,13 @@ internalMappers.Cat = {
|
|||
serializedName: "DogElementType",
|
||||
type: {
|
||||
name: "Composite",
|
||||
className: "Dog"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "Dog",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.Dog = {
|
||||
required: false,
|
||||
|
@ -69,32 +69,32 @@ internalMappers.Dog = {
|
|||
required: false,
|
||||
serializedName: "id",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
name: {
|
||||
required: false,
|
||||
serializedName: "name",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
pettype: {
|
||||
required: true,
|
||||
serializedName: "pet\\.type",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
food: {
|
||||
required: false,
|
||||
serializedName: "food",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.Fish = {
|
||||
required: false,
|
||||
|
@ -103,7 +103,7 @@ internalMappers.Fish = {
|
|||
name: "Composite",
|
||||
polymorphicDiscriminator: {
|
||||
serializedName: "fish.type",
|
||||
clientName: "fishtype"
|
||||
clientName: "fishtype",
|
||||
},
|
||||
uberParent: "Fish",
|
||||
className: "Fish",
|
||||
|
@ -112,15 +112,15 @@ internalMappers.Fish = {
|
|||
required: false,
|
||||
serializedName: "species",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
length: {
|
||||
required: true,
|
||||
serializedName: "length",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
siblings: {
|
||||
required: false,
|
||||
|
@ -134,23 +134,23 @@ internalMappers.Fish = {
|
|||
name: "Composite",
|
||||
polymorphicDiscriminator: {
|
||||
serializedName: "fish.type",
|
||||
clientName: "fishtype"
|
||||
clientName: "fishtype",
|
||||
},
|
||||
uberParent: "Fish",
|
||||
className: "Fish"
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "Fish",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fishtype: {
|
||||
required: true,
|
||||
serializedName: "fish\\.type",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.Invoice = {
|
||||
required: false,
|
||||
|
@ -163,15 +163,15 @@ internalMappers.Invoice = {
|
|||
serializedName: "invoiceId",
|
||||
required: true,
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
invDate: {
|
||||
serializedName: "invDate",
|
||||
required: false,
|
||||
type: {
|
||||
name: "Date"
|
||||
}
|
||||
name: "Date",
|
||||
},
|
||||
},
|
||||
invProducts: {
|
||||
serializedName: "invProducts",
|
||||
|
@ -184,15 +184,15 @@ internalMappers.Invoice = {
|
|||
value: {
|
||||
type: {
|
||||
name: "Composite",
|
||||
className: "Product"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "Product",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.Pet = {
|
||||
required: false,
|
||||
|
@ -206,25 +206,25 @@ internalMappers.Pet = {
|
|||
required: false,
|
||||
serializedName: "id",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
name: {
|
||||
required: false,
|
||||
serializedName: "name",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
pettype: {
|
||||
required: true,
|
||||
serializedName: "pet\\.type",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.PetAP = {
|
||||
required: false,
|
||||
|
@ -233,8 +233,8 @@ internalMappers.PetAP = {
|
|||
name: "Composite",
|
||||
additionalProperties: {
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
className: "PetAP",
|
||||
modelProperties: {
|
||||
|
@ -242,15 +242,15 @@ internalMappers.PetAP = {
|
|||
required: true,
|
||||
serializedName: "id",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
name: {
|
||||
required: false,
|
||||
serializedName: "name",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
eyeColor: {
|
||||
required: true,
|
||||
|
@ -258,31 +258,31 @@ internalMappers.PetAP = {
|
|||
isConstant: true,
|
||||
defaultValue: "brown",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
favoriteFood: {
|
||||
required: false,
|
||||
serializedName: "favoriteFood",
|
||||
defaultValue: "bones",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
status: {
|
||||
required: false,
|
||||
readOnly: true,
|
||||
serializedName: "status",
|
||||
type: {
|
||||
name: "Boolean"
|
||||
}
|
||||
name: "Boolean",
|
||||
},
|
||||
},
|
||||
odatalocation: {
|
||||
required: true,
|
||||
serializedName: "@odata\\.location",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
additionalProperties1: {
|
||||
required: false,
|
||||
|
@ -293,13 +293,13 @@ internalMappers.PetAP = {
|
|||
required: false,
|
||||
serializedName: "NumberElementType",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.PetGallery = {
|
||||
required: false,
|
||||
|
@ -312,15 +312,15 @@ internalMappers.PetGallery = {
|
|||
required: false,
|
||||
serializedName: "id",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
name: {
|
||||
required: false,
|
||||
serializedName: "name",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
pets: {
|
||||
required: false,
|
||||
|
@ -334,13 +334,13 @@ internalMappers.PetGallery = {
|
|||
name: "Composite",
|
||||
polymorphicDiscriminator: "pet.type",
|
||||
uberParent: "Pet",
|
||||
className: "Pet"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "Pet",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.Product = {
|
||||
required: false,
|
||||
|
@ -351,33 +351,31 @@ internalMappers.Product = {
|
|||
modelProperties: {
|
||||
id: {
|
||||
serializedName: "id",
|
||||
constraints: {
|
||||
|
||||
},
|
||||
constraints: {},
|
||||
required: true,
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
name: {
|
||||
serializedName: "name",
|
||||
required: true,
|
||||
type: {
|
||||
name: "String"
|
||||
name: "String",
|
||||
},
|
||||
constraints: {
|
||||
MaxLength: 256,
|
||||
MinLength: 1,
|
||||
Pattern: /^[A-Za-z0-9-._]+$/
|
||||
}
|
||||
Pattern: /^[A-Za-z0-9-._]+$/,
|
||||
},
|
||||
},
|
||||
provisioningState: {
|
||||
serializedName: "properties.provisioningState",
|
||||
required: false,
|
||||
type: {
|
||||
name: "Enum",
|
||||
allowedValues: ["Creating", "Failed", "Succeeded"]
|
||||
}
|
||||
allowedValues: ["Creating", "Failed", "Succeeded"],
|
||||
},
|
||||
},
|
||||
tags: {
|
||||
serializedName: "tags",
|
||||
|
@ -386,25 +384,25 @@ internalMappers.Product = {
|
|||
name: "Dictionary",
|
||||
value: {
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
dispatchTime: {
|
||||
serializedName: "dispatchTime",
|
||||
required: false,
|
||||
type: {
|
||||
name: "DateTime"
|
||||
}
|
||||
name: "DateTime",
|
||||
},
|
||||
},
|
||||
invoiceInfo: {
|
||||
serializedName: "invoiceInfo",
|
||||
required: false,
|
||||
type: {
|
||||
name: "Composite",
|
||||
className: "Invoice"
|
||||
}
|
||||
className: "Invoice",
|
||||
},
|
||||
},
|
||||
subProducts: {
|
||||
serializedName: "subProducts",
|
||||
|
@ -414,13 +412,13 @@ internalMappers.Product = {
|
|||
element: {
|
||||
type: {
|
||||
name: "Composite",
|
||||
className: "SubProduct"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "SubProduct",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.ProductListResult = {
|
||||
required: false,
|
||||
|
@ -437,13 +435,13 @@ internalMappers.ProductListResult = {
|
|||
element: {
|
||||
type: {
|
||||
name: "Composite",
|
||||
className: "Product"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "Product",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.ProductListResultNextLink = {
|
||||
required: false,
|
||||
|
@ -460,20 +458,20 @@ internalMappers.ProductListResultNextLink = {
|
|||
element: {
|
||||
type: {
|
||||
name: "Composite",
|
||||
className: "Product"
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "Product",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nextLink: {
|
||||
serializedName: "nextLink",
|
||||
required: false,
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.SawShark = {
|
||||
required: false,
|
||||
|
@ -482,7 +480,7 @@ internalMappers.SawShark = {
|
|||
name: "Composite",
|
||||
polymorphicDiscriminator: {
|
||||
serializedName: "fish.type",
|
||||
clientName: "fishtype"
|
||||
clientName: "fishtype",
|
||||
},
|
||||
uberParent: "Fish",
|
||||
className: "Sawshark",
|
||||
|
@ -491,15 +489,15 @@ internalMappers.SawShark = {
|
|||
required: false,
|
||||
serializedName: "species",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
length: {
|
||||
required: true,
|
||||
serializedName: "length",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
siblings: {
|
||||
required: false,
|
||||
|
@ -513,44 +511,44 @@ internalMappers.SawShark = {
|
|||
name: "Composite",
|
||||
polymorphicDiscriminator: {
|
||||
serializedName: "fish.type",
|
||||
clientName: "fishtype"
|
||||
clientName: "fishtype",
|
||||
},
|
||||
uberParent: "Fish",
|
||||
className: "Fish"
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "Fish",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fishtype: {
|
||||
required: true,
|
||||
serializedName: "fish\\.type",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
age: {
|
||||
required: false,
|
||||
serializedName: "age",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
birthday: {
|
||||
required: true,
|
||||
serializedName: "birthday",
|
||||
type: {
|
||||
name: "DateTime"
|
||||
}
|
||||
name: "DateTime",
|
||||
},
|
||||
},
|
||||
picture: {
|
||||
required: false,
|
||||
serializedName: "picture",
|
||||
type: {
|
||||
name: "ByteArray"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "ByteArray",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.Shark = {
|
||||
required: false,
|
||||
|
@ -559,7 +557,7 @@ internalMappers.Shark = {
|
|||
name: "Composite",
|
||||
polymorphicDiscriminator: {
|
||||
serializedName: "fish.type",
|
||||
clientName: "fishtype"
|
||||
clientName: "fishtype",
|
||||
},
|
||||
uberParent: "Fish",
|
||||
className: "Shark",
|
||||
|
@ -568,15 +566,15 @@ internalMappers.Shark = {
|
|||
required: false,
|
||||
serializedName: "species",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
length: {
|
||||
required: true,
|
||||
serializedName: "length",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
siblings: {
|
||||
required: false,
|
||||
|
@ -590,37 +588,37 @@ internalMappers.Shark = {
|
|||
name: "Composite",
|
||||
polymorphicDiscriminator: {
|
||||
serializedName: "fish.type",
|
||||
clientName: "fishtype"
|
||||
clientName: "fishtype",
|
||||
},
|
||||
uberParent: "Fish",
|
||||
className: "Fish"
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "Fish",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fishtype: {
|
||||
required: true,
|
||||
serializedName: "fish\\.type",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
age: {
|
||||
required: false,
|
||||
serializedName: "age",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
birthday: {
|
||||
required: true,
|
||||
serializedName: "birthday",
|
||||
type: {
|
||||
name: "DateTime"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "DateTime",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
internalMappers.SubProduct = {
|
||||
required: false,
|
||||
|
@ -633,50 +631,50 @@ internalMappers.SubProduct = {
|
|||
serializedName: "subId",
|
||||
required: true,
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
subName: {
|
||||
serializedName: "subName",
|
||||
required: true,
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
provisioningState: {
|
||||
serializedName: "provisioningState",
|
||||
required: false,
|
||||
type: {
|
||||
name: "Enum",
|
||||
allowedValues: ["Creating", "Failed", "Succeeded"]
|
||||
}
|
||||
allowedValues: ["Creating", "Failed", "Succeeded"],
|
||||
},
|
||||
},
|
||||
makeTime: {
|
||||
serializedName: "makeTime",
|
||||
required: false,
|
||||
type: {
|
||||
name: "DateTime"
|
||||
}
|
||||
name: "DateTime",
|
||||
},
|
||||
},
|
||||
invoiceInfo: {
|
||||
serializedName: "invoiceInfo",
|
||||
required: false,
|
||||
type: {
|
||||
name: "Composite",
|
||||
className: "Invoice"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
className: "Invoice",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
internalMappers.discriminators = {
|
||||
"Fish": internalMappers.Fish,
|
||||
Fish: internalMappers.Fish,
|
||||
"Fish.shark": internalMappers.Shark,
|
||||
"Fish.sawshark": internalMappers.SawShark,
|
||||
"Pet": internalMappers.Pet,
|
||||
Pet: internalMappers.Pet,
|
||||
"Pet.Cat": internalMappers.Cat,
|
||||
"Pet.Dog": internalMappers.Dog
|
||||
"Pet.Dog": internalMappers.Dog,
|
||||
};
|
||||
|
||||
export const Mappers = internalMappers;
|
||||
|
|
|
@ -19,7 +19,8 @@ function getAbortController(): AbortController {
|
|||
if (typeof AbortController === "function") {
|
||||
controller = new AbortController();
|
||||
} else {
|
||||
const AbortControllerPonyfill = require("abortcontroller-polyfill/dist/cjs-ponyfill").AbortController;
|
||||
const AbortControllerPonyfill = require("abortcontroller-polyfill/dist/cjs-ponyfill")
|
||||
.AbortController;
|
||||
controller = new AbortControllerPonyfill();
|
||||
}
|
||||
return controller;
|
||||
|
@ -27,7 +28,7 @@ function getAbortController(): AbortController {
|
|||
|
||||
describe("defaultHttpClient", function () {
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
let httpMock: HttpMockFacade;
|
||||
|
@ -61,7 +62,16 @@ describe("defaultHttpClient", function () {
|
|||
});
|
||||
const controller = getAbortController();
|
||||
const veryBigPayload = "very long string";
|
||||
const request = new WebResource(resourceUrl, "POST", veryBigPayload, undefined, undefined, true, undefined, controller.signal);
|
||||
const request = new WebResource(
|
||||
resourceUrl,
|
||||
"POST",
|
||||
veryBigPayload,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
undefined,
|
||||
controller.signal
|
||||
);
|
||||
const client = new DefaultHttpClient();
|
||||
const promise = client.sendRequest(request);
|
||||
controller.abort();
|
||||
|
@ -78,14 +88,14 @@ describe("defaultHttpClient", function () {
|
|||
httpMock.get("http://my.fake.domain/set-cookie", {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Set-Cookie": "data=123456"
|
||||
}
|
||||
"Set-Cookie": "data=123456",
|
||||
},
|
||||
});
|
||||
|
||||
httpMock.get("http://my.fake.domain/cookie", async (_url, _method, _body, headers) => {
|
||||
return {
|
||||
status: 200,
|
||||
headers: headers
|
||||
headers: headers,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -99,7 +109,9 @@ describe("defaultHttpClient", function () {
|
|||
const response2 = await client.sendRequest(request2);
|
||||
response2.headers.get("Cookie")!.should.equal("data=123456");
|
||||
|
||||
const request3 = new WebResource("http://my.fake.domain/cookie", "GET", undefined, undefined, { Cookie: "data=abcdefg" });
|
||||
const request3 = new WebResource("http://my.fake.domain/cookie", "GET", undefined, undefined, {
|
||||
Cookie: "data=abcdefg",
|
||||
});
|
||||
const response3 = await client.sendRequest(request3);
|
||||
response3.headers.get("Cookie")!.should.equal("data=abcdefg");
|
||||
});
|
||||
|
@ -114,11 +126,29 @@ describe("defaultHttpClient", function () {
|
|||
const controller = getAbortController();
|
||||
const buf = "Very large string";
|
||||
const requests = [
|
||||
new WebResource("/fileupload", "POST", buf, undefined, undefined, true, undefined, controller.signal),
|
||||
new WebResource("/fileupload", "POST", buf, undefined, undefined, true, undefined, controller.signal)
|
||||
new WebResource(
|
||||
"/fileupload",
|
||||
"POST",
|
||||
buf,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
undefined,
|
||||
controller.signal
|
||||
),
|
||||
new WebResource(
|
||||
"/fileupload",
|
||||
"POST",
|
||||
buf,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
undefined,
|
||||
controller.signal
|
||||
),
|
||||
];
|
||||
const client = new DefaultHttpClient();
|
||||
const promises = requests.map(r => client.sendRequest(r));
|
||||
const promises = requests.map((r) => client.sendRequest(r));
|
||||
controller.abort();
|
||||
// Ensure each promise is individually rejected
|
||||
for (const promise of promises) {
|
||||
|
@ -143,16 +173,30 @@ describe("defaultHttpClient", function () {
|
|||
|
||||
it("for simple bodies", async function () {
|
||||
httpMock.post("/fileupload", async (_url, _method, _body) => {
|
||||
return { status: 251, body: body.repeat(9).substring(0, 200), headers: { "Content-Length": "200" } };
|
||||
return {
|
||||
status: 251,
|
||||
body: body.repeat(9).substring(0, 200),
|
||||
headers: { "Content-Length": "200" },
|
||||
};
|
||||
});
|
||||
|
||||
const upload: Notified = { notified: false };
|
||||
const download: Notified = { notified: false };
|
||||
|
||||
const body = "Very large string to upload";
|
||||
const request = new WebResource("/fileupload", "POST", body, undefined, undefined, false, undefined, undefined, 0,
|
||||
ev => listener(upload, ev),
|
||||
ev => listener(download, ev));
|
||||
const request = new WebResource(
|
||||
"/fileupload",
|
||||
"POST",
|
||||
body,
|
||||
undefined,
|
||||
undefined,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
0,
|
||||
(ev) => listener(upload, ev),
|
||||
(ev) => listener(download, ev)
|
||||
);
|
||||
|
||||
const client = new DefaultHttpClient();
|
||||
const response = await client.sendRequest(request);
|
||||
|
@ -173,24 +217,38 @@ describe("defaultHttpClient", function () {
|
|||
const size = isNode ? payload.toString().length : undefined;
|
||||
|
||||
httpMock.post("/bigfileupload", async (_url, _method, _body) => {
|
||||
return { status: 250, body: payload, headers: { "Content-Type": "text/javascript", "Content-length": size } };
|
||||
return {
|
||||
status: 250,
|
||||
body: payload,
|
||||
headers: { "Content-Type": "text/javascript", "Content-length": size },
|
||||
};
|
||||
});
|
||||
|
||||
const upload: Notified = { notified: false };
|
||||
const download: Notified = { notified: false };
|
||||
|
||||
const request = new WebResource("/bigfileupload", "POST", payload, undefined, undefined, true, undefined, undefined, 0,
|
||||
ev => listener(upload, ev),
|
||||
ev => listener(download, ev));
|
||||
const request = new WebResource(
|
||||
"/bigfileupload",
|
||||
"POST",
|
||||
payload,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
undefined,
|
||||
undefined,
|
||||
0,
|
||||
(ev) => listener(upload, ev),
|
||||
(ev) => listener(download, ev)
|
||||
);
|
||||
|
||||
const client = new DefaultHttpClient();
|
||||
const response = await client.sendRequest(request);
|
||||
response.status.should.equal(250);
|
||||
if (response.blobBody) {
|
||||
await response.blobBody;
|
||||
} else if ((typeof response.readableStreamBody === "function")) {
|
||||
} else if (typeof response.readableStreamBody === "function") {
|
||||
const streamBody = (response.readableStreamBody as Function)();
|
||||
streamBody.on("data", () => { });
|
||||
streamBody.on("data", () => {});
|
||||
await new Promise((resolve, reject) => {
|
||||
streamBody.on("end", resolve);
|
||||
streamBody.on("error", reject);
|
||||
|
@ -205,7 +263,17 @@ describe("defaultHttpClient", function () {
|
|||
it("should honor request timeouts", async function () {
|
||||
httpMock.timeout("GET", "/slow");
|
||||
|
||||
const request = new WebResource("/slow", "GET", undefined, undefined, undefined, false, false, undefined, 100);
|
||||
const request = new WebResource(
|
||||
"/slow",
|
||||
"GET",
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
false,
|
||||
false,
|
||||
undefined,
|
||||
100
|
||||
);
|
||||
const client = new DefaultHttpClient();
|
||||
try {
|
||||
await client.sendRequest(request);
|
||||
|
@ -234,12 +302,12 @@ describe("defaultHttpClient", function () {
|
|||
httpMock.put(requestUrl, async (_url, _method, body, _headers) => {
|
||||
if (!body) {
|
||||
return {
|
||||
status: 200
|
||||
status: 200,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
status: 400,
|
||||
body: `Expected empty body but got "${JSON.stringify(body)}"`
|
||||
body: `Expected empty body but got "${JSON.stringify(body)}"`,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
@ -264,8 +332,7 @@ describe("defaultHttpClient", function () {
|
|||
assert(response.headers);
|
||||
assert.strictEqual(response.headers.get("content-type")!.split(";")[0], "text/html");
|
||||
const responseBody: string | null | undefined = response.bodyAsText;
|
||||
const expectedResponseBody =
|
||||
`<!doctype html>
|
||||
const expectedResponseBody = `<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Example Domain</title>
|
||||
|
@ -314,7 +381,8 @@ describe("defaultHttpClient", function () {
|
|||
`;
|
||||
assert.strictEqual(
|
||||
responseBody && responseBody.replace(/\s/g, ""),
|
||||
expectedResponseBody.replace(/\s/g, ""));
|
||||
expectedResponseBody.replace(/\s/g, "")
|
||||
);
|
||||
httpMock.teardown();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,11 +12,10 @@ const emptyRequestPolicy: RequestPolicy = {
|
|||
sendRequest(request: WebResource): Promise<HttpOperationResponse> {
|
||||
// tslint:disable-next-line: no-null-keyword
|
||||
return Promise.resolve({ request, status: 200, headers: new HttpHeaders(), bodyAsText: null });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
describe("Log filter", () => {
|
||||
|
||||
it("should log messages when a logger object is provided", (done) => {
|
||||
const expected = `>> Request: {
|
||||
"url": "https://foo.com",
|
||||
|
@ -34,17 +33,21 @@ describe("Log filter", () => {
|
|||
>> Body: null
|
||||
`;
|
||||
let output = "";
|
||||
const logger = (message: string): void => { output += message + "\n"; };
|
||||
const logger = (message: string): void => {
|
||||
output += message + "\n";
|
||||
};
|
||||
const lf = new LogPolicy(emptyRequestPolicy, new RequestPolicyOptions(), logger);
|
||||
const req = new WebResource("https://foo.com", "PUT", { "a": 1 });
|
||||
lf.sendRequest(req).then(() => {
|
||||
// console.dir(output, { depth: null });
|
||||
// console.log(">>>>>>>");
|
||||
// console.dir(expected);
|
||||
assert.deepEqual(output, expected);
|
||||
done();
|
||||
}).catch((err: Error) => {
|
||||
done(err);
|
||||
});
|
||||
const req = new WebResource("https://foo.com", "PUT", { a: 1 });
|
||||
lf.sendRequest(req)
|
||||
.then(() => {
|
||||
// console.dir(output, { depth: null });
|
||||
// console.log(">>>>>>>");
|
||||
// console.dir(expected);
|
||||
assert.deepEqual(output, expected);
|
||||
done();
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,7 +14,12 @@ export type MockResponseData = {
|
|||
headers?: any;
|
||||
};
|
||||
|
||||
export type MockResponseFunction = (url?: string, method?: string, body?: any, headers?: any) => Promise<MockResponseData>;
|
||||
export type MockResponseFunction = (
|
||||
url?: string,
|
||||
method?: string,
|
||||
body?: any,
|
||||
headers?: any
|
||||
) => Promise<MockResponseData>;
|
||||
|
||||
export type MockResponse = MockResponseData | MockResponseFunction;
|
||||
|
||||
|
@ -30,7 +35,7 @@ export interface HttpMockFacade {
|
|||
}
|
||||
|
||||
export function getHttpMock(): HttpMockFacade {
|
||||
return (isNode ? new FetchHttpMock() : new BrowserHttpMock());
|
||||
return isNode ? new FetchHttpMock() : new BrowserHttpMock();
|
||||
}
|
||||
|
||||
class FetchHttpMock implements HttpMockFacade {
|
||||
|
@ -48,7 +53,7 @@ class FetchHttpMock implements HttpMockFacade {
|
|||
|
||||
timeout(_method: HttpMethods, url: UrlFilter): void {
|
||||
const delay = new Promise((resolve) => {
|
||||
setTimeout(() => resolve({$uri: url, delay: 500}), 2500);
|
||||
setTimeout(() => resolve({ $uri: url, delay: 500 }), 2500);
|
||||
});
|
||||
|
||||
fetchMock.mock(url, delay);
|
||||
|
@ -82,7 +87,8 @@ class FetchHttpMock implements HttpMockFacade {
|
|||
}) as fetch.MockResponseFunction;
|
||||
}
|
||||
|
||||
const matcher = (_url: string, opts: fetch.MockRequest) => (url === _url) && (opts.method === method);
|
||||
const matcher = (_url: string, opts: fetch.MockRequest) =>
|
||||
url === _url && opts.method === method;
|
||||
fetchMock.mock(matcher, mockResponse);
|
||||
}
|
||||
|
||||
|
@ -111,13 +117,21 @@ export class BrowserHttpMock implements HttpMockFacade {
|
|||
mockHttpMethod(method: HttpMethods, url: UrlFilter, response: MockResponse): void {
|
||||
if (typeof response === "function") {
|
||||
xhrMock.use(method, url, async (req, res) => {
|
||||
const result = await response(req.url().toString(), req.method().toString(), req.body(), req.headers());
|
||||
return res.status(result.status || 200).body(result.body || {}).headers(result.headers || {});
|
||||
const result = await response(
|
||||
req.url().toString(),
|
||||
req.method().toString(),
|
||||
req.body(),
|
||||
req.headers()
|
||||
);
|
||||
return res
|
||||
.status(result.status || 200)
|
||||
.body(result.body || {})
|
||||
.headers(result.headers || {});
|
||||
});
|
||||
} else {
|
||||
xhrMock.use(method, url, {
|
||||
status: response.status,
|
||||
body: response.body
|
||||
body: response.body,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +157,6 @@ export class BrowserHttpMock implements HttpMockFacade {
|
|||
}
|
||||
|
||||
timeout(method: HttpMethods, url: UrlFilter): void {
|
||||
return this.mockHttpMethod(method, url, () => new Promise(() => { }));
|
||||
return this.mockHttpMethod(method, url, () => new Promise(() => {}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,14 @@ import { assert } from "chai";
|
|||
import { SuiteFunction, PendingSuiteFunction, TestFunction, PendingTestFunction } from "mocha";
|
||||
import { isNode } from "../lib/util/utils";
|
||||
|
||||
export const nodeIt: TestFunction | PendingTestFunction = (!isNode ? it.skip : it);
|
||||
export const browserIt: TestFunction | PendingTestFunction = (isNode ? it.skip : it);
|
||||
export const nodeDescribe: SuiteFunction | PendingSuiteFunction = (!isNode ? describe.skip : describe);
|
||||
export const browserDescribe: SuiteFunction | PendingSuiteFunction = (isNode ? describe.skip : describe);
|
||||
export const nodeIt: TestFunction | PendingTestFunction = !isNode ? it.skip : it;
|
||||
export const browserIt: TestFunction | PendingTestFunction = isNode ? it.skip : it;
|
||||
export const nodeDescribe: SuiteFunction | PendingSuiteFunction = !isNode
|
||||
? describe.skip
|
||||
: describe;
|
||||
export const browserDescribe: SuiteFunction | PendingSuiteFunction = isNode
|
||||
? describe.skip
|
||||
: describe;
|
||||
|
||||
/**
|
||||
* Assert that the provided syncFunction throws an Error. If the expectedError is undefined, then
|
||||
|
@ -17,7 +21,10 @@ export const browserDescribe: SuiteFunction | PendingSuiteFunction = (isNode ? d
|
|||
* @param syncFunction The synchronous function that is expected to thrown an Error.
|
||||
* @param expectedError The Error that is expected to be thrown.
|
||||
*/
|
||||
export function throws(syncFunction: () => void, expectedError?: ((error: Error) => void) | Error): Error {
|
||||
export function throws(
|
||||
syncFunction: () => void,
|
||||
expectedError?: ((error: Error) => void) | Error
|
||||
): Error {
|
||||
let thrownError: Error | undefined;
|
||||
|
||||
try {
|
||||
|
@ -27,7 +34,7 @@ export function throws(syncFunction: () => void, expectedError?: ((error: Error)
|
|||
}
|
||||
|
||||
if (!thrownError) {
|
||||
assert.throws(() => { });
|
||||
assert.throws(() => {});
|
||||
} else if (expectedError instanceof Error) {
|
||||
assert.deepEqual(thrownError, expectedError);
|
||||
} else if (expectedError) {
|
||||
|
@ -44,7 +51,10 @@ export function throws(syncFunction: () => void, expectedError?: ((error: Error)
|
|||
* @param asyncFunction The asynchronous function that is expected to thrown an Error.
|
||||
* @param expectedError The Error that is expected to be thrown.
|
||||
*/
|
||||
export async function throwsAsync<T>(asyncFunction: (() => Promise<T>) | Promise<T>, expectedError?: ((error: Error) => void) | Error): Promise<Error> {
|
||||
export async function throwsAsync<T>(
|
||||
asyncFunction: (() => Promise<T>) | Promise<T>,
|
||||
expectedError?: ((error: Error) => void) | Error
|
||||
): Promise<Error> {
|
||||
let thrownError: Error | undefined;
|
||||
|
||||
try {
|
||||
|
@ -54,7 +64,7 @@ export async function throwsAsync<T>(asyncFunction: (() => Promise<T>) | Promise
|
|||
}
|
||||
|
||||
if (!thrownError) {
|
||||
assert.throws(() => { });
|
||||
assert.throws(() => {});
|
||||
} else if (expectedError instanceof Error) {
|
||||
assert.deepEqual(thrownError, expectedError);
|
||||
} else if (expectedError) {
|
||||
|
|
|
@ -16,7 +16,7 @@ const emptyRequestPolicy: RequestPolicy = {
|
|||
sendRequest(request: WebResource): Promise<HttpOperationResponse> {
|
||||
request.should.exist;
|
||||
return Promise.resolve({ request: request, status: 200, headers: request.headers });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const getPlainUserAgentPolicy = (headerValue?: string): RequestPolicy => {
|
||||
|
@ -96,18 +96,18 @@ describe("MsRestUserAgentPolicy", () => {
|
|||
});
|
||||
});
|
||||
|
||||
browserDescribe("for browser", function() {
|
||||
browserDescribe("for browser", function () {
|
||||
const userAgentHeaderKey = "x-ms-command-name";
|
||||
|
||||
const emptyRequestPolicy: RequestPolicy = {
|
||||
sendRequest(request: WebResource): Promise<HttpOperationResponse> {
|
||||
request.should.exist;
|
||||
return Promise.resolve({ request: request, status: 200, headers: request.headers });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const getUserAgent = async (headerValue?: string): Promise<string> => {
|
||||
const factory = userAgentPolicy({ value: headerValue});
|
||||
const factory = userAgentPolicy({ value: headerValue });
|
||||
const policy = factory.create(emptyRequestPolicy, new RequestPolicyOptions());
|
||||
const resource = new WebResource();
|
||||
await policy.sendRequest(resource);
|
||||
|
@ -118,7 +118,10 @@ describe("MsRestUserAgentPolicy", () => {
|
|||
describe("MsRestUserAgentPolicy (Browser)", () => {
|
||||
it("should not modify user agent header if already present", async () => {
|
||||
const factory = userAgentPolicy();
|
||||
const browserUserAgentPolicy = factory.create(emptyRequestPolicy, new RequestPolicyOptions());
|
||||
const browserUserAgentPolicy = factory.create(
|
||||
emptyRequestPolicy,
|
||||
new RequestPolicyOptions()
|
||||
);
|
||||
const customUserAgent = "my custom user agent";
|
||||
const resource = new WebResource();
|
||||
resource.headers.set(userAgentHeaderKey, customUserAgent);
|
||||
|
@ -132,7 +135,10 @@ describe("MsRestUserAgentPolicy", () => {
|
|||
it("should use injected user agent string if provided", async () => {
|
||||
const customUserAgent = "my custom user agent";
|
||||
const factory = userAgentPolicy({ value: customUserAgent });
|
||||
const browserUserAgentPolicy = factory.create(emptyRequestPolicy, new RequestPolicyOptions());
|
||||
const browserUserAgentPolicy = factory.create(
|
||||
emptyRequestPolicy,
|
||||
new RequestPolicyOptions()
|
||||
);
|
||||
const resource = new WebResource();
|
||||
await browserUserAgentPolicy.sendRequest(resource);
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ describe("getParameterPathString()", () => {
|
|||
mapper: {
|
||||
serializedName: "value",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
};
|
||||
assert.strictEqual(getPathStringFromParameter(parameter), "pathToParameterValue");
|
||||
});
|
||||
|
@ -33,9 +33,9 @@ describe("getParameterPathString()", () => {
|
|||
mapper: {
|
||||
serializedName: "value",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
};
|
||||
assert.strictEqual(getPathStringFromParameter(parameter), "path.to.parameter.value");
|
||||
});
|
||||
|
@ -46,9 +46,9 @@ describe("getParameterPathString()", () => {
|
|||
mapper: {
|
||||
serializedName: "value",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
};
|
||||
assert.strictEqual(getPathStringFromParameter(parameter), "pa.th.to.par.ameter.valu.e");
|
||||
});
|
||||
|
@ -56,15 +56,15 @@ describe("getParameterPathString()", () => {
|
|||
it("should return the mapper's serialized name when the parameterPath is an object", () => {
|
||||
const parameter: OperationParameter = {
|
||||
parameterPath: {
|
||||
"a": "A",
|
||||
"b": "B"
|
||||
a: "A",
|
||||
b: "B",
|
||||
},
|
||||
mapper: {
|
||||
serializedName: "value",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
};
|
||||
assert.strictEqual(getPathStringFromParameter(parameter), "value");
|
||||
});
|
||||
|
|
|
@ -33,30 +33,19 @@ describe("AgentPolicy", function () {
|
|||
it("factory passes correct agent settings", function () {
|
||||
const factory = agentPolicy(agentSettings);
|
||||
|
||||
const policy = factory.create(
|
||||
emptyRequestPolicy,
|
||||
emptyPolicyOptions
|
||||
) as AgentPolicy;
|
||||
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
|
||||
);
|
||||
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 policy = new AgentPolicy(emptyRequestPolicy, emptyPolicyOptions, agentSettings);
|
||||
const request = new WebResource();
|
||||
|
||||
await policy.sendRequest(request);
|
||||
|
@ -65,16 +54,12 @@ describe("AgentPolicy", function () {
|
|||
});
|
||||
|
||||
it("should not override agent settings to the web request", async function () {
|
||||
const policy = new AgentPolicy(
|
||||
emptyRequestPolicy,
|
||||
emptyPolicyOptions,
|
||||
agentSettings
|
||||
);
|
||||
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}),
|
||||
http: new http.Agent({ keepAlive: true }),
|
||||
https: new http.Agent({ keepAlive: true }),
|
||||
};
|
||||
request.agentSettings = requestSpecificAgentSettings;
|
||||
|
||||
|
|
|
@ -5,7 +5,13 @@ import { assert } from "chai";
|
|||
import { HttpHeaders } from "../../lib/httpHeaders";
|
||||
import { HttpOperationResponse } from "../../lib/httpOperationResponse";
|
||||
import { HttpClient, OperationSpec, Serializer } from "../../lib/msRest";
|
||||
import { DeserializationPolicy, deserializationPolicy, deserializeResponseBody, defaultJsonContentTypes, defaultXmlContentTypes } from "../../lib/policies/deserializationPolicy";
|
||||
import {
|
||||
DeserializationPolicy,
|
||||
deserializationPolicy,
|
||||
deserializeResponseBody,
|
||||
defaultJsonContentTypes,
|
||||
defaultXmlContentTypes,
|
||||
} from "../../lib/policies/deserializationPolicy";
|
||||
import { RequestPolicy, RequestPolicyOptions } from "../../lib/policies/requestPolicy";
|
||||
import { WebResource, WebResourceLike } from "../../lib/webResource";
|
||||
|
||||
|
@ -15,13 +21,17 @@ describe("deserializationPolicy", function () {
|
|||
return Promise.resolve({
|
||||
request: request,
|
||||
status: 200,
|
||||
headers: new HttpHeaders()
|
||||
headers: new HttpHeaders(),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
it(`should not modify a request that has no request body mapper`, async function () {
|
||||
const deserializationPolicy = new DeserializationPolicy(mockPolicy, {}, new RequestPolicyOptions());
|
||||
const deserializationPolicy = new DeserializationPolicy(
|
||||
mockPolicy,
|
||||
{},
|
||||
new RequestPolicyOptions()
|
||||
);
|
||||
|
||||
const request = createRequest();
|
||||
request.body = "hello there!";
|
||||
|
@ -33,12 +43,13 @@ describe("deserializationPolicy", function () {
|
|||
it("should parse a JSON response body", async function () {
|
||||
const request: WebResourceLike = createRequest();
|
||||
const mockClient: HttpClient = {
|
||||
sendRequest: req => Promise.resolve({
|
||||
request: req,
|
||||
status: 200,
|
||||
headers: new HttpHeaders({ "Content-Type": "application/json" }),
|
||||
bodyAsText: "[123, 456, 789]"
|
||||
})
|
||||
sendRequest: (req) =>
|
||||
Promise.resolve({
|
||||
request: req,
|
||||
status: 200,
|
||||
headers: new HttpHeaders({ "Content-Type": "application/json" }),
|
||||
bodyAsText: "[123, 456, 789]",
|
||||
}),
|
||||
};
|
||||
|
||||
const policy = deserializationPolicy().create(mockClient, new RequestPolicyOptions());
|
||||
|
@ -49,12 +60,13 @@ describe("deserializationPolicy", function () {
|
|||
it("should parse a JSON response body with a charset specified in Content-Type", async function () {
|
||||
const request: WebResourceLike = createRequest();
|
||||
const mockClient: HttpClient = {
|
||||
sendRequest: req => Promise.resolve({
|
||||
request: req,
|
||||
status: 200,
|
||||
headers: new HttpHeaders({ "Content-Type": "application/json;charset=UTF-8" }),
|
||||
bodyAsText: "[123, 456, 789]"
|
||||
})
|
||||
sendRequest: (req) =>
|
||||
Promise.resolve({
|
||||
request: req,
|
||||
status: 200,
|
||||
headers: new HttpHeaders({ "Content-Type": "application/json;charset=UTF-8" }),
|
||||
bodyAsText: "[123, 456, 789]",
|
||||
}),
|
||||
};
|
||||
|
||||
const policy = deserializationPolicy().create(mockClient, new RequestPolicyOptions());
|
||||
|
@ -65,12 +77,13 @@ describe("deserializationPolicy", function () {
|
|||
it("should parse a JSON response body with an uppercase Content-Type", async function () {
|
||||
const request: WebResourceLike = createRequest();
|
||||
const mockClient: HttpClient = {
|
||||
sendRequest: req => Promise.resolve({
|
||||
request: req,
|
||||
status: 200,
|
||||
headers: new HttpHeaders({ "Content-Type": "APPLICATION/JSON" }),
|
||||
bodyAsText: "[123, 456, 789]"
|
||||
})
|
||||
sendRequest: (req) =>
|
||||
Promise.resolve({
|
||||
request: req,
|
||||
status: 200,
|
||||
headers: new HttpHeaders({ "Content-Type": "APPLICATION/JSON" }),
|
||||
bodyAsText: "[123, 456, 789]",
|
||||
}),
|
||||
};
|
||||
|
||||
const policy = deserializationPolicy().create(mockClient, new RequestPolicyOptions());
|
||||
|
@ -81,12 +94,13 @@ describe("deserializationPolicy", function () {
|
|||
it("should parse a JSON response body with a missing Content-Type", async function () {
|
||||
const request: WebResourceLike = createRequest();
|
||||
const mockClient: HttpClient = {
|
||||
sendRequest: req => Promise.resolve({
|
||||
request: req,
|
||||
status: 200,
|
||||
headers: new HttpHeaders(),
|
||||
bodyAsText: "[123, 456, 789]"
|
||||
})
|
||||
sendRequest: (req) =>
|
||||
Promise.resolve({
|
||||
request: req,
|
||||
status: 200,
|
||||
headers: new HttpHeaders(),
|
||||
bodyAsText: "[123, 456, 789]",
|
||||
}),
|
||||
};
|
||||
|
||||
const policy = deserializationPolicy().create(mockClient, new RequestPolicyOptions());
|
||||
|
@ -99,7 +113,7 @@ describe("deserializationPolicy", function () {
|
|||
const response: HttpOperationResponse = {
|
||||
request: createRequest(),
|
||||
status: 200,
|
||||
headers: new HttpHeaders()
|
||||
headers: new HttpHeaders(),
|
||||
};
|
||||
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponse(response);
|
||||
|
@ -117,9 +131,9 @@ describe("deserializationPolicy", function () {
|
|||
request: createRequest(),
|
||||
status: 200,
|
||||
headers: new HttpHeaders({
|
||||
"content-type": "application/xml"
|
||||
"content-type": "application/xml",
|
||||
}),
|
||||
bodyAsText: `<fruit><apples>3</apples></fruit>`
|
||||
bodyAsText: `<fruit><apples>3</apples></fruit>`,
|
||||
};
|
||||
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponse(response);
|
||||
|
@ -128,7 +142,7 @@ describe("deserializationPolicy", function () {
|
|||
assert.strictEqual(deserializedResponse.readableStreamBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.blobBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.bodyAsText, `<fruit><apples>3</apples></fruit>`);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, { "apples": "3" });
|
||||
assert.deepEqual(deserializedResponse.parsedBody, { apples: "3" });
|
||||
assert.strictEqual(deserializedResponse.parsedHeaders, undefined);
|
||||
});
|
||||
|
||||
|
@ -137,9 +151,9 @@ describe("deserializationPolicy", function () {
|
|||
request: createRequest(),
|
||||
status: 200,
|
||||
headers: new HttpHeaders({
|
||||
"content-type": "application/xml"
|
||||
"content-type": "application/xml",
|
||||
}),
|
||||
bodyAsText: `<fruit><apples tasty="yes">3</apples></fruit>`
|
||||
bodyAsText: `<fruit><apples tasty="yes">3</apples></fruit>`,
|
||||
};
|
||||
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponse(response);
|
||||
|
@ -147,14 +161,17 @@ describe("deserializationPolicy", function () {
|
|||
assert(deserializedResponse);
|
||||
assert.strictEqual(deserializedResponse.readableStreamBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.blobBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.bodyAsText, `<fruit><apples tasty="yes">3</apples></fruit>`);
|
||||
assert.strictEqual(
|
||||
deserializedResponse.bodyAsText,
|
||||
`<fruit><apples tasty="yes">3</apples></fruit>`
|
||||
);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, {
|
||||
"apples": {
|
||||
"$": {
|
||||
"tasty": "yes"
|
||||
apples: {
|
||||
$: {
|
||||
tasty: "yes",
|
||||
},
|
||||
"_": "3"
|
||||
}
|
||||
_: "3",
|
||||
},
|
||||
});
|
||||
assert.strictEqual(deserializedResponse.parsedHeaders, undefined);
|
||||
});
|
||||
|
@ -177,20 +194,20 @@ describe("deserializationPolicy", function () {
|
|||
xmlName: "apples",
|
||||
serializedName: "apples",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
status: 200,
|
||||
headers: new HttpHeaders({
|
||||
"content-type": "application/xml"
|
||||
"content-type": "application/xml",
|
||||
}),
|
||||
bodyAsText: `<fruit><apples tasty="yes">3</apples></fruit>`
|
||||
bodyAsText: `<fruit><apples tasty="yes">3</apples></fruit>`,
|
||||
};
|
||||
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponse(response);
|
||||
|
@ -198,8 +215,11 @@ describe("deserializationPolicy", function () {
|
|||
assert(deserializedResponse);
|
||||
assert.strictEqual(deserializedResponse.readableStreamBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.blobBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.bodyAsText, `<fruit><apples tasty="yes">3</apples></fruit>`);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, { "apples": "3" });
|
||||
assert.strictEqual(
|
||||
deserializedResponse.bodyAsText,
|
||||
`<fruit><apples tasty="yes">3</apples></fruit>`
|
||||
);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, { apples: "3" });
|
||||
assert.strictEqual(deserializedResponse.parsedHeaders, undefined);
|
||||
});
|
||||
|
||||
|
@ -221,20 +241,20 @@ describe("deserializationPolicy", function () {
|
|||
xmlName: "apples",
|
||||
serializedName: "apples",
|
||||
type: {
|
||||
name: "Number"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "Number",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
status: 200,
|
||||
headers: new HttpHeaders({
|
||||
"content-type": "application/xml"
|
||||
"content-type": "application/xml",
|
||||
}),
|
||||
bodyAsText: `<fruit><apples tasty="yes">3</apples></fruit>`
|
||||
bodyAsText: `<fruit><apples tasty="yes">3</apples></fruit>`,
|
||||
};
|
||||
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponse(response);
|
||||
|
@ -242,8 +262,11 @@ describe("deserializationPolicy", function () {
|
|||
assert(deserializedResponse);
|
||||
assert.strictEqual(deserializedResponse.readableStreamBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.blobBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.bodyAsText, `<fruit><apples tasty="yes">3</apples></fruit>`);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, { "apples": 3 });
|
||||
assert.strictEqual(
|
||||
deserializedResponse.bodyAsText,
|
||||
`<fruit><apples tasty="yes">3</apples></fruit>`
|
||||
);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, { apples: 3 });
|
||||
assert.strictEqual(deserializedResponse.parsedHeaders, undefined);
|
||||
});
|
||||
|
||||
|
@ -273,23 +296,23 @@ describe("deserializationPolicy", function () {
|
|||
xmlIsAttribute: true,
|
||||
serializedName: "tasty",
|
||||
type: {
|
||||
name: "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: "String",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
status: 200,
|
||||
headers: new HttpHeaders({
|
||||
"content-type": "application/xml"
|
||||
"content-type": "application/xml",
|
||||
}),
|
||||
bodyAsText: `<fruit><apples tasty="yes">3</apples></fruit>`
|
||||
bodyAsText: `<fruit><apples tasty="yes">3</apples></fruit>`,
|
||||
};
|
||||
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponse(response);
|
||||
|
@ -297,8 +320,11 @@ describe("deserializationPolicy", function () {
|
|||
assert(deserializedResponse);
|
||||
assert.strictEqual(deserializedResponse.readableStreamBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.blobBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.bodyAsText, `<fruit><apples tasty="yes">3</apples></fruit>`);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, { "apples": { "tasty": "yes" } });
|
||||
assert.strictEqual(
|
||||
deserializedResponse.bodyAsText,
|
||||
`<fruit><apples tasty="yes">3</apples></fruit>`
|
||||
);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, { apples: { tasty: "yes" } });
|
||||
assert.strictEqual(deserializedResponse.parsedHeaders, undefined);
|
||||
});
|
||||
|
||||
|
@ -307,9 +333,9 @@ describe("deserializationPolicy", function () {
|
|||
request: createRequest(),
|
||||
status: 200,
|
||||
headers: new HttpHeaders({
|
||||
"content-type": "application/atom+xml"
|
||||
"content-type": "application/atom+xml",
|
||||
}),
|
||||
bodyAsText: `<fruit><apples>3</apples></fruit>`
|
||||
bodyAsText: `<fruit><apples>3</apples></fruit>`,
|
||||
};
|
||||
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponse(response);
|
||||
|
@ -318,7 +344,7 @@ describe("deserializationPolicy", function () {
|
|||
assert.strictEqual(deserializedResponse.readableStreamBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.blobBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.bodyAsText, `<fruit><apples>3</apples></fruit>`);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, { "apples": "3" });
|
||||
assert.deepEqual(deserializedResponse.parsedBody, { apples: "3" });
|
||||
assert.strictEqual(deserializedResponse.parsedHeaders, undefined);
|
||||
});
|
||||
|
||||
|
@ -327,9 +353,9 @@ describe("deserializationPolicy", function () {
|
|||
request: createRequest(),
|
||||
status: 200,
|
||||
headers: new HttpHeaders({
|
||||
"content-type": "application/atom+xml"
|
||||
"content-type": "application/atom+xml",
|
||||
}),
|
||||
bodyAsText: `<fruit><apples taste="good">3</apples></fruit>`
|
||||
bodyAsText: `<fruit><apples taste="good">3</apples></fruit>`,
|
||||
};
|
||||
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponse(response);
|
||||
|
@ -337,14 +363,17 @@ describe("deserializationPolicy", function () {
|
|||
assert(deserializedResponse);
|
||||
assert.strictEqual(deserializedResponse.readableStreamBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.blobBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.bodyAsText, `<fruit><apples taste="good">3</apples></fruit>`);
|
||||
assert.strictEqual(
|
||||
deserializedResponse.bodyAsText,
|
||||
`<fruit><apples taste="good">3</apples></fruit>`
|
||||
);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, {
|
||||
"apples": {
|
||||
"$": {
|
||||
"taste": "good"
|
||||
apples: {
|
||||
$: {
|
||||
taste: "good",
|
||||
},
|
||||
"_": "3"
|
||||
}
|
||||
_: "3",
|
||||
},
|
||||
});
|
||||
assert.strictEqual(deserializedResponse.parsedHeaders, undefined);
|
||||
});
|
||||
|
@ -354,24 +383,31 @@ describe("deserializationPolicy", function () {
|
|||
request: createRequest(),
|
||||
status: 200,
|
||||
headers: new HttpHeaders({
|
||||
"content-type": "my/weird-xml"
|
||||
"content-type": "my/weird-xml",
|
||||
}),
|
||||
bodyAsText: `<fruit><apples taste="good">3</apples></fruit>`
|
||||
bodyAsText: `<fruit><apples taste="good">3</apples></fruit>`,
|
||||
};
|
||||
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponseBody([], ["my/weird-xml"], response);
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponseBody(
|
||||
[],
|
||||
["my/weird-xml"],
|
||||
response
|
||||
);
|
||||
|
||||
assert(deserializedResponse);
|
||||
assert.strictEqual(deserializedResponse.readableStreamBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.blobBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.bodyAsText, `<fruit><apples taste="good">3</apples></fruit>`);
|
||||
assert.strictEqual(
|
||||
deserializedResponse.bodyAsText,
|
||||
`<fruit><apples taste="good">3</apples></fruit>`
|
||||
);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, {
|
||||
"apples": {
|
||||
"$": {
|
||||
"taste": "good"
|
||||
apples: {
|
||||
$: {
|
||||
taste: "good",
|
||||
},
|
||||
"_": "3"
|
||||
}
|
||||
_: "3",
|
||||
},
|
||||
});
|
||||
assert.strictEqual(deserializedResponse.parsedHeaders, undefined);
|
||||
});
|
||||
|
@ -381,9 +417,9 @@ describe("deserializationPolicy", function () {
|
|||
request: createRequest(),
|
||||
status: 200,
|
||||
headers: new HttpHeaders({
|
||||
"content-type": "application/atom+xml;type=entry;charset=utf-8"
|
||||
"content-type": "application/atom+xml;type=entry;charset=utf-8",
|
||||
}),
|
||||
bodyAsText: `<entry xmlns="http://www.w3.org/2005/Atom"><id>https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False</id><title type="text">testQueuePath</title><published>2018-10-09T19:56:34Z</published><updated>2018-10-09T19:56:35Z</updated><author><name>daschulttest1</name></author><link rel="self" href="https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False"/><content type="application/xml"><QueueDescription xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><LockDuration>PT1M</LockDuration><MaxSizeInMegabytes>1024</MaxSizeInMegabytes><RequiresDuplicateDetection>false</RequiresDuplicateDetection><RequiresSession>false</RequiresSession><DefaultMessageTimeToLive>P14D</DefaultMessageTimeToLive><DeadLetteringOnMessageExpiration>false</DeadLetteringOnMessageExpiration><DuplicateDetectionHistoryTimeWindow>PT10M</DuplicateDetectionHistoryTimeWindow><MaxDeliveryCount>10</MaxDeliveryCount><EnableBatchedOperations>true</EnableBatchedOperations><SizeInBytes>0</SizeInBytes><MessageCount>0</MessageCount><IsAnonymousAccessible>false</IsAnonymousAccessible><AuthorizationRules></AuthorizationRules><Status>Active</Status><CreatedAt>2018-10-09T19:56:34.903Z</CreatedAt><UpdatedAt>2018-10-09T19:56:35.013Z</UpdatedAt><AccessedAt>0001-01-01T00:00:00Z</AccessedAt><SupportOrdering>true</SupportOrdering><CountDetails xmlns:d2p1="http://schemas.microsoft.com/netservices/2011/06/servicebus"><d2p1:ActiveMessageCount>0</d2p1:ActiveMessageCount><d2p1:DeadLetterMessageCount>0</d2p1:DeadLetterMessageCount><d2p1:ScheduledMessageCount>0</d2p1:ScheduledMessageCount><d2p1:TransferMessageCount>0</d2p1:TransferMessageCount><d2p1:TransferDeadLetterMessageCount>0</d2p1:TransferDeadLetterMessageCount></CountDetails><AutoDeleteOnIdle>P10675199DT2H48M5.4775807S</AutoDeleteOnIdle><EnablePartitioning>false</EnablePartitioning><EntityAvailabilityStatus>Available</EntityAvailabilityStatus><EnableExpress>false</EnableExpress></QueueDescription></content></entry>`
|
||||
bodyAsText: `<entry xmlns="http://www.w3.org/2005/Atom"><id>https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False</id><title type="text">testQueuePath</title><published>2018-10-09T19:56:34Z</published><updated>2018-10-09T19:56:35Z</updated><author><name>daschulttest1</name></author><link rel="self" href="https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False"/><content type="application/xml"><QueueDescription xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><LockDuration>PT1M</LockDuration><MaxSizeInMegabytes>1024</MaxSizeInMegabytes><RequiresDuplicateDetection>false</RequiresDuplicateDetection><RequiresSession>false</RequiresSession><DefaultMessageTimeToLive>P14D</DefaultMessageTimeToLive><DeadLetteringOnMessageExpiration>false</DeadLetteringOnMessageExpiration><DuplicateDetectionHistoryTimeWindow>PT10M</DuplicateDetectionHistoryTimeWindow><MaxDeliveryCount>10</MaxDeliveryCount><EnableBatchedOperations>true</EnableBatchedOperations><SizeInBytes>0</SizeInBytes><MessageCount>0</MessageCount><IsAnonymousAccessible>false</IsAnonymousAccessible><AuthorizationRules></AuthorizationRules><Status>Active</Status><CreatedAt>2018-10-09T19:56:34.903Z</CreatedAt><UpdatedAt>2018-10-09T19:56:35.013Z</UpdatedAt><AccessedAt>0001-01-01T00:00:00Z</AccessedAt><SupportOrdering>true</SupportOrdering><CountDetails xmlns:d2p1="http://schemas.microsoft.com/netservices/2011/06/servicebus"><d2p1:ActiveMessageCount>0</d2p1:ActiveMessageCount><d2p1:DeadLetterMessageCount>0</d2p1:DeadLetterMessageCount><d2p1:ScheduledMessageCount>0</d2p1:ScheduledMessageCount><d2p1:TransferMessageCount>0</d2p1:TransferMessageCount><d2p1:TransferDeadLetterMessageCount>0</d2p1:TransferDeadLetterMessageCount></CountDetails><AutoDeleteOnIdle>P10675199DT2H48M5.4775807S</AutoDeleteOnIdle><EnablePartitioning>false</EnablePartitioning><EntityAvailabilityStatus>Available</EntityAvailabilityStatus><EnableExpress>false</EnableExpress></QueueDescription></content></entry>`,
|
||||
};
|
||||
|
||||
const deserializedResponse: HttpOperationResponse = await deserializeResponse(response);
|
||||
|
@ -391,72 +427,77 @@ describe("deserializationPolicy", function () {
|
|||
assert(deserializedResponse);
|
||||
assert.strictEqual(deserializedResponse.readableStreamBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.blobBody, undefined);
|
||||
assert.strictEqual(deserializedResponse.bodyAsText, `<entry xmlns="http://www.w3.org/2005/Atom"><id>https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False</id><title type="text">testQueuePath</title><published>2018-10-09T19:56:34Z</published><updated>2018-10-09T19:56:35Z</updated><author><name>daschulttest1</name></author><link rel="self" href="https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False"/><content type="application/xml"><QueueDescription xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><LockDuration>PT1M</LockDuration><MaxSizeInMegabytes>1024</MaxSizeInMegabytes><RequiresDuplicateDetection>false</RequiresDuplicateDetection><RequiresSession>false</RequiresSession><DefaultMessageTimeToLive>P14D</DefaultMessageTimeToLive><DeadLetteringOnMessageExpiration>false</DeadLetteringOnMessageExpiration><DuplicateDetectionHistoryTimeWindow>PT10M</DuplicateDetectionHistoryTimeWindow><MaxDeliveryCount>10</MaxDeliveryCount><EnableBatchedOperations>true</EnableBatchedOperations><SizeInBytes>0</SizeInBytes><MessageCount>0</MessageCount><IsAnonymousAccessible>false</IsAnonymousAccessible><AuthorizationRules></AuthorizationRules><Status>Active</Status><CreatedAt>2018-10-09T19:56:34.903Z</CreatedAt><UpdatedAt>2018-10-09T19:56:35.013Z</UpdatedAt><AccessedAt>0001-01-01T00:00:00Z</AccessedAt><SupportOrdering>true</SupportOrdering><CountDetails xmlns:d2p1="http://schemas.microsoft.com/netservices/2011/06/servicebus"><d2p1:ActiveMessageCount>0</d2p1:ActiveMessageCount><d2p1:DeadLetterMessageCount>0</d2p1:DeadLetterMessageCount><d2p1:ScheduledMessageCount>0</d2p1:ScheduledMessageCount><d2p1:TransferMessageCount>0</d2p1:TransferMessageCount><d2p1:TransferDeadLetterMessageCount>0</d2p1:TransferDeadLetterMessageCount></CountDetails><AutoDeleteOnIdle>P10675199DT2H48M5.4775807S</AutoDeleteOnIdle><EnablePartitioning>false</EnablePartitioning><EntityAvailabilityStatus>Available</EntityAvailabilityStatus><EnableExpress>false</EnableExpress></QueueDescription></content></entry>`);
|
||||
assert.strictEqual(
|
||||
deserializedResponse.bodyAsText,
|
||||
`<entry xmlns="http://www.w3.org/2005/Atom"><id>https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False</id><title type="text">testQueuePath</title><published>2018-10-09T19:56:34Z</published><updated>2018-10-09T19:56:35Z</updated><author><name>daschulttest1</name></author><link rel="self" href="https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False"/><content type="application/xml"><QueueDescription xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><LockDuration>PT1M</LockDuration><MaxSizeInMegabytes>1024</MaxSizeInMegabytes><RequiresDuplicateDetection>false</RequiresDuplicateDetection><RequiresSession>false</RequiresSession><DefaultMessageTimeToLive>P14D</DefaultMessageTimeToLive><DeadLetteringOnMessageExpiration>false</DeadLetteringOnMessageExpiration><DuplicateDetectionHistoryTimeWindow>PT10M</DuplicateDetectionHistoryTimeWindow><MaxDeliveryCount>10</MaxDeliveryCount><EnableBatchedOperations>true</EnableBatchedOperations><SizeInBytes>0</SizeInBytes><MessageCount>0</MessageCount><IsAnonymousAccessible>false</IsAnonymousAccessible><AuthorizationRules></AuthorizationRules><Status>Active</Status><CreatedAt>2018-10-09T19:56:34.903Z</CreatedAt><UpdatedAt>2018-10-09T19:56:35.013Z</UpdatedAt><AccessedAt>0001-01-01T00:00:00Z</AccessedAt><SupportOrdering>true</SupportOrdering><CountDetails xmlns:d2p1="http://schemas.microsoft.com/netservices/2011/06/servicebus"><d2p1:ActiveMessageCount>0</d2p1:ActiveMessageCount><d2p1:DeadLetterMessageCount>0</d2p1:DeadLetterMessageCount><d2p1:ScheduledMessageCount>0</d2p1:ScheduledMessageCount><d2p1:TransferMessageCount>0</d2p1:TransferMessageCount><d2p1:TransferDeadLetterMessageCount>0</d2p1:TransferDeadLetterMessageCount></CountDetails><AutoDeleteOnIdle>P10675199DT2H48M5.4775807S</AutoDeleteOnIdle><EnablePartitioning>false</EnablePartitioning><EntityAvailabilityStatus>Available</EntityAvailabilityStatus><EnableExpress>false</EnableExpress></QueueDescription></content></entry>`
|
||||
);
|
||||
assert.deepEqual(deserializedResponse.parsedBody, {
|
||||
"$": {
|
||||
"xmlns": "http://www.w3.org/2005/Atom"
|
||||
$: {
|
||||
xmlns: "http://www.w3.org/2005/Atom",
|
||||
},
|
||||
"author": {
|
||||
"name": "daschulttest1"
|
||||
author: {
|
||||
name: "daschulttest1",
|
||||
},
|
||||
"content": {
|
||||
"$": {
|
||||
"type": "application/xml"
|
||||
content: {
|
||||
$: {
|
||||
type: "application/xml",
|
||||
},
|
||||
"QueueDescription": {
|
||||
"$": {
|
||||
"xmlns": "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect",
|
||||
"xmlns:i": "http://www.w3.org/2001/XMLSchema-instance"
|
||||
QueueDescription: {
|
||||
$: {
|
||||
xmlns: "http://schemas.microsoft.com/netservices/2010/10/servicebus/connect",
|
||||
"xmlns:i": "http://www.w3.org/2001/XMLSchema-instance",
|
||||
},
|
||||
"AccessedAt": "0001-01-01T00:00:00Z",
|
||||
"AuthorizationRules": "",
|
||||
"AutoDeleteOnIdle": "P10675199DT2H48M5.4775807S",
|
||||
"CountDetails": {
|
||||
"$": {
|
||||
"xmlns:d2p1": "http://schemas.microsoft.com/netservices/2011/06/servicebus"
|
||||
AccessedAt: "0001-01-01T00:00:00Z",
|
||||
AuthorizationRules: "",
|
||||
AutoDeleteOnIdle: "P10675199DT2H48M5.4775807S",
|
||||
CountDetails: {
|
||||
$: {
|
||||
"xmlns:d2p1": "http://schemas.microsoft.com/netservices/2011/06/servicebus",
|
||||
},
|
||||
"d2p1:ActiveMessageCount": "0",
|
||||
"d2p1:DeadLetterMessageCount": "0",
|
||||
"d2p1:ScheduledMessageCount": "0",
|
||||
"d2p1:TransferDeadLetterMessageCount": "0",
|
||||
"d2p1:TransferMessageCount": "0"
|
||||
"d2p1:TransferMessageCount": "0",
|
||||
},
|
||||
"CreatedAt": "2018-10-09T19:56:34.903Z",
|
||||
"DeadLetteringOnMessageExpiration": "false",
|
||||
"DefaultMessageTimeToLive": "P14D",
|
||||
"DuplicateDetectionHistoryTimeWindow": "PT10M",
|
||||
"EnableBatchedOperations": "true",
|
||||
"EnableExpress": "false",
|
||||
"EnablePartitioning": "false",
|
||||
"EntityAvailabilityStatus": "Available",
|
||||
"IsAnonymousAccessible": "false",
|
||||
"LockDuration": "PT1M",
|
||||
"MaxDeliveryCount": "10",
|
||||
"MaxSizeInMegabytes": "1024",
|
||||
"MessageCount": "0",
|
||||
"RequiresDuplicateDetection": "false",
|
||||
"RequiresSession": "false",
|
||||
"SizeInBytes": "0",
|
||||
"Status": "Active",
|
||||
"SupportOrdering": "true",
|
||||
"UpdatedAt": "2018-10-09T19:56:35.013Z"
|
||||
}
|
||||
},
|
||||
"id": "https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False",
|
||||
"link": {
|
||||
"$": {
|
||||
"href": "https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False",
|
||||
"rel": "self"
|
||||
}
|
||||
},
|
||||
"published": "2018-10-09T19:56:34Z",
|
||||
"title": {
|
||||
"$": {
|
||||
"type": "text"
|
||||
CreatedAt: "2018-10-09T19:56:34.903Z",
|
||||
DeadLetteringOnMessageExpiration: "false",
|
||||
DefaultMessageTimeToLive: "P14D",
|
||||
DuplicateDetectionHistoryTimeWindow: "PT10M",
|
||||
EnableBatchedOperations: "true",
|
||||
EnableExpress: "false",
|
||||
EnablePartitioning: "false",
|
||||
EntityAvailabilityStatus: "Available",
|
||||
IsAnonymousAccessible: "false",
|
||||
LockDuration: "PT1M",
|
||||
MaxDeliveryCount: "10",
|
||||
MaxSizeInMegabytes: "1024",
|
||||
MessageCount: "0",
|
||||
RequiresDuplicateDetection: "false",
|
||||
RequiresSession: "false",
|
||||
SizeInBytes: "0",
|
||||
Status: "Active",
|
||||
SupportOrdering: "true",
|
||||
UpdatedAt: "2018-10-09T19:56:35.013Z",
|
||||
},
|
||||
"_": "testQueuePath"
|
||||
},
|
||||
"updated": "2018-10-09T19:56:35Z"
|
||||
id:
|
||||
"https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False",
|
||||
link: {
|
||||
$: {
|
||||
href:
|
||||
"https://daschulttest1.servicebus.windows.net/testQueuePath/?api-version=2017-04&enrich=False",
|
||||
rel: "self",
|
||||
},
|
||||
},
|
||||
published: "2018-10-09T19:56:34Z",
|
||||
title: {
|
||||
$: {
|
||||
type: "text",
|
||||
},
|
||||
_: "testQueuePath",
|
||||
},
|
||||
updated: "2018-10-09T19:56:35Z",
|
||||
});
|
||||
assert.strictEqual(deserializedResponse.parsedHeaders, undefined);
|
||||
});
|
||||
|
|
|
@ -16,15 +16,16 @@ describe("ProxyPolicy", function () {
|
|||
host: "https://example.com",
|
||||
port: 3030,
|
||||
username: "admin",
|
||||
password: "_password"
|
||||
password: "_password",
|
||||
};
|
||||
|
||||
const emptyRequestPolicy = {
|
||||
sendRequest: (_: WebResourceLike) => Promise.resolve({
|
||||
request: new WebResource(),
|
||||
status: 404,
|
||||
headers: new HttpHeaders(undefined)
|
||||
})
|
||||
sendRequest: (_: WebResourceLike) =>
|
||||
Promise.resolve({
|
||||
request: new WebResource(),
|
||||
status: 404,
|
||||
headers: new HttpHeaders(undefined),
|
||||
}),
|
||||
};
|
||||
|
||||
const emptyPolicyOptions = new RequestPolicyOptions();
|
||||
|
@ -38,7 +39,6 @@ describe("ProxyPolicy", function () {
|
|||
done();
|
||||
});
|
||||
|
||||
|
||||
it("sets correct proxy settings through constructor", function (done) {
|
||||
const policy = new ProxyPolicy(emptyRequestPolicy, emptyPolicyOptions, proxySettings);
|
||||
policy.proxySettings.should.be.deep.equal(proxySettings);
|
||||
|
@ -68,7 +68,8 @@ describe("ProxyPolicy", function () {
|
|||
|
||||
browserDescribe("for browser", () => {
|
||||
it("should throw an Error while constructing object", () => {
|
||||
const construct = () => new ProxyPolicy(emptyRequestPolicy, emptyPolicyOptions, proxySettings);
|
||||
const construct = () =>
|
||||
new ProxyPolicy(emptyRequestPolicy, emptyPolicyOptions, proxySettings);
|
||||
construct.should.throw();
|
||||
});
|
||||
});
|
||||
|
@ -122,9 +123,9 @@ describe("getDefaultProxySettings", () => {
|
|||
|
||||
describe("should prefer HTTPS proxy over HTTP proxy", () => {
|
||||
[
|
||||
{ name: "lower case", func: (envVar: string) => envVar.toLowerCase() },
|
||||
{ name: "upper case", func: (envVar: string) => envVar.toUpperCase() }
|
||||
].forEach(testCase => {
|
||||
{ name: "lower case", func: (envVar: string) => envVar.toLowerCase() },
|
||||
{ name: "upper case", func: (envVar: string) => envVar.toUpperCase() },
|
||||
].forEach((testCase) => {
|
||||
it(`with ${testCase.name}`, () => {
|
||||
const httpProxy = "http://proxy.microsoft.com";
|
||||
const httpsProxy = "https://proxy.azure.com";
|
||||
|
@ -149,7 +150,7 @@ describe("getDefaultProxySettings", () => {
|
|||
});
|
||||
});
|
||||
|
||||
["HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"].forEach(envVariableName => {
|
||||
["HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"].forEach((envVariableName) => {
|
||||
it(`should should load setting from "${envVariableName}" environmental variable`, () => {
|
||||
process.env[envVariableName] = proxyUrl;
|
||||
const proxySettings: ProxySettings = getDefaultProxySettings()!;
|
||||
|
@ -162,11 +163,13 @@ describe("getDefaultProxySettings", () => {
|
|||
});
|
||||
|
||||
browserDescribe("for browser", () => {
|
||||
[undefined, "http://proxy.microsoft.com", "https://proxy.azure.com:8080"].forEach(proxyUrl => {
|
||||
it(`should return undefined for ${proxyUrl}`, () => {
|
||||
const proxySettings = getDefaultProxySettings(proxyUrl);
|
||||
should().not.exist(proxySettings);
|
||||
});
|
||||
});
|
||||
[undefined, "http://proxy.microsoft.com", "https://proxy.azure.com:8080"].forEach(
|
||||
(proxyUrl) => {
|
||||
it(`should return undefined for ${proxyUrl}`, () => {
|
||||
const proxySettings = getDefaultProxySettings(proxyUrl);
|
||||
should().not.exist(proxySettings);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,11 +10,11 @@ import { HttpHeaders, RequestPolicyOptions } from "../../lib/msRest";
|
|||
|
||||
describe("ThrottlingRetryPolicy", () => {
|
||||
class PassThroughPolicy {
|
||||
constructor(private _response: HttpOperationResponse) { }
|
||||
constructor(private _response: HttpOperationResponse) {}
|
||||
public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
|
||||
const response = {
|
||||
...this._response,
|
||||
request: request
|
||||
request: request,
|
||||
};
|
||||
|
||||
return Promise.resolve(response);
|
||||
|
@ -24,10 +24,16 @@ describe("ThrottlingRetryPolicy", () => {
|
|||
const defaultResponse = {
|
||||
status: 200,
|
||||
request: new WebResource(),
|
||||
headers: new HttpHeaders()
|
||||
headers: new HttpHeaders(),
|
||||
};
|
||||
|
||||
function createDefaultThrottlingRetryPolicy(response?: HttpOperationResponse, actionHandler?: (httpRequest: WebResourceLike, response: HttpOperationResponse) => Promise<HttpOperationResponse>) {
|
||||
function createDefaultThrottlingRetryPolicy(
|
||||
response?: HttpOperationResponse,
|
||||
actionHandler?: (
|
||||
httpRequest: WebResourceLike,
|
||||
response: HttpOperationResponse
|
||||
) => Promise<HttpOperationResponse>
|
||||
) {
|
||||
if (!response) {
|
||||
response = defaultResponse;
|
||||
}
|
||||
|
@ -43,7 +49,7 @@ describe("ThrottlingRetryPolicy", () => {
|
|||
sendRequest: (requestToSend: WebResourceLike): Promise<HttpOperationResponse> => {
|
||||
assert(request !== requestToSend);
|
||||
return Promise.resolve(defaultResponse);
|
||||
}
|
||||
},
|
||||
};
|
||||
const policy = new ThrottlingRetryPolicy(nextPolicy, new RequestPolicyOptions());
|
||||
await policy.sendRequest(request);
|
||||
|
@ -54,7 +60,7 @@ describe("ThrottlingRetryPolicy", () => {
|
|||
request.url = "http://url";
|
||||
request.method = "PATCH";
|
||||
request.body = { someProperty: "someValue" };
|
||||
request.headers = new HttpHeaders({ "header": "abc" });
|
||||
request.headers = new HttpHeaders({ header: "abc" });
|
||||
request.query = { q: "param" };
|
||||
|
||||
const policy = createDefaultThrottlingRetryPolicy();
|
||||
|
@ -68,11 +74,13 @@ describe("ThrottlingRetryPolicy", () => {
|
|||
const mockResponse = {
|
||||
status: 400,
|
||||
headers: new HttpHeaders({
|
||||
"Retry-After": "100"
|
||||
"Retry-After": "100",
|
||||
}),
|
||||
request: request
|
||||
request: request,
|
||||
};
|
||||
const policy = createDefaultThrottlingRetryPolicy(mockResponse, _ => { throw new AssertionError("fail"); });
|
||||
const policy = createDefaultThrottlingRetryPolicy(mockResponse, (_) => {
|
||||
throw new AssertionError("fail");
|
||||
});
|
||||
|
||||
const response = await policy.sendRequest(request);
|
||||
|
||||
|
@ -84,9 +92,9 @@ describe("ThrottlingRetryPolicy", () => {
|
|||
const mockResponse = {
|
||||
status: 429,
|
||||
headers: new HttpHeaders({
|
||||
"Retry-After": "100"
|
||||
"Retry-After": "100",
|
||||
}),
|
||||
request: request
|
||||
request: request,
|
||||
};
|
||||
const policy = createDefaultThrottlingRetryPolicy(mockResponse, (_, response) => {
|
||||
assert.deepEqual(response, mockResponse);
|
||||
|
@ -112,7 +120,9 @@ describe("ThrottlingRetryPolicy", () => {
|
|||
|
||||
it("should return sleep interval value in milliseconds for full date format", function (done) {
|
||||
const clock = sinon.useFakeTimers(new Date("Fri, 31 Dec 1999 23:00:00 GMT").getTime());
|
||||
const retryAfter = ThrottlingRetryPolicy.parseRetryAfterHeader("Fri, 31 Dec 1999 23:02:00 GMT");
|
||||
const retryAfter = ThrottlingRetryPolicy.parseRetryAfterHeader(
|
||||
"Fri, 31 Dec 1999 23:02:00 GMT"
|
||||
);
|
||||
|
||||
assert.equal(retryAfter, 2 * 60 * 1000);
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@ import { createProxyAgent, createTunnel } from "../lib/proxyAgent";
|
|||
describe("proxyAgent", () => {
|
||||
describe("createProxyAgent", () => {
|
||||
type HttpsAgent = https.Agent & {
|
||||
defaultPort: number | undefined,
|
||||
defaultPort: number | undefined;
|
||||
options: {
|
||||
proxy: tunnel.ProxyOptions
|
||||
},
|
||||
proxyOptions: tunnel.ProxyOptions
|
||||
proxy: tunnel.ProxyOptions;
|
||||
};
|
||||
proxyOptions: tunnel.ProxyOptions;
|
||||
};
|
||||
|
||||
[
|
||||
|
@ -24,13 +24,15 @@ describe("proxyAgent", () => {
|
|||
{ proxy: "http", request: "http", port: undefined, isProxyHttps: false },
|
||||
{ proxy: "hTtp", request: "https", port: 443, isProxyHttps: true },
|
||||
{ proxy: "HTTPS", request: "http", port: undefined, isProxyHttps: false },
|
||||
{ proxy: "https", request: "hTTps", port: 443, isProxyHttps: true }
|
||||
].forEach(testCase => {
|
||||
it(`should return ${testCase.isProxyHttps ? "HTTPS" : "HTTP"} proxy for ${testCase.proxy.toUpperCase()} proxy server and ${testCase.request.toUpperCase()} request`, function (done) {
|
||||
{ proxy: "https", request: "hTTps", port: 443, isProxyHttps: true },
|
||||
].forEach((testCase) => {
|
||||
it(`should return ${
|
||||
testCase.isProxyHttps ? "HTTPS" : "HTTP"
|
||||
} proxy for ${testCase.proxy.toUpperCase()} proxy server and ${testCase.request.toUpperCase()} request`, function (done) {
|
||||
const urlHost = "proxy.microsoft.com";
|
||||
const proxySettings = {
|
||||
host: `${testCase.proxy}://${urlHost}`,
|
||||
port: 8080
|
||||
port: 8080,
|
||||
};
|
||||
const requestUrl = `${testCase.request}://example.com`;
|
||||
|
||||
|
@ -48,10 +50,10 @@ describe("proxyAgent", () => {
|
|||
it("should copy headers correctly", function (done) {
|
||||
const proxySettings = {
|
||||
host: "http://proxy.microsoft.com",
|
||||
port: 8080
|
||||
port: 8080,
|
||||
};
|
||||
const headers = new HttpHeaders({
|
||||
"User-Agent": "Node.js"
|
||||
"User-Agent": "Node.js",
|
||||
});
|
||||
|
||||
const proxyAgent = createProxyAgent("http://example.com", proxySettings, headers);
|
||||
|
@ -65,24 +67,24 @@ describe("proxyAgent", () => {
|
|||
describe("createTunnel", () => {
|
||||
const defaultProxySettings = {
|
||||
host: "http://proxy.microsoft.com",
|
||||
port: 8080
|
||||
port: 8080,
|
||||
};
|
||||
|
||||
type HttpsAgent = https.Agent & {
|
||||
defaultPort: number | undefined,
|
||||
defaultPort: number | undefined;
|
||||
options: {
|
||||
proxy: tunnel.ProxyOptions
|
||||
}
|
||||
proxy: tunnel.ProxyOptions;
|
||||
};
|
||||
};
|
||||
|
||||
[true, false].forEach(value => {
|
||||
[true, false].forEach((value) => {
|
||||
it(`returns HTTP agent for HTTP request and HTTP${value ? "S" : ""} proxy`, function () {
|
||||
const tunnelConfig: tunnel.HttpsOverHttpsOptions = {
|
||||
proxy: {
|
||||
host: defaultProxySettings.host,
|
||||
port: defaultProxySettings.port,
|
||||
headers: {}
|
||||
}
|
||||
headers: {},
|
||||
},
|
||||
};
|
||||
|
||||
const tunnel = createTunnel(false, value, tunnelConfig) as HttpsAgent;
|
||||
|
@ -92,14 +94,14 @@ describe("proxyAgent", () => {
|
|||
});
|
||||
});
|
||||
|
||||
[true, false].forEach(value => {
|
||||
[true, false].forEach((value) => {
|
||||
it(`returns HTTPS agent for HTTPS request and HTTP${value ? "S" : ""} proxy`, function () {
|
||||
const tunnelConfig: tunnel.HttpsOverHttpsOptions = {
|
||||
proxy: {
|
||||
host: defaultProxySettings.host,
|
||||
port: defaultProxySettings.port,
|
||||
headers: {}
|
||||
}
|
||||
headers: {},
|
||||
},
|
||||
};
|
||||
|
||||
const tunnel = createTunnel(true, value, tunnelConfig) as HttpsAgent;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
230
test/urlTests.ts
230
test/urlTests.ts
|
@ -109,23 +109,32 @@ describe("URLQuery", () => {
|
|||
});
|
||||
|
||||
it(`parse with base64 token as last parameter`, () => {
|
||||
const expectedValue = "ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==";
|
||||
const parsedURL = URLQuery.parse("?api-version=2020-06-01&bas64Value=ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==");
|
||||
const expectedValue =
|
||||
"ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==";
|
||||
const parsedURL = URLQuery.parse(
|
||||
"?api-version=2020-06-01&bas64Value=ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz=="
|
||||
);
|
||||
assert.strictEqual(parsedURL.get("bas64Value"), expectedValue);
|
||||
assert.strictEqual(parsedURL.get("api-version"), "2020-06-01");
|
||||
});
|
||||
|
||||
it(`parse with base64 token as middle parameter`, () => {
|
||||
const expectedValue = "ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==";
|
||||
const parsedURL = URLQuery.parse("?api-version=2020-06-01&bas64Value=ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==&extraParam=foo");
|
||||
const expectedValue =
|
||||
"ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==";
|
||||
const parsedURL = URLQuery.parse(
|
||||
"?api-version=2020-06-01&bas64Value=ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==&extraParam=foo"
|
||||
);
|
||||
assert.strictEqual(parsedURL.get("bas64Value"), expectedValue);
|
||||
assert.strictEqual(parsedURL.get("api-version"), "2020-06-01");
|
||||
assert.strictEqual(parsedURL.get("extraParam"), "foo");
|
||||
});
|
||||
|
||||
it(`parse with base64 token as first parameter`, () => {
|
||||
const expectedValue = "ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==";
|
||||
const parsedURL = URLQuery.parse("?bas64Value=ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==&api-version=2020-06-01");
|
||||
const expectedValue =
|
||||
"ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==";
|
||||
const parsedURL = URLQuery.parse(
|
||||
"?bas64Value=ODIzZnNkdi01YXNjLTEzc2EtMTI1NS1jYTNhc2QxMmRhMyEvU3Vic2NyaXB0aW9ucy8xMTExMTEtMTExMS0xMTExLTExMTEtMTExMTExMTExL1Jlc291cmNlR3JvdXBzL0FFLVdPUktFUlMvVk1TY2FsZVNldHMvQUUtV09SS0VSUy1TQ0FMRS0xMDAwL1ZNcy8xNDMz==&api-version=2020-06-01"
|
||||
);
|
||||
assert.strictEqual(parsedURL.get("bas64Value"), expectedValue);
|
||||
assert.strictEqual(parsedURL.get("api-version"), "2020-06-01");
|
||||
});
|
||||
|
@ -283,7 +292,10 @@ describe("URLBuilder", () => {
|
|||
assert.strictEqual(urlBuilder.getScheme(), "https");
|
||||
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
|
||||
assert.strictEqual(urlBuilder.getPath(), "mypath");
|
||||
assert.strictEqual(urlBuilder.toString(), "https://www.example.com/mypath?thing=stuff&otherthing=otherstuff");
|
||||
assert.strictEqual(
|
||||
urlBuilder.toString(),
|
||||
"https://www.example.com/mypath?thing=stuff&otherthing=otherstuff"
|
||||
);
|
||||
});
|
||||
|
||||
it(`to "https" and setHost() to "www.example.com" and setPath() to "http://www.othersite.com/mypath?thing=stuff" and setQueryParameter() to "otherthing=otherstuff"`, () => {
|
||||
|
@ -294,7 +306,10 @@ describe("URLBuilder", () => {
|
|||
urlBuilder.setQueryParameter("otherthing", "otherstuff");
|
||||
assert.strictEqual(urlBuilder.getScheme(), "http");
|
||||
assert.strictEqual(urlBuilder.getPath(), "/mypath");
|
||||
assert.strictEqual(urlBuilder.toString(), "http://www.othersite.com/mypath?thing=stuff&otherthing=otherstuff");
|
||||
assert.strictEqual(
|
||||
urlBuilder.toString(),
|
||||
"http://www.othersite.com/mypath?thing=stuff&otherthing=otherstuff"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -831,23 +846,38 @@ describe("URLBuilder", () => {
|
|||
});
|
||||
|
||||
it(`with "ftp://www.bing.com:8080"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("ftp://www.bing.com:8080").toString(), "ftp://www.bing.com:8080");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("ftp://www.bing.com:8080").toString(),
|
||||
"ftp://www.bing.com:8080"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "www.bing.com/my/path"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("www.bing.com/my/path").toString(), "www.bing.com/my/path");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("www.bing.com/my/path").toString(),
|
||||
"www.bing.com/my/path"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "ftp://www.bing.com/my/path"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("ftp://www.bing.com/my/path").toString(), "ftp://www.bing.com/my/path");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("ftp://www.bing.com/my/path").toString(),
|
||||
"ftp://www.bing.com/my/path"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "www.bing.com:1234/my/path"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("www.bing.com:1234/my/path").toString(), "www.bing.com:1234/my/path");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("www.bing.com:1234/my/path").toString(),
|
||||
"www.bing.com:1234/my/path"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "ftp://www.bing.com:1234/my/path"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("ftp://www.bing.com:1234/my/path").toString(), "ftp://www.bing.com:1234/my/path");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("ftp://www.bing.com:1234/my/path").toString(),
|
||||
"ftp://www.bing.com:1234/my/path"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "www.bing.com?a=1"`, () => {
|
||||
|
@ -855,67 +885,115 @@ describe("URLBuilder", () => {
|
|||
});
|
||||
|
||||
it(`with "https://www.bing.com?a=1"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("https://www.bing.com?a=1").toString(), "https://www.bing.com?a=1");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("https://www.bing.com?a=1").toString(),
|
||||
"https://www.bing.com?a=1"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "www.bing.com:123?a=1"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("www.bing.com:123?a=1").toString(), "www.bing.com:123?a=1");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("www.bing.com:123?a=1").toString(),
|
||||
"www.bing.com:123?a=1"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "https://www.bing.com:987?a=1"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("https://www.bing.com:987?a=1").toString(), "https://www.bing.com:987?a=1");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("https://www.bing.com:987?a=1").toString(),
|
||||
"https://www.bing.com:987?a=1"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "www.bing.com/folder/index.html?a=1"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("www.bing.com/folder/index.html?a=1").toString(), "www.bing.com/folder/index.html?a=1");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("www.bing.com/folder/index.html?a=1").toString(),
|
||||
"www.bing.com/folder/index.html?a=1"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "https://www.bing.com/image.gif?a=1"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("https://www.bing.com/image.gif?a=1").toString(), "https://www.bing.com/image.gif?a=1");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("https://www.bing.com/image.gif?a=1").toString(),
|
||||
"https://www.bing.com/image.gif?a=1"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "www.bing.com:123/index.html?a=1"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("www.bing.com:123/index.html?a=1").toString(), "www.bing.com:123/index.html?a=1");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("www.bing.com:123/index.html?a=1").toString(),
|
||||
"www.bing.com:123/index.html?a=1"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "https://www.bing.com:987/my/path/again?a=1"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("https://www.bing.com:987/my/path/again?a=1").toString(), "https://www.bing.com:987/my/path/again?a=1");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("https://www.bing.com:987/my/path/again?a=1").toString(),
|
||||
"https://www.bing.com:987/my/path/again?a=1"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "www.bing.com?a=1&b=2"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("www.bing.com?a=1&b=2").toString(), "www.bing.com?a=1&b=2");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("www.bing.com?a=1&b=2").toString(),
|
||||
"www.bing.com?a=1&b=2"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "https://www.bing.com?a=1&b=2"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("https://www.bing.com?a=1&b=2").toString(), "https://www.bing.com?a=1&b=2");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("https://www.bing.com?a=1&b=2").toString(),
|
||||
"https://www.bing.com?a=1&b=2"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "www.bing.com:123?a=1&b=2"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("www.bing.com:123?a=1&b=2").toString(), "www.bing.com:123?a=1&b=2");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("www.bing.com:123?a=1&b=2").toString(),
|
||||
"www.bing.com:123?a=1&b=2"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "https://www.bing.com:987?a=1&b=2"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("https://www.bing.com:987?a=1&b=2").toString(), "https://www.bing.com:987?a=1&b=2");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("https://www.bing.com:987?a=1&b=2").toString(),
|
||||
"https://www.bing.com:987?a=1&b=2"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "www.bing.com/folder/index.html?a=1&b=2"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("www.bing.com/folder/index.html?a=1&b=2").toString(), "www.bing.com/folder/index.html?a=1&b=2");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("www.bing.com/folder/index.html?a=1&b=2").toString(),
|
||||
"www.bing.com/folder/index.html?a=1&b=2"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "https://www.bing.com/image.gif?a=1&b=2"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("https://www.bing.com/image.gif?a=1&b=2").toString(), "https://www.bing.com/image.gif?a=1&b=2");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("https://www.bing.com/image.gif?a=1&b=2").toString(),
|
||||
"https://www.bing.com/image.gif?a=1&b=2"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "www.bing.com:123/index.html?a=1&b=2"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("www.bing.com:123/index.html?a=1&b=2").toString(), "www.bing.com:123/index.html?a=1&b=2");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("www.bing.com:123/index.html?a=1&b=2").toString(),
|
||||
"www.bing.com:123/index.html?a=1&b=2"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "https://www.bing.com:987/my/path/again?a=1&b=2"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("https://www.bing.com:987/my/path/again?a=1&b=2").toString(), "https://www.bing.com:987/my/path/again?a=1&b=2");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("https://www.bing.com:987/my/path/again?a=1&b=2").toString(),
|
||||
"https://www.bing.com:987/my/path/again?a=1&b=2"
|
||||
);
|
||||
});
|
||||
|
||||
it(`with "https://www.bing.com/my:/path"`, () => {
|
||||
assert.strictEqual(URLBuilder.parse("https://www.bing.com/my:/path").toString(), "https://www.bing.com/my:/path");
|
||||
assert.strictEqual(
|
||||
URLBuilder.parse("https://www.bing.com/my:/path").toString(),
|
||||
"https://www.bing.com/my:/path"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1005,12 +1083,30 @@ describe("URLTokenizer", () => {
|
|||
const tokenizer = new URLTokenizer(text);
|
||||
if (expectedURLTokens) {
|
||||
for (let i = 0; i < expectedURLTokens.length; ++i) {
|
||||
assert.strictEqual(tokenizer.next(), true, `Expected to find ${expectedURLTokens.length} URLTokens, but found ${i} instead.`);
|
||||
assert.deepEqual(tokenizer.current(), expectedURLTokens[i], `Expected the ${i + 1} URLToken to be ${JSON.stringify(expectedURLTokens[i])}, but found ${JSON.stringify(tokenizer.current())} instead.`);
|
||||
assert.strictEqual(
|
||||
tokenizer.next(),
|
||||
true,
|
||||
`Expected to find ${expectedURLTokens.length} URLTokens, but found ${i} instead.`
|
||||
);
|
||||
assert.deepEqual(
|
||||
tokenizer.current(),
|
||||
expectedURLTokens[i],
|
||||
`Expected the ${i + 1} URLToken to be ${JSON.stringify(
|
||||
expectedURLTokens[i]
|
||||
)}, but found ${JSON.stringify(tokenizer.current())} instead.`
|
||||
);
|
||||
}
|
||||
}
|
||||
assert.strictEqual(tokenizer.next(), false, `Only expected to find ${(expectedURLTokens ? expectedURLTokens.length : 0)} URL token(s).`);
|
||||
assert.strictEqual(tokenizer.current(), undefined, `After reading all of the URLTokens, expected the current value to be undefined.`);
|
||||
assert.strictEqual(
|
||||
tokenizer.next(),
|
||||
false,
|
||||
`Only expected to find ${expectedURLTokens ? expectedURLTokens.length : 0} URL token(s).`
|
||||
);
|
||||
assert.strictEqual(
|
||||
tokenizer.current(),
|
||||
undefined,
|
||||
`After reading all of the URLTokens, expected the current value to be undefined.`
|
||||
);
|
||||
}
|
||||
|
||||
it(`with ""`, () => {
|
||||
|
@ -1018,37 +1114,25 @@ describe("URLTokenizer", () => {
|
|||
});
|
||||
|
||||
it(`with "http"`, () => {
|
||||
nextTest("http", [
|
||||
URLToken.host("http")
|
||||
]);
|
||||
nextTest("http", [URLToken.host("http")]);
|
||||
});
|
||||
|
||||
it(`with "http:"`, () => {
|
||||
nextTest("http:", [
|
||||
URLToken.host("http"),
|
||||
URLToken.port("")
|
||||
]);
|
||||
nextTest("http:", [URLToken.host("http"), URLToken.port("")]);
|
||||
});
|
||||
|
||||
it(`with "http:/"`, () => {
|
||||
nextTest("http:/", [
|
||||
URLToken.host("http"),
|
||||
URLToken.port(""),
|
||||
URLToken.path("/")
|
||||
]);
|
||||
nextTest("http:/", [URLToken.host("http"), URLToken.port(""), URLToken.path("/")]);
|
||||
});
|
||||
|
||||
it(`with "http://"`, () => {
|
||||
nextTest("http://", [
|
||||
URLToken.scheme("http"),
|
||||
URLToken.host("")
|
||||
]);
|
||||
nextTest("http://", [URLToken.scheme("http"), URLToken.host("")]);
|
||||
});
|
||||
|
||||
it(`with "https://www.example.com"`, () => {
|
||||
nextTest("https://www.example.com", [
|
||||
URLToken.scheme("https"),
|
||||
URLToken.host("www.example.com")
|
||||
URLToken.host("www.example.com"),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1056,7 +1140,7 @@ describe("URLTokenizer", () => {
|
|||
nextTest("https://www.example.com:", [
|
||||
URLToken.scheme("https"),
|
||||
URLToken.host("www.example.com"),
|
||||
URLToken.port("")
|
||||
URLToken.port(""),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1064,7 +1148,7 @@ describe("URLTokenizer", () => {
|
|||
nextTest("https://www.example.com:8080", [
|
||||
URLToken.scheme("https"),
|
||||
URLToken.host("www.example.com"),
|
||||
URLToken.port("8080")
|
||||
URLToken.port("8080"),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1073,7 +1157,7 @@ describe("URLTokenizer", () => {
|
|||
URLToken.scheme("ftp"),
|
||||
URLToken.host("www.bing.com"),
|
||||
URLToken.port("123"),
|
||||
URLToken.path("/")
|
||||
URLToken.path("/"),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1082,7 +1166,7 @@ describe("URLTokenizer", () => {
|
|||
URLToken.scheme("ftp"),
|
||||
URLToken.host("www.bing.com"),
|
||||
URLToken.port("123"),
|
||||
URLToken.path("/a/b/c.txt")
|
||||
URLToken.path("/a/b/c.txt"),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1091,7 +1175,7 @@ describe("URLTokenizer", () => {
|
|||
URLToken.scheme("ftp"),
|
||||
URLToken.host("www.bing.com"),
|
||||
URLToken.port("123"),
|
||||
URLToken.query("")
|
||||
URLToken.query(""),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1100,7 +1184,7 @@ describe("URLTokenizer", () => {
|
|||
URLToken.scheme("ftp"),
|
||||
URLToken.host("www.bing.com"),
|
||||
URLToken.port("123"),
|
||||
URLToken.query("a=b&c=d")
|
||||
URLToken.query("a=b&c=d"),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1108,7 +1192,7 @@ describe("URLTokenizer", () => {
|
|||
nextTest("https://www.example.com/", [
|
||||
URLToken.scheme("https"),
|
||||
URLToken.host("www.example.com"),
|
||||
URLToken.path("/")
|
||||
URLToken.path("/"),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1116,7 +1200,7 @@ describe("URLTokenizer", () => {
|
|||
nextTest("https://www.example.com/index.html", [
|
||||
URLToken.scheme("https"),
|
||||
URLToken.host("www.example.com"),
|
||||
URLToken.path("/index.html")
|
||||
URLToken.path("/index.html"),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1125,7 +1209,7 @@ describe("URLTokenizer", () => {
|
|||
URLToken.scheme("https"),
|
||||
URLToken.host("www.example.com"),
|
||||
URLToken.path("/index.html"),
|
||||
URLToken.query("")
|
||||
URLToken.query(""),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1134,7 +1218,7 @@ describe("URLTokenizer", () => {
|
|||
URLToken.scheme("https"),
|
||||
URLToken.host("www.example.com"),
|
||||
URLToken.path("/index.html"),
|
||||
URLToken.query("")
|
||||
URLToken.query(""),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1143,7 +1227,7 @@ describe("URLTokenizer", () => {
|
|||
URLToken.scheme("https"),
|
||||
URLToken.host("www.example.com"),
|
||||
URLToken.path("/index.html"),
|
||||
URLToken.query("alpha=beta")
|
||||
URLToken.query("alpha=beta"),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1151,7 +1235,7 @@ describe("URLTokenizer", () => {
|
|||
nextTest("https://www.example.com?", [
|
||||
URLToken.scheme("https"),
|
||||
URLToken.host("www.example.com"),
|
||||
URLToken.query("")
|
||||
URLToken.query(""),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -1159,36 +1243,24 @@ describe("URLTokenizer", () => {
|
|||
nextTest("https://www.example.com?a=b", [
|
||||
URLToken.scheme("https"),
|
||||
URLToken.host("www.example.com"),
|
||||
URLToken.query("a=b")
|
||||
URLToken.query("a=b"),
|
||||
]);
|
||||
});
|
||||
|
||||
it(`with "www.test.com/"`, () => {
|
||||
nextTest("www.test.com/", [
|
||||
URLToken.host("www.test.com"),
|
||||
URLToken.path("/")
|
||||
]);
|
||||
nextTest("www.test.com/", [URLToken.host("www.test.com"), URLToken.path("/")]);
|
||||
});
|
||||
|
||||
it(`with "www.test.com?"`, () => {
|
||||
nextTest("www.test.com?", [
|
||||
URLToken.host("www.test.com"),
|
||||
URLToken.query("")
|
||||
]);
|
||||
nextTest("www.test.com?", [URLToken.host("www.test.com"), URLToken.query("")]);
|
||||
});
|
||||
|
||||
it(`with "folder/index.html"`, () => {
|
||||
nextTest("folder/index.html", [
|
||||
URLToken.host("folder"),
|
||||
URLToken.path("/index.html")
|
||||
]);
|
||||
nextTest("folder/index.html", [URLToken.host("folder"), URLToken.path("/index.html")]);
|
||||
});
|
||||
|
||||
it(`with "/folder/index.html"`, () => {
|
||||
nextTest("/folder/index.html", [
|
||||
URLToken.host(""),
|
||||
URLToken.path("/folder/index.html")
|
||||
]);
|
||||
nextTest("/folder/index.html", [URLToken.host(""), URLToken.path("/folder/index.html")]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,45 +6,47 @@ import { WebResource } from "../lib/webResource";
|
|||
import { assert } from "chai";
|
||||
import { parseHeaders, XhrHttpClient } from "../lib/xhrHttpClient";
|
||||
|
||||
describe("XhrHttpClient", function() {
|
||||
it("parses headers", function() {
|
||||
describe("XhrHttpClient", function () {
|
||||
it("parses headers", function () {
|
||||
const xhr = {
|
||||
getAllResponseHeaders: () =>
|
||||
"Content-Length: 42\r\n" +
|
||||
"value: hello\r\n"
|
||||
getAllResponseHeaders: () => "Content-Length: 42\r\n" + "value: hello\r\n",
|
||||
} as XMLHttpRequest;
|
||||
const headers = parseHeaders(xhr);
|
||||
assert.strictEqual(headers.get("content-length"), "42");
|
||||
assert.strictEqual(headers.get("value"), "hello");
|
||||
});
|
||||
|
||||
it("parses empty string headers", function() {
|
||||
it("parses empty string headers", function () {
|
||||
const xhr = {
|
||||
getAllResponseHeaders: () =>
|
||||
"Content-Type: \r\n" + // preserve trailing whitespace in test case
|
||||
"value:\r\n"
|
||||
"value:\r\n",
|
||||
} as XMLHttpRequest;
|
||||
const headers = parseHeaders(xhr);
|
||||
assert.strictEqual(headers.get("content-type"), "");
|
||||
assert.strictEqual(headers.get("value"), "");
|
||||
});
|
||||
|
||||
it("throws when proxy settings are passed", function() {
|
||||
it("throws when proxy settings are passed", function () {
|
||||
const request = new WebResource();
|
||||
request.proxySettings = {
|
||||
host: "1.1.1.1",
|
||||
port: 8080
|
||||
port: 8080,
|
||||
};
|
||||
|
||||
const client = new XhrHttpClient();
|
||||
assert.throws(() => { client.sendRequest(request); }, Error);
|
||||
assert.throws(() => {
|
||||
client.sendRequest(request);
|
||||
}, Error);
|
||||
});
|
||||
|
||||
it("throws when agent settings are passed", function() {
|
||||
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);
|
||||
assert.throws(() => {
|
||||
client.sendRequest(request);
|
||||
}, Error);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,13 +6,21 @@ describe("XML serializer", function () {
|
|||
describe("parseXML(string)", function () {
|
||||
it("with undefined", async function () {
|
||||
const error: Error = await msAssert.throwsAsync(parseXML(undefined as any));
|
||||
assert.notStrictEqual(error.message.indexOf("Document is empty"), -1, `error.message ("${error.message}") should have contained "Document is empty"`);
|
||||
assert.notStrictEqual(
|
||||
error.message.indexOf("Document is empty"),
|
||||
-1,
|
||||
`error.message ("${error.message}") should have contained "Document is empty"`
|
||||
);
|
||||
});
|
||||
|
||||
it("with null", async function () {
|
||||
// tslint:disable-next-line:no-null-keyword
|
||||
const error: Error = await msAssert.throwsAsync(parseXML(null as any));
|
||||
assert.notStrictEqual(error.message.indexOf("Document is empty"), -1, `error.message ("${error.message}") should have contained "Document is empty"`);
|
||||
assert.notStrictEqual(
|
||||
error.message.indexOf("Document is empty"),
|
||||
-1,
|
||||
`error.message ("${error.message}") should have contained "Document is empty"`
|
||||
);
|
||||
});
|
||||
|
||||
it("with empty", async function () {
|
||||
|
@ -31,9 +39,9 @@ describe("XML serializer", function () {
|
|||
it("with empty element with attribute", async function () {
|
||||
const xml: any = await parseXML(`<fruit healthy="true" />`);
|
||||
assert.deepStrictEqual(xml, {
|
||||
"$": {
|
||||
"healthy": "true"
|
||||
}
|
||||
$: {
|
||||
healthy: "true",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -50,56 +58,56 @@ describe("XML serializer", function () {
|
|||
it("with element with attribute", async function () {
|
||||
const xml: any = await parseXML(`<fruit healthy="true"></fruit>`);
|
||||
assert.deepStrictEqual(xml, {
|
||||
"$": {
|
||||
"healthy": "true"
|
||||
}
|
||||
$: {
|
||||
healthy: "true",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("with element with attribute and value", async function () {
|
||||
const xml: any = await parseXML(`<fruit healthy="true">yum</fruit>`);
|
||||
assert.deepStrictEqual(xml, {
|
||||
"$": {
|
||||
"healthy": "true"
|
||||
$: {
|
||||
healthy: "true",
|
||||
},
|
||||
"_": "yum"
|
||||
_: "yum",
|
||||
});
|
||||
});
|
||||
|
||||
it("with element with child empty element", async function () {
|
||||
const xml: any = await parseXML(`<fruit><apples/></fruit>`);
|
||||
assert.deepStrictEqual(xml, {
|
||||
"apples": ``
|
||||
apples: ``,
|
||||
});
|
||||
});
|
||||
|
||||
it("with element with child empty element with attribute", async function () {
|
||||
const xml: any = await parseXML(`<fruit><apples tasty="true"/></fruit>`);
|
||||
assert.deepStrictEqual(xml, {
|
||||
"apples": {
|
||||
"$": {
|
||||
"tasty": "true"
|
||||
}
|
||||
}
|
||||
apples: {
|
||||
$: {
|
||||
tasty: "true",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("with element with child element with value", async function () {
|
||||
const xml: any = await parseXML(`<fruit><apples>yum</apples></fruit>`);
|
||||
assert.deepStrictEqual(xml, {
|
||||
"apples": "yum"
|
||||
apples: "yum",
|
||||
});
|
||||
});
|
||||
|
||||
it("with element with child element with attribute and value", async function () {
|
||||
const xml: any = await parseXML(`<fruit><apples tasty="true">yum</apples></fruit>`);
|
||||
assert.deepStrictEqual(xml, {
|
||||
"apples": {
|
||||
"$": {
|
||||
"tasty": "true"
|
||||
apples: {
|
||||
$: {
|
||||
tasty: "true",
|
||||
},
|
||||
"_": "yum"
|
||||
}
|
||||
_: "yum",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,13 @@
|
|||
"class-name": true,
|
||||
"comment-format": [true, "check-space"],
|
||||
"indent": [true, "spaces"],
|
||||
"ter-indent": [true, 2],
|
||||
"ter-indent": [
|
||||
true,
|
||||
2,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"linebreak-style": [true, "LF"],
|
||||
"one-line": [true,
|
||||
"check-open-brace",
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as glob from "glob";
|
|||
import * as path from "path";
|
||||
|
||||
const config: webpack.Configuration = {
|
||||
entry: glob.sync(path.join(__dirname, "test/**/*[^node\.].ts")),
|
||||
entry: glob.sync(path.join(__dirname, "test/**/*[^node.].ts")),
|
||||
mode: "development",
|
||||
devtool: "source-map",
|
||||
stats: {
|
||||
|
@ -20,19 +20,37 @@ const config: webpack.Configuration = {
|
|||
errors: true,
|
||||
errorDetails: false,
|
||||
warnings: false,
|
||||
publicPath: false
|
||||
publicPath: false,
|
||||
},
|
||||
output: {
|
||||
filename: "msRest.browser.test.js",
|
||||
path: path.resolve(__dirname, "test")
|
||||
path: path.resolve(__dirname, "test"),
|
||||
},
|
||||
plugins: [
|
||||
new webpack.NormalModuleReplacementPlugin(/(\.).+util\/base64/, path.resolve(__dirname, "./lib/util/base64.browser.ts")),
|
||||
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"))
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/(\.).+util\/base64/,
|
||||
path.resolve(__dirname, "./lib/util/base64.browser.ts")
|
||||
),
|
||||
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: {
|
||||
rules: [
|
||||
|
@ -40,12 +58,12 @@ const config: webpack.Configuration = {
|
|||
test: /\.tsx?$/,
|
||||
loader: "ts-loader",
|
||||
exclude: /(node_modules)/,
|
||||
options: { configFile: path.join(__dirname, "./tsconfig.es.json") }
|
||||
}
|
||||
]
|
||||
options: { configFile: path.join(__dirname, "./tsconfig.es.json") },
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".tsx", ".ts", ".js"]
|
||||
extensions: [".tsx", ".ts", ".js"],
|
||||
},
|
||||
node: {
|
||||
dns: false,
|
||||
|
@ -57,7 +75,7 @@ const config: webpack.Configuration = {
|
|||
tty: false,
|
||||
tunnel: "empty",
|
||||
v8: false,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export = config;
|
||||
|
|
Загрузка…
Ссылка в новой задаче