wslay
wslay copied to clipboard
Incorrect Opcode for continuation frame?
I am using the wslay library in a code that uses socket timeouts on a 'recv' requests.
My WS Servers sends my two frames over the network:
- frame1-> final:0, opcode:text, data_len:1024
- frame2-> final:1, opcode:0, data_len: 100
The wslay_frame_recv() functions returns to me 3 frames (probably because of the recv timeouts) as follows:
- frame1-> final:0, opcode:text, data_len:532
- frame2-> final:0, opcode:text, data_len:492
- frame3-> final:1, opcode:0, data_len:100
As per my understanding, in the frame that I received, frame 2 should have opcode 0 instead of 'text'. Because from the application's point of view, if this is a fragment on the network or fragmented by the WS library. Is this understanding correct?
It is not fragmented by WS library at least. Because the wslay_frame_recv() returns only available payload in the received buffer, application may have to call wslay_frame_recv() several times. If that happens, opcode is populated with the its frame's opcode (in this case 'text') in the subsequent return values. I think it is not a problem for the application because websocket RFC says intermediary may coalesces/fragment a frame any time and no intermixed frame is not allowed. So you can just check the first opcode and read through the frame until the all payload of fin frame is received.
If that happens, opcode is populated with the its frame's opcode (in this case 'text') in the subsequent return values.
Would it not be better to set the opcode of these intermediate wlay_frame_recv() calls to 0 (CONTINUATION_FRAME)?
When I run the current implementation through a WebSockets conformance test suite then it fails. Because as per the RFC: "A fragmented message consists of a single frame with the FIN bit clear and an opcode other than 0, followed by zero or more frames with the FIN bit clear and the opcode set to 0, and terminated by a single frame with the FIN bit set and an opcode of 0"
So you are right when you say that it is not fragmented by the WS library, but the impression that the application (test suite) gets is that the wslay_frame_recv() returned a frame fragment that is not in accordance with the specification.
This depends on the point of view. The wslay_frame_recv() is a library API and is not a function that returns the actual WebSocket frame. That said, I'm open to set opcode to 0. But other people may be confused because those payload does not actually come from continuation frame.
If you want to check the reception of each frame, there is event based API and following callback functions are available:
struct wslay_event_on_frame_recv_start_arg {
/* fin bit; 1 for final frame, or 0. */
uint8_t fin;
/* reserved bits: rsv = (RSV1 << 2) | (RSV2 << 1) | RSV3 */
uint8_t rsv;
/* opcode of the frame */
uint8_t opcode;
/* payload length of ths frame */
uint64_t payload_length;
};
/*
* Callback function invoked by wslay_event_recv() when a new frame
* starts to be received. This callback function is only invoked once
* for each frame.
*/
typedef void (*wslay_event_on_frame_recv_start_callback)
(wslay_event_context_ptr ctx,
const struct wslay_event_on_frame_recv_start_arg *arg, void *user_data);
struct wslay_event_on_frame_recv_chunk_arg {
/* chunk of payload data */
const uint8_t *data;
/* length of data */
size_t data_length;
};
/*
* Callback function invoked by wslay_event_recv() when a chunk of
* frame payload is received.
*/
typedef void (*wslay_event_on_frame_recv_chunk_callback)
(wslay_event_context_ptr ctx,
const struct wslay_event_on_frame_recv_chunk_arg *arg, void *user_data);
/*
* Callback function invoked by wslay_event_recv() when a frame is
* completely received.
*/
typedef void (*wslay_event_on_frame_recv_end_callback)
(wslay_event_context_ptr ctx, void *user_data);