Skip to content

Commit 9c109f7

Browse files
authored
Gracefully handling array-like arguments in sendAll() and sendMulticast() (#569)
1 parent 984f45d commit 9c109f7

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Unreleased
22

3-
-
3+
- [fixed] Gracefully handling array-like objects in `messaging.sendAll()` and
4+
`messaging.sendMulticast()` APIs.
5+
- [fixed] Updated the metadata server URL (used by the application default credentials)
6+
to the `v1` endpoint.
47

58
# v8.1.0
69

src/messaging/messaging.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,13 @@ export class Messaging implements FirebaseServiceInterface {
291291
* of the send operation.
292292
*/
293293
public sendAll(messages: Message[], dryRun?: boolean): Promise<BatchResponse> {
294+
if (validator.isArray(messages) && messages.constructor !== Array) {
295+
// In more recent JS specs, an array-like object might have a constructor that is not of
296+
// Array type. Our deepCopy() method doesn't handle them properly. Convert such objects to
297+
// a regular array here before calling deepCopy(). See issue #566 for details.
298+
messages = Array.from(messages);
299+
}
300+
294301
const copy: Message[] = deepCopy(messages);
295302
if (!validator.isNonEmptyArray(copy)) {
296303
throw new FirebaseMessagingError(

test/unit/messaging/messaging.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ function disableRetries(messaging: Messaging) {
303303
(messaging as any).messagingRequestHandler.httpClient.retry = null;
304304
}
305305

306+
class CustomArray extends Array { }
307+
306308
describe('Messaging', () => {
307309
let mockApp: FirebaseApp;
308310
let messaging: Messaging;
@@ -608,6 +610,40 @@ describe('Messaging', () => {
608610
});
609611
});
610612

613+
it('should be fulfilled with a BatchResponse given array-like (issue #566)', () => {
614+
const messageIds = [
615+
'projects/projec_id/messages/1',
616+
'projects/projec_id/messages/2',
617+
'projects/projec_id/messages/3',
618+
];
619+
mockedRequests.push(mockBatchRequest(messageIds));
620+
const message = {
621+
token: 'a',
622+
android: {
623+
ttl: 3600,
624+
},
625+
};
626+
const arrayLike = new CustomArray();
627+
arrayLike.push(message);
628+
arrayLike.push(message);
629+
arrayLike.push(message);
630+
// Explicitly patch the constructor so that down compiling to ES5 doesn't affect the test.
631+
// See https://github.com/firebase/firebase-admin-node/issues/566#issuecomment-501974238
632+
// for more context.
633+
arrayLike.constructor = CustomArray;
634+
635+
return messaging.sendAll(arrayLike)
636+
.then((response: BatchResponse) => {
637+
expect(response.successCount).to.equal(3);
638+
expect(response.failureCount).to.equal(0);
639+
response.responses.forEach((resp, idx) => {
640+
expect(resp.success).to.be.true;
641+
expect(resp.messageId).to.equal(messageIds[idx]);
642+
expect(resp.error).to.be.undefined;
643+
});
644+
});
645+
});
646+
611647
it('should be fulfilled with a BatchResponse given valid messages in dryRun mode', () => {
612648
const messageIds = [
613649
'projects/projec_id/messages/1',

0 commit comments

Comments
 (0)