coder / websocket

Minimal and idiomatic WebSocket library for Go
ISC License
3.83k stars 288 forks source link

Add protection against concurrent Readers #391

Open oslook opened 1 year ago

oslook commented 1 year ago

During my use of the library(server and client both v1.8.7), the server occasionally receives the following prompt,

failed to get reader: received header with unexpected rsv bits set: false:true:true

which seems to be related to this part of the code.

write.go L300:

    c.writeHeader.rsv1 = false
    if flate && (opcode == opText || opcode == opBinary) {
        c.writeHeader.rsv1 = true
    }

Could you please confirm if it is necessary to add the following code here?

    c.writeHeader.rsv1 = false
    c.writeHeader.rsv2 = false
    c.writeHeader.rsv3 = false
vendion commented 1 year ago

I'm getting something slightly similar using the same version: failed to get reader: received header with unexpected rsv bits set: true:true:true

soypat commented 1 year ago

Me too- I've checked with wireshark and the websocket frame is OK, it's just being parsed wrong on nhooyr/websocket's side.

nhooyr commented 12 months ago

That's quite concerning that all three of you guys are seeing that... I'd suggest disabling compression though it'll be disabled by default in the next release.

I'll go through the code again to see if I can find the bug. The autobahn compression tests pass fine under the race detector so I'm surprised to see a bug like this.

nhooyr commented 12 months ago

@soypat If possible, can you share the frames you checked with wireshark? Maybe I can replay them with the library and thus reproduce. That would help immensely in debugging.

nhooyr commented 11 months ago

There's been enough changes for v1.8.8 that whatever this was is likely fixed. Compression in particular is disabled by default now and I recommend keeping it that way. Let me know if you see it again once v1.8.8 is released.

nhooyr commented 11 months ago

Nvm I was able to reproduce, see https://github.com/nhooyr/websocket/commit/249edb209389a1b6fd3b1f79de78417982077284

nhooyr commented 11 months ago

Were you guys using the library through a proxy?

nhooyr commented 11 months ago

Nvm, that bug was from my proxy not working correctly. Fixed now.

nhooyr commented 11 months ago

Actually nvm, this is probably caused by #355 so I'll close after fixing that.

nhooyr commented 11 months ago

Done so closing.

maggie44 commented 10 months ago

I still see this error on occasions. Seen it today on the latest release: failed to get reader: received header with unexpected rsv bits set: true:true:false"

Whenever I see it, it so far has always been the result of me having two readers open at the same time. It states in the library that Only one Reader may be open at a time, but sometimes an error in my code where I have two readers causes the issue.

Not sure if the error message could be clearer for diagnosis. Adding this quick comment here in case anyone comes across this issue and finds this thread.

nhooyr commented 10 months ago

Ah yea that would do it. I'll add a link to this thread in that error message.

Could also add some protection here perhaps without much performance cost.

maggie44 commented 10 months ago

I wonder if there is also a way to have two readers, where both (or multiple) receive the same message. This would be helpful for me in a number of scenarios. Or maybe when initiating one reader it closes the other. I am already passing the ws connection around, but ideally wouldn't have to pass around the reader, and could just close one and open it up elsewhere.

nhooyr commented 10 months ago

There shouldn't be any scenario where you want to do a concurrent read on the connection. There should only ever be one goroutine reading from the connection. Can you clarify why you feel you need multiple readers or even why you're passing the reader around like that? Perhaps an example in code?

maggie44 commented 10 months ago

On the multiple reader, makes sense. Closing and reopening or passing around, I read in a loop but some messages call a series of functions and those functions need to take over the connection and receive all future messages after their call. For those functions I need to either stop the loop and move the reader down or relay all messages through a channel on through another connection.

Hard to fully explain, maybe at some point it will hit me how best to do it. Didn’t want to hijack the thread though, will think on it.

GoldenSheep402 commented 2 months ago

The problem still appear in my project?