Skip to content

Fix broadcast error handling and URLSession session injection - #263

Merged
kylebrowning merged 2 commits into
mainfrom
fix/client-error-paths
Oct 8, 2026
Merged

kylebrowning merged 2 commits into
mainfrom
fix/client-error-paths

Conversation

@kylebrowning

@kylebrowning kylebrowning commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Bug fixes surfaced by a codebase review, each with a regression test.

Fixes

  • APNSURLSessionClient.sendBroadcast ignored the injected session. It called URLSession.shared while send used self.session, so a proxy, delegate, or mock session applied to device pushes but not broadcasts. It also omitted the user-agent header the device-push path sets.
  • APNSClient.sendBroadcast lost the status code on undecodable error bodies. It used a strict try on body collection and decoding, so a 503 with an HTML body surfaced as a DecodingError instead of APNSError(responseStatus: 503, reason: nil). send was already lenient here; broadcast now matches.
  • URLSession request URLs are guarded with a new APNSUrlSessionClientError.invalidURL instead of force-unwrapped. Modern Foundation percent-encodes most bad input rather than returning nil, so this is defensive only and has no test.

Tests

  • testSendControlsNotification: the controls send path had zero coverage.
  • testSendBroadcast_forced503NonJSONBody… and …forced500EmptyBody… for the NIO broadcast error path.
  • testSendAlert_forced500EmptyBody… and …forced503NonJSONBody… for the URLSession client, which had no error-body tests.
  • testSendBroadcast_usesInjectedSession uses a URLProtocol mock that only the injected session sees.

APNSTestServer.setResponseOverride now also applies to POST /4/broadcasts/apps/{bundleID} to support the broadcast tests.

Full suite: 160 tests, 0 failures.

- APNSURLSessionClient.sendBroadcast used URLSession.shared instead of the
  injected session, and omitted the user-agent header the device-push path sets.
- APNSClient.sendBroadcast threw a raw decoding error on empty or non-JSON error
  bodies instead of a typed APNSError, unlike send.
- JWT kid and iss are now JSON-escaped so a stray quote in configuration cannot
  produce a malformed token.
- URLSession request URLs are guarded instead of force-unwrapped.
- APNSTestServer response overrides now apply to the broadcast send endpoint.

Adds regression tests for each, plus the previously untested controls send path.
Apple team and key identifiers are alphanumeric, so the escaping had no
real-world effect.
@kylebrowning
kylebrowning merged commit 22b40f6 into main Oct 8, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant