Open
Description
If users don't use the streaming interface (which is likely), then AHC will just buffer everything into memory without any limit. Worse, not only is the default "no limit" but we can't even set a limit. Even worse is that the docs don't mention this issue.
This means that every server can DOS an AHC client that uses the non-streaming interface by just sending data as fast as it can.
This is execute
(which is used by get
/post
/...):
/// Execute arbitrary HTTP request using specified URL.
///
/// - parameters:
/// - request: HTTP request to execute.
/// - deadline: Point in time by which the request must complete.
/// - logger: The logger to use for this request.
public func execute(request: Request, deadline: NIODeadline? = nil, logger: Logger) -> EventLoopFuture<Response> {
let accumulator = ResponseAccumulator(request: request)
return self.execute(request: request, delegate: accumulator, deadline: deadline, logger: logger).futureResult
}
and ResponseAccumulator
is
public func didReceiveBodyPart(task: HTTPClient.Task<Response>, _ part: ByteBuffer) -> EventLoopFuture<Void> {
switch self.state {
case .idle:
preconditionFailure("no head received before body")
case .head(let head):
self.state = .body(head, part)
case .body(let head, var body):
var part = part
body.writeBuffer(&part)
self.state = .body(head, body)
case .end:
preconditionFailure("request already processed")
case .error:
break
}
return task.eventLoop.makeSucceededFuture(())
}
so it just buffers into body
without any limits :(.