async-http-client: Cannot cancel inside delegate
To cancel an in-progress request, the user can call cancel() on the HTTPTask.
However, if they are doing streaming there is no way to cancel from inside their HTTPResponseDelegate.
public protocol HTTPResponseDelegate : class {
associatedtype Response
func didTransmitRequestBody()
func didReceiveHead(_ head: HTTPResponseHead)
func didReceivePart(_ buffer: ByteBuffer)
func didReceiveError(_ error: Error)
func didFinishRequest() throws -> Response
}
Functions like didReceivePart() do not have access to the task, so they can’t call cancel(). The delegate can’t store a reference to the task because the delegate is passed in to execute() (for example), which happens before the task is created.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 24 (12 by maintainers)
Happy to PR this, shouldn’t be too hard (famous last words).
I’ve implemented a prototype, it is indeed potentially dangerous. If one returns
.continuewhen.endorerrorare received, future will never be completed. Only option is to complete promise with some kind ofReturnedNextOnEnderror if we receive.continueon.end, but this is a runtime error, which is not great in already runtime-error-filled environment of async frameworks (with didReceiveEnd you just cannot not provide a result)… One solution here would be to drop promise fromHTTPHandlerbut in this case users of the library will have to provide a promise, which is not great (you cannot just create a promise, you need access to anEventLoop). And it could make code that handles redirects to a different URL origin more complex (I’m not yet sure about that, will test it today). Having state is also not super convenient with this type of functional consumer. With delegate its easier to re-use due to state encapsulation, but in case of a function, you have to have state be captured by a closure, and this is messy, imho, especially if you have more than one variable to capture. One can create a class for that state, but by this point you already have a class, so why not just conform to a protocol and use class as a delegate instead. I will experiment with dropping promise fromHTTPHandlerto see if it has potential. Also, I will experiment with having only one function in a protocol (similar to RxSwift observer).I’ll implement it today-tomorrow and will play with failure modes to see what we can do here