Skip to content

Commit

Permalink
Added dedicated error for payloads that are too large
Browse files Browse the repository at this point in the history
  • Loading branch information
dimitribouniol committed Dec 20, 2024
1 parent c18ac34 commit 22d0b12
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 1 deletion.
20 changes: 20 additions & 0 deletions Sources/WebPush/Errors/MessageTooLargeError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// MessageTooLargeError.swift
// swift-webpush
//
// Created by Dimitri Bouniol on 2024-12-13.
// Copyright © 2024 Mochi Development, Inc. All rights reserved.
//

import Foundation

/// The message was too large, and could not be delivered to the push service.
///
/// - SeeAlso: ``WebPushManager/maximumMessageSize``
public struct MessageTooLargeError: LocalizedError, Hashable {
public init() {}

public var errorDescription: String? {
"The message was too large, and could not be delivered to the push service."
}
}
4 changes: 3 additions & 1 deletion Sources/WebPush/WebPushManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,9 @@ public actor WebPushManager: Sendable {
switch response.status {
case .created: break
case .notFound, .gone: throw BadSubscriberError()
// TODO: 413 payload too large - log.error and throw error
case .payloadTooLarge:
logger.error("The encrypted payload was too large and was rejected by the push service.")
throw MessageTooLargeError()
// TODO: 429 too many requests, 500 internal server error, 503 server shutting down - check config and perform a retry after a delay?
default: throw HTTPError(response: response)
}
Expand Down
29 changes: 29 additions & 0 deletions Tests/WebPushTests/WebPushManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,35 @@ struct WebPushManagerTests {
}
}

@Test func sendExtraLargeMessageFails() async throws {
await confirmation { requestWasMade in
let vapidConfiguration = VAPID.Configuration.makeTesting()

let subscriberPrivateKey = P256.KeyAgreement.PrivateKey(compactRepresentable: false)
var authenticationSecret: [UInt8] = Array(repeating: 0, count: 16)
for index in authenticationSecret.indices { authenticationSecret[index] = .random(in: .min ... .max) }

let subscriber = Subscriber(
endpoint: URL(string: "https://example.com/subscriber")!,
userAgentKeyMaterial: UserAgentKeyMaterial(publicKey: subscriberPrivateKey.publicKey, authenticationSecret: Data(authenticationSecret)),
vapidKeyID: vapidConfiguration.primaryKey!.id
)

let manager = WebPushManager(
vapidConfiguration: vapidConfiguration,
backgroundActivityLogger: Logger(label: "WebPushManagerTests", factory: { PrintLogHandler(label: $0, metadataProvider: $1) }),
executor: .httpClient(MockHTTPClient({ request in
requestWasMade()
return HTTPClientResponse(status: .payloadTooLarge)
}))
)

await #expect(throws: MessageTooLargeError()) {
try await manager.send(data: Array(repeating: 0, count: 3994), to: subscriber)
}
}
}

@Test func sendMessageToNotFoundPushServerError() async throws {
await confirmation { requestWasMade in
let vapidConfiguration = VAPID.Configuration.mockedConfiguration
Expand Down

0 comments on commit 22d0b12

Please sign in to comment.