Open
Description
We currently ignore the error code of the go away. I think if it is a protocol error we will never receive any further HTTP2Frame on the connection or any stream and need manually cancel all active streams. Maybe this is better handled at the nio http2 level but I'm not sure yet.
Reproducer:
func testGoAwayFromServerDoesntHangRequest() throws {
//try XCTSkipIf(true, "this currently hangs")
let bin = HTTPBin(.http2())
defer { XCTAssertNoThrow(try bin.shutdown()) }
let loggerFactor = StreamLogHandler.standardOutput(label:)
var bgLogger = Logger(label: "BG", factory: loggerFactor)
bgLogger.logLevel = .trace
let client = HTTPClient(
eventLoopGroupProvider: .createNew,
configuration: .init(certificateVerification: .none),
backgroundActivityLogger: bgLogger
)
defer { XCTAssertNoThrow(try client.syncShutdown()) }
var request = try HTTPClient.Request(url: bin.baseURL, method: .POST)
// add ~64 KB header
let headerValue = String(repeating: "0", count: 1024)
for headerID in 0..<64 {
request.headers.replaceOrAdd(name: "larg-header-\(headerID)", value: headerValue)
}
// non empty body is important to trigger this bug as we otherwise finish the request in a single flush
request.body = .byteBuffer(ByteBuffer(bytes: [0]))
var rqLogger = Logger(label: "RQ", factory: loggerFactor)
rqLogger.logLevel = .trace
XCTAssertThrows(try client.execute(request: request, deadline: .distantFuture, logger: rqLogger).wait())
}
Activity
Lukasa commentedon Jan 26, 2023
Whether streams will continue is dependent on the "last stream ID" in a GOAWAY.
dnadoba commentedon Jan 26, 2023
So I see this go away frame received on the client side:
I think the relevant RFC section is this:
However, the error code is protocol error and not no error.
Lukasa commentedon Jan 26, 2023
Yeah, this isn't graceful shutdown, it's definitely an error. But PROTOCOL_ERROR doesn't necessarily imply that the connection is lost, merely that a protocol error was committed. If the server wants us to stop talking, it needs to be more emphatic than this.