apple / swift-nio

Event-driven network application framework for high performance protocol servers & clients, non-blocking.
https://swiftpackageindex.com/apple/swift-nio/documentation
Apache License 2.0
7.85k stars 633 forks source link

NIOTypedWebSocketServerUpgrader hangs when connection is opened and closed without sending any data #2742

Open adam-fowler opened 3 weeks ago

adam-fowler commented 3 weeks ago

Expected behavior

Given a server setup with WebSocket upgrade using NIOTypedWebSocketServerUpgrader and allowRemoteHalfClosure set to true on the childChannel. If I open a connection to this server and close it immediately without sending any data the negotiation future returned from configureUpgradableHTTPServerPipeline on the server should throw a connection closed error.

Actual behavior

The negotiation future never completes leaving the child channel dangling.

If allowRemoteHalfClosure is set to false on the server then the negotiation future throws a inappropriateOperationForState error which isn't ideal but at least I can catch that the client has closed the connection

Steps to reproduce

  1. Using the NIOWebSocketServer.swift example
  2. Add .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) before bind call in run
  3. Use a client to connect and close connection immediately
    try await ClientBootstrap(group: MultiThreadedEventLoopGroup.singleton)
    .connect(host: "localhost", port: 8888)
    .flatMap { $0.close() }
    .get()
  4. Note that negotiation future never completes

SwiftNIO version/commit hash

e5a216ba89deba84356bad9d4c2eab99071c745b

System & version information

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4) Target: x86_64-apple-macosx14.0

Lukasa commented 2 weeks ago

Yeah, this is a really good catch. We'd welcome a fix into the server upgrader here to make it aware of half closure.