quic-go / webtransport-go

WebTransport implementation based on quic-go (https://datatracker.ietf.org/doc/draft-ietf-webtrans-http3/)
https://quic-go.net
MIT License
346 stars 55 forks source link

Readable streams never end #121

Closed achingbrain closed 8 months ago

achingbrain commented 8 months ago

Here is a repro: https://github.com/achingbrain/go-webtransport-readable-never-ends largely based on interop/main.go from this repo.

The details are in the readme, but running npm start starts a webtransport-go server that listens on a port, accepts incoming WebTransport sessions, waits for an incoming bidirectional stream to be opened and pipes the stream back to itself.

Some JavaScript is printed out that you can paste into https://codepen.io/pen/?editors=0012 and see it run.

It connects to the webtransport-go server, opens a bidirectional stream, writes a single message into the stream and closes the writable, then reads from the readable until it closes.

The output is:

"CLIENT create session"
"CLIENT wait for session"
"CLIENT session ready"
"CLIENT create bidi stream"
"CLIENT get writer"
"CLIENT wait for writer"
"CLIENT write"
"CLIENT close writer"
"CLIENT read from stream"
"CLIENT got from stream" // [object Object] 
{
  "done": false,
  "value": {
    "0": 0,
    "1": 1,
    "2": 2,
    "3": 3
  }
}
"CLIENT read from stream"

After the final "CLIENT read from stream", the readable is read from again and it should return { done: true } to signal it's ending but no further data is received.

The server end seems to see the stream finish so perhaps the FIN isn't being sent?

2024/03/10 15:02:13 SERVER incoming session
2024/03/10 15:02:13 SERVER wait for stream
2024/03/10 15:02:13 SERVER echo stream back to itself
2024/03/10 15:02:13 SERVER stream finished
marten-seemann commented 8 months ago

io.Copy doesn't close the stream (it takes an io.Writer, not an io.WriteCloser). You'll have to manually close the stream once io.Copy has returned.

achingbrain commented 8 months ago

Ah, thanks for taking a look. It all starts to work if the stream is explicitly closed by the server.