-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Websockets: a bug in curl_ws_recv #10438
Comments
That would explain my confused comment in #10347. That failing assert may have been pointing to this. |
I don't think that is correct. The |
Clearly, I haven't puzzled my way through the websockets code sufficiently yet... |
BTW, this really shows we should improve the test suite for WebSocket. It's too "bare bones" right now. |
@bagder What is a frame? |
I mean frame as in a WebSocket frame as defined in RFC 6455.
If they are indeed a single 20K WebSocket frame, then the two data pieces are indeed just two parts of the same frame. The libcurl API can provide the frame to the application in two parts though.
Bytesleft should then be |
Suppose I pass 1K buffer to curl_ws_recv. If Bytesleft is initally 4K, then I will get 4K data in 4 curl_ws_recv calls, bytesLeft will decreased to 0 (4-1-1-1-1) and game over. If I call curl_ws_recv 5th time for some reason then new 4K fragment will be read, accidently decoded and bytesLeft will have random value. |
Sorry, I don't follow. I understand that there is an issue here, I just think that the fix needs to be different than what you proposed above.
Why? When Lines 431 to 446 in ead2b2d
|
Oops sorry you're right, in the case of bytesleft == 0 ws_decode block is not called, datalen is assigned to 0 and we get an endless loop.
I believe that my bad English does not allow me to convince you. :-) |
Hence wsp->frame.bytesleft should contain bytes left in the frame to be delivered to a caller. Initially (right after ws_decode call) it is 20K (full frame size), 1K of these 20K are memcopied to the 1K user's buffer, at the same time bytesleft is reduced by 1K, so the user gets back 1K in *nread and 19K in meta.bytesleft after 1st curl_ws_recv call. Next call gets a user 1K in *nread and 18K in bytesleft and so on. |
Actually you aren't right, the condition is "!wsp->frame.bytesleft" so when bytesleft == 0 then the condition is true and the block is reached. But it makes little difference, in any case when bytesleft is initially set to 4K, the code fails. By the way, in struct websocket (ws.h) there is a member oleft:
which is never used. In my example that 4K should be assigned to this wsp->oleft. |
The fix is bigger than what has been discussed here. I am working on it. |
#10447 has a proposed fix, and also a new test case (2305) to verify this kind of scenario. |
I have tested this fix (on my test suite), it works great, thank you! |
+ remove 'oleft' from the struct + deal with "overflow data" in a separate dynbuf Reported-by: Mike Duglas Fixes curl#10438 Closes curl#10447
Description
Current curl_ws_recv implementation (ws.c) works properly if a message (frame) size is less than 16K and buffer size is equal or greater than a message size, so curl_ws_recv reads entire message in one call. In other cases it returns incomplete data or hangs.
To make it working, wsp->frame.bytesleft needs to be initialized not with oleft ("bytes yet to come (for this frame)"), but with datalen + oleft ("total payload size"):
I tested modified code, it works as expected.
I expected the following
curl/libcurl version
curl 7.87.1-DEV (i386-pc-win32) libcurl/7.87.1-DEV Schannel WinIDN
operating system
Windows 11
The text was updated successfully, but these errors were encountered: