Buy commercial curl support from WolfSSL. We help you work
out your issues, debug your libcurl applications, use the API, port to new
platforms, add new features and more. With a team lead by the curl founder
himself.
RE: curl websockets
- Contemporary messages sorted: [ by date ] [ by thread ] [ by subject ] [ by author ] [ by messages with attachments ]
From: Dmitry Karpov via curl-library <curl-library_at_cool.haxx.se>
Date: Tue, 6 Jul 2021 21:07:17 +0000
> 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 <felipe_at_felipegasper.com>
Sent: Saturday, July 3, 2021 3:44 AM
To: libcurl development <curl-library_at_cool.haxx.se>
Cc: Dmitry Karpov <dkarpov_at_roku.com>
Subject: Re: curl websockets
> On Jul 2, 2021, at 9:07 PM, Dmitry Karpov via curl-library <curl-library_at_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
Received on 2021-07-06
Date: Tue, 6 Jul 2021 21:07:17 +0000
> 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 <felipe_at_felipegasper.com>
Sent: Saturday, July 3, 2021 3:44 AM
To: libcurl development <curl-library_at_cool.haxx.se>
Cc: Dmitry Karpov <dkarpov_at_roku.com>
Subject: Re: curl websockets
> On Jul 2, 2021, at 9:07 PM, Dmitry Karpov via curl-library <curl-library_at_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
Received on 2021-07-06