> Curl will have to allocate a buffer for each frame’s data anyway; maybe just 
> give that buffer to the callback? Then allow the caller either to assume 
> ownership of it, or free the buffer after the callback is done.

In general, WS client needs to get message buffers, which should contain fully 
assembled messages from one or multiple fragments, rather than individual 
frames for each fragment.
So there should be some frame processor and message assembler that does that 
job and provides full message payloads to WS client code with rather individual 
frames.

And because client code can have its own ways of allocating memory, then WS 
client, in my opinion, should provide an option to provide a buffer or data 
writing callback (I provided both in my WS client implementation) telling where 
to write assembled message payloads. 

In this case, WS client will need to allocate internal buffers only for WS 
frame headers, and it can write frame payloads directly into the message buffer 
provided by client code (or call a data writing callback).
This approach can help to minimize memory usage by WS client if the client code 
wants to allocate memory for message payloads itself.

On the other hand, it should also be possible to tell WS client to allocate 
some internal buffer of certain size (controlled by WS option) for assembled 
message and pass a pointer to it in some kind of "OnMessageReceived" callback 
when message is fully received and assembled. 

This buffer can be made static to minimize allocations/deallocations for quite 
typical use cases when client code just needs to read and process the received 
message data and discard it afterwards, and it can be made a client code 
responsibility to copy data from the internal buffer if the client code needs 
this data to live beyond the "OnMessageReceived" callback.


> 1015 is an interesting one … I guess it’s for a STARTTLS-type workflow where 
> the TLS rides on WebSocket?

This is what is often called "secure WebSocket" - WebSocket over TLS 
(essentially upgrade to WS from HTTPs) and TLS handshake errors seem to 
represent very important connection closure reasons, so the WS protocol decided 
to distinguish it via a special closure status code. The closure reason text is 
supposed to provide additional information (wrong cipher etc.) which should 
help to debug errors like that.

> Regarding connection closures, WebSocket seems to follow SCTP’s model; that 
> may be useful prior art to consult.

Yes, WS connection closures are similar to SCTP’s model. They both have similar 
stages and should be closed gracefully.
I think it is a good idea to consult SCTP’s model, but in my opinion, WS  
protocol describes pretty well the closure procedure and all the corner cases, 
so it would be probably easier just to use WS protocol spec for WS client side 
implementation.
At the end, WS client needs to implement WS closures very close to what the 
protocol prescribes.

Thanks,
Dmitry Karpov

-----Original Message-----
From: Felipe Gasper <fel...@felipegasper.com> 
Sent: Saturday, July 3, 2021 3:44 AM
To: libcurl development <curl-library@cool.haxx.se>
Cc: Dmitry Karpov <dkar...@roku.com>
Subject: Re: curl websockets


> On Jul 2, 2021, at 9:07 PM, Dmitry Karpov via curl-library 
> <curl-library@cool.haxx.se> wrote:
> 
>> could libcurl wait for all the fragmented messages to arrive, then concat 
>> them and serve the completed message to the calling application?
> 
> I don't think it is possible in all the cases. WebSocket text/data messages 
> can have 64-bit length, so it is just not possible to assemble large messages.
> I implemented WebSocket protocol in some C++ curl-based client and I used the 
> following approach:
> 
> 1. Notify client that some WS not control message (i.e. text/data) has 
> arrived.
> 2. In the notification callback, Client either provides a buffer to store the 
> message (can be useful for short messages) or data writing callback to store 
> large messages (where data concatenation is not feasible).
>     - If provided buffer is too small to hold the message, then we need to 
> handle it as WebSocket protocol prescribes - close WS connection with 1009 
> 'Buffer too small' error code.
> 
> 3. I also provided a special callback for incoming control messages (i.e. 
> Ping) while large data messages are being received, so client can handle 
> multiple messages (one large data and multiple control messages at the same 
> time) at the same time.

Curl will have to allocate a buffer for each frame’s data anyway; maybe just 
give that buffer to the callback? Then allow the caller either to assume 
ownership of it, or free the buffer after the callback is done.

> WebSocket protocol is very specific about how and when WS connection should 
> handle certain errors, and which status codes should be used in different 
> connection closure cases, so sometimes some specific transport errors (like 
> Tls handshake errors) should be explicitly handled and reported as WS 
> connection closures with specific status codes (i.e. 1015 'TLS handshake 
> failure').

1015 is an interesting one … I guess it’s for a STARTTLS-type workflow where 
the TLS rides on WebSocket?

Regarding connection closures, WebSocket seems to follow SCTP’s model; that may 
be useful prior art to consult.

-F

-------------------------------------------------------------------
Unsubscribe: https://cool.haxx.se/list/listinfo/curl-library
Etiquette:   https://curl.se/mail/etiquette.html

Reply via email to