Skip to content

Commit adba736

Browse files
authored
Add Channel Handler Removed. (#63)
* Fail if we dont get a proper response * add channel handlers removed. * Typo in test. * Addressing comments. * Update to use a new Response Struct * Update to use correct errors. * Update to use new decoding API from swift nio * Consistent internal naming of errors. * Update swift nio package version. * Adding comment.
1 parent 1746cd2 commit adba736

File tree

4 files changed

+52
-4
lines changed

4 files changed

+52
-4
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ let package = Package(
88
.library(name: "APNSwift", targets: ["APNSwift"]),
99
],
1010
dependencies: [
11-
.package(url: "https://github.com/apple/swift-nio.git", .upToNextMajor(from: "2.8.0")),
11+
.package(url: "https://github.com/apple/swift-nio.git", .upToNextMajor(from: "2.10.1")),
1212
.package(url: "https://github.com/apple/swift-nio-ssl.git", .upToNextMajor(from: "2.4.0")),
1313
.package(url: "https://github.com/apple/swift-nio-http2.git", .upToNextMajor(from: "1.6.0")),
1414
],

Sources/APNSwift/APNSwiftErrors.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414

1515
import Foundation
1616

17+
/// An error for when the connections ends, but we still have promises in our queue.
18+
public struct NoResponseReceivedBeforeConnectionEnded: Error, Equatable {}
19+
/// An error where a request was made to Apple, but the response body buffer was nil
20+
public struct NoResponseBodyFromApple: Error, Equatable {}
21+
1722
/// This is an enum that provides the possible responses from Apple
1823
public struct APNSwiftError: Equatable {
1924
public enum ResponseError: Error, Equatable {
@@ -59,6 +64,7 @@ public struct APNSwiftError: Equatable {
5964
return rawValue
6065
}
6166
}
67+
6268
public enum SigningError: Error {
6369
case invalidAuthKey
6470
case invalidASN1

Sources/APNSwift/APNSwiftStreamHandler.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,15 @@ final class APNSwiftStreamHandler: ChannelDuplexHandler {
3333
let res = unwrapInboundIn(data)
3434
guard let current = self.queue.popLast() else { return }
3535
guard res.header.status == .ok else {
36-
if var buffer = res.byteBuffer, let data = buffer.readData(length: buffer.readableBytes), let error = try? JSONDecoder().decode(APNSwiftError.ResponseStruct.self, from: data) {
36+
guard let buffer = res.byteBuffer else {
37+
return current.responsePromise.fail(NoResponseBodyFromApple())
38+
}
39+
do {
40+
let error = try JSONDecoder().decode(APNSwiftError.ResponseStruct.self, from: buffer)
3741
return current.responsePromise.fail(APNSwiftError.ResponseError.badRequest(error.reason))
42+
} catch {
43+
return current.responsePromise.fail(error)
3844
}
39-
return
4045
}
4146
current.responsePromise.succeed(Void())
4247
}
@@ -46,4 +51,10 @@ final class APNSwiftStreamHandler: ChannelDuplexHandler {
4651
queue.insert(input, at: 0)
4752
context.write(wrapOutboundOut(input.request), promise: promise)
4853
}
54+
55+
func handlerRemoved(context: ChannelHandlerContext) {
56+
while let context = queue.popLast() {
57+
context.responsePromise.fail(NoResponseReceivedBeforeConnectionEnded())
58+
}
59+
}
4960
}

Tests/APNSwiftTests/APNSwiftRequestTests.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,40 @@ final class APNSwiftRequestTests: XCTestCase {
219219
XCTFail("response is: \(error), should be: \(expected)")
220220
}
221221
default:
222-
XCTFail("response should not success")
222+
XCTFail("response should not succeed")
223223
}
224224
}
225+
XCTAssertNoThrow(XCTAssertNotNil(try channel.readOutbound()))
226+
XCTAssertNoThrow(XCTAssertTrue(try channel.finish().isClean))
227+
228+
}
229+
230+
func testErrorsFromAPNSLeak() throws {
231+
let encodedData = try JSONEncoder().encode(["test string"])
232+
let allocator = ByteBufferAllocator()
233+
var errorBuffer = allocator.buffer(capacity: encodedData.count)
234+
errorBuffer.writeBytes(encodedData)
235+
236+
let channel = EmbeddedChannel(handler: APNSwiftStreamHandler())
237+
let responsePromise = channel.eventLoop.makePromise(of: Void.self)
238+
let context = APNSwiftRequestContext(
239+
request: errorBuffer,
240+
responsePromise: responsePromise
241+
)
242+
try channel.writeOutbound(context)
243+
responsePromise.futureResult.whenComplete { temp in
244+
switch temp {
245+
case .failure(let error):
246+
let error = error as! NoResponseReceivedBeforeConnectionEnded
247+
let expected = NoResponseReceivedBeforeConnectionEnded()
248+
if error != expected {
249+
XCTFail("response is: \(error), should be: \(expected)")
250+
}
251+
default:
252+
XCTFail("response should not succeed")
253+
}
254+
}
255+
XCTAssertNoThrow(XCTAssertNotNil(try channel.readOutbound()))
225256
XCTAssertNoThrow(XCTAssertTrue(try channel.finish().isClean))
226257
}
227258

0 commit comments

Comments
 (0)