Skip to content

Commit e5001c1

Browse files
authored
feat(fcm): Add HTTP2 support for sendEach() and sendEachForMulticast() (#2550)
* Refactor `api-requets` to prepare to handle both HTTP/1.1 and HTTP/2 requests * Added HTTP2 support for `sendEach()` and sendEachForMulticast` with integration tests * fix: lint * Added unit tests * Added tests for `Http2Client` and `AuthorizedHttp2Client` * Address api review changes and typos. * TW changes, backticks and typos * fix deprecation note * Reword deprecation note.
1 parent 9682e7e commit e5001c1

29 files changed

+2902
-500
lines changed

etc/firebase-admin.messaging.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ export type Message = TokenMessage | TopicMessage | ConditionMessage;
189189
// @public
190190
export class Messaging {
191191
get app(): App;
192+
// @deprecated
193+
enableLegacyHttpTransport(): void;
192194
send(message: Message, dryRun?: boolean): Promise<string>;
193195
// @deprecated
194196
sendAll(messages: Message[], dryRun?: boolean): Promise<BatchResponse>;

src/app-check/app-check-api-client-internal.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import { App } from '../app';
1919
import { FirebaseApp } from '../app/firebase-app';
2020
import {
21-
HttpRequestConfig, HttpClient, HttpError, AuthorizedHttpClient, HttpResponse
21+
HttpRequestConfig, HttpClient, RequestResponseError, AuthorizedHttpClient, RequestResponse
2222
} from '../utils/api-request';
2323
import { PrefixedFirebaseError } from '../utils/error';
2424
import * as utils from '../utils/index';
@@ -157,7 +157,7 @@ export class AppCheckApiClient {
157157
});
158158
}
159159

160-
private toFirebaseError(err: HttpError): PrefixedFirebaseError {
160+
private toFirebaseError(err: RequestResponseError): PrefixedFirebaseError {
161161
if (err instanceof PrefixedFirebaseError) {
162162
return err;
163163
}
@@ -184,7 +184,7 @@ export class AppCheckApiClient {
184184
* @param resp - API response object.
185185
* @returns An AppCheckToken instance.
186186
*/
187-
private toAppCheckToken(resp: HttpResponse): AppCheckToken {
187+
private toAppCheckToken(resp: RequestResponse): AppCheckToken {
188188
const token = resp.data.token;
189189
// `ttl` is a string with the suffix "s" preceded by the number of seconds,
190190
// with nanoseconds expressed as fractional seconds.

src/app-check/token-generator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
APP_CHECK_ERROR_CODE_MAPPING,
2525
} from './app-check-api-client-internal';
2626
import { AppCheckTokenOptions } from './app-check-api';
27-
import { HttpError } from '../utils/api-request';
27+
import { RequestResponseError } from '../utils/api-request';
2828

2929
const ONE_MINUTE_IN_SECONDS = 60;
3030
const ONE_MINUTE_IN_MILLIS = ONE_MINUTE_IN_SECONDS * 1000;
@@ -147,7 +147,7 @@ export function appCheckErrorFromCryptoSignerError(err: Error): Error {
147147
return err;
148148
}
149149
if (err.code === CryptoSignerErrorCode.SERVER_ERROR && validator.isNonNullObject(err.cause)) {
150-
const httpError = err.cause as HttpError
150+
const httpError = err.cause as RequestResponseError
151151
const errorResponse = httpError.response.data;
152152
if (errorResponse?.error) {
153153
const status = errorResponse.error.status;

src/app/credential-internal.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import path = require('path');
2222
import { Agent } from 'http';
2323
import { Credential, GoogleOAuthAccessToken } from './credential';
2424
import { AppErrorCodes, FirebaseAppError } from '../utils/error';
25-
import { HttpClient, HttpRequestConfig, HttpError, HttpResponse } from '../utils/api-request';
25+
import { HttpClient, HttpRequestConfig, RequestResponseError, RequestResponse } from '../utils/api-request';
2626
import * as util from '../utils/validator';
2727

2828
const GOOGLE_TOKEN_AUDIENCE = 'https://accounts.google.com/o/oauth2/token';
@@ -232,7 +232,8 @@ export class ComputeEngineCredential implements Credential {
232232
return this.projectId;
233233
})
234234
.catch((err) => {
235-
const detail: string = (err instanceof HttpError) ? getDetailFromResponse(err.response) : err.message;
235+
const detail: string =
236+
(err instanceof RequestResponseError) ? getDetailFromResponse(err.response) : err.message;
236237
throw new FirebaseAppError(
237238
AppErrorCodes.INVALID_CREDENTIAL,
238239
`Failed to determine project ID: ${detail}`);
@@ -251,7 +252,8 @@ export class ComputeEngineCredential implements Credential {
251252
return this.accountId;
252253
})
253254
.catch((err) => {
254-
const detail: string = (err instanceof HttpError) ? getDetailFromResponse(err.response) : err.message;
255+
const detail: string =
256+
(err instanceof RequestResponseError) ? getDetailFromResponse(err.response) : err.message;
255257
throw new FirebaseAppError(
256258
AppErrorCodes.INVALID_CREDENTIAL,
257259
`Failed to determine service account email: ${detail}`);
@@ -553,7 +555,7 @@ function requestIDToken(client: HttpClient, request: HttpRequestConfig): Promise
553555
* Constructs a human-readable error message from the given Error.
554556
*/
555557
function getErrorMessage(err: Error): string {
556-
const detail: string = (err instanceof HttpError) ? getDetailFromResponse(err.response) : err.message;
558+
const detail: string = (err instanceof RequestResponseError) ? getDetailFromResponse(err.response) : err.message;
557559
return `Error fetching access token: ${detail}`;
558560
}
559561

@@ -562,7 +564,7 @@ function getErrorMessage(err: Error): string {
562564
* the response is JSON-formatted, looks up the error and error_description fields sent by the
563565
* Google Auth servers. Otherwise returns the entire response payload as the error detail.
564566
*/
565-
function getDetailFromResponse(response: HttpResponse): string {
567+
function getDetailFromResponse(response: RequestResponse): string {
566568
if (response.isJson() && response.data.error) {
567569
const json = response.data;
568570
let detail = json.error;

src/auth/auth-api-request.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { FirebaseApp } from '../app/firebase-app';
2222
import { deepCopy, deepExtend } from '../utils/deep-copy';
2323
import { AuthClientErrorCode, FirebaseAuthError } from '../utils/error';
2424
import {
25-
ApiSettings, AuthorizedHttpClient, HttpRequestConfig, HttpError,
25+
ApiSettings, AuthorizedHttpClient, HttpRequestConfig, RequestResponseError,
2626
} from '../utils/api-request';
2727
import * as utils from '../utils/index';
2828

@@ -1933,7 +1933,7 @@ export abstract class AbstractAuthRequestHandler {
19331933
return response.data;
19341934
})
19351935
.catch((err) => {
1936-
if (err instanceof HttpError) {
1936+
if (err instanceof RequestResponseError) {
19371937
const error = err.response.data;
19381938
const errorCode = AbstractAuthRequestHandler.getErrorCode(error);
19391939
if (!errorCode) {

src/auth/token-generator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717

1818
import { AuthClientErrorCode, ErrorInfo, FirebaseAuthError } from '../utils/error';
19-
import { HttpError } from '../utils/api-request';
19+
import { RequestResponseError } from '../utils/api-request';
2020
import { CryptoSigner, CryptoSignerError, CryptoSignerErrorCode } from '../utils/crypto-signer';
2121

2222
import * as validator from '../utils/validator';
@@ -213,7 +213,7 @@ export function handleCryptoSignerError(err: Error): Error {
213213
}
214214
if (err.code === CryptoSignerErrorCode.SERVER_ERROR && validator.isNonNullObject(err.cause)) {
215215
const httpError = err.cause;
216-
const errorResponse = (httpError as HttpError).response.data;
216+
const errorResponse = (httpError as RequestResponseError).response.data;
217217
if (validator.isNonNullObject(errorResponse) && errorResponse.error) {
218218
const errorCode = errorResponse.error.status;
219219
const description = 'Please refer to https://firebase.google.com/docs/auth/admin/create-custom-tokens ' +

src/database/database.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { Database as DatabaseImpl } from '@firebase/database-compat/standalone';
2424
import { App } from '../app';
2525
import { FirebaseApp } from '../app/firebase-app';
2626
import * as validator from '../utils/validator';
27-
import { AuthorizedHttpClient, HttpRequestConfig, HttpError } from '../utils/api-request';
27+
import { AuthorizedHttpClient, HttpRequestConfig, RequestResponseError } from '../utils/api-request';
2828
import { getSdkVersion } from '../utils/index';
2929

3030
/**
@@ -292,7 +292,7 @@ class DatabaseRulesClient {
292292
}
293293

294294
private handleError(err: Error): Error {
295-
if (err instanceof HttpError) {
295+
if (err instanceof RequestResponseError) {
296296
return new FirebaseDatabaseError({
297297
code: AppErrorCodes.INTERNAL_ERROR,
298298
message: this.getErrorMessage(err),
@@ -301,7 +301,7 @@ class DatabaseRulesClient {
301301
return err;
302302
}
303303

304-
private getErrorMessage(err: HttpError): string {
304+
private getErrorMessage(err: RequestResponseError): string {
305305
const intro = 'Error while accessing security rules';
306306
try {
307307
const body: { error?: string } = err.response.data;

src/eventarc/eventarc-client-internal.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { FirebaseEventarcError, toCloudEventProtoFormat } from './eventarc-utils
2020
import { App } from '../app';
2121
import { Channel } from './eventarc';
2222
import {
23-
HttpRequestConfig, HttpClient, HttpError, AuthorizedHttpClient
23+
HttpRequestConfig, HttpClient, RequestResponseError, AuthorizedHttpClient
2424
} from '../utils/api-request';
2525
import { FirebaseApp } from '../app/firebase-app';
2626
import * as utils from '../utils';
@@ -117,7 +117,7 @@ export class EventarcApiClient {
117117
});
118118
}
119119

120-
private toFirebaseError(err: HttpError): PrefixedFirebaseError {
120+
private toFirebaseError(err: RequestResponseError): PrefixedFirebaseError {
121121
if (err instanceof PrefixedFirebaseError) {
122122
return err;
123123
}

src/extensions/extensions-api-client-internal.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import { App } from '../app';
1919
import { FirebaseApp } from '../app/firebase-app';
20-
import { AuthorizedHttpClient, HttpClient, HttpError, HttpRequestConfig } from '../utils/api-request';
20+
import { AuthorizedHttpClient, HttpClient, RequestResponseError, HttpRequestConfig } from '../utils/api-request';
2121
import { FirebaseAppError, PrefixedFirebaseError } from '../utils/error';
2222
import * as validator from '../utils/validator';
2323
import * as utils from '../utils';
@@ -76,7 +76,7 @@ export class ExtensionsApiClient {
7676
}/${EXTENSIONS_API_VERSION}/projects/${projectId}/instances/${instanceId}/runtimeData`;
7777
}
7878

79-
private toFirebaseError(err: HttpError): PrefixedFirebaseError {
79+
private toFirebaseError(err: RequestResponseError): PrefixedFirebaseError {
8080
if (err instanceof PrefixedFirebaseError) {
8181
return err;
8282
}

src/functions/functions-api-client-internal.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import { App } from '../app';
1919
import { FirebaseApp } from '../app/firebase-app';
2020
import {
21-
HttpRequestConfig, HttpClient, HttpError, AuthorizedHttpClient
21+
HttpRequestConfig, HttpClient, RequestResponseError, AuthorizedHttpClient
2222
} from '../utils/api-request';
2323
import { PrefixedFirebaseError } from '../utils/error';
2424
import * as utils from '../utils/index';
@@ -99,7 +99,7 @@ export class FunctionsApiClient {
9999
};
100100
await this.httpClient.send(request);
101101
} catch (err: unknown) {
102-
if (err instanceof HttpError) {
102+
if (err instanceof RequestResponseError) {
103103
if (err.response.status === 404) {
104104
// if no task with the provided ID exists, then ignore the delete.
105105
return;
@@ -156,7 +156,7 @@ export class FunctionsApiClient {
156156
};
157157
await this.httpClient.send(request);
158158
} catch (err: unknown) {
159-
if (err instanceof HttpError) {
159+
if (err instanceof RequestResponseError) {
160160
if (err.response.status === 409) {
161161
throw new FirebaseFunctionsError('task-already-exists', `A task with ID ${opts?.id} already exists`);
162162
} else {
@@ -321,7 +321,7 @@ export class FunctionsApiClient {
321321
return task;
322322
}
323323

324-
private toFirebaseError(err: HttpError): PrefixedFirebaseError {
324+
private toFirebaseError(err: RequestResponseError): PrefixedFirebaseError {
325325
if (err instanceof PrefixedFirebaseError) {
326326
return err;
327327
}

0 commit comments

Comments
 (0)