websockets: remodeled API to support 63 bit frame sizes

curl_ws_recv() now receives data to fill up the provided buffer, but can
return a partial fragment. The function now also get a pointer to a
curl_ws_frame struct with metadata that also mentions the offset and
total size of the fragment (of which you might be receiving a smaller
piece). This way, large incoming fragments will be "streamed" to the
application. When the curl_ws_frame struct field 'bytesleft' is 0, the
final fragment piece has been delivered.

curl_ws_recv() was also adjusted to work with a buffer size smaller than
the fragment size. (Possibly needless to say as the fragment size can
now be 63 bit large).

curl_ws_send() now supports sending a piece of a fragment, in a
streaming manner, in addition to sending the entire fragment in a single
call if it is small enough. To send a huge fragment, curl_ws_send() can
be used to send it in many small calls by first telling libcurl about
the total expected fragment size, and then send the payload in N number
of separate invokes and libcurl will stream those over the wire.

The struct curl_ws_meta() returns is now called 'curl_ws_frame' and it
has been extended with two new fields: *offset* and *bytesleft*. To help
describe the passed on data chunk when a fragment is delivered in many
smaller pieces.

The documentation has been updated accordingly.

Closes #9636
This commit is contained in:
Daniel Stenberg 2022-10-03 17:40:02 +02:00
parent 83de62babc
commit e3f335148a
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
12 changed files with 325 additions and 172 deletions

View file

@ -29,19 +29,21 @@ curl_ws_meta - meta data WebSocket information
.nf
#include <curl/easy.h>
struct curl_ws_metadata {
int age; /* zero */
int recvflags; /* See the CURLWS_* defines */
struct curl_ws_frame {
int age; /* zero */
int flags; /* See the CURLWS_* defines */
curl_off_t offset; /* the offset of this data into the frame */
curl_off_t bytesleft; /* number of pending bytes left of the payload */
};
struct curl_ws_metadata *curl_ws_meta(CURL *curl);
struct curl_ws_frame *curl_ws_meta(CURL *curl);
.fi
.SH DESCRIPTION
This function call is EXPERIMENTAL.
When the write callback (\fICURLOPT_WRITEFUNCTION(3)\fP) is invoked on
received WebSocket traffic, \fIcurl_ws_meta(3)\fP can be called from within
the callback to provide additional information about the data.
the callback to provide additional information about the current frame.
This function only works from within the callback, and only when receiving
WebSocket data.
@ -54,9 +56,30 @@ to the callback by libcurl itself, applications that want to use
.SH "struct fields"
.IP age
This field specify the age of this struct. It is always zero for now.
.IP recvflags
This is a bitmask with the exact same meaning as the \fBrecvflags\fP
documented for \fIcurl_ws_recv(3)\fP.
.IP flags
This is a bitmask with individual bits set that describes the WebSocket
data. See the list below.
.IP offset
When this frame is a continuation of fragment data already delivered, this is
the offset into the final fragment where this piece belongs.
.IP bytesleft
If this is not a complete fragment, the \fIbytesleft\fP field informs about
how many additional bytes are expected to arrive before this fragment is
complete.
.SH FLAGS
.IP CURLWS_TEXT
The buffer contains text data. Note that this makes a difference to WebSocket
but libcurl itself will not make any verification of the content or
precautions that you actually receive valid UTF-8 content.
.IP CURLWS_BINARY
This is binary data.
.IP CURLWS_CONT
This is not the final fragment of the message, it implies that there will be
another fragment coming as part of the same message.
.IP CURLWS_CLOSE
This transfer is now closed.
.IP CURLWS_PING
This as an incoming ping message, that expects a pong response.
.SH EXAMPLE
.nf
@ -70,9 +93,9 @@ static size_t writecb(unsigned char *buffer,
size_t size, size_t nitems, void *p)
{
struct customdata *c = (struct customdata *)p;
struct curl_ws_metadata *m = curl_ws_meta(c->easy);
struct curl_ws_frame *m = curl_ws_meta(c->easy);
/* m->recvflags tells us about the traffic */
/* m->flags tells us about the traffic */
}
{
@ -86,10 +109,10 @@ static size_t writecb(unsigned char *buffer,
.SH AVAILABILITY
Added in 7.86.0.
.SH RETURN VALUE
This function returns a pointer to a metadata struct with information that is
valid for this specific callback invocation. If it cannot return this
information, or if the function is called in the wrong context, it returns
NULL.
This function returns a pointer to a \fIcurl_ws_frame\fP struct with
information that is valid for this specific callback invocation. If it cannot
return this information, or if the function is called in the wrong context, it
returns NULL.
.SH "SEE ALSO"
.BR curl_easy_setopt "(3), "
.BR curl_easy_getinfo "(3), "

View file

@ -30,28 +30,22 @@ curl_ws_recv - receive WebSocket data
#include <curl/easy.h>
CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
size_t *recv, unsigned int *flags);
size_t *recv, struct curl_ws_frame **meta);
.fi
.SH DESCRIPTION
This function call is EXPERIMENTAL.
Retrieves as much as possible of a received WebSocket data fragment into the
\fBbuffer\fP, but not more than \fBbuflen\fP bytes. The provide
\fIflags\fP argument gets bits set to help characterize the fragment.
.SH FLAGS
.IP CURLWS_TEXT
The buffer contains text data. Note that this makes a difference to WebSocket
but libcurl itself will not make any verification of the content or
precautions that you actually receive valid UTF-8 content.
.IP CURLWS_BINARY
This is binary data.
.IP CURLWS_CONT
This is not the final fragment of the message, it implies that there will be
another fragment coming as part of the same message.
.IP CURLWS_CLOSE
This transfer is now closed.
.IP CURLWS_PING
This as an incoming ping message, that expects a pong response.
\fBbuffer\fP, but not more than \fBbuflen\fP bytes. \fIrecv\fP is set to the
number of bytes actually stored.
If there is more fragment data to deliver than what fits in the provided
\fIbuffer\fP, libcurl returns a full buffer and the application needs to call
this function again to continue draining the buffer.
The \fImeta\fP pointer gets set to point to a \fIstruct curl_ws_frame\fP that
contains information about the received data. See the \fIcurl_ws_meta(3)\fP
for details on that struct.
.SH EXAMPLE
.nf

View file

@ -24,18 +24,31 @@
.\"
.TH curl_ws_send 3 "12 Jun 2022" "libcurl 7.85.0" "libcurl Manual"
.SH NAME
curl_ws_send - receive WebSocket data
curl_ws_send - send WebSocket data
.SH SYNOPSIS
.nf
#include <curl/easy.h>
CURLcode curl_ws_send(CURL *curl, const void *buffer, size_t buflen,
size_t *sent, unsigned int flags);
size_t *sent, curl_off_t framesize,
unsigned int flags);
.fi
.SH DESCRIPTION
This function call is EXPERIMENTAL.
Send the specific message fragment over the established WebSocket connection.
Send the specific message fragment over an established WebSocket
connection. The \fIbuffer\fP holds the data to send and it is \fIbuflen\fP
number of payload bytes in that memory area.
\fIsent\fP is returned as the number of payload bytes actually sent.
To send a (huge) fragment using multiple calls with partial content per
invoke, set the \fICURLWS_OFFSET\fP bit and the \fIframesize\fP argument as
the total expected size for the first part, then set the \fICURLWS_OFFSET\fP
with a zero \fItotalsize\fP for the following parts.
If not sending a partial fragment or if this is raw mode, \fIframsize\fP
should be set to zero.
If \fBCURLWS_RAW_MODE\fP is enabled in \fICURLOPT_WS_OPTIONS(3)\fP, the
\fBflags\fP argument should be set to 0.
@ -47,8 +60,6 @@ but libcurl itself will not make any verification of the content or
precautions that you actually send valid UTF-8 content.
.IP CURLWS_BINARY
This is binary data.
.IP CURLWS_NOCOMPRESS
No-op if theres no compression anyway.
.IP CURLWS_CONT
This is not the final fragment of the message, which implies that there will
be another fragment coming as part of the same message where this bit is not
@ -59,6 +70,12 @@ Close this transfer.
This as a ping.
.IP CURLWS_PONG
This as a pong.
.IP CURLWS_OFFSET
The provided data is only a partial fragment and there will be more in a
following call to \fIcurl_ws_send()\fP. When sending only a piece of the
fragment like this, the \fIframesize\fP must be provided with the total
expected frame size in the first call and it needs to be zero in subsequent
calls.
.SH EXAMPLE
.nf

View file

@ -1111,7 +1111,7 @@ CURLWARNING 7.66.0
CURLWS_BINARY 7.86.0
CURLWS_CLOSE 7.86.0
CURLWS_CONT 7.86.0
CURLWS_NOCOMPRESS 7.86.0
CURLWS_OFFSET 7.86.0
CURLWS_PING 7.86.0
CURLWS_PONG 7.86.0
CURLWS_RAW_MODE 7.86.0