@azure/storage-common 12.5.0 → 12.6.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/StorageResponseFormat.d.ts +1 -1
- package/dist/browser/StorageResponseFormat.js +1 -1
- package/dist/browser/StorageResponseFormat.js.map +1 -1
- package/dist/browser/StructuredMessageEncodingStream-browser.d.mts.map +1 -1
- package/dist/browser/StructuredMessageEncodingStream-browser.mjs +1 -2
- package/dist/browser/StructuredMessageEncodingStream-browser.mjs.map +1 -1
- package/dist/browser/package.json +6 -1
- package/dist/browser/policies/StorageRetryPolicy.js +1 -1
- package/dist/browser/policies/StorageRetryPolicy.js.map +1 -1
- package/dist/browser/policies/StorageRetryPolicyV2.d.ts.map +1 -1
- package/dist/browser/policies/StorageRetryPolicyV2.js +28 -0
- package/dist/browser/policies/StorageRetryPolicyV2.js.map +1 -1
- package/dist/browser/utils/constants.d.ts.map +1 -1
- package/dist/browser/utils/constants.js +1 -1
- package/dist/browser/utils/constants.js.map +1 -1
- package/dist/browser/utils/utils.common.d.ts.map +1 -1
- package/dist/browser/utils/utils.common.js +5 -9
- package/dist/browser/utils/utils.common.js.map +1 -1
- package/dist/commonjs/BufferScheduler.d.ts.map +1 -1
- package/dist/commonjs/BufferScheduler.js +24 -7
- package/dist/commonjs/BufferScheduler.js.map +2 -2
- package/dist/commonjs/BuffersStream.d.ts.map +1 -1
- package/dist/commonjs/BuffersStream.js +0 -1
- package/dist/commonjs/BuffersStream.js.map +2 -2
- package/dist/commonjs/StorageResponseFormat.d.ts +1 -1
- package/dist/commonjs/StorageResponseFormat.js +1 -1
- package/dist/commonjs/StorageResponseFormat.js.map +1 -1
- package/dist/commonjs/indexPlatform.d.ts +1 -0
- package/dist/commonjs/indexPlatform.d.ts.map +1 -1
- package/dist/commonjs/indexPlatform.js +3 -0
- package/dist/commonjs/indexPlatform.js.map +2 -2
- package/dist/commonjs/package.json +6 -1
- package/dist/commonjs/policies/SharedKeySigning.d.ts +32 -0
- package/dist/commonjs/policies/SharedKeySigning.d.ts.map +1 -0
- package/dist/commonjs/policies/SharedKeySigning.js +125 -0
- package/dist/commonjs/policies/SharedKeySigning.js.map +7 -0
- package/dist/commonjs/policies/StorageRetryPolicy.js +1 -1
- package/dist/commonjs/policies/StorageRetryPolicy.js.map +2 -2
- package/dist/commonjs/policies/StorageRetryPolicyV2.d.ts.map +1 -1
- package/dist/commonjs/policies/StorageRetryPolicyV2.js +16 -0
- package/dist/commonjs/policies/StorageRetryPolicyV2.js.map +2 -2
- package/dist/commonjs/policies/StorageSharedKeyCredentialPolicy.d.ts +0 -28
- package/dist/commonjs/policies/StorageSharedKeyCredentialPolicy.d.ts.map +1 -1
- package/dist/commonjs/policies/StorageSharedKeyCredentialPolicy.js +10 -94
- package/dist/commonjs/policies/StorageSharedKeyCredentialPolicy.js.map +2 -2
- package/dist/commonjs/policies/StorageSharedKeyCredentialPolicyV2.d.ts.map +1 -1
- package/dist/commonjs/policies/StorageSharedKeyCredentialPolicyV2.js +2 -76
- package/dist/commonjs/policies/StorageSharedKeyCredentialPolicyV2.js.map +2 -2
- package/dist/commonjs/tsdoc-metadata.json +1 -1
- package/dist/commonjs/utils/constants.d.ts.map +1 -1
- package/dist/commonjs/utils/constants.js +1 -1
- package/dist/commonjs/utils/constants.js.map +1 -1
- package/dist/commonjs/utils/utils.common.d.ts.map +1 -1
- package/dist/commonjs/utils/utils.common.js +11 -9
- package/dist/commonjs/utils/utils.common.js.map +2 -2
- package/dist/esm/BufferScheduler.d.ts.map +1 -1
- package/dist/esm/BufferScheduler.js +29 -7
- package/dist/esm/BufferScheduler.js.map +1 -1
- package/dist/esm/BuffersStream.d.ts.map +1 -1
- package/dist/esm/BuffersStream.js +0 -1
- package/dist/esm/BuffersStream.js.map +1 -1
- package/dist/esm/StorageResponseFormat.d.ts +1 -1
- package/dist/esm/StorageResponseFormat.js +1 -1
- package/dist/esm/StorageResponseFormat.js.map +1 -1
- package/dist/esm/indexPlatform.d.ts +1 -0
- package/dist/esm/indexPlatform.d.ts.map +1 -1
- package/dist/esm/indexPlatform.js +1 -0
- package/dist/esm/indexPlatform.js.map +1 -1
- package/dist/esm/package.json +6 -1
- package/dist/esm/policies/SharedKeySigning.d.ts +32 -0
- package/dist/esm/policies/SharedKeySigning.d.ts.map +1 -0
- package/dist/esm/policies/SharedKeySigning.js +156 -0
- package/dist/esm/policies/SharedKeySigning.js.map +1 -0
- package/dist/esm/policies/StorageRetryPolicy.js +1 -1
- package/dist/esm/policies/StorageRetryPolicy.js.map +1 -1
- package/dist/esm/policies/StorageRetryPolicyV2.d.ts.map +1 -1
- package/dist/esm/policies/StorageRetryPolicyV2.js +28 -0
- package/dist/esm/policies/StorageRetryPolicyV2.js.map +1 -1
- package/dist/esm/policies/StorageSharedKeyCredentialPolicy.d.ts +0 -28
- package/dist/esm/policies/StorageSharedKeyCredentialPolicy.d.ts.map +1 -1
- package/dist/esm/policies/StorageSharedKeyCredentialPolicy.js +9 -105
- package/dist/esm/policies/StorageSharedKeyCredentialPolicy.js.map +1 -1
- package/dist/esm/policies/StorageSharedKeyCredentialPolicyV2.d.ts.map +1 -1
- package/dist/esm/policies/StorageSharedKeyCredentialPolicyV2.js +2 -101
- package/dist/esm/policies/StorageSharedKeyCredentialPolicyV2.js.map +1 -1
- package/dist/esm/utils/constants.d.ts.map +1 -1
- package/dist/esm/utils/constants.js +1 -1
- package/dist/esm/utils/constants.js.map +1 -1
- package/dist/esm/utils/utils.common.d.ts.map +1 -1
- package/dist/esm/utils/utils.common.js +5 -9
- package/dist/esm/utils/utils.common.js.map +1 -1
- package/dist/react-native/StorageResponseFormat.d.ts +1 -1
- package/dist/react-native/StorageResponseFormat.js +1 -1
- package/dist/react-native/StorageResponseFormat.js.map +1 -1
- package/dist/react-native/package.json +6 -1
- package/dist/react-native/policies/StorageRetryPolicy.js +1 -1
- package/dist/react-native/policies/StorageRetryPolicy.js.map +1 -1
- package/dist/react-native/policies/StorageRetryPolicyV2.d.ts.map +1 -1
- package/dist/react-native/policies/StorageRetryPolicyV2.js +28 -0
- package/dist/react-native/policies/StorageRetryPolicyV2.js.map +1 -1
- package/dist/react-native/utils/constants.d.ts.map +1 -1
- package/dist/react-native/utils/constants.js +1 -1
- package/dist/react-native/utils/constants.js.map +1 -1
- package/dist/react-native/utils/utils.common.d.ts.map +1 -1
- package/dist/react-native/utils/utils.common.js +5 -9
- package/dist/react-native/utils/utils.common.js.map +1 -1
- package/package.json +9 -9
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
import { HeaderConstants } from "../utils/constants.js";
|
|
4
|
+
import { getURLPath } from "../utils/utils.common.js";
|
|
5
|
+
import { compareHeader } from "../utils/SharedKeyComparator.js";
|
|
6
|
+
/**
|
|
7
|
+
* Retrieve header value according to shared key sign rules.
|
|
8
|
+
* @see https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key
|
|
9
|
+
*/
|
|
10
|
+
function getHeaderValueToSign(request, headerName) {
|
|
11
|
+
const value = request.headers.get(headerName);
|
|
12
|
+
if (!value) {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
// When using version 2015-02-21 or later, if Content-Length is zero, then
|
|
16
|
+
// set the Content-Length part of the StringToSign to an empty string.
|
|
17
|
+
// https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key
|
|
18
|
+
if (headerName === HeaderConstants.CONTENT_LENGTH && value === "0") {
|
|
19
|
+
return "";
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* To construct the CanonicalizedHeaders portion of the signature string, follow these steps:
|
|
25
|
+
* 1. Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header.
|
|
26
|
+
* 2. Convert each HTTP header name to lowercase.
|
|
27
|
+
* 3. Sort the headers lexicographically by header name, in ascending order.
|
|
28
|
+
* Each header may appear only once in the string.
|
|
29
|
+
* 4. Replace any linear whitespace in the header value with a single space.
|
|
30
|
+
* 5. Trim any whitespace around the colon in the header.
|
|
31
|
+
* 6. Finally, append a new-line character to each canonicalized header in the resulting list.
|
|
32
|
+
* Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string.
|
|
33
|
+
*
|
|
34
|
+
*/
|
|
35
|
+
function getCanonicalizedHeadersString(request) {
|
|
36
|
+
let headersArray = [];
|
|
37
|
+
for (const [name, value] of request.headers) {
|
|
38
|
+
if (name.toLowerCase().startsWith(HeaderConstants.PREFIX_FOR_STORAGE)) {
|
|
39
|
+
headersArray.push({ name, value });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
headersArray.sort((a, b) => {
|
|
43
|
+
return compareHeader(a.name.toLowerCase(), b.name.toLowerCase());
|
|
44
|
+
});
|
|
45
|
+
// Remove duplicate headers
|
|
46
|
+
headersArray = headersArray.filter((value, index, array) => {
|
|
47
|
+
if (index > 0 && value.name.toLowerCase() === array[index - 1].name.toLowerCase()) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
});
|
|
52
|
+
let canonicalizedHeadersStringToSign = "";
|
|
53
|
+
headersArray.forEach((header) => {
|
|
54
|
+
canonicalizedHeadersStringToSign += `${header.name
|
|
55
|
+
.toLowerCase()
|
|
56
|
+
.trimRight()}:${header.value.trimLeft()}\n`;
|
|
57
|
+
});
|
|
58
|
+
return canonicalizedHeadersStringToSign;
|
|
59
|
+
}
|
|
60
|
+
function getCanonicalizedResourceString(request, accountName) {
|
|
61
|
+
const path = getURLPath(request.url) || "/";
|
|
62
|
+
let canonicalizedResourceString = "";
|
|
63
|
+
canonicalizedResourceString += `/${accountName}${path}`;
|
|
64
|
+
// A name that repeats, whether spelled identically or differing only by case, contributes all
|
|
65
|
+
// of its values as one sorted, comma-joined line.
|
|
66
|
+
const valuesByKey = getCanonicalizedQueryValues(request.url);
|
|
67
|
+
for (const key of [...valuesByKey.keys()].sort()) {
|
|
68
|
+
canonicalizedResourceString += `\n${key}:${valuesByKey.get(key).sort().join(",")}`;
|
|
69
|
+
}
|
|
70
|
+
return canonicalizedResourceString;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Groups query parameter values by lowercased name. Parses the raw query rather than reusing
|
|
74
|
+
* `getURLQueries`, which keeps only the last value for a repeated name and discards parameters
|
|
75
|
+
* that the service still canonicalizes.
|
|
76
|
+
*/
|
|
77
|
+
function getCanonicalizedQueryValues(url) {
|
|
78
|
+
const valuesByKey = new Map();
|
|
79
|
+
const queryString = new URL(url).search.replace(/^\?/, "").trim();
|
|
80
|
+
if (!queryString) {
|
|
81
|
+
return valuesByKey;
|
|
82
|
+
}
|
|
83
|
+
for (const pair of queryString.split("&")) {
|
|
84
|
+
if (!pair) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// Split at the first "=" only: "=" is legal inside a value, and a name carried without one
|
|
88
|
+
// still participates in the signature.
|
|
89
|
+
const separator = pair.indexOf("=");
|
|
90
|
+
const key = decodeURIComponent(separator === -1 ? pair : pair.substring(0, separator)).toLowerCase();
|
|
91
|
+
const values = valuesByKey.get(key) ?? [];
|
|
92
|
+
values.push(separator === -1 ? "" : decodeURIComponent(pair.substring(separator + 1)));
|
|
93
|
+
valuesByKey.set(key, values);
|
|
94
|
+
}
|
|
95
|
+
return valuesByKey;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Sets the request headers that participate in the Shared Key signature and are derived from
|
|
99
|
+
* the request itself: `x-ms-date`, and `Content-Length` for a string or Buffer body.
|
|
100
|
+
*
|
|
101
|
+
* `Content-Length` is a signed field: a request with a body whose `Content-Length` isn't set
|
|
102
|
+
* gets a signature the service rejects.
|
|
103
|
+
*/
|
|
104
|
+
export function prepareSharedKeyHeaders(request) {
|
|
105
|
+
request.headers.set(HeaderConstants.X_MS_DATE, new Date().toUTCString());
|
|
106
|
+
if (request.body &&
|
|
107
|
+
(typeof request.body === "string" || Buffer.isBuffer(request.body)) &&
|
|
108
|
+
request.body.length > 0) {
|
|
109
|
+
request.headers.set(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(request.body));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Builds the string to sign for the Azure Storage Shared Key authorization scheme.
|
|
114
|
+
*
|
|
115
|
+
* Before building it, sets the request headers that the signature covers and that come from
|
|
116
|
+
* the request itself: `x-ms-date`, and `Content-Length` for a string or Buffer body. Send the
|
|
117
|
+
* request with these headers, since the signature depends on them.
|
|
118
|
+
*
|
|
119
|
+
* @param request - The request to sign. Its `x-ms-date` header is set, and so is its
|
|
120
|
+
* `Content-Length` header when the body is a string or a Buffer.
|
|
121
|
+
* @param accountName - The storage account name used to build the canonicalized resource.
|
|
122
|
+
* @returns The string to sign, ready to be signed with HMAC-SHA256.
|
|
123
|
+
* @see https://learn.microsoft.com/rest/api/storageservices/authorize-with-shared-key
|
|
124
|
+
*/
|
|
125
|
+
export function buildStorageSharedKeyStringToSign(request, accountName) {
|
|
126
|
+
prepareSharedKeyHeaders(request);
|
|
127
|
+
return buildStringToSign(request, accountName);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Builds the string to sign from the request as it is, without setting any header. For a caller
|
|
131
|
+
* that sets the signed headers itself on the request it sends.
|
|
132
|
+
*
|
|
133
|
+
* @param request - The request whose headers and URL form the string to sign.
|
|
134
|
+
* @param accountName - The storage account name used to build the canonicalized resource.
|
|
135
|
+
*/
|
|
136
|
+
export function buildStringToSign(request, accountName) {
|
|
137
|
+
return ([
|
|
138
|
+
request.method.toUpperCase(),
|
|
139
|
+
getHeaderValueToSign(request, HeaderConstants.CONTENT_ENCODING),
|
|
140
|
+
getHeaderValueToSign(request, HeaderConstants.CONTENT_LANGUAGE),
|
|
141
|
+
getHeaderValueToSign(request, HeaderConstants.CONTENT_LENGTH),
|
|
142
|
+
getHeaderValueToSign(request, HeaderConstants.CONTENT_MD5),
|
|
143
|
+
getHeaderValueToSign(request, HeaderConstants.CONTENT_TYPE),
|
|
144
|
+
// Signed requests always carry x-ms-date, which requires this slot to stay empty.
|
|
145
|
+
"",
|
|
146
|
+
getHeaderValueToSign(request, HeaderConstants.IF_MODIFIED_SINCE),
|
|
147
|
+
getHeaderValueToSign(request, HeaderConstants.IF_MATCH),
|
|
148
|
+
getHeaderValueToSign(request, HeaderConstants.IF_NONE_MATCH),
|
|
149
|
+
getHeaderValueToSign(request, HeaderConstants.IF_UNMODIFIED_SINCE),
|
|
150
|
+
getHeaderValueToSign(request, HeaderConstants.RANGE),
|
|
151
|
+
].join("\n") +
|
|
152
|
+
"\n" +
|
|
153
|
+
getCanonicalizedHeadersString(request) +
|
|
154
|
+
getCanonicalizedResourceString(request, accountName));
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=SharedKeySigning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SharedKeySigning.js","sourceRoot":"","sources":["../../../src/policies/SharedKeySigning.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAGlC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE;;;GAGG;AACH,SAAS,oBAAoB,CAAC,OAAwB,EAAE,UAAkB;IACxE,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAE9C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,0EAA0E;IAC1E,sEAAsE;IACtE,oFAAoF;IACpF,IAAI,UAAU,KAAK,eAAe,CAAC,cAAc,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;QACnE,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,6BAA6B,CAAC,OAAwB;IAC7D,IAAI,YAAY,GAA2C,EAAE,CAAC;IAC9D,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAC5C,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACtE,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAU,EAAE;QACjC,OAAO,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,2BAA2B;IAC3B,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QACzD,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YAClF,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,IAAI,gCAAgC,GAAW,EAAE,CAAC;IAClD,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QAC9B,gCAAgC,IAAI,GAAG,MAAM,CAAC,IAAI;aAC/C,WAAW,EAAE;aACb,SAAS,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,OAAO,gCAAgC,CAAC;AAC1C,CAAC;AAED,SAAS,8BAA8B,CAAC,OAAwB,EAAE,WAAmB;IACnF,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;IAE5C,IAAI,2BAA2B,GAAW,EAAE,CAAC;IAC7C,2BAA2B,IAAI,IAAI,WAAW,GAAG,IAAI,EAAE,CAAC;IAExD,8FAA8F;IAC9F,kDAAkD;IAClD,MAAM,WAAW,GAAG,2BAA2B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7D,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACjD,2BAA2B,IAAI,KAAK,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACtF,CAAC;IAED,OAAO,2BAA2B,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,SAAS,2BAA2B,CAAC,GAAW;IAC9C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;IAChD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,SAAS;QACX,CAAC;QAED,2FAA2F;QAC3F,uCAAuC;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,kBAAkB,CAC5B,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CACvD,CAAC,WAAW,EAAE,CAAC;QAChB,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACvF,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAwB;IAC9D,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAEzE,IACE,OAAO,CAAC,IAAI;QACZ,CAAC,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EACvB,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,cAAc,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACvF,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iCAAiC,CAC/C,OAAwB,EACxB,WAAmB;IAEnB,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,OAAO,iBAAiB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAwB,EAAE,WAAmB;IAC7E,OAAO,CACL;QACE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE;QAC5B,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,gBAAgB,CAAC;QAC/D,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,gBAAgB,CAAC;QAC/D,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,cAAc,CAAC;QAC7D,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,WAAW,CAAC;QAC1D,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,YAAY,CAAC;QAC3D,kFAAkF;QAClF,EAAE;QACF,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,iBAAiB,CAAC;QAChE,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,QAAQ,CAAC;QACvD,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,aAAa,CAAC;QAC5D,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,mBAAmB,CAAC;QAClE,oBAAoB,CAAC,OAAO,EAAE,eAAe,CAAC,KAAK,CAAC;KACrD,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,IAAI;QACJ,6BAA6B,CAAC,OAAO,CAAC;QACtC,8BAA8B,CAAC,OAAO,EAAE,WAAW,CAAC,CACrD,CAAC;AACJ,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PipelineRequest } from \"@azure/core-rest-pipeline\";\nimport { HeaderConstants } from \"../utils/constants.js\";\nimport { getURLPath } from \"../utils/utils.common.js\";\nimport { compareHeader } from \"../utils/SharedKeyComparator.js\";\n\n/**\n * Retrieve header value according to shared key sign rules.\n * @see https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key\n */\nfunction getHeaderValueToSign(request: PipelineRequest, headerName: string): string {\n const value = request.headers.get(headerName);\n\n if (!value) {\n return \"\";\n }\n\n // When using version 2015-02-21 or later, if Content-Length is zero, then\n // set the Content-Length part of the StringToSign to an empty string.\n // https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key\n if (headerName === HeaderConstants.CONTENT_LENGTH && value === \"0\") {\n return \"\";\n }\n\n return value;\n}\n\n/**\n * To construct the CanonicalizedHeaders portion of the signature string, follow these steps:\n * 1. Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header.\n * 2. Convert each HTTP header name to lowercase.\n * 3. Sort the headers lexicographically by header name, in ascending order.\n * Each header may appear only once in the string.\n * 4. Replace any linear whitespace in the header value with a single space.\n * 5. Trim any whitespace around the colon in the header.\n * 6. Finally, append a new-line character to each canonicalized header in the resulting list.\n * Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string.\n *\n */\nfunction getCanonicalizedHeadersString(request: PipelineRequest): string {\n let headersArray: Array<{ name: string; value: string }> = [];\n for (const [name, value] of request.headers) {\n if (name.toLowerCase().startsWith(HeaderConstants.PREFIX_FOR_STORAGE)) {\n headersArray.push({ name, value });\n }\n }\n\n headersArray.sort((a, b): number => {\n return compareHeader(a.name.toLowerCase(), b.name.toLowerCase());\n });\n\n // Remove duplicate headers\n headersArray = headersArray.filter((value, index, array) => {\n if (index > 0 && value.name.toLowerCase() === array[index - 1].name.toLowerCase()) {\n return false;\n }\n return true;\n });\n\n let canonicalizedHeadersStringToSign: string = \"\";\n headersArray.forEach((header) => {\n canonicalizedHeadersStringToSign += `${header.name\n .toLowerCase()\n .trimRight()}:${header.value.trimLeft()}\\n`;\n });\n\n return canonicalizedHeadersStringToSign;\n}\n\nfunction getCanonicalizedResourceString(request: PipelineRequest, accountName: string): string {\n const path = getURLPath(request.url) || \"/\";\n\n let canonicalizedResourceString: string = \"\";\n canonicalizedResourceString += `/${accountName}${path}`;\n\n // A name that repeats, whether spelled identically or differing only by case, contributes all\n // of its values as one sorted, comma-joined line.\n const valuesByKey = getCanonicalizedQueryValues(request.url);\n for (const key of [...valuesByKey.keys()].sort()) {\n canonicalizedResourceString += `\\n${key}:${valuesByKey.get(key)!.sort().join(\",\")}`;\n }\n\n return canonicalizedResourceString;\n}\n\n/**\n * Groups query parameter values by lowercased name. Parses the raw query rather than reusing\n * `getURLQueries`, which keeps only the last value for a repeated name and discards parameters\n * that the service still canonicalizes.\n */\nfunction getCanonicalizedQueryValues(url: string): Map<string, string[]> {\n const valuesByKey = new Map<string, string[]>();\n const queryString = new URL(url).search.replace(/^\\?/, \"\").trim();\n if (!queryString) {\n return valuesByKey;\n }\n\n for (const pair of queryString.split(\"&\")) {\n if (!pair) {\n continue;\n }\n\n // Split at the first \"=\" only: \"=\" is legal inside a value, and a name carried without one\n // still participates in the signature.\n const separator = pair.indexOf(\"=\");\n const key = decodeURIComponent(\n separator === -1 ? pair : pair.substring(0, separator),\n ).toLowerCase();\n const values = valuesByKey.get(key) ?? [];\n values.push(separator === -1 ? \"\" : decodeURIComponent(pair.substring(separator + 1)));\n valuesByKey.set(key, values);\n }\n\n return valuesByKey;\n}\n\n/**\n * Sets the request headers that participate in the Shared Key signature and are derived from\n * the request itself: `x-ms-date`, and `Content-Length` for a string or Buffer body.\n *\n * `Content-Length` is a signed field: a request with a body whose `Content-Length` isn't set\n * gets a signature the service rejects.\n */\nexport function prepareSharedKeyHeaders(request: PipelineRequest): void {\n request.headers.set(HeaderConstants.X_MS_DATE, new Date().toUTCString());\n\n if (\n request.body &&\n (typeof request.body === \"string\" || Buffer.isBuffer(request.body)) &&\n request.body.length > 0\n ) {\n request.headers.set(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(request.body));\n }\n}\n\n/**\n * Builds the string to sign for the Azure Storage Shared Key authorization scheme.\n *\n * Before building it, sets the request headers that the signature covers and that come from\n * the request itself: `x-ms-date`, and `Content-Length` for a string or Buffer body. Send the\n * request with these headers, since the signature depends on them.\n *\n * @param request - The request to sign. Its `x-ms-date` header is set, and so is its\n * `Content-Length` header when the body is a string or a Buffer.\n * @param accountName - The storage account name used to build the canonicalized resource.\n * @returns The string to sign, ready to be signed with HMAC-SHA256.\n * @see https://learn.microsoft.com/rest/api/storageservices/authorize-with-shared-key\n */\nexport function buildStorageSharedKeyStringToSign(\n request: PipelineRequest,\n accountName: string,\n): string {\n prepareSharedKeyHeaders(request);\n return buildStringToSign(request, accountName);\n}\n\n/**\n * Builds the string to sign from the request as it is, without setting any header. For a caller\n * that sets the signed headers itself on the request it sends.\n *\n * @param request - The request whose headers and URL form the string to sign.\n * @param accountName - The storage account name used to build the canonicalized resource.\n */\nexport function buildStringToSign(request: PipelineRequest, accountName: string): string {\n return (\n [\n request.method.toUpperCase(),\n getHeaderValueToSign(request, HeaderConstants.CONTENT_ENCODING),\n getHeaderValueToSign(request, HeaderConstants.CONTENT_LANGUAGE),\n getHeaderValueToSign(request, HeaderConstants.CONTENT_LENGTH),\n getHeaderValueToSign(request, HeaderConstants.CONTENT_MD5),\n getHeaderValueToSign(request, HeaderConstants.CONTENT_TYPE),\n // Signed requests always carry x-ms-date, which requires this slot to stay empty.\n \"\",\n getHeaderValueToSign(request, HeaderConstants.IF_MODIFIED_SINCE),\n getHeaderValueToSign(request, HeaderConstants.IF_MATCH),\n getHeaderValueToSign(request, HeaderConstants.IF_NONE_MATCH),\n getHeaderValueToSign(request, HeaderConstants.IF_UNMODIFIED_SINCE),\n getHeaderValueToSign(request, HeaderConstants.RANGE),\n ].join(\"\\n\") +\n \"\\n\" +\n getCanonicalizedHeadersString(request) +\n getCanonicalizedResourceString(request, accountName)\n );\n}\n"]}
|
|
@@ -116,7 +116,7 @@ export class StorageRetryPolicy extends BaseRequestPolicy {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
await this.delay(isPrimaryRetry, attempt, request.abortSignal);
|
|
119
|
-
return this.attemptSendRequest(request, secondaryHas404,
|
|
119
|
+
return this.attemptSendRequest(request, secondaryHas404, attempt + 1);
|
|
120
120
|
}
|
|
121
121
|
/**
|
|
122
122
|
* Decide whether to retry according to last HTTP response and retry counters.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageRetryPolicy.js","sourceRoot":"","sources":["../../../src/policies/StorageRetryPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AbortSignalLike } from \"@azure/abort-controller\";\nimport { AbortError } from \"@azure/abort-controller\";\nimport type {\n RequestPolicy,\n RequestPolicyOptionsLike as RequestPolicyOptions,\n RequestPolicyFactory,\n WebResourceLike as WebResource,\n CompatResponse as HttpOperationResponse,\n} from \"@azure/core-http-compat\";\nimport { BaseRequestPolicy } from \"./RequestPolicy.js\";\nimport type { RestError } from \"@azure/core-rest-pipeline\";\n\nimport type { StorageRetryOptions } from \"../StorageRetryPolicyFactory.js\";\nimport { HeaderConstants, URLConstants } from \"../utils/constants.js\";\nimport { delay, setURLHost, setURLParameter } from \"../utils/utils.common.js\";\nimport { logger } from \"../log.js\";\nimport { StorageRetryPolicyType } from \"./StorageRetryPolicyType.js\";\n\n/**\n * A factory method used to generated a RetryPolicy factory.\n *\n * @param retryOptions -\n */\nexport function NewRetryPolicyFactory(retryOptions?: StorageRetryOptions): RequestPolicyFactory {\n return {\n create: (nextPolicy: RequestPolicy, options: RequestPolicyOptions): StorageRetryPolicy => {\n return new StorageRetryPolicy(nextPolicy, options, retryOptions);\n },\n };\n}\n\n// Default values of StorageRetryOptions\nconst DEFAULT_RETRY_OPTIONS: StorageRetryOptions = {\n maxRetryDelayInMs: 120 * 1000,\n maxTries: 4,\n retryDelayInMs: 4 * 1000,\n retryPolicyType: StorageRetryPolicyType.EXPONENTIAL,\n secondaryHost: \"\",\n tryTimeoutInMs: undefined, // Use server side default timeout strategy\n};\n\nconst RETRY_ABORT_ERROR = new AbortError(\"The operation was aborted.\");\n\n/**\n * Retry policy with exponential retry and linear retry implemented.\n */\nexport class StorageRetryPolicy extends BaseRequestPolicy {\n /**\n * RetryOptions.\n */\n private readonly retryOptions: StorageRetryOptions;\n\n /**\n * Creates an instance of RetryPolicy.\n *\n * @param nextPolicy -\n * @param options -\n * @param retryOptions -\n */\n constructor(\n nextPolicy: RequestPolicy,\n options: RequestPolicyOptions,\n retryOptions: StorageRetryOptions = DEFAULT_RETRY_OPTIONS,\n ) {\n super(nextPolicy, options);\n\n // Initialize retry options\n this.retryOptions = {\n retryPolicyType: retryOptions.retryPolicyType\n ? retryOptions.retryPolicyType\n : DEFAULT_RETRY_OPTIONS.retryPolicyType,\n\n maxTries:\n retryOptions.maxTries && retryOptions.maxTries >= 1\n ? Math.floor(retryOptions.maxTries)\n : DEFAULT_RETRY_OPTIONS.maxTries,\n\n tryTimeoutInMs:\n retryOptions.tryTimeoutInMs && retryOptions.tryTimeoutInMs >= 0\n ? retryOptions.tryTimeoutInMs\n : DEFAULT_RETRY_OPTIONS.tryTimeoutInMs,\n\n retryDelayInMs:\n retryOptions.retryDelayInMs && retryOptions.retryDelayInMs >= 0\n ? Math.min(\n retryOptions.retryDelayInMs,\n retryOptions.maxRetryDelayInMs\n ? retryOptions.maxRetryDelayInMs\n : DEFAULT_RETRY_OPTIONS.maxRetryDelayInMs!,\n )\n : DEFAULT_RETRY_OPTIONS.retryDelayInMs,\n\n maxRetryDelayInMs:\n retryOptions.maxRetryDelayInMs && retryOptions.maxRetryDelayInMs >= 0\n ? retryOptions.maxRetryDelayInMs\n : DEFAULT_RETRY_OPTIONS.maxRetryDelayInMs,\n\n secondaryHost: retryOptions.secondaryHost\n ? retryOptions.secondaryHost\n : DEFAULT_RETRY_OPTIONS.secondaryHost,\n };\n }\n\n /**\n * Sends request.\n *\n * @param request -\n */\n public async sendRequest(request: WebResource): Promise<HttpOperationResponse> {\n return this.attemptSendRequest(request, false, 1);\n }\n\n /**\n * Decide and perform next retry. Won't mutate request parameter.\n *\n * @param request -\n * @param secondaryHas404 - If attempt was against the secondary & it returned a StatusNotFound (404), then\n * the resource was not found. This may be due to replication delay. So, in this\n * case, we'll never try the secondary again for this operation.\n * @param attempt - How many retries has been attempted to performed, starting from 1, which includes\n * the attempt will be performed by this method call.\n */\n protected async attemptSendRequest(\n request: WebResource,\n secondaryHas404: boolean,\n attempt: number,\n ): Promise<HttpOperationResponse> {\n const newRequest: WebResource = request.clone();\n\n const isPrimaryRetry =\n secondaryHas404 ||\n !this.retryOptions.secondaryHost ||\n !(request.method === \"GET\" || request.method === \"HEAD\" || request.method === \"OPTIONS\") ||\n attempt % 2 === 1;\n\n if (!isPrimaryRetry) {\n newRequest.url = setURLHost(newRequest.url, this.retryOptions.secondaryHost!);\n }\n\n // Set the server-side timeout query parameter \"timeout=[seconds]\"\n if (this.retryOptions.tryTimeoutInMs) {\n newRequest.url = setURLParameter(\n newRequest.url,\n URLConstants.Parameters.TIMEOUT,\n Math.floor(this.retryOptions.tryTimeoutInMs! / 1000).toString(),\n );\n }\n\n let response: HttpOperationResponse | undefined;\n try {\n logger.info(`RetryPolicy: =====> Try=${attempt} ${isPrimaryRetry ? \"Primary\" : \"Secondary\"}`);\n response = await this._nextPolicy.sendRequest(newRequest);\n if (!this.shouldRetry(isPrimaryRetry, attempt, response)) {\n return response;\n }\n\n secondaryHas404 = secondaryHas404 || (!isPrimaryRetry && response.status === 404);\n } catch (err: any) {\n logger.error(`RetryPolicy: Caught error, message: ${err.message}, code: ${err.code}`);\n if (!this.shouldRetry(isPrimaryRetry, attempt, response, err)) {\n throw err;\n }\n }\n\n await this.delay(isPrimaryRetry, attempt, request.abortSignal);\n return this.attemptSendRequest(request, secondaryHas404, ++attempt);\n }\n\n /**\n * Decide whether to retry according to last HTTP response and retry counters.\n *\n * @param isPrimaryRetry -\n * @param attempt -\n * @param response -\n * @param err -\n */\n protected shouldRetry(\n isPrimaryRetry: boolean,\n attempt: number,\n response?: HttpOperationResponse,\n err?: RestError,\n ): boolean {\n if (attempt >= this.retryOptions.maxTries!) {\n logger.info(\n `RetryPolicy: Attempt(s) ${attempt} >= maxTries ${\n this.retryOptions.maxTries!\n }, no further try.`,\n );\n return false;\n }\n\n // Handle network failures, you may need to customize the list when you implement\n // your own http client\n const retriableErrors = [\n \"ETIMEDOUT\",\n \"ESOCKETTIMEDOUT\",\n \"ECONNREFUSED\",\n \"ECONNRESET\",\n \"ENOENT\",\n \"ENOTFOUND\",\n \"TIMEOUT\",\n \"EPIPE\",\n \"REQUEST_SEND_ERROR\", // For default xhr based http client provided in ms-rest-js\n ];\n if (err) {\n for (const retriableError of retriableErrors) {\n if (\n err.name.toUpperCase().includes(retriableError) ||\n err.message.toUpperCase().includes(retriableError) ||\n (err.code && err.code.toString().toUpperCase() === retriableError)\n ) {\n logger.info(`RetryPolicy: Network error ${retriableError} found, will retry.`);\n return true;\n }\n }\n }\n\n // If attempt was against the secondary & it returned a StatusNotFound (404), then\n // the resource was not found. This may be due to replication delay. So, in this\n // case, we'll never try the secondary again for this operation.\n if (response || err) {\n const statusCode = response ? response.status : err ? err.statusCode : 0;\n if (!isPrimaryRetry && statusCode === 404) {\n logger.info(`RetryPolicy: Secondary access with 404, will retry.`);\n return true;\n }\n\n // Server internal error or server timeout\n if (statusCode === 503 || statusCode === 500) {\n logger.info(`RetryPolicy: Will retry for status code ${statusCode}.`);\n return true;\n }\n }\n\n if (response) {\n // Retry select Copy Source Error Codes.\n if (response?.status >= 400) {\n const copySourceError = response.headers.get(HeaderConstants.X_MS_CopySourceErrorCode);\n if (copySourceError !== undefined) {\n switch (copySourceError) {\n case \"InternalError\":\n case \"OperationTimedOut\":\n case \"ServerBusy\":\n return true;\n }\n }\n }\n }\n\n if (err?.code === \"PARSE_ERROR\" && err?.message.startsWith(`Error \"Error: Unclosed root tag`)) {\n logger.info(\n \"RetryPolicy: Incomplete XML response likely due to service timeout, will retry.\",\n );\n return true;\n }\n\n return false;\n }\n\n /**\n * Delay a calculated time between retries.\n *\n * @param isPrimaryRetry -\n * @param attempt -\n * @param abortSignal -\n */\n private async delay(\n isPrimaryRetry: boolean,\n attempt: number,\n abortSignal?: AbortSignalLike,\n ): Promise<void> {\n let delayTimeInMs: number = 0;\n\n if (isPrimaryRetry) {\n switch (this.retryOptions.retryPolicyType) {\n case StorageRetryPolicyType.EXPONENTIAL:\n delayTimeInMs = Math.min(\n (Math.pow(2, attempt - 1) - 1) * this.retryOptions.retryDelayInMs!,\n this.retryOptions.maxRetryDelayInMs!,\n );\n break;\n case StorageRetryPolicyType.FIXED:\n delayTimeInMs = this.retryOptions.retryDelayInMs!;\n break;\n }\n } else {\n delayTimeInMs = Math.random() * 1000;\n }\n\n logger.info(`RetryPolicy: Delay for ${delayTimeInMs}ms`);\n return delay(delayTimeInMs, abortSignal, RETRY_ABORT_ERROR);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"StorageRetryPolicy.js","sourceRoot":"","sources":["../../../src/policies/StorageRetryPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AbortSignalLike } from \"@azure/abort-controller\";\nimport { AbortError } from \"@azure/abort-controller\";\nimport type {\n RequestPolicy,\n RequestPolicyOptionsLike as RequestPolicyOptions,\n RequestPolicyFactory,\n WebResourceLike as WebResource,\n CompatResponse as HttpOperationResponse,\n} from \"@azure/core-http-compat\";\nimport { BaseRequestPolicy } from \"./RequestPolicy.js\";\nimport type { RestError } from \"@azure/core-rest-pipeline\";\n\nimport type { StorageRetryOptions } from \"../StorageRetryPolicyFactory.js\";\nimport { HeaderConstants, URLConstants } from \"../utils/constants.js\";\nimport { delay, setURLHost, setURLParameter } from \"../utils/utils.common.js\";\nimport { logger } from \"../log.js\";\nimport { StorageRetryPolicyType } from \"./StorageRetryPolicyType.js\";\n\n/**\n * A factory method used to generated a RetryPolicy factory.\n *\n * @param retryOptions -\n */\nexport function NewRetryPolicyFactory(retryOptions?: StorageRetryOptions): RequestPolicyFactory {\n return {\n create: (nextPolicy: RequestPolicy, options: RequestPolicyOptions): StorageRetryPolicy => {\n return new StorageRetryPolicy(nextPolicy, options, retryOptions);\n },\n };\n}\n\n// Default values of StorageRetryOptions\nconst DEFAULT_RETRY_OPTIONS: StorageRetryOptions = {\n maxRetryDelayInMs: 120 * 1000,\n maxTries: 4,\n retryDelayInMs: 4 * 1000,\n retryPolicyType: StorageRetryPolicyType.EXPONENTIAL,\n secondaryHost: \"\",\n tryTimeoutInMs: undefined, // Use server side default timeout strategy\n};\n\nconst RETRY_ABORT_ERROR = new AbortError(\"The operation was aborted.\");\n\n/**\n * Retry policy with exponential retry and linear retry implemented.\n */\nexport class StorageRetryPolicy extends BaseRequestPolicy {\n /**\n * RetryOptions.\n */\n private readonly retryOptions: StorageRetryOptions;\n\n /**\n * Creates an instance of RetryPolicy.\n *\n * @param nextPolicy -\n * @param options -\n * @param retryOptions -\n */\n constructor(\n nextPolicy: RequestPolicy,\n options: RequestPolicyOptions,\n retryOptions: StorageRetryOptions = DEFAULT_RETRY_OPTIONS,\n ) {\n super(nextPolicy, options);\n\n // Initialize retry options\n this.retryOptions = {\n retryPolicyType: retryOptions.retryPolicyType\n ? retryOptions.retryPolicyType\n : DEFAULT_RETRY_OPTIONS.retryPolicyType,\n\n maxTries:\n retryOptions.maxTries && retryOptions.maxTries >= 1\n ? Math.floor(retryOptions.maxTries)\n : DEFAULT_RETRY_OPTIONS.maxTries,\n\n tryTimeoutInMs:\n retryOptions.tryTimeoutInMs && retryOptions.tryTimeoutInMs >= 0\n ? retryOptions.tryTimeoutInMs\n : DEFAULT_RETRY_OPTIONS.tryTimeoutInMs,\n\n retryDelayInMs:\n retryOptions.retryDelayInMs && retryOptions.retryDelayInMs >= 0\n ? Math.min(\n retryOptions.retryDelayInMs,\n retryOptions.maxRetryDelayInMs\n ? retryOptions.maxRetryDelayInMs\n : DEFAULT_RETRY_OPTIONS.maxRetryDelayInMs!,\n )\n : DEFAULT_RETRY_OPTIONS.retryDelayInMs,\n\n maxRetryDelayInMs:\n retryOptions.maxRetryDelayInMs && retryOptions.maxRetryDelayInMs >= 0\n ? retryOptions.maxRetryDelayInMs\n : DEFAULT_RETRY_OPTIONS.maxRetryDelayInMs,\n\n secondaryHost: retryOptions.secondaryHost\n ? retryOptions.secondaryHost\n : DEFAULT_RETRY_OPTIONS.secondaryHost,\n };\n }\n\n /**\n * Sends request.\n *\n * @param request -\n */\n public async sendRequest(request: WebResource): Promise<HttpOperationResponse> {\n return this.attemptSendRequest(request, false, 1);\n }\n\n /**\n * Decide and perform next retry. Won't mutate request parameter.\n *\n * @param request -\n * @param secondaryHas404 - If attempt was against the secondary & it returned a StatusNotFound (404), then\n * the resource was not found. This may be due to replication delay. So, in this\n * case, we'll never try the secondary again for this operation.\n * @param attempt - How many retries has been attempted to performed, starting from 1, which includes\n * the attempt will be performed by this method call.\n */\n protected async attemptSendRequest(\n request: WebResource,\n secondaryHas404: boolean,\n attempt: number,\n ): Promise<HttpOperationResponse> {\n const newRequest: WebResource = request.clone();\n\n const isPrimaryRetry =\n secondaryHas404 ||\n !this.retryOptions.secondaryHost ||\n !(request.method === \"GET\" || request.method === \"HEAD\" || request.method === \"OPTIONS\") ||\n attempt % 2 === 1;\n\n if (!isPrimaryRetry) {\n newRequest.url = setURLHost(newRequest.url, this.retryOptions.secondaryHost!);\n }\n\n // Set the server-side timeout query parameter \"timeout=[seconds]\"\n if (this.retryOptions.tryTimeoutInMs) {\n newRequest.url = setURLParameter(\n newRequest.url,\n URLConstants.Parameters.TIMEOUT,\n Math.floor(this.retryOptions.tryTimeoutInMs! / 1000).toString(),\n );\n }\n\n let response: HttpOperationResponse | undefined;\n try {\n logger.info(`RetryPolicy: =====> Try=${attempt} ${isPrimaryRetry ? \"Primary\" : \"Secondary\"}`);\n response = await this._nextPolicy.sendRequest(newRequest);\n if (!this.shouldRetry(isPrimaryRetry, attempt, response)) {\n return response;\n }\n\n secondaryHas404 = secondaryHas404 || (!isPrimaryRetry && response.status === 404);\n } catch (err: any) {\n logger.error(`RetryPolicy: Caught error, message: ${err.message}, code: ${err.code}`);\n if (!this.shouldRetry(isPrimaryRetry, attempt, response, err)) {\n throw err;\n }\n }\n\n await this.delay(isPrimaryRetry, attempt, request.abortSignal);\n return this.attemptSendRequest(request, secondaryHas404, attempt + 1);\n }\n\n /**\n * Decide whether to retry according to last HTTP response and retry counters.\n *\n * @param isPrimaryRetry -\n * @param attempt -\n * @param response -\n * @param err -\n */\n protected shouldRetry(\n isPrimaryRetry: boolean,\n attempt: number,\n response?: HttpOperationResponse,\n err?: RestError,\n ): boolean {\n if (attempt >= this.retryOptions.maxTries!) {\n logger.info(\n `RetryPolicy: Attempt(s) ${attempt} >= maxTries ${\n this.retryOptions.maxTries!\n }, no further try.`,\n );\n return false;\n }\n\n // Handle network failures, you may need to customize the list when you implement\n // your own http client\n const retriableErrors = [\n \"ETIMEDOUT\",\n \"ESOCKETTIMEDOUT\",\n \"ECONNREFUSED\",\n \"ECONNRESET\",\n \"ENOENT\",\n \"ENOTFOUND\",\n \"TIMEOUT\",\n \"EPIPE\",\n \"REQUEST_SEND_ERROR\", // For default xhr based http client provided in ms-rest-js\n ];\n if (err) {\n for (const retriableError of retriableErrors) {\n if (\n err.name.toUpperCase().includes(retriableError) ||\n err.message.toUpperCase().includes(retriableError) ||\n (err.code && err.code.toString().toUpperCase() === retriableError)\n ) {\n logger.info(`RetryPolicy: Network error ${retriableError} found, will retry.`);\n return true;\n }\n }\n }\n\n // If attempt was against the secondary & it returned a StatusNotFound (404), then\n // the resource was not found. This may be due to replication delay. So, in this\n // case, we'll never try the secondary again for this operation.\n if (response || err) {\n const statusCode = response ? response.status : err ? err.statusCode : 0;\n if (!isPrimaryRetry && statusCode === 404) {\n logger.info(`RetryPolicy: Secondary access with 404, will retry.`);\n return true;\n }\n\n // Server internal error or server timeout\n if (statusCode === 503 || statusCode === 500) {\n logger.info(`RetryPolicy: Will retry for status code ${statusCode}.`);\n return true;\n }\n }\n\n if (response) {\n // Retry select Copy Source Error Codes.\n if (response?.status >= 400) {\n const copySourceError = response.headers.get(HeaderConstants.X_MS_CopySourceErrorCode);\n if (copySourceError !== undefined) {\n switch (copySourceError) {\n case \"InternalError\":\n case \"OperationTimedOut\":\n case \"ServerBusy\":\n return true;\n }\n }\n }\n }\n\n if (err?.code === \"PARSE_ERROR\" && err?.message.startsWith(`Error \"Error: Unclosed root tag`)) {\n logger.info(\n \"RetryPolicy: Incomplete XML response likely due to service timeout, will retry.\",\n );\n return true;\n }\n\n return false;\n }\n\n /**\n * Delay a calculated time between retries.\n *\n * @param isPrimaryRetry -\n * @param attempt -\n * @param abortSignal -\n */\n private async delay(\n isPrimaryRetry: boolean,\n attempt: number,\n abortSignal?: AbortSignalLike,\n ): Promise<void> {\n let delayTimeInMs: number = 0;\n\n if (isPrimaryRetry) {\n switch (this.retryOptions.retryPolicyType) {\n case StorageRetryPolicyType.EXPONENTIAL:\n delayTimeInMs = Math.min(\n (Math.pow(2, attempt - 1) - 1) * this.retryOptions.retryDelayInMs!,\n this.retryOptions.maxRetryDelayInMs!,\n );\n break;\n case StorageRetryPolicyType.FIXED:\n delayTimeInMs = this.retryOptions.retryDelayInMs!;\n break;\n }\n } else {\n delayTimeInMs = Math.random() * 1000;\n }\n\n logger.info(`RetryPolicy: Delay for ${delayTimeInMs}ms`);\n return delay(delayTimeInMs, abortSignal, RETRY_ABORT_ERROR);\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageRetryPolicyV2.d.ts","sourceRoot":"","sources":["../../../src/policies/StorageRetryPolicyV2.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EAIf,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAKnG;;GAEG;AACH,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"StorageRetryPolicyV2.d.ts","sourceRoot":"","sources":["../../../src/policies/StorageRetryPolicyV2.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EAIf,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAKnG;;GAEG;AACH,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAwD3D;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,cAAc,CAkKpF"}
|
|
@@ -32,6 +32,31 @@ const retriableErrors = [
|
|
|
32
32
|
"REQUEST_SEND_ERROR",
|
|
33
33
|
];
|
|
34
34
|
const RETRY_ABORT_ERROR = new AbortError("The operation was aborted.");
|
|
35
|
+
/**
|
|
36
|
+
* Releases the body of a response that is dropped for a retry. A streamed body that is never read
|
|
37
|
+
* keeps its connection busy until the server closes it. Node.js bodies are drained rather than
|
|
38
|
+
* destroyed, so the connection can be reused; error bodies are small. Errors while releasing a body
|
|
39
|
+
* are logged and don't stop the retry.
|
|
40
|
+
*
|
|
41
|
+
* The parameters name only the members used here, because each platform build types only its own
|
|
42
|
+
* body kind.
|
|
43
|
+
*/
|
|
44
|
+
async function releaseResponseBody(nodeBody, browserBody) {
|
|
45
|
+
if (nodeBody) {
|
|
46
|
+
// Nothing else reads a dropped body, and Node.js throws an "error" event that has no listener
|
|
47
|
+
// as an uncaught exception.
|
|
48
|
+
nodeBody.on("error", (e) => {
|
|
49
|
+
logger.warning(`RetryPolicy: Failed to drain the response body: ${getErrorMessage(e)}`);
|
|
50
|
+
});
|
|
51
|
+
nodeBody.resume();
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
await browserBody?.cancel();
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
logger.warning(`RetryPolicy: Failed to cancel the response body: ${getErrorMessage(e)}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
35
60
|
/**
|
|
36
61
|
* Retry policy with exponential retry and linear retry implemented.
|
|
37
62
|
*/
|
|
@@ -150,6 +175,9 @@ export function storageRetryPolicy(options = {}) {
|
|
|
150
175
|
}
|
|
151
176
|
retryAgain = shouldRetry({ isPrimaryRetry, attempt, response, error });
|
|
152
177
|
if (retryAgain) {
|
|
178
|
+
if (response) {
|
|
179
|
+
await releaseResponseBody(response.readableStreamBody, response.browserStreamBody);
|
|
180
|
+
}
|
|
153
181
|
await delay(calculateDelay(isPrimaryRetry, attempt), request.abortSignal, RETRY_ABORT_ERROR);
|
|
154
182
|
}
|
|
155
183
|
attempt++;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageRetryPolicyV2.js","sourceRoot":"","sources":["../../../src/policies/StorageRetryPolicyV2.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAOrD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAA4B,MAAM,iCAAiC,CAAC;AACnG,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE3D,wCAAwC;AACxC,MAAM,qBAAqB,GAAG;IAC5B,iBAAiB,EAAE,GAAG,GAAG,IAAI;IAC7B,QAAQ,EAAE,CAAC;IACX,cAAc,EAAE,CAAC,GAAG,IAAI;IACxB,eAAe,EAAE,sBAAsB,CAAC,WAAW;IACnD,aAAa,EAAE,EAAE;IACjB,cAAc,EAAE,SAAS,EAAE,2CAA2C;CAC9D,CAAC;AAEX,MAAM,eAAe,GAAG;IACtB,WAAW;IACX,iBAAiB;IACjB,cAAc;IACd,YAAY;IACZ,QAAQ;IACR,WAAW;IACX,SAAS;IACT,OAAO;IACP,oBAAoB;CACZ,CAAC;AAEX,MAAM,iBAAiB,GAAG,IAAI,UAAU,CAAC,4BAA4B,CAAC,CAAC;AAEvE;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAA+B,EAAE;IAClE,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,qBAAqB,CAAC,eAAe,CAAC;IACzF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,qBAAqB,CAAC,QAAQ,CAAC;IACpE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,qBAAqB,CAAC,cAAc,CAAC;IACtF,MAAM,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,IAAI,qBAAqB,CAAC,iBAAiB,CAAC;IAC/F,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,qBAAqB,CAAC,aAAa,CAAC;IACnF,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,qBAAqB,CAAC,cAAc,CAAC;IAEtF,SAAS,WAAW,CAAC,EACnB,cAAc,EACd,OAAO,EACP,QAAQ,EACR,KAAK,GAMN;QACC,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,2BAA2B,OAAO,gBAAgB,QAAQ,mBAAmB,CAAC,CAAC;YAC3F,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;gBAC7C,IACE,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;oBACjD,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;oBACpD,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,EACtE,CAAC;oBACD,MAAM,CAAC,IAAI,CAAC,8BAA8B,cAAc,qBAAqB,CAAC,CAAC;oBAC/E,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YACD,IACE,KAAK,EAAE,IAAI,KAAK,aAAa;gBAC7B,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,iCAAiC,CAAC,EAC5D,CAAC;gBACD,MAAM,CAAC,IAAI,CACT,iFAAiF,CAClF,CAAC;gBACF,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,kFAAkF;QAClF,gFAAgF;QAChF,gEAAgE;QAChE,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,UAAU,GAAG,QAAQ,EAAE,MAAM,IAAI,KAAK,EAAE,UAAU,IAAI,CAAC,CAAC;YAC9D,IAAI,CAAC,cAAc,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;gBAC1C,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;gBACnE,OAAO,IAAI,CAAC;YACd,CAAC;YAED,0CAA0C;YAC1C,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;gBAC7C,MAAM,CAAC,IAAI,CAAC,2CAA2C,UAAU,GAAG,CAAC,CAAC;gBACtE,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,wCAAwC;YACxC,IAAI,QAAQ,EAAE,MAAM,IAAI,GAAG,EAAE,CAAC;gBAC5B,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,wBAAwB,CAAC,CAAC;gBACvF,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;oBAClC,QAAQ,eAAe,EAAE,CAAC;wBACxB,KAAK,eAAe,CAAC;wBACrB,KAAK,mBAAmB,CAAC;wBACzB,KAAK,YAAY;4BACf,OAAO,IAAI,CAAC;oBAChB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IACD,SAAS,cAAc,CAAC,cAAuB,EAAE,OAAe;QAC9D,IAAI,aAAa,GAAG,CAAC,CAAC;QAEtB,IAAI,cAAc,EAAE,CAAC;YACnB,QAAQ,eAAe,EAAE,CAAC;gBACxB,KAAK,sBAAsB,CAAC,WAAW;oBACrC,aAAa,GAAG,IAAI,CAAC,GAAG,CACtB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,cAAc,EAC/C,iBAAiB,CAClB,CAAC;oBACF,MAAM;gBACR,KAAK,sBAAsB,CAAC,KAAK;oBAC/B,aAAa,GAAG,cAAc,CAAC;oBAC/B,MAAM;YACV,CAAC;QACH,CAAC;aAAM,CAAC;YACN,aAAa,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;QACvC,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,0BAA0B,aAAa,IAAI,CAAC,CAAC;QACzD,OAAO,aAAa,CAAC;IACvB,CAAC;IACD,OAAO;QACL,IAAI,EAAE,sBAAsB;QAC5B,KAAK,CAAC,WAAW,CAAC,OAAwB,EAAE,IAAiB;YAC3D,kEAAkE;YAClE,IAAI,cAAc,EAAE,CAAC;gBACnB,OAAO,CAAC,GAAG,GAAG,eAAe,CAC3B,OAAO,CAAC,GAAG,EACX,YAAY,CAAC,UAAU,CAAC,OAAO,EAC/B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC,CAC1C,CAAC;YACJ,CAAC;YACD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC;YAC/B,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACxF,IAAI,eAAe,GAAG,KAAK,CAAC;YAC5B,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAI,UAAU,GAAG,IAAI,CAAC;YACtB,IAAI,QAAsC,CAAC;YAC3C,IAAI,KAA4B,CAAC;YACjC,OAAO,UAAU,EAAE,CAAC;gBAClB,MAAM,cAAc,GAClB,eAAe;oBACf,CAAC,YAAY;oBACb,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;oBACpD,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;gBACpB,OAAO,CAAC,GAAG,GAAG,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAa,CAAC;gBAC1D,QAAQ,GAAG,SAAS,CAAC;gBACrB,KAAK,GAAG,SAAS,CAAC;gBAClB,IAAI,CAAC;oBACH,MAAM,CAAC,IAAI,CACT,2BAA2B,OAAO,IAAI,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,CACjF,CAAC;oBACF,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC/B,eAAe,GAAG,eAAe,IAAI,CAAC,CAAC,cAAc,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC;gBACpF,CAAC;gBAAC,OAAO,CAAU,EAAE,CAAC;oBACpB,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;wBACnB,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;wBAClF,KAAK,GAAG,CAAC,CAAC;oBACZ,CAAC;yBAAM,CAAC;wBACN,MAAM,CAAC,KAAK,CAAC,uCAAuC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;wBAC1E,MAAM,CAAC,CAAC;oBACV,CAAC;gBACH,CAAC;gBACD,UAAU,GAAG,WAAW,CAAC,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;gBACvE,IAAI,UAAU,EAAE,CAAC;oBACf,MAAM,KAAK,CACT,cAAc,CAAC,cAAc,EAAE,OAAO,CAAC,EACvC,OAAO,CAAC,WAAW,EACnB,iBAAiB,CAClB,CAAC;gBACJ,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,MAAM,KAAK,IAAI,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;QAC1E,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { AbortError } from \"@azure/abort-controller\";\nimport type {\n PipelinePolicy,\n PipelineRequest,\n SendRequest,\n PipelineResponse,\n} from \"@azure/core-rest-pipeline\";\nimport { isRestError, RestError } from \"@azure/core-rest-pipeline\";\nimport { getErrorMessage } from \"@azure/core-util\";\nimport { StorageRetryPolicyType, type StorageRetryOptions } from \"../StorageRetryPolicyFactory.js\";\nimport { HeaderConstants, URLConstants } from \"../utils/constants.js\";\nimport { delay, setURLHost, setURLParameter } from \"../utils/utils.common.js\";\nimport { logger } from \"../log.js\";\n\n/**\n * Name of the {@link storageRetryPolicy}\n */\nexport const storageRetryPolicyName = \"storageRetryPolicy\";\n\n// Default values of StorageRetryOptions\nconst DEFAULT_RETRY_OPTIONS = {\n maxRetryDelayInMs: 120 * 1000,\n maxTries: 4,\n retryDelayInMs: 4 * 1000,\n retryPolicyType: StorageRetryPolicyType.EXPONENTIAL,\n secondaryHost: \"\",\n tryTimeoutInMs: undefined, // Use server side default timeout strategy\n} as const;\n\nconst retriableErrors = [\n \"ETIMEDOUT\",\n \"ESOCKETTIMEDOUT\",\n \"ECONNREFUSED\",\n \"ECONNRESET\",\n \"ENOENT\",\n \"ENOTFOUND\",\n \"TIMEOUT\",\n \"EPIPE\",\n \"REQUEST_SEND_ERROR\",\n] as const;\n\nconst RETRY_ABORT_ERROR = new AbortError(\"The operation was aborted.\");\n\n/**\n * Retry policy with exponential retry and linear retry implemented.\n */\nexport function storageRetryPolicy(options: StorageRetryOptions = {}): PipelinePolicy {\n const retryPolicyType = options.retryPolicyType ?? DEFAULT_RETRY_OPTIONS.retryPolicyType;\n const maxTries = options.maxTries ?? DEFAULT_RETRY_OPTIONS.maxTries;\n const retryDelayInMs = options.retryDelayInMs ?? DEFAULT_RETRY_OPTIONS.retryDelayInMs;\n const maxRetryDelayInMs = options.maxRetryDelayInMs ?? DEFAULT_RETRY_OPTIONS.maxRetryDelayInMs;\n const secondaryHost = options.secondaryHost ?? DEFAULT_RETRY_OPTIONS.secondaryHost;\n const tryTimeoutInMs = options.tryTimeoutInMs ?? DEFAULT_RETRY_OPTIONS.tryTimeoutInMs;\n\n function shouldRetry({\n isPrimaryRetry,\n attempt,\n response,\n error,\n }: {\n isPrimaryRetry: boolean;\n attempt: number;\n response?: PipelineResponse;\n error?: RestError;\n }): boolean {\n if (attempt >= maxTries) {\n logger.info(`RetryPolicy: Attempt(s) ${attempt} >= maxTries ${maxTries}, no further try.`);\n return false;\n }\n if (error) {\n for (const retriableError of retriableErrors) {\n if (\n error.name.toUpperCase().includes(retriableError) ||\n error.message.toUpperCase().includes(retriableError) ||\n (error.code && error.code.toString().toUpperCase() === retriableError)\n ) {\n logger.info(`RetryPolicy: Network error ${retriableError} found, will retry.`);\n return true;\n }\n }\n if (\n error?.code === \"PARSE_ERROR\" &&\n error?.message.startsWith(`Error \"Error: Unclosed root tag`)\n ) {\n logger.info(\n \"RetryPolicy: Incomplete XML response likely due to service timeout, will retry.\",\n );\n return true;\n }\n }\n\n // If attempt was against the secondary & it returned a StatusNotFound (404), then\n // the resource was not found. This may be due to replication delay. So, in this\n // case, we'll never try the secondary again for this operation.\n if (response || error) {\n const statusCode = response?.status ?? error?.statusCode ?? 0;\n if (!isPrimaryRetry && statusCode === 404) {\n logger.info(`RetryPolicy: Secondary access with 404, will retry.`);\n return true;\n }\n\n // Server internal error or server timeout\n if (statusCode === 503 || statusCode === 500) {\n logger.info(`RetryPolicy: Will retry for status code ${statusCode}.`);\n return true;\n }\n }\n\n if (response) {\n // Retry select Copy Source Error Codes.\n if (response?.status >= 400) {\n const copySourceError = response.headers.get(HeaderConstants.X_MS_CopySourceErrorCode);\n if (copySourceError !== undefined) {\n switch (copySourceError) {\n case \"InternalError\":\n case \"OperationTimedOut\":\n case \"ServerBusy\":\n return true;\n }\n }\n }\n }\n\n return false;\n }\n function calculateDelay(isPrimaryRetry: boolean, attempt: number): number {\n let delayTimeInMs = 0;\n\n if (isPrimaryRetry) {\n switch (retryPolicyType) {\n case StorageRetryPolicyType.EXPONENTIAL:\n delayTimeInMs = Math.min(\n (Math.pow(2, attempt - 1) - 1) * retryDelayInMs,\n maxRetryDelayInMs,\n );\n break;\n case StorageRetryPolicyType.FIXED:\n delayTimeInMs = retryDelayInMs;\n break;\n }\n } else {\n delayTimeInMs = Math.random() * 1000;\n }\n\n logger.info(`RetryPolicy: Delay for ${delayTimeInMs}ms`);\n return delayTimeInMs;\n }\n return {\n name: storageRetryPolicyName,\n async sendRequest(request: PipelineRequest, next: SendRequest): Promise<PipelineResponse> {\n // Set the server-side timeout query parameter \"timeout=[seconds]\"\n if (tryTimeoutInMs) {\n request.url = setURLParameter(\n request.url,\n URLConstants.Parameters.TIMEOUT,\n String(Math.floor(tryTimeoutInMs / 1000)),\n );\n }\n const primaryUrl = request.url;\n const secondaryUrl = secondaryHost ? setURLHost(request.url, secondaryHost) : undefined;\n let secondaryHas404 = false;\n let attempt = 1;\n let retryAgain = true;\n let response: PipelineResponse | undefined;\n let error: RestError | undefined;\n while (retryAgain) {\n const isPrimaryRetry: boolean =\n secondaryHas404 ||\n !secondaryUrl ||\n ![\"GET\", \"HEAD\", \"OPTIONS\"].includes(request.method) ||\n attempt % 2 === 1;\n request.url = isPrimaryRetry ? primaryUrl : secondaryUrl!;\n response = undefined;\n error = undefined;\n try {\n logger.info(\n `RetryPolicy: =====> Try=${attempt} ${isPrimaryRetry ? \"Primary\" : \"Secondary\"}`,\n );\n response = await next(request);\n secondaryHas404 = secondaryHas404 || (!isPrimaryRetry && response.status === 404);\n } catch (e: unknown) {\n if (isRestError(e)) {\n logger.error(`RetryPolicy: Caught error, message: ${e.message}, code: ${e.code}`);\n error = e;\n } else {\n logger.error(`RetryPolicy: Caught error, message: ${getErrorMessage(e)}`);\n throw e;\n }\n }\n retryAgain = shouldRetry({ isPrimaryRetry, attempt, response, error });\n if (retryAgain) {\n await delay(\n calculateDelay(isPrimaryRetry, attempt),\n request.abortSignal,\n RETRY_ABORT_ERROR,\n );\n }\n attempt++;\n }\n if (response) {\n return response;\n }\n throw error ?? new RestError(\"RetryPolicy failed without known error.\");\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"StorageRetryPolicyV2.js","sourceRoot":"","sources":["../../../src/policies/StorageRetryPolicyV2.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { AbortError } from \"@azure/abort-controller\";\nimport type {\n PipelinePolicy,\n PipelineRequest,\n SendRequest,\n PipelineResponse,\n} from \"@azure/core-rest-pipeline\";\nimport { isRestError, RestError } from \"@azure/core-rest-pipeline\";\nimport { getErrorMessage } from \"@azure/core-util\";\nimport { StorageRetryPolicyType, type StorageRetryOptions } from \"../StorageRetryPolicyFactory.js\";\nimport { HeaderConstants, URLConstants } from \"../utils/constants.js\";\nimport { delay, setURLHost, setURLParameter } from \"../utils/utils.common.js\";\nimport { logger } from \"../log.js\";\n\n/**\n * Name of the {@link storageRetryPolicy}\n */\nexport const storageRetryPolicyName = \"storageRetryPolicy\";\n\n// Default values of StorageRetryOptions\nconst DEFAULT_RETRY_OPTIONS = {\n maxRetryDelayInMs: 120 * 1000,\n maxTries: 4,\n retryDelayInMs: 4 * 1000,\n retryPolicyType: StorageRetryPolicyType.EXPONENTIAL,\n secondaryHost: \"\",\n tryTimeoutInMs: undefined, // Use server side default timeout strategy\n} as const;\n\nconst retriableErrors = [\n \"ETIMEDOUT\",\n \"ESOCKETTIMEDOUT\",\n \"ECONNREFUSED\",\n \"ECONNRESET\",\n \"ENOENT\",\n \"ENOTFOUND\",\n \"TIMEOUT\",\n \"EPIPE\",\n \"REQUEST_SEND_ERROR\",\n] as const;\n\nconst RETRY_ABORT_ERROR = new AbortError(\"The operation was aborted.\");\n\n/**\n * Releases the body of a response that is dropped for a retry. A streamed body that is never read\n * keeps its connection busy until the server closes it. Node.js bodies are drained rather than\n * destroyed, so the connection can be reused; error bodies are small. Errors while releasing a body\n * are logged and don't stop the retry.\n *\n * The parameters name only the members used here, because each platform build types only its own\n * body kind.\n */\nasync function releaseResponseBody(\n nodeBody:\n | { on(event: \"error\", listener: (error: unknown) => void): unknown; resume(): unknown }\n | undefined,\n browserBody: { cancel(): Promise<void> } | undefined,\n): Promise<void> {\n if (nodeBody) {\n // Nothing else reads a dropped body, and Node.js throws an \"error\" event that has no listener\n // as an uncaught exception.\n nodeBody.on(\"error\", (e: unknown) => {\n logger.warning(`RetryPolicy: Failed to drain the response body: ${getErrorMessage(e)}`);\n });\n nodeBody.resume();\n }\n try {\n await browserBody?.cancel();\n } catch (e: unknown) {\n logger.warning(`RetryPolicy: Failed to cancel the response body: ${getErrorMessage(e)}`);\n }\n}\n\n/**\n * Retry policy with exponential retry and linear retry implemented.\n */\nexport function storageRetryPolicy(options: StorageRetryOptions = {}): PipelinePolicy {\n const retryPolicyType = options.retryPolicyType ?? DEFAULT_RETRY_OPTIONS.retryPolicyType;\n const maxTries = options.maxTries ?? DEFAULT_RETRY_OPTIONS.maxTries;\n const retryDelayInMs = options.retryDelayInMs ?? DEFAULT_RETRY_OPTIONS.retryDelayInMs;\n const maxRetryDelayInMs = options.maxRetryDelayInMs ?? DEFAULT_RETRY_OPTIONS.maxRetryDelayInMs;\n const secondaryHost = options.secondaryHost ?? DEFAULT_RETRY_OPTIONS.secondaryHost;\n const tryTimeoutInMs = options.tryTimeoutInMs ?? DEFAULT_RETRY_OPTIONS.tryTimeoutInMs;\n\n function shouldRetry({\n isPrimaryRetry,\n attempt,\n response,\n error,\n }: {\n isPrimaryRetry: boolean;\n attempt: number;\n response?: PipelineResponse;\n error?: RestError;\n }): boolean {\n if (attempt >= maxTries) {\n logger.info(`RetryPolicy: Attempt(s) ${attempt} >= maxTries ${maxTries}, no further try.`);\n return false;\n }\n if (error) {\n for (const retriableError of retriableErrors) {\n if (\n error.name.toUpperCase().includes(retriableError) ||\n error.message.toUpperCase().includes(retriableError) ||\n (error.code && error.code.toString().toUpperCase() === retriableError)\n ) {\n logger.info(`RetryPolicy: Network error ${retriableError} found, will retry.`);\n return true;\n }\n }\n if (\n error?.code === \"PARSE_ERROR\" &&\n error?.message.startsWith(`Error \"Error: Unclosed root tag`)\n ) {\n logger.info(\n \"RetryPolicy: Incomplete XML response likely due to service timeout, will retry.\",\n );\n return true;\n }\n }\n\n // If attempt was against the secondary & it returned a StatusNotFound (404), then\n // the resource was not found. This may be due to replication delay. So, in this\n // case, we'll never try the secondary again for this operation.\n if (response || error) {\n const statusCode = response?.status ?? error?.statusCode ?? 0;\n if (!isPrimaryRetry && statusCode === 404) {\n logger.info(`RetryPolicy: Secondary access with 404, will retry.`);\n return true;\n }\n\n // Server internal error or server timeout\n if (statusCode === 503 || statusCode === 500) {\n logger.info(`RetryPolicy: Will retry for status code ${statusCode}.`);\n return true;\n }\n }\n\n if (response) {\n // Retry select Copy Source Error Codes.\n if (response?.status >= 400) {\n const copySourceError = response.headers.get(HeaderConstants.X_MS_CopySourceErrorCode);\n if (copySourceError !== undefined) {\n switch (copySourceError) {\n case \"InternalError\":\n case \"OperationTimedOut\":\n case \"ServerBusy\":\n return true;\n }\n }\n }\n }\n\n return false;\n }\n function calculateDelay(isPrimaryRetry: boolean, attempt: number): number {\n let delayTimeInMs = 0;\n\n if (isPrimaryRetry) {\n switch (retryPolicyType) {\n case StorageRetryPolicyType.EXPONENTIAL:\n delayTimeInMs = Math.min(\n (Math.pow(2, attempt - 1) - 1) * retryDelayInMs,\n maxRetryDelayInMs,\n );\n break;\n case StorageRetryPolicyType.FIXED:\n delayTimeInMs = retryDelayInMs;\n break;\n }\n } else {\n delayTimeInMs = Math.random() * 1000;\n }\n\n logger.info(`RetryPolicy: Delay for ${delayTimeInMs}ms`);\n return delayTimeInMs;\n }\n return {\n name: storageRetryPolicyName,\n async sendRequest(request: PipelineRequest, next: SendRequest): Promise<PipelineResponse> {\n // Set the server-side timeout query parameter \"timeout=[seconds]\"\n if (tryTimeoutInMs) {\n request.url = setURLParameter(\n request.url,\n URLConstants.Parameters.TIMEOUT,\n String(Math.floor(tryTimeoutInMs / 1000)),\n );\n }\n const primaryUrl = request.url;\n const secondaryUrl = secondaryHost ? setURLHost(request.url, secondaryHost) : undefined;\n let secondaryHas404 = false;\n let attempt = 1;\n let retryAgain = true;\n let response: PipelineResponse | undefined;\n let error: RestError | undefined;\n while (retryAgain) {\n const isPrimaryRetry: boolean =\n secondaryHas404 ||\n !secondaryUrl ||\n ![\"GET\", \"HEAD\", \"OPTIONS\"].includes(request.method) ||\n attempt % 2 === 1;\n request.url = isPrimaryRetry ? primaryUrl : secondaryUrl!;\n response = undefined;\n error = undefined;\n try {\n logger.info(\n `RetryPolicy: =====> Try=${attempt} ${isPrimaryRetry ? \"Primary\" : \"Secondary\"}`,\n );\n response = await next(request);\n secondaryHas404 = secondaryHas404 || (!isPrimaryRetry && response.status === 404);\n } catch (e: unknown) {\n if (isRestError(e)) {\n logger.error(`RetryPolicy: Caught error, message: ${e.message}, code: ${e.code}`);\n error = e;\n } else {\n logger.error(`RetryPolicy: Caught error, message: ${getErrorMessage(e)}`);\n throw e;\n }\n }\n retryAgain = shouldRetry({ isPrimaryRetry, attempt, response, error });\n if (retryAgain) {\n if (response) {\n await releaseResponseBody(response.readableStreamBody, response.browserStreamBody);\n }\n await delay(\n calculateDelay(isPrimaryRetry, attempt),\n request.abortSignal,\n RETRY_ABORT_ERROR,\n );\n }\n attempt++;\n }\n if (response) {\n return response;\n }\n throw error ?? new RestError(\"RetryPolicy failed without known error.\");\n },\n };\n}\n"]}
|
|
@@ -22,33 +22,5 @@ export declare class StorageSharedKeyCredentialPolicy extends CredentialPolicy {
|
|
|
22
22
|
* @param request -
|
|
23
23
|
*/
|
|
24
24
|
protected signRequest(request: WebResource): WebResource;
|
|
25
|
-
/**
|
|
26
|
-
* Retrieve header value according to shared key sign rules.
|
|
27
|
-
* @see https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key
|
|
28
|
-
*
|
|
29
|
-
* @param request -
|
|
30
|
-
* @param headerName -
|
|
31
|
-
*/
|
|
32
|
-
private getHeaderValueToSign;
|
|
33
|
-
/**
|
|
34
|
-
* To construct the CanonicalizedHeaders portion of the signature string, follow these steps:
|
|
35
|
-
* 1. Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header.
|
|
36
|
-
* 2. Convert each HTTP header name to lowercase.
|
|
37
|
-
* 3. Sort the headers lexicographically by header name, in ascending order.
|
|
38
|
-
* Each header may appear only once in the string.
|
|
39
|
-
* 4. Replace any linear whitespace in the header value with a single space.
|
|
40
|
-
* 5. Trim any whitespace around the colon in the header.
|
|
41
|
-
* 6. Finally, append a new-line character to each canonicalized header in the resulting list.
|
|
42
|
-
* Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string.
|
|
43
|
-
*
|
|
44
|
-
* @param request -
|
|
45
|
-
*/
|
|
46
|
-
private getCanonicalizedHeadersString;
|
|
47
|
-
/**
|
|
48
|
-
* Retrieves the webResource canonicalized resource string.
|
|
49
|
-
*
|
|
50
|
-
* @param request -
|
|
51
|
-
*/
|
|
52
|
-
private getCanonicalizedResourceString;
|
|
53
25
|
}
|
|
54
26
|
//# sourceMappingURL=StorageSharedKeyCredentialPolicy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageSharedKeyCredentialPolicy.d.ts","sourceRoot":"","sources":["../../../src/policies/StorageSharedKeyCredentialPolicy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,aAAa,EACb,wBAAwB,IAAI,oBAAoB,EAChD,eAAe,IAAI,WAAW,EAC/B,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"StorageSharedKeyCredentialPolicy.d.ts","sourceRoot":"","sources":["../../../src/policies/StorageSharedKeyCredentialPolicy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,aAAa,EACb,wBAAwB,IAAI,oBAAoB,EAChD,eAAe,IAAI,WAAW,EAC/B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kDAAkD,CAAC;AAEnG,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD;;GAEG;AACH,qBAAa,gCAAiC,SAAQ,gBAAgB;IACpE;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IAErD;;;;;OAKG;gBAED,UAAU,EAAE,aAAa,EACzB,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,0BAA0B;IAMrC;;;;OAIG;IACH,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW;CA8BzD"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
|
+
import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
|
|
3
4
|
import { HeaderConstants } from "../utils/constants.js";
|
|
4
|
-
import { getURLPath, getURLQueries } from "../utils/utils.common.js";
|
|
5
5
|
import { CredentialPolicy } from "./CredentialPolicy.js";
|
|
6
|
-
import {
|
|
6
|
+
import { buildStringToSign } from "./SharedKeySigning.js";
|
|
7
7
|
/**
|
|
8
8
|
* StorageSharedKeyCredentialPolicy is a policy used to sign HTTP request with a shared key.
|
|
9
9
|
*/
|
|
@@ -34,112 +34,16 @@ export class StorageSharedKeyCredentialPolicy extends CredentialPolicy {
|
|
|
34
34
|
request.body.length > 0) {
|
|
35
35
|
request.headers.set(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(request.body));
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
this.getHeaderValueToSign(request, HeaderConstants.DATE),
|
|
45
|
-
this.getHeaderValueToSign(request, HeaderConstants.IF_MODIFIED_SINCE),
|
|
46
|
-
this.getHeaderValueToSign(request, HeaderConstants.IF_MATCH),
|
|
47
|
-
this.getHeaderValueToSign(request, HeaderConstants.IF_NONE_MATCH),
|
|
48
|
-
this.getHeaderValueToSign(request, HeaderConstants.IF_UNMODIFIED_SINCE),
|
|
49
|
-
this.getHeaderValueToSign(request, HeaderConstants.RANGE),
|
|
50
|
-
].join("\n") +
|
|
51
|
-
"\n" +
|
|
52
|
-
this.getCanonicalizedHeadersString(request) +
|
|
53
|
-
this.getCanonicalizedResourceString(request);
|
|
37
|
+
// Shares the core-v2 signer so both credential paths canonicalize identically. The headers
|
|
38
|
+
// are already set above, on the request that is sent, so the copy is only read.
|
|
39
|
+
const stringToSign = buildStringToSign(createPipelineRequest({
|
|
40
|
+
url: request.url,
|
|
41
|
+
method: request.method,
|
|
42
|
+
headers: createHttpHeaders(request.headers.toJson({ preserveCase: true })),
|
|
43
|
+
}), this.factory.accountName);
|
|
54
44
|
const signature = this.factory.computeHMACSHA256(stringToSign);
|
|
55
45
|
request.headers.set(HeaderConstants.AUTHORIZATION, `SharedKey ${this.factory.accountName}:${signature}`);
|
|
56
|
-
// console.log(`[URL]:${request.url}`);
|
|
57
|
-
// console.log(`[HEADERS]:${request.headers.toString()}`);
|
|
58
|
-
// console.log(`[STRING TO SIGN]:${JSON.stringify(stringToSign)}`);
|
|
59
|
-
// console.log(`[KEY]: ${request.headers.get(HeaderConstants.AUTHORIZATION)}`);
|
|
60
46
|
return request;
|
|
61
47
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Retrieve header value according to shared key sign rules.
|
|
64
|
-
* @see https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key
|
|
65
|
-
*
|
|
66
|
-
* @param request -
|
|
67
|
-
* @param headerName -
|
|
68
|
-
*/
|
|
69
|
-
getHeaderValueToSign(request, headerName) {
|
|
70
|
-
const value = request.headers.get(headerName);
|
|
71
|
-
if (!value) {
|
|
72
|
-
return "";
|
|
73
|
-
}
|
|
74
|
-
// When using version 2015-02-21 or later, if Content-Length is zero, then
|
|
75
|
-
// set the Content-Length part of the StringToSign to an empty string.
|
|
76
|
-
// https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key
|
|
77
|
-
if (headerName === HeaderConstants.CONTENT_LENGTH && value === "0") {
|
|
78
|
-
return "";
|
|
79
|
-
}
|
|
80
|
-
return value;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* To construct the CanonicalizedHeaders portion of the signature string, follow these steps:
|
|
84
|
-
* 1. Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header.
|
|
85
|
-
* 2. Convert each HTTP header name to lowercase.
|
|
86
|
-
* 3. Sort the headers lexicographically by header name, in ascending order.
|
|
87
|
-
* Each header may appear only once in the string.
|
|
88
|
-
* 4. Replace any linear whitespace in the header value with a single space.
|
|
89
|
-
* 5. Trim any whitespace around the colon in the header.
|
|
90
|
-
* 6. Finally, append a new-line character to each canonicalized header in the resulting list.
|
|
91
|
-
* Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string.
|
|
92
|
-
*
|
|
93
|
-
* @param request -
|
|
94
|
-
*/
|
|
95
|
-
getCanonicalizedHeadersString(request) {
|
|
96
|
-
let headersArray = request.headers.headersArray().filter((value) => {
|
|
97
|
-
return value.name.toLowerCase().startsWith(HeaderConstants.PREFIX_FOR_STORAGE);
|
|
98
|
-
});
|
|
99
|
-
headersArray.sort((a, b) => {
|
|
100
|
-
return compareHeader(a.name.toLowerCase(), b.name.toLowerCase());
|
|
101
|
-
});
|
|
102
|
-
// Remove duplicate headers
|
|
103
|
-
headersArray = headersArray.filter((value, index, array) => {
|
|
104
|
-
if (index > 0 && value.name.toLowerCase() === array[index - 1].name.toLowerCase()) {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
return true;
|
|
108
|
-
});
|
|
109
|
-
let canonicalizedHeadersStringToSign = "";
|
|
110
|
-
headersArray.forEach((header) => {
|
|
111
|
-
canonicalizedHeadersStringToSign += `${header.name
|
|
112
|
-
.toLowerCase()
|
|
113
|
-
.trimRight()}:${header.value.trimLeft()}\n`;
|
|
114
|
-
});
|
|
115
|
-
return canonicalizedHeadersStringToSign;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Retrieves the webResource canonicalized resource string.
|
|
119
|
-
*
|
|
120
|
-
* @param request -
|
|
121
|
-
*/
|
|
122
|
-
getCanonicalizedResourceString(request) {
|
|
123
|
-
const path = getURLPath(request.url) || "/";
|
|
124
|
-
let canonicalizedResourceString = "";
|
|
125
|
-
canonicalizedResourceString += `/${this.factory.accountName}${path}`;
|
|
126
|
-
const queries = getURLQueries(request.url);
|
|
127
|
-
const lowercaseQueries = {};
|
|
128
|
-
if (queries) {
|
|
129
|
-
const queryKeys = [];
|
|
130
|
-
for (const key in queries) {
|
|
131
|
-
if (Object.prototype.hasOwnProperty.call(queries, key)) {
|
|
132
|
-
const lowercaseKey = key.toLowerCase();
|
|
133
|
-
lowercaseQueries[lowercaseKey] = queries[key];
|
|
134
|
-
queryKeys.push(lowercaseKey);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
queryKeys.sort();
|
|
138
|
-
for (const key of queryKeys) {
|
|
139
|
-
canonicalizedResourceString += `\n${key}:${decodeURIComponent(lowercaseQueries[key])}`;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return canonicalizedResourceString;
|
|
143
|
-
}
|
|
144
48
|
}
|
|
145
49
|
//# sourceMappingURL=StorageSharedKeyCredentialPolicy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageSharedKeyCredentialPolicy.js","sourceRoot":"","sources":["../../../src/policies/StorageSharedKeyCredentialPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type {\n RequestPolicy,\n RequestPolicyOptionsLike as RequestPolicyOptions,\n WebResourceLike as WebResource,\n} from \"@azure/core-http-compat\";\nimport type { StorageSharedKeyCredential } from \"#platform/credentials/StorageSharedKeyCredential\";\nimport { HeaderConstants } from \"../utils/constants.js\";\nimport { getURLPath, getURLQueries } from \"../utils/utils.common.js\";\nimport { CredentialPolicy } from \"./CredentialPolicy.js\";\nimport { compareHeader } from \"../utils/SharedKeyComparator.js\";\n\n/**\n * StorageSharedKeyCredentialPolicy is a policy used to sign HTTP request with a shared key.\n */\nexport class StorageSharedKeyCredentialPolicy extends CredentialPolicy {\n /**\n * Reference to StorageSharedKeyCredential which generates StorageSharedKeyCredentialPolicy\n */\n private readonly factory: StorageSharedKeyCredential;\n\n /**\n * Creates an instance of StorageSharedKeyCredentialPolicy.\n * @param nextPolicy -\n * @param options -\n * @param factory -\n */\n constructor(\n nextPolicy: RequestPolicy,\n options: RequestPolicyOptions,\n factory: StorageSharedKeyCredential,\n ) {\n super(nextPolicy, options);\n this.factory = factory;\n }\n\n /**\n * Signs request.\n *\n * @param request -\n */\n protected signRequest(request: WebResource): WebResource {\n request.headers.set(HeaderConstants.X_MS_DATE, new Date().toUTCString());\n\n if (\n request.body &&\n (typeof request.body === \"string\" || (request.body as Buffer) !== undefined) &&\n request.body.length > 0\n ) {\n request.headers.set(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(request.body));\n }\n\n const stringToSign: string =\n [\n request.method.toUpperCase(),\n this.getHeaderValueToSign(request, HeaderConstants.CONTENT_LANGUAGE),\n this.getHeaderValueToSign(request, HeaderConstants.CONTENT_ENCODING),\n this.getHeaderValueToSign(request, HeaderConstants.CONTENT_LENGTH),\n this.getHeaderValueToSign(request, HeaderConstants.CONTENT_MD5),\n this.getHeaderValueToSign(request, HeaderConstants.CONTENT_TYPE),\n this.getHeaderValueToSign(request, HeaderConstants.DATE),\n this.getHeaderValueToSign(request, HeaderConstants.IF_MODIFIED_SINCE),\n this.getHeaderValueToSign(request, HeaderConstants.IF_MATCH),\n this.getHeaderValueToSign(request, HeaderConstants.IF_NONE_MATCH),\n this.getHeaderValueToSign(request, HeaderConstants.IF_UNMODIFIED_SINCE),\n this.getHeaderValueToSign(request, HeaderConstants.RANGE),\n ].join(\"\\n\") +\n \"\\n\" +\n this.getCanonicalizedHeadersString(request) +\n this.getCanonicalizedResourceString(request);\n\n const signature: string = this.factory.computeHMACSHA256(stringToSign);\n request.headers.set(\n HeaderConstants.AUTHORIZATION,\n `SharedKey ${this.factory.accountName}:${signature}`,\n );\n\n // console.log(`[URL]:${request.url}`);\n // console.log(`[HEADERS]:${request.headers.toString()}`);\n // console.log(`[STRING TO SIGN]:${JSON.stringify(stringToSign)}`);\n // console.log(`[KEY]: ${request.headers.get(HeaderConstants.AUTHORIZATION)}`);\n return request;\n }\n\n /**\n * Retrieve header value according to shared key sign rules.\n * @see https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key\n *\n * @param request -\n * @param headerName -\n */\n private getHeaderValueToSign(request: WebResource, headerName: string): string {\n const value = request.headers.get(headerName);\n\n if (!value) {\n return \"\";\n }\n\n // When using version 2015-02-21 or later, if Content-Length is zero, then\n // set the Content-Length part of the StringToSign to an empty string.\n // https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key\n if (headerName === HeaderConstants.CONTENT_LENGTH && value === \"0\") {\n return \"\";\n }\n\n return value;\n }\n\n /**\n * To construct the CanonicalizedHeaders portion of the signature string, follow these steps:\n * 1. Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header.\n * 2. Convert each HTTP header name to lowercase.\n * 3. Sort the headers lexicographically by header name, in ascending order.\n * Each header may appear only once in the string.\n * 4. Replace any linear whitespace in the header value with a single space.\n * 5. Trim any whitespace around the colon in the header.\n * 6. Finally, append a new-line character to each canonicalized header in the resulting list.\n * Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string.\n *\n * @param request -\n */\n private getCanonicalizedHeadersString(request: WebResource): string {\n let headersArray = request.headers.headersArray().filter((value) => {\n return value.name.toLowerCase().startsWith(HeaderConstants.PREFIX_FOR_STORAGE);\n });\n\n headersArray.sort((a, b): number => {\n return compareHeader(a.name.toLowerCase(), b.name.toLowerCase());\n });\n\n // Remove duplicate headers\n headersArray = headersArray.filter((value, index, array) => {\n if (index > 0 && value.name.toLowerCase() === array[index - 1].name.toLowerCase()) {\n return false;\n }\n return true;\n });\n\n let canonicalizedHeadersStringToSign: string = \"\";\n headersArray.forEach((header) => {\n canonicalizedHeadersStringToSign += `${header.name\n .toLowerCase()\n .trimRight()}:${header.value.trimLeft()}\\n`;\n });\n\n return canonicalizedHeadersStringToSign;\n }\n\n /**\n * Retrieves the webResource canonicalized resource string.\n *\n * @param request -\n */\n private getCanonicalizedResourceString(request: WebResource): string {\n const path = getURLPath(request.url) || \"/\";\n\n let canonicalizedResourceString: string = \"\";\n canonicalizedResourceString += `/${this.factory.accountName}${path}`;\n\n const queries = getURLQueries(request.url);\n const lowercaseQueries: { [key: string]: string } = {};\n if (queries) {\n const queryKeys: string[] = [];\n for (const key in queries) {\n if (Object.prototype.hasOwnProperty.call(queries, key)) {\n const lowercaseKey = key.toLowerCase();\n lowercaseQueries[lowercaseKey] = queries[key];\n queryKeys.push(lowercaseKey);\n }\n }\n\n queryKeys.sort();\n for (const key of queryKeys) {\n canonicalizedResourceString += `\\n${key}:${decodeURIComponent(lowercaseQueries[key])}`;\n }\n }\n\n return canonicalizedResourceString;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"StorageSharedKeyCredentialPolicy.js","sourceRoot":"","sources":["../../../src/policies/StorageSharedKeyCredentialPolicy.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAOlC,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAErF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;GAEG;AACH,MAAM,OAAO,gCAAiC,SAAQ,gBAAgB;IACpE;;OAEG;IACc,OAAO,CAA6B;IAErD;;;;;OAKG;IACH,YACE,UAAyB,EACzB,OAA6B,EAC7B,OAAmC;QAEnC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACO,WAAW,CAAC,OAAoB;QACxC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QAEzE,IACE,OAAO,CAAC,IAAI;YACZ,CAAC,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAK,OAAO,CAAC,IAAe,KAAK,SAAS,CAAC;YAC5E,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EACvB,CAAC;YACD,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,cAAc,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACvF,CAAC;QAED,2FAA2F;QAC3F,gFAAgF;QAChF,MAAM,YAAY,GAAW,iBAAiB,CAC5C,qBAAqB,CAAC;YACpB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;SAC3E,CAAC,EACF,IAAI,CAAC,OAAO,CAAC,WAAW,CACzB,CAAC;QAEF,MAAM,SAAS,GAAW,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;QACvE,OAAO,CAAC,OAAO,CAAC,GAAG,CACjB,eAAe,CAAC,aAAa,EAC7B,aAAa,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,SAAS,EAAE,CACrD,CAAC;QAEF,OAAO,OAAO,CAAC;IACjB,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type {\n RequestPolicy,\n RequestPolicyOptionsLike as RequestPolicyOptions,\n WebResourceLike as WebResource,\n} from \"@azure/core-http-compat\";\nimport { createHttpHeaders, createPipelineRequest } from \"@azure/core-rest-pipeline\";\nimport type { StorageSharedKeyCredential } from \"#platform/credentials/StorageSharedKeyCredential\";\nimport { HeaderConstants } from \"../utils/constants.js\";\nimport { CredentialPolicy } from \"./CredentialPolicy.js\";\nimport { buildStringToSign } from \"./SharedKeySigning.js\";\n\n/**\n * StorageSharedKeyCredentialPolicy is a policy used to sign HTTP request with a shared key.\n */\nexport class StorageSharedKeyCredentialPolicy extends CredentialPolicy {\n /**\n * Reference to StorageSharedKeyCredential which generates StorageSharedKeyCredentialPolicy\n */\n private readonly factory: StorageSharedKeyCredential;\n\n /**\n * Creates an instance of StorageSharedKeyCredentialPolicy.\n * @param nextPolicy -\n * @param options -\n * @param factory -\n */\n constructor(\n nextPolicy: RequestPolicy,\n options: RequestPolicyOptions,\n factory: StorageSharedKeyCredential,\n ) {\n super(nextPolicy, options);\n this.factory = factory;\n }\n\n /**\n * Signs request.\n *\n * @param request -\n */\n protected signRequest(request: WebResource): WebResource {\n request.headers.set(HeaderConstants.X_MS_DATE, new Date().toUTCString());\n\n if (\n request.body &&\n (typeof request.body === \"string\" || (request.body as Buffer) !== undefined) &&\n request.body.length > 0\n ) {\n request.headers.set(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(request.body));\n }\n\n // Shares the core-v2 signer so both credential paths canonicalize identically. The headers\n // are already set above, on the request that is sent, so the copy is only read.\n const stringToSign: string = buildStringToSign(\n createPipelineRequest({\n url: request.url,\n method: request.method,\n headers: createHttpHeaders(request.headers.toJson({ preserveCase: true })),\n }),\n this.factory.accountName,\n );\n\n const signature: string = this.factory.computeHMACSHA256(stringToSign);\n request.headers.set(\n HeaderConstants.AUTHORIZATION,\n `SharedKey ${this.factory.accountName}:${signature}`,\n );\n\n return request;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageSharedKeyCredentialPolicyV2.d.ts","sourceRoot":"","sources":["../../../src/policies/StorageSharedKeyCredentialPolicyV2.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAIV,cAAc,EACf,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"StorageSharedKeyCredentialPolicyV2.d.ts","sourceRoot":"","sources":["../../../src/policies/StorageSharedKeyCredentialPolicyV2.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAIV,cAAc,EACf,MAAM,2BAA2B,CAAC;AAInC;;GAEG;AACH,eAAO,MAAM,oCAAoC,qCAAqC,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,uCAAuC;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,uCAAuC,GAC/C,cAAc,CAyBhB"}
|