firebase-admin 12.2.0 → 12.3.0
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/lib/app/core.d.ts +1 -1
- package/lib/app/core.js +1 -1
- package/lib/app/credential-factory.d.ts +1 -1
- package/lib/app/credential-factory.js +1 -1
- package/lib/app/credential-internal.d.ts +1 -1
- package/lib/app/credential-internal.js +4 -4
- package/lib/app/credential.d.ts +1 -1
- package/lib/app/credential.js +1 -1
- package/lib/app/firebase-app.d.ts +1 -1
- package/lib/app/firebase-app.js +1 -1
- package/lib/app/firebase-namespace.d.ts +1 -1
- package/lib/app/firebase-namespace.js +1 -1
- package/lib/app/index.d.ts +1 -1
- package/lib/app/index.js +1 -1
- package/lib/app/lifecycle.d.ts +1 -1
- package/lib/app/lifecycle.js +1 -1
- package/lib/app-check/app-check-api-client-internal.d.ts +1 -1
- package/lib/app-check/app-check-api-client-internal.js +1 -1
- package/lib/app-check/app-check-api.d.ts +1 -1
- package/lib/app-check/app-check-api.js +1 -1
- package/lib/app-check/app-check-namespace.d.ts +1 -1
- package/lib/app-check/app-check-namespace.js +1 -1
- package/lib/app-check/app-check.d.ts +1 -1
- package/lib/app-check/app-check.js +1 -1
- package/lib/app-check/index.d.ts +1 -1
- package/lib/app-check/index.js +1 -1
- package/lib/app-check/token-generator.d.ts +1 -1
- package/lib/app-check/token-generator.js +1 -1
- package/lib/app-check/token-verifier.d.ts +1 -1
- package/lib/app-check/token-verifier.js +1 -1
- package/lib/auth/action-code-settings-builder.d.ts +1 -1
- package/lib/auth/action-code-settings-builder.js +1 -1
- package/lib/auth/auth-api-request.d.ts +1 -1
- package/lib/auth/auth-api-request.js +2 -2
- package/lib/auth/auth-config.d.ts +1 -1
- package/lib/auth/auth-config.js +1 -1
- package/lib/auth/auth-namespace.d.ts +1 -1
- package/lib/auth/auth-namespace.js +1 -1
- package/lib/auth/auth.d.ts +1 -1
- package/lib/auth/auth.js +1 -1
- package/lib/auth/base-auth.d.ts +1 -1
- package/lib/auth/base-auth.js +1 -1
- package/lib/auth/identifier.d.ts +1 -1
- package/lib/auth/identifier.js +1 -1
- package/lib/auth/index.d.ts +1 -1
- package/lib/auth/index.js +1 -1
- package/lib/auth/project-config-manager.d.ts +1 -1
- package/lib/auth/project-config-manager.js +1 -1
- package/lib/auth/project-config.d.ts +1 -1
- package/lib/auth/project-config.js +1 -1
- package/lib/auth/tenant-manager.d.ts +1 -1
- package/lib/auth/tenant-manager.js +1 -1
- package/lib/auth/tenant.d.ts +1 -1
- package/lib/auth/tenant.js +1 -1
- package/lib/auth/token-generator.d.ts +1 -1
- package/lib/auth/token-generator.js +1 -1
- package/lib/auth/token-verifier.d.ts +1 -1
- package/lib/auth/token-verifier.js +1 -1
- package/lib/auth/user-import-builder.d.ts +1 -1
- package/lib/auth/user-import-builder.js +1 -1
- package/lib/auth/user-record.d.ts +1 -1
- package/lib/auth/user-record.js +1 -1
- package/lib/credential/index.d.ts +1 -1
- package/lib/credential/index.js +1 -1
- package/lib/database/database-namespace.d.ts +1 -1
- package/lib/database/database-namespace.js +1 -1
- package/lib/database/database.d.ts +1 -1
- package/lib/database/database.js +2 -2
- package/lib/database/index.d.ts +1 -1
- package/lib/database/index.js +1 -1
- package/lib/default-namespace.d.ts +1 -1
- package/lib/default-namespace.js +1 -1
- package/lib/eventarc/cloudevent.d.ts +1 -1
- package/lib/eventarc/cloudevent.js +1 -1
- package/lib/eventarc/eventarc-client-internal.d.ts +1 -1
- package/lib/eventarc/eventarc-client-internal.js +1 -1
- package/lib/eventarc/eventarc-utils.d.ts +1 -1
- package/lib/eventarc/eventarc-utils.js +1 -1
- package/lib/eventarc/eventarc.d.ts +1 -1
- package/lib/eventarc/eventarc.js +1 -1
- package/lib/eventarc/index.d.ts +1 -1
- package/lib/eventarc/index.js +1 -1
- package/lib/extensions/extensions-api-client-internal.d.ts +1 -1
- package/lib/extensions/extensions-api-client-internal.js +1 -1
- package/lib/extensions/extensions-api.d.ts +1 -1
- package/lib/extensions/extensions-api.js +1 -1
- package/lib/extensions/extensions.d.ts +1 -1
- package/lib/extensions/extensions.js +1 -1
- package/lib/extensions/index.d.ts +1 -1
- package/lib/extensions/index.js +1 -1
- package/lib/firebase-namespace-api.d.ts +1 -1
- package/lib/firebase-namespace-api.js +1 -1
- package/lib/firestore/firestore-internal.d.ts +1 -1
- package/lib/firestore/firestore-internal.js +1 -1
- package/lib/firestore/firestore-namespace.d.ts +1 -1
- package/lib/firestore/firestore-namespace.js +1 -1
- package/lib/firestore/index.d.ts +1 -1
- package/lib/firestore/index.js +1 -1
- package/lib/functions/functions-api-client-internal.d.ts +1 -1
- package/lib/functions/functions-api-client-internal.js +3 -3
- package/lib/functions/functions-api.d.ts +1 -1
- package/lib/functions/functions-api.js +1 -1
- package/lib/functions/functions.d.ts +1 -1
- package/lib/functions/functions.js +1 -1
- package/lib/functions/index.d.ts +1 -1
- package/lib/functions/index.js +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/installations/index.d.ts +1 -1
- package/lib/installations/index.js +1 -1
- package/lib/installations/installations-namespace.d.ts +1 -1
- package/lib/installations/installations-namespace.js +1 -1
- package/lib/installations/installations-request-handler.d.ts +1 -1
- package/lib/installations/installations-request-handler.js +2 -2
- package/lib/installations/installations.d.ts +1 -1
- package/lib/installations/installations.js +1 -1
- package/lib/instance-id/index.d.ts +1 -1
- package/lib/instance-id/index.js +1 -1
- package/lib/instance-id/instance-id-namespace.d.ts +1 -1
- package/lib/instance-id/instance-id-namespace.js +1 -1
- package/lib/instance-id/instance-id.d.ts +1 -1
- package/lib/instance-id/instance-id.js +1 -1
- package/lib/machine-learning/index.d.ts +1 -1
- package/lib/machine-learning/index.js +1 -1
- package/lib/machine-learning/machine-learning-api-client.d.ts +1 -1
- package/lib/machine-learning/machine-learning-api-client.js +1 -1
- package/lib/machine-learning/machine-learning-namespace.d.ts +1 -1
- package/lib/machine-learning/machine-learning-namespace.js +1 -1
- package/lib/machine-learning/machine-learning-utils.d.ts +1 -1
- package/lib/machine-learning/machine-learning-utils.js +1 -1
- package/lib/machine-learning/machine-learning.d.ts +1 -1
- package/lib/machine-learning/machine-learning.js +1 -1
- package/lib/messaging/batch-request-internal.d.ts +4 -4
- package/lib/messaging/batch-request-internal.js +2 -2
- package/lib/messaging/index.d.ts +1 -1
- package/lib/messaging/index.js +1 -1
- package/lib/messaging/messaging-api-request-internal.d.ts +15 -4
- package/lib/messaging/messaging-api-request-internal.js +39 -10
- package/lib/messaging/messaging-api.d.ts +1 -1
- package/lib/messaging/messaging-api.js +1 -1
- package/lib/messaging/messaging-errors-internal.d.ts +6 -6
- package/lib/messaging/messaging-errors-internal.js +4 -4
- package/lib/messaging/messaging-internal.d.ts +1 -1
- package/lib/messaging/messaging-internal.js +1 -1
- package/lib/messaging/messaging-namespace.d.ts +1 -1
- package/lib/messaging/messaging-namespace.js +1 -1
- package/lib/messaging/messaging.d.ts +16 -1
- package/lib/messaging/messaging.js +37 -9
- package/lib/project-management/android-app.d.ts +1 -1
- package/lib/project-management/android-app.js +1 -1
- package/lib/project-management/app-metadata.d.ts +1 -1
- package/lib/project-management/app-metadata.js +1 -1
- package/lib/project-management/index.d.ts +1 -1
- package/lib/project-management/index.js +1 -1
- package/lib/project-management/ios-app.d.ts +1 -1
- package/lib/project-management/ios-app.js +1 -1
- package/lib/project-management/project-management-api-request-internal.d.ts +1 -1
- package/lib/project-management/project-management-api-request-internal.js +3 -3
- package/lib/project-management/project-management-namespace.d.ts +1 -1
- package/lib/project-management/project-management-namespace.js +1 -1
- package/lib/project-management/project-management.d.ts +1 -1
- package/lib/project-management/project-management.js +1 -1
- package/lib/remote-config/condition-evaluator-internal.d.ts +1 -1
- package/lib/remote-config/condition-evaluator-internal.js +20 -14
- package/lib/remote-config/index.d.ts +1 -1
- package/lib/remote-config/index.js +1 -1
- package/lib/remote-config/internal/value-impl.d.ts +1 -1
- package/lib/remote-config/internal/value-impl.js +1 -1
- package/lib/remote-config/remote-config-api-client-internal.d.ts +1 -1
- package/lib/remote-config/remote-config-api-client-internal.js +1 -1
- package/lib/remote-config/remote-config-api.d.ts +1 -1
- package/lib/remote-config/remote-config-api.js +1 -1
- package/lib/remote-config/remote-config-namespace.d.ts +1 -1
- package/lib/remote-config/remote-config-namespace.js +1 -1
- package/lib/remote-config/remote-config.d.ts +1 -1
- package/lib/remote-config/remote-config.js +1 -1
- package/lib/security-rules/index.d.ts +1 -1
- package/lib/security-rules/index.js +1 -1
- package/lib/security-rules/security-rules-api-client-internal.d.ts +1 -1
- package/lib/security-rules/security-rules-api-client-internal.js +1 -1
- package/lib/security-rules/security-rules-internal.d.ts +1 -1
- package/lib/security-rules/security-rules-internal.js +1 -1
- package/lib/security-rules/security-rules-namespace.d.ts +1 -1
- package/lib/security-rules/security-rules-namespace.js +1 -1
- package/lib/security-rules/security-rules.d.ts +1 -1
- package/lib/security-rules/security-rules.js +1 -1
- package/lib/storage/index.d.ts +1 -1
- package/lib/storage/index.js +1 -1
- package/lib/storage/storage-namespace.d.ts +1 -1
- package/lib/storage/storage-namespace.js +1 -1
- package/lib/storage/storage.d.ts +1 -1
- package/lib/storage/storage.js +1 -1
- package/lib/storage/utils.d.ts +1 -1
- package/lib/storage/utils.js +1 -1
- package/lib/utils/api-request.d.ts +134 -42
- package/lib/utils/api-request.js +430 -186
- package/lib/utils/crypto-signer.d.ts +1 -1
- package/lib/utils/crypto-signer.js +2 -2
- package/lib/utils/deep-copy.d.ts +1 -1
- package/lib/utils/deep-copy.js +1 -1
- package/lib/utils/error.d.ts +1 -1
- package/lib/utils/error.js +1 -1
- package/lib/utils/index.d.ts +1 -1
- package/lib/utils/index.js +1 -1
- package/lib/utils/jwt.d.ts +1 -1
- package/lib/utils/jwt.js +3 -3
- package/lib/utils/validator.d.ts +1 -1
- package/lib/utils/validator.js +1 -1
- package/package.json +4 -5
package/lib/utils/api-request.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! firebase-admin v12.
|
|
1
|
+
/*! firebase-admin v12.3.0 */
|
|
2
2
|
"use strict";
|
|
3
3
|
/*!
|
|
4
4
|
* @license
|
|
@@ -17,16 +17,17 @@
|
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.ExponentialBackoffPoller = exports.ApiSettings = exports.AuthorizedHttpClient = exports.parseHttpResponse = exports.HttpClient = exports.defaultRetryConfig = exports.
|
|
20
|
+
exports.Http2SessionHandler = exports.ExponentialBackoffPoller = exports.ApiSettings = exports.AuthorizedHttp2Client = exports.AuthorizedHttpClient = exports.parseHttpResponse = exports.Http2Client = exports.HttpClient = exports.RequestClient = exports.defaultRetryConfig = exports.RequestResponseError = void 0;
|
|
21
21
|
const error_1 = require("./error");
|
|
22
22
|
const validator = require("./validator");
|
|
23
23
|
const http = require("http");
|
|
24
24
|
const https = require("https");
|
|
25
|
+
const http2 = require("http2");
|
|
25
26
|
const url = require("url");
|
|
26
27
|
const events_1 = require("events");
|
|
27
|
-
class
|
|
28
|
+
class DefaultRequestResponse {
|
|
28
29
|
/**
|
|
29
|
-
* Constructs a new
|
|
30
|
+
* Constructs a new `RequestResponse` from the given `LowLevelResponse`.
|
|
30
31
|
*/
|
|
31
32
|
constructor(resp) {
|
|
32
33
|
this.status = resp.status;
|
|
@@ -57,10 +58,10 @@ class DefaultHttpResponse {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
/**
|
|
60
|
-
* Represents a multipart HTTP response. Parts that constitute the response body can be accessed
|
|
61
|
+
* Represents a multipart HTTP or HTTP/2 response. Parts that constitute the response body can be accessed
|
|
61
62
|
* via the multipart getter. Getters for text and data throw errors.
|
|
62
63
|
*/
|
|
63
|
-
class
|
|
64
|
+
class MultipartRequestResponse {
|
|
64
65
|
constructor(resp) {
|
|
65
66
|
this.status = resp.status;
|
|
66
67
|
this.headers = resp.headers;
|
|
@@ -76,19 +77,19 @@ class MultipartHttpResponse {
|
|
|
76
77
|
return false;
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
|
-
class
|
|
80
|
+
class RequestResponseError extends Error {
|
|
80
81
|
constructor(response) {
|
|
81
82
|
super(`Server responded with status ${response.status}.`);
|
|
82
83
|
this.response = response;
|
|
83
84
|
// Set the prototype so that instanceof checks will work correctly.
|
|
84
85
|
// See: https://github.com/Microsoft/TypeScript/issues/13965
|
|
85
|
-
Object.setPrototypeOf(this,
|
|
86
|
+
Object.setPrototypeOf(this, RequestResponseError.prototype);
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
|
-
exports.
|
|
89
|
+
exports.RequestResponseError = RequestResponseError;
|
|
89
90
|
/**
|
|
90
|
-
* Default retry configuration for HTTP requests. Retries up to 4 times on connection reset and timeout
|
|
91
|
-
* as well as
|
|
91
|
+
* Default retry configuration for HTTP and HTTP/2 requests. Retries up to 4 times on connection reset and timeout
|
|
92
|
+
* errors as well as 503 errors. Exposed as a function to ensure that every `RequestClient` gets its own `RetryConfig`
|
|
92
93
|
* instance.
|
|
93
94
|
*/
|
|
94
95
|
function defaultRetryConfig() {
|
|
@@ -102,7 +103,7 @@ function defaultRetryConfig() {
|
|
|
102
103
|
}
|
|
103
104
|
exports.defaultRetryConfig = defaultRetryConfig;
|
|
104
105
|
/**
|
|
105
|
-
* Ensures that the given RetryConfig object is valid.
|
|
106
|
+
* Ensures that the given `RetryConfig` object is valid.
|
|
106
107
|
*
|
|
107
108
|
* @param retry - The configuration to be validated.
|
|
108
109
|
*/
|
|
@@ -125,64 +126,18 @@ function validateRetryConfig(retry) {
|
|
|
125
126
|
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_ARGUMENT, 'ioErrorCodes must be an array');
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
|
-
class
|
|
129
|
+
class RequestClient {
|
|
129
130
|
constructor(retry = defaultRetryConfig()) {
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
if (retry) {
|
|
132
|
+
this.retry = retry;
|
|
132
133
|
validateRetryConfig(this.retry);
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
|
-
|
|
136
|
-
* Sends an HTTP request to a remote server. If the server responds with a successful response (2xx), the returned
|
|
137
|
-
* promise resolves with an HttpResponse. If the server responds with an error (3xx, 4xx, 5xx), the promise rejects
|
|
138
|
-
* with an HttpError. In case of all other errors, the promise rejects with a FirebaseAppError. If a request fails
|
|
139
|
-
* due to a low-level network error, transparently retries the request once before rejecting the promise.
|
|
140
|
-
*
|
|
141
|
-
* If the request data is specified as an object, it will be serialized into a JSON string. The application/json
|
|
142
|
-
* content-type header will also be automatically set in this case. For all other payload types, the content-type
|
|
143
|
-
* header should be explicitly set by the caller. To send a JSON leaf value (e.g. "foo", 5), parse it into JSON,
|
|
144
|
-
* and pass as a string or a Buffer along with the appropriate content-type header.
|
|
145
|
-
*
|
|
146
|
-
* @param config - HTTP request to be sent.
|
|
147
|
-
* @returns A promise that resolves with the response details.
|
|
148
|
-
*/
|
|
149
|
-
send(config) {
|
|
150
|
-
return this.sendWithRetry(config);
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Sends an HTTP request. In the event of an error, retries the HTTP request according to the
|
|
154
|
-
* RetryConfig set on the HttpClient.
|
|
155
|
-
*
|
|
156
|
-
* @param config - HTTP request to be sent.
|
|
157
|
-
* @param retryAttempts - Number of retries performed up to now.
|
|
158
|
-
* @returns A promise that resolves with the response details.
|
|
159
|
-
*/
|
|
160
|
-
sendWithRetry(config, retryAttempts = 0) {
|
|
161
|
-
return AsyncHttpCall.invoke(config)
|
|
162
|
-
.then((resp) => {
|
|
163
|
-
return this.createHttpResponse(resp);
|
|
164
|
-
})
|
|
165
|
-
.catch((err) => {
|
|
166
|
-
const [delayMillis, canRetry] = this.getRetryDelayMillis(retryAttempts, err);
|
|
167
|
-
if (canRetry && this.retry && delayMillis <= this.retry.maxDelayInMillis) {
|
|
168
|
-
return this.waitForRetry(delayMillis).then(() => {
|
|
169
|
-
return this.sendWithRetry(config, retryAttempts + 1);
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
if (err.response) {
|
|
173
|
-
throw new HttpError(this.createHttpResponse(err.response));
|
|
174
|
-
}
|
|
175
|
-
if (err.code === 'ETIMEDOUT') {
|
|
176
|
-
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_TIMEOUT, `Error while making request: ${err.message}.`);
|
|
177
|
-
}
|
|
178
|
-
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making request: ${err.message}. Error code: ${err.code}`);
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
createHttpResponse(resp) {
|
|
136
|
+
createRequestResponse(resp) {
|
|
182
137
|
if (resp.multipart) {
|
|
183
|
-
return new
|
|
138
|
+
return new MultipartRequestResponse(resp);
|
|
184
139
|
}
|
|
185
|
-
return new
|
|
140
|
+
return new DefaultRequestResponse(resp);
|
|
186
141
|
}
|
|
187
142
|
waitForRetry(delayMillis) {
|
|
188
143
|
if (delayMillis > 0) {
|
|
@@ -231,8 +186,8 @@ class HttpClient {
|
|
|
231
186
|
}
|
|
232
187
|
return false;
|
|
233
188
|
}
|
|
234
|
-
|
|
235
|
-
* Parses the Retry-After
|
|
189
|
+
/**???
|
|
190
|
+
* Parses the Retry-After header as a milliseconds value. Return value is negative if the Retry-After header
|
|
236
191
|
* contains an expired timestamp or otherwise malformed.
|
|
237
192
|
*/
|
|
238
193
|
parseRetryAfterIntoMillis(retryAfter) {
|
|
@@ -258,13 +213,119 @@ class HttpClient {
|
|
|
258
213
|
return Math.min(delayInSeconds * 1000, this.retry.maxDelayInMillis);
|
|
259
214
|
}
|
|
260
215
|
}
|
|
216
|
+
exports.RequestClient = RequestClient;
|
|
217
|
+
class HttpClient extends RequestClient {
|
|
218
|
+
constructor(retry) {
|
|
219
|
+
super(retry);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Sends an HTTP request to a remote server. If the server responds with a successful response (2xx), the returned
|
|
223
|
+
* promise resolves with an `RequestResponse`. If the server responds with an error (3xx, 4xx, 5xx), the promise
|
|
224
|
+
* rejects with an `RequestResponseError`. In case of all other errors, the promise rejects with a `FirebaseAppError`.
|
|
225
|
+
* If a request fails due to a low-level network error, the client transparently retries the request once before
|
|
226
|
+
* rejecting the promise.
|
|
227
|
+
*
|
|
228
|
+
* If the request data is specified as an object, it will be serialized into a JSON string. The application/json
|
|
229
|
+
* content-type header will also be automatically set in this case. For all other payload types, the content-type
|
|
230
|
+
* header should be explicitly set by the caller. To send a JSON leaf value (e.g. "foo", 5), parse it into JSON,
|
|
231
|
+
* and pass as a string or a Buffer along with the appropriate content-type header.
|
|
232
|
+
*
|
|
233
|
+
* @param config - HTTP request to be sent.
|
|
234
|
+
* @returns A promise that resolves with the response details.
|
|
235
|
+
*/
|
|
236
|
+
send(config) {
|
|
237
|
+
return this.sendWithRetry(config);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Sends an HTTP request. In the event of an error, retries the HTTP request according to the
|
|
241
|
+
* `RetryConfig` set on the `HttpClient`.
|
|
242
|
+
*
|
|
243
|
+
* @param config - HTTP request to be sent.
|
|
244
|
+
* @param retryAttempts - Number of retries performed up to now.
|
|
245
|
+
* @returns A promise that resolves with the response details.
|
|
246
|
+
*/
|
|
247
|
+
sendWithRetry(config, retryAttempts = 0) {
|
|
248
|
+
return AsyncHttpCall.invoke(config)
|
|
249
|
+
.then((resp) => {
|
|
250
|
+
return this.createRequestResponse(resp);
|
|
251
|
+
})
|
|
252
|
+
.catch((err) => {
|
|
253
|
+
const [delayMillis, canRetry] = this.getRetryDelayMillis(retryAttempts, err);
|
|
254
|
+
if (canRetry && this.retry && delayMillis <= this.retry.maxDelayInMillis) {
|
|
255
|
+
return this.waitForRetry(delayMillis).then(() => {
|
|
256
|
+
return this.sendWithRetry(config, retryAttempts + 1);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
if (err.response) {
|
|
260
|
+
throw new RequestResponseError(this.createRequestResponse(err.response));
|
|
261
|
+
}
|
|
262
|
+
if (err.code === 'ETIMEDOUT') {
|
|
263
|
+
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_TIMEOUT, `Error while making request: ${err.message}.`);
|
|
264
|
+
}
|
|
265
|
+
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making request: ${err.message}. Error code: ${err.code}`);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
261
269
|
exports.HttpClient = HttpClient;
|
|
270
|
+
class Http2Client extends RequestClient {
|
|
271
|
+
constructor(retry = defaultRetryConfig()) {
|
|
272
|
+
super(retry);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Sends an HTTP/2 request to a remote server. If the server responds with a successful response (2xx), the returned
|
|
276
|
+
* promise resolves with an `RequestResponse`. If the server responds with an error (3xx, 4xx, 5xx), the promise
|
|
277
|
+
* rejects with an `RequestResponseError`. In case of all other errors, the promise rejects with a `FirebaseAppError`.
|
|
278
|
+
* If a request fails due to a low-level network error, the client transparently retries the request once before
|
|
279
|
+
* rejecting the promise.
|
|
280
|
+
*
|
|
281
|
+
* If the request data is specified as an object, it will be serialized into a JSON string. The application/json
|
|
282
|
+
* content-type header will also be automatically set in this case. For all other payload types, the content-type
|
|
283
|
+
* header should be explicitly set by the caller. To send a JSON leaf value (e.g. "foo", 5), parse it into JSON,
|
|
284
|
+
* and pass as a string or a Buffer along with the appropriate content-type header.
|
|
285
|
+
*
|
|
286
|
+
* @param config - HTTP/2 request to be sent.
|
|
287
|
+
* @returns A promise that resolves with the response details.
|
|
288
|
+
*/
|
|
289
|
+
send(config) {
|
|
290
|
+
return this.sendWithRetry(config);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Sends an HTTP/2 request. In the event of an error, retries the HTTP/2 request according to the
|
|
294
|
+
* `RetryConfig` set on the `Http2Client`.
|
|
295
|
+
*
|
|
296
|
+
* @param config - HTTP/2 request to be sent.
|
|
297
|
+
* @param retryAttempts - Number of retries performed up to now.
|
|
298
|
+
* @returns A promise that resolves with the response details.
|
|
299
|
+
*/
|
|
300
|
+
sendWithRetry(config, retryAttempts = 0) {
|
|
301
|
+
return AsyncHttp2Call.invoke(config)
|
|
302
|
+
.then((resp) => {
|
|
303
|
+
return this.createRequestResponse(resp);
|
|
304
|
+
})
|
|
305
|
+
.catch((err) => {
|
|
306
|
+
const [delayMillis, canRetry] = this.getRetryDelayMillis(retryAttempts, err);
|
|
307
|
+
if (canRetry && this.retry && delayMillis <= this.retry.maxDelayInMillis) {
|
|
308
|
+
return this.waitForRetry(delayMillis).then(() => {
|
|
309
|
+
return this.sendWithRetry(config, retryAttempts + 1);
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
if (err.response) {
|
|
313
|
+
throw new RequestResponseError(this.createRequestResponse(err.response));
|
|
314
|
+
}
|
|
315
|
+
if (err.code === 'ETIMEDOUT') {
|
|
316
|
+
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_TIMEOUT, `Error while making request: ${err.message}.`);
|
|
317
|
+
}
|
|
318
|
+
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making request: ${err.message}. Error code: ${err.code}`);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
exports.Http2Client = Http2Client;
|
|
262
323
|
/**
|
|
263
|
-
* Parses a full HTTP response message containing both a header and a body.
|
|
324
|
+
* Parses a full HTTP or HTTP/2 response message containing both a header and a body.
|
|
264
325
|
*
|
|
265
|
-
* @param response - The HTTP response to be parsed.
|
|
266
|
-
* @param config - The request configuration that resulted in the HTTP response.
|
|
267
|
-
* @returns An object containing the parsed
|
|
326
|
+
* @param response - The HTTP or HTTP/2 response to be parsed.
|
|
327
|
+
* @param config - The request configuration that resulted in the HTTP or HTTP/2 response.
|
|
328
|
+
* @returns An object containing the response's parsed status, headers and the body.
|
|
268
329
|
*/
|
|
269
330
|
function parseHttpResponse(response, config) {
|
|
270
331
|
const responseText = validator.isBuffer(response) ?
|
|
@@ -297,82 +358,16 @@ function parseHttpResponse(response, config) {
|
|
|
297
358
|
if (!validator.isNumber(lowLevelResponse.status)) {
|
|
298
359
|
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Malformed HTTP status line.');
|
|
299
360
|
}
|
|
300
|
-
return new
|
|
361
|
+
return new DefaultRequestResponse(lowLevelResponse);
|
|
301
362
|
}
|
|
302
363
|
exports.parseHttpResponse = parseHttpResponse;
|
|
303
364
|
/**
|
|
304
|
-
* A helper class for
|
|
305
|
-
* http and https packages of Node.js, providing content processing, timeouts and error handling.
|
|
365
|
+
* A helper class for common functionality needed to send requests over the wire.
|
|
306
366
|
* It also wraps the callback API of the Node.js standard library in a more flexible Promise API.
|
|
307
367
|
*/
|
|
308
|
-
class
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
*/
|
|
312
|
-
static invoke(config) {
|
|
313
|
-
return new AsyncHttpCall(config).promise;
|
|
314
|
-
}
|
|
315
|
-
constructor(config) {
|
|
316
|
-
try {
|
|
317
|
-
this.config = new HttpRequestConfigImpl(config);
|
|
318
|
-
this.options = this.config.buildRequestOptions();
|
|
319
|
-
this.entity = this.config.buildEntity(this.options.headers);
|
|
320
|
-
this.promise = new Promise((resolve, reject) => {
|
|
321
|
-
this.resolve = resolve;
|
|
322
|
-
this.reject = reject;
|
|
323
|
-
this.execute();
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
catch (err) {
|
|
327
|
-
this.promise = Promise.reject(this.enhanceError(err, null));
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
execute() {
|
|
331
|
-
const transport = this.options.protocol === 'https:' ? https : http;
|
|
332
|
-
const req = transport.request(this.options, (res) => {
|
|
333
|
-
this.handleResponse(res, req);
|
|
334
|
-
});
|
|
335
|
-
// Handle errors
|
|
336
|
-
req.on('error', (err) => {
|
|
337
|
-
if (req.aborted) {
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
this.enhanceAndReject(err, null, req);
|
|
341
|
-
});
|
|
342
|
-
const timeout = this.config.timeout;
|
|
343
|
-
const timeoutCallback = () => {
|
|
344
|
-
req.abort();
|
|
345
|
-
this.rejectWithError(`timeout of ${timeout}ms exceeded`, 'ETIMEDOUT', req);
|
|
346
|
-
};
|
|
347
|
-
if (timeout) {
|
|
348
|
-
// Listen to timeouts and throw an error.
|
|
349
|
-
req.setTimeout(timeout, timeoutCallback);
|
|
350
|
-
}
|
|
351
|
-
// Send the request
|
|
352
|
-
req.end(this.entity);
|
|
353
|
-
}
|
|
354
|
-
handleResponse(res, req) {
|
|
355
|
-
if (req.aborted) {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
if (!res.statusCode) {
|
|
359
|
-
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Expected a statusCode on the response from a ClientRequest');
|
|
360
|
-
}
|
|
361
|
-
const response = {
|
|
362
|
-
status: res.statusCode,
|
|
363
|
-
headers: res.headers,
|
|
364
|
-
request: req,
|
|
365
|
-
data: undefined,
|
|
366
|
-
config: this.config,
|
|
367
|
-
};
|
|
368
|
-
const boundary = this.getMultipartBoundary(res.headers);
|
|
369
|
-
const respStream = this.uncompressResponse(res);
|
|
370
|
-
if (boundary) {
|
|
371
|
-
this.handleMultipartResponse(response, respStream, boundary);
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
this.handleRegularResponse(response, respStream);
|
|
375
|
-
}
|
|
368
|
+
class AsyncRequestCall {
|
|
369
|
+
constructor(configImpl) {
|
|
370
|
+
this.configImpl = configImpl;
|
|
376
371
|
}
|
|
377
372
|
/**
|
|
378
373
|
* Extracts multipart boundary from the HTTP header. The content-type header of a multipart
|
|
@@ -401,19 +396,6 @@ class AsyncHttpCall {
|
|
|
401
396
|
}, emptyObject);
|
|
402
397
|
return headerParams.boundary;
|
|
403
398
|
}
|
|
404
|
-
uncompressResponse(res) {
|
|
405
|
-
// Uncompress the response body transparently if required.
|
|
406
|
-
let respStream = res;
|
|
407
|
-
const encodings = ['gzip', 'compress', 'deflate'];
|
|
408
|
-
if (res.headers['content-encoding'] && encodings.indexOf(res.headers['content-encoding']) !== -1) {
|
|
409
|
-
// Add the unzipper to the body stream processing pipeline.
|
|
410
|
-
const zlib = require('zlib'); // eslint-disable-line @typescript-eslint/no-var-requires
|
|
411
|
-
respStream = respStream.pipe(zlib.createUnzip());
|
|
412
|
-
// Remove the content-encoding in order to not confuse downstream operations.
|
|
413
|
-
delete res.headers['content-encoding'];
|
|
414
|
-
}
|
|
415
|
-
return respStream;
|
|
416
|
-
}
|
|
417
399
|
handleMultipartResponse(response, respStream, boundary) {
|
|
418
400
|
const busboy = require('@fastify/busboy'); // eslint-disable-line @typescript-eslint/no-var-requires
|
|
419
401
|
const multipartParser = new busboy.Dicer({ boundary });
|
|
@@ -441,7 +423,7 @@ class AsyncHttpCall {
|
|
|
441
423
|
});
|
|
442
424
|
respStream.on('error', (err) => {
|
|
443
425
|
const req = response.request;
|
|
444
|
-
if (req && req.
|
|
426
|
+
if (req && req.destroyed) {
|
|
445
427
|
return;
|
|
446
428
|
}
|
|
447
429
|
this.enhanceAndReject(err, null, req);
|
|
@@ -452,7 +434,7 @@ class AsyncHttpCall {
|
|
|
452
434
|
});
|
|
453
435
|
}
|
|
454
436
|
/**
|
|
455
|
-
* Finalizes the current
|
|
437
|
+
* Finalizes the current request call in-flight by either resolving or rejecting the associated
|
|
456
438
|
* promise. In the event of an error, adds additional useful information to the returned error.
|
|
457
439
|
*/
|
|
458
440
|
finalizeResponse(response) {
|
|
@@ -465,7 +447,7 @@ class AsyncHttpCall {
|
|
|
465
447
|
}
|
|
466
448
|
/**
|
|
467
449
|
* Creates a new error from the given message, and enhances it with other information available.
|
|
468
|
-
* Then the promise associated with this
|
|
450
|
+
* Then the promise associated with this request call is rejected with the resulting error.
|
|
469
451
|
*/
|
|
470
452
|
rejectWithError(message, code, request, response) {
|
|
471
453
|
const error = new Error(message);
|
|
@@ -475,11 +457,11 @@ class AsyncHttpCall {
|
|
|
475
457
|
this.reject(this.enhanceError(error, code, request, response));
|
|
476
458
|
}
|
|
477
459
|
/**
|
|
478
|
-
* Enhances the given error by adding more information to it. Specifically, the
|
|
460
|
+
* Enhances the given error by adding more information to it. Specifically, the request config,
|
|
479
461
|
* the underlying request and response will be attached to the error.
|
|
480
462
|
*/
|
|
481
463
|
enhanceError(error, code, request, response) {
|
|
482
|
-
error.config = this.
|
|
464
|
+
error.config = this.configImpl;
|
|
483
465
|
if (code) {
|
|
484
466
|
error.code = code;
|
|
485
467
|
}
|
|
@@ -489,10 +471,190 @@ class AsyncHttpCall {
|
|
|
489
471
|
}
|
|
490
472
|
}
|
|
491
473
|
/**
|
|
492
|
-
*
|
|
474
|
+
* A helper class for sending HTTP requests over the wire. This is a wrapper around the standard
|
|
475
|
+
* http and https packages of Node.js, providing content processing, timeouts and error handling.
|
|
476
|
+
* It also wraps the callback API of the Node.js standard library in a more flexible Promise API.
|
|
493
477
|
*/
|
|
494
|
-
class
|
|
478
|
+
class AsyncHttpCall extends AsyncRequestCall {
|
|
479
|
+
/**
|
|
480
|
+
* Sends an HTTP request based on the provided configuration.
|
|
481
|
+
*/
|
|
482
|
+
static invoke(config) {
|
|
483
|
+
return new AsyncHttpCall(config).promise;
|
|
484
|
+
}
|
|
495
485
|
constructor(config) {
|
|
486
|
+
const httpConfigImpl = new HttpRequestConfigImpl(config);
|
|
487
|
+
super(httpConfigImpl);
|
|
488
|
+
try {
|
|
489
|
+
this.httpConfigImpl = httpConfigImpl;
|
|
490
|
+
this.options = this.httpConfigImpl.buildRequestOptions();
|
|
491
|
+
this.entity = this.httpConfigImpl.buildEntity(this.options.headers);
|
|
492
|
+
this.promise = new Promise((resolve, reject) => {
|
|
493
|
+
this.resolve = resolve;
|
|
494
|
+
this.reject = reject;
|
|
495
|
+
this.execute();
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
catch (err) {
|
|
499
|
+
this.promise = Promise.reject(this.enhanceError(err, null));
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
execute() {
|
|
503
|
+
const transport = this.options.protocol === 'https:' ? https : http;
|
|
504
|
+
const req = transport.request(this.options, (res) => {
|
|
505
|
+
this.handleResponse(res, req);
|
|
506
|
+
});
|
|
507
|
+
// Handle errors
|
|
508
|
+
req.on('error', (err) => {
|
|
509
|
+
if (req.aborted) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
this.enhanceAndReject(err, null, req);
|
|
513
|
+
});
|
|
514
|
+
const timeout = this.httpConfigImpl.timeout;
|
|
515
|
+
const timeoutCallback = () => {
|
|
516
|
+
req.destroy();
|
|
517
|
+
this.rejectWithError(`timeout of ${timeout}ms exceeded`, 'ETIMEDOUT', req);
|
|
518
|
+
};
|
|
519
|
+
if (timeout) {
|
|
520
|
+
// Listen to timeouts and throw an error.
|
|
521
|
+
req.setTimeout(timeout, timeoutCallback);
|
|
522
|
+
}
|
|
523
|
+
// Send the request
|
|
524
|
+
req.end(this.entity);
|
|
525
|
+
}
|
|
526
|
+
handleResponse(res, req) {
|
|
527
|
+
if (req.aborted) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
if (!res.statusCode) {
|
|
531
|
+
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Expected a statusCode on the response from a ClientRequest');
|
|
532
|
+
}
|
|
533
|
+
const response = {
|
|
534
|
+
status: res.statusCode,
|
|
535
|
+
headers: res.headers,
|
|
536
|
+
request: req,
|
|
537
|
+
data: undefined,
|
|
538
|
+
config: this.httpConfigImpl,
|
|
539
|
+
};
|
|
540
|
+
const boundary = this.getMultipartBoundary(res.headers);
|
|
541
|
+
const respStream = this.uncompressResponse(res);
|
|
542
|
+
if (boundary) {
|
|
543
|
+
this.handleMultipartResponse(response, respStream, boundary);
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
this.handleRegularResponse(response, respStream);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
uncompressResponse(res) {
|
|
550
|
+
// Uncompress the response body transparently if required.
|
|
551
|
+
let respStream = res;
|
|
552
|
+
const encodings = ['gzip', 'compress', 'deflate'];
|
|
553
|
+
if (res.headers['content-encoding'] && encodings.indexOf(res.headers['content-encoding']) !== -1) {
|
|
554
|
+
// Add the unzipper to the body stream processing pipeline.
|
|
555
|
+
const zlib = require('zlib'); // eslint-disable-line @typescript-eslint/no-var-requires
|
|
556
|
+
respStream = respStream.pipe(zlib.createUnzip());
|
|
557
|
+
// Remove the content-encoding in order to not confuse downstream operations.
|
|
558
|
+
delete res.headers['content-encoding'];
|
|
559
|
+
}
|
|
560
|
+
return respStream;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
class AsyncHttp2Call extends AsyncRequestCall {
|
|
564
|
+
/**
|
|
565
|
+
* Sends an HTTP2 request based on the provided configuration.
|
|
566
|
+
*/
|
|
567
|
+
static invoke(config) {
|
|
568
|
+
return new AsyncHttp2Call(config).promise;
|
|
569
|
+
}
|
|
570
|
+
constructor(config) {
|
|
571
|
+
const http2ConfigImpl = new Http2RequestConfigImpl(config);
|
|
572
|
+
super(http2ConfigImpl);
|
|
573
|
+
try {
|
|
574
|
+
this.http2ConfigImpl = http2ConfigImpl;
|
|
575
|
+
this.options = this.http2ConfigImpl.buildRequestOptions();
|
|
576
|
+
this.entity = this.http2ConfigImpl.buildEntity(this.options.headers);
|
|
577
|
+
this.promise = new Promise((resolve, reject) => {
|
|
578
|
+
this.resolve = resolve;
|
|
579
|
+
this.reject = reject;
|
|
580
|
+
this.execute();
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
catch (err) {
|
|
584
|
+
this.promise = Promise.reject(this.enhanceError(err, null));
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
execute() {
|
|
588
|
+
const req = this.http2ConfigImpl.http2SessionHandler.session.request({
|
|
589
|
+
':method': this.options.method,
|
|
590
|
+
':scheme': this.options.protocol,
|
|
591
|
+
':path': this.options.path,
|
|
592
|
+
...this.options.headers
|
|
593
|
+
});
|
|
594
|
+
req.on('response', (headers) => {
|
|
595
|
+
this.handleHttp2Response(headers, req);
|
|
596
|
+
});
|
|
597
|
+
// Handle errors
|
|
598
|
+
req.on('error', (err) => {
|
|
599
|
+
if (req.aborted) {
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
this.enhanceAndReject(err, null, req);
|
|
603
|
+
});
|
|
604
|
+
const timeout = this.http2ConfigImpl.timeout;
|
|
605
|
+
const timeoutCallback = () => {
|
|
606
|
+
req.destroy();
|
|
607
|
+
this.rejectWithError(`timeout of ${timeout}ms exceeded`, 'ETIMEDOUT', req);
|
|
608
|
+
};
|
|
609
|
+
if (timeout) {
|
|
610
|
+
// Listen to timeouts and throw an error.
|
|
611
|
+
req.setTimeout(timeout, timeoutCallback);
|
|
612
|
+
}
|
|
613
|
+
req.end(this.entity);
|
|
614
|
+
}
|
|
615
|
+
handleHttp2Response(headers, stream) {
|
|
616
|
+
if (stream.aborted) {
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
if (!headers[':status']) {
|
|
620
|
+
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Expected a statusCode on the response from a ClientRequest');
|
|
621
|
+
}
|
|
622
|
+
const response = {
|
|
623
|
+
status: headers[':status'],
|
|
624
|
+
headers: headers,
|
|
625
|
+
request: stream,
|
|
626
|
+
data: undefined,
|
|
627
|
+
config: this.http2ConfigImpl,
|
|
628
|
+
};
|
|
629
|
+
const boundary = this.getMultipartBoundary(headers);
|
|
630
|
+
const respStream = this.uncompressResponse(headers, stream);
|
|
631
|
+
if (boundary) {
|
|
632
|
+
this.handleMultipartResponse(response, respStream, boundary);
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
this.handleRegularResponse(response, respStream);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
uncompressResponse(headers, stream) {
|
|
639
|
+
// Uncompress the response body transparently if required.
|
|
640
|
+
let respStream = stream;
|
|
641
|
+
const encodings = ['gzip', 'compress', 'deflate'];
|
|
642
|
+
if (headers['content-encoding'] && encodings.indexOf(headers['content-encoding']) !== -1) {
|
|
643
|
+
// Add the unzipper to the body stream processing pipeline.
|
|
644
|
+
const zlib = require('zlib'); // eslint-disable-line @typescript-eslint/no-var-requires
|
|
645
|
+
respStream = respStream.pipe(zlib.createUnzip());
|
|
646
|
+
// Remove the content-encoding in order to not confuse downstream operations.
|
|
647
|
+
delete headers['content-encoding'];
|
|
648
|
+
}
|
|
649
|
+
return respStream;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* An adapter class with common functionality needed to extract options and entity data from a `RequestConfig`.
|
|
654
|
+
*/
|
|
655
|
+
class BaseRequestConfigImpl {
|
|
656
|
+
constructor(config) {
|
|
657
|
+
this.config = config;
|
|
496
658
|
this.config = config;
|
|
497
659
|
}
|
|
498
660
|
get method() {
|
|
@@ -510,27 +672,6 @@ class HttpRequestConfigImpl {
|
|
|
510
672
|
get timeout() {
|
|
511
673
|
return this.config.timeout;
|
|
512
674
|
}
|
|
513
|
-
get httpAgent() {
|
|
514
|
-
return this.config.httpAgent;
|
|
515
|
-
}
|
|
516
|
-
buildRequestOptions() {
|
|
517
|
-
const parsed = this.buildUrl();
|
|
518
|
-
const protocol = parsed.protocol;
|
|
519
|
-
let port = parsed.port;
|
|
520
|
-
if (!port) {
|
|
521
|
-
const isHttps = protocol === 'https:';
|
|
522
|
-
port = isHttps ? '443' : '80';
|
|
523
|
-
}
|
|
524
|
-
return {
|
|
525
|
-
protocol,
|
|
526
|
-
hostname: parsed.hostname,
|
|
527
|
-
port,
|
|
528
|
-
path: parsed.path,
|
|
529
|
-
method: this.method,
|
|
530
|
-
agent: this.httpAgent,
|
|
531
|
-
headers: Object.assign({}, this.headers),
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
675
|
buildEntity(headers) {
|
|
535
676
|
let data;
|
|
536
677
|
if (!this.hasEntity() || !this.isEntityEnclosingRequest()) {
|
|
@@ -588,6 +729,58 @@ class HttpRequestConfigImpl {
|
|
|
588
729
|
return this.method !== 'GET' && this.method !== 'HEAD';
|
|
589
730
|
}
|
|
590
731
|
}
|
|
732
|
+
/**
|
|
733
|
+
* An adapter class for extracting options and entity data from an `HttpRequestConfig`.
|
|
734
|
+
*/
|
|
735
|
+
class HttpRequestConfigImpl extends BaseRequestConfigImpl {
|
|
736
|
+
constructor(httpConfig) {
|
|
737
|
+
super(httpConfig);
|
|
738
|
+
this.httpConfig = httpConfig;
|
|
739
|
+
}
|
|
740
|
+
get httpAgent() {
|
|
741
|
+
return this.httpConfig.httpAgent;
|
|
742
|
+
}
|
|
743
|
+
buildRequestOptions() {
|
|
744
|
+
const parsed = this.buildUrl();
|
|
745
|
+
const protocol = parsed.protocol;
|
|
746
|
+
let port = parsed.port;
|
|
747
|
+
if (!port) {
|
|
748
|
+
const isHttps = protocol === 'https:';
|
|
749
|
+
port = isHttps ? '443' : '80';
|
|
750
|
+
}
|
|
751
|
+
return {
|
|
752
|
+
protocol,
|
|
753
|
+
hostname: parsed.hostname,
|
|
754
|
+
port,
|
|
755
|
+
path: parsed.path,
|
|
756
|
+
method: this.method,
|
|
757
|
+
agent: this.httpAgent,
|
|
758
|
+
headers: Object.assign({}, this.headers),
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* An adapter class for extracting options and entity data from an `Http2RequestConfig`.
|
|
764
|
+
*/
|
|
765
|
+
class Http2RequestConfigImpl extends BaseRequestConfigImpl {
|
|
766
|
+
constructor(http2Config) {
|
|
767
|
+
super(http2Config);
|
|
768
|
+
this.http2Config = http2Config;
|
|
769
|
+
}
|
|
770
|
+
get http2SessionHandler() {
|
|
771
|
+
return this.http2Config.http2SessionHandler;
|
|
772
|
+
}
|
|
773
|
+
buildRequestOptions() {
|
|
774
|
+
const parsed = this.buildUrl();
|
|
775
|
+
const protocol = parsed.protocol;
|
|
776
|
+
return {
|
|
777
|
+
protocol,
|
|
778
|
+
path: parsed.path,
|
|
779
|
+
method: this.method,
|
|
780
|
+
headers: Object.assign({}, this.headers),
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
}
|
|
591
784
|
class AuthorizedHttpClient extends HttpClient {
|
|
592
785
|
constructor(app) {
|
|
593
786
|
super();
|
|
@@ -612,17 +805,35 @@ class AuthorizedHttpClient extends HttpClient {
|
|
|
612
805
|
}
|
|
613
806
|
getToken() {
|
|
614
807
|
return this.app.INTERNAL.getToken()
|
|
615
|
-
.then((accessTokenObj) =>
|
|
616
|
-
return accessTokenObj.accessToken;
|
|
617
|
-
});
|
|
808
|
+
.then((accessTokenObj) => accessTokenObj.accessToken);
|
|
618
809
|
}
|
|
619
810
|
}
|
|
620
811
|
exports.AuthorizedHttpClient = AuthorizedHttpClient;
|
|
812
|
+
class AuthorizedHttp2Client extends Http2Client {
|
|
813
|
+
constructor(app) {
|
|
814
|
+
super();
|
|
815
|
+
this.app = app;
|
|
816
|
+
}
|
|
817
|
+
send(request) {
|
|
818
|
+
return this.getToken().then((token) => {
|
|
819
|
+
const requestCopy = Object.assign({}, request);
|
|
820
|
+
requestCopy.headers = Object.assign({}, request.headers);
|
|
821
|
+
const authHeader = 'Authorization';
|
|
822
|
+
requestCopy.headers[authHeader] = `Bearer ${token}`;
|
|
823
|
+
return super.send(requestCopy);
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
getToken() {
|
|
827
|
+
return this.app.INTERNAL.getToken()
|
|
828
|
+
.then((accessTokenObj) => accessTokenObj.accessToken);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
exports.AuthorizedHttp2Client = AuthorizedHttp2Client;
|
|
621
832
|
/**
|
|
622
833
|
* Class that defines all the settings for the backend API endpoint.
|
|
623
834
|
*
|
|
624
835
|
* @param endpoint - The Firebase Auth backend endpoint.
|
|
625
|
-
* @param httpMethod - The
|
|
836
|
+
* @param httpMethod - The HTTP method for that endpoint.
|
|
626
837
|
* @constructor
|
|
627
838
|
*/
|
|
628
839
|
class ApiSettings {
|
|
@@ -767,3 +978,36 @@ class ExponentialBackoffPoller extends events_1.EventEmitter {
|
|
|
767
978
|
}
|
|
768
979
|
}
|
|
769
980
|
exports.ExponentialBackoffPoller = ExponentialBackoffPoller;
|
|
981
|
+
class Http2SessionHandler {
|
|
982
|
+
constructor(url) {
|
|
983
|
+
this.http2Session = this.createSession(url);
|
|
984
|
+
}
|
|
985
|
+
createSession(url) {
|
|
986
|
+
if (!this.http2Session || this.isClosed) {
|
|
987
|
+
const opts = {
|
|
988
|
+
// Set local max concurrent stream limit to respect backend limit
|
|
989
|
+
peerMaxConcurrentStreams: 100,
|
|
990
|
+
ALPNProtocols: ['h2']
|
|
991
|
+
};
|
|
992
|
+
const http2Session = http2.connect(url, opts);
|
|
993
|
+
http2Session.on('goaway', (errorCode, _, opaqueData) => {
|
|
994
|
+
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making requests: GOAWAY - ${opaqueData.toString()}, Error code: ${errorCode}`);
|
|
995
|
+
});
|
|
996
|
+
http2Session.on('error', (error) => {
|
|
997
|
+
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making requests: ${error}`);
|
|
998
|
+
});
|
|
999
|
+
return http2Session;
|
|
1000
|
+
}
|
|
1001
|
+
return this.http2Session;
|
|
1002
|
+
}
|
|
1003
|
+
get session() {
|
|
1004
|
+
return this.http2Session;
|
|
1005
|
+
}
|
|
1006
|
+
get isClosed() {
|
|
1007
|
+
return this.http2Session.closed;
|
|
1008
|
+
}
|
|
1009
|
+
close() {
|
|
1010
|
+
this.http2Session.close();
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
exports.Http2SessionHandler = Http2SessionHandler;
|