Skip to content

Commit

Permalink
Add Channel Handler Removed. (#63)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
kylebrowning authored Nov 26, 2019
1 parent 1746cd2 commit adba736
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let package = Package(
.library(name: "APNSwift", targets: ["APNSwift"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-nio.git", .upToNextMajor(from: "2.8.0")),
.package(url: "https://github.com/apple/swift-nio.git", .upToNextMajor(from: "2.10.1")),
.package(url: "https://github.com/apple/swift-nio-ssl.git", .upToNextMajor(from: "2.4.0")),
.package(url: "https://github.com/apple/swift-nio-http2.git", .upToNextMajor(from: "1.6.0")),
],
Expand Down
6 changes: 6 additions & 0 deletions Sources/APNSwift/APNSwiftErrors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

import Foundation

/// An error for when the connections ends, but we still have promises in our queue.
public struct NoResponseReceivedBeforeConnectionEnded: Error, Equatable {}
/// An error where a request was made to Apple, but the response body buffer was nil
public struct NoResponseBodyFromApple: Error, Equatable {}

/// This is an enum that provides the possible responses from Apple
public struct APNSwiftError: Equatable {
public enum ResponseError: Error, Equatable {
Expand Down Expand Up @@ -59,6 +64,7 @@ public struct APNSwiftError: Equatable {
return rawValue
}
}

public enum SigningError: Error {
case invalidAuthKey
case invalidASN1
Expand Down
15 changes: 13 additions & 2 deletions Sources/APNSwift/APNSwiftStreamHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ final class APNSwiftStreamHandler: ChannelDuplexHandler {
let res = unwrapInboundIn(data)
guard let current = self.queue.popLast() else { return }
guard res.header.status == .ok else {
if var buffer = res.byteBuffer, let data = buffer.readData(length: buffer.readableBytes), let error = try? JSONDecoder().decode(APNSwiftError.ResponseStruct.self, from: data) {
guard let buffer = res.byteBuffer else {
return current.responsePromise.fail(NoResponseBodyFromApple())
}
do {
let error = try JSONDecoder().decode(APNSwiftError.ResponseStruct.self, from: buffer)
return current.responsePromise.fail(APNSwiftError.ResponseError.badRequest(error.reason))
} catch {
return current.responsePromise.fail(error)
}
return
}
current.responsePromise.succeed(Void())
}
Expand All @@ -46,4 +51,10 @@ final class APNSwiftStreamHandler: ChannelDuplexHandler {
queue.insert(input, at: 0)
context.write(wrapOutboundOut(input.request), promise: promise)
}

func handlerRemoved(context: ChannelHandlerContext) {
while let context = queue.popLast() {
context.responsePromise.fail(NoResponseReceivedBeforeConnectionEnded())
}
}
}
33 changes: 32 additions & 1 deletion Tests/APNSwiftTests/APNSwiftRequestTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,40 @@ final class APNSwiftRequestTests: XCTestCase {
XCTFail("response is: \(error), should be: \(expected)")
}
default:
XCTFail("response should not success")
XCTFail("response should not succeed")
}
}
XCTAssertNoThrow(XCTAssertNotNil(try channel.readOutbound()))
XCTAssertNoThrow(XCTAssertTrue(try channel.finish().isClean))

}

func testErrorsFromAPNSLeak() throws {
let encodedData = try JSONEncoder().encode(["test string"])
let allocator = ByteBufferAllocator()
var errorBuffer = allocator.buffer(capacity: encodedData.count)
errorBuffer.writeBytes(encodedData)

let channel = EmbeddedChannel(handler: APNSwiftStreamHandler())
let responsePromise = channel.eventLoop.makePromise(of: Void.self)
let context = APNSwiftRequestContext(
request: errorBuffer,
responsePromise: responsePromise
)
try channel.writeOutbound(context)
responsePromise.futureResult.whenComplete { temp in
switch temp {
case .failure(let error):
let error = error as! NoResponseReceivedBeforeConnectionEnded
let expected = NoResponseReceivedBeforeConnectionEnded()
if error != expected {
XCTFail("response is: \(error), should be: \(expected)")
}
default:
XCTFail("response should not succeed")
}
}
XCTAssertNoThrow(XCTAssertNotNil(try channel.readOutbound()))
XCTAssertNoThrow(XCTAssertTrue(try channel.finish().isClean))
}

Expand Down

0 comments on commit adba736

Please sign in to comment.