mirror of
https://github.com/curl/curl.git
synced 2025-04-24 16:40:32 +08:00
Websocket en-/decoding
- state is fully kept at connection, since curl_ws_send() and curl_ws_rec() have lifetime beyond usual transfers - no more limit on frame sizes Reported-by: simplerobot on github Fixes #10962 Closes #10999
This commit is contained in:
parent
3f0b81c112
commit
930c00c259
20
lib/easy.c
20
lib/easy.c
@ -1223,6 +1223,26 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSOCKETS
|
||||
CURLcode Curl_connect_only_attach(struct Curl_easy *data)
|
||||
{
|
||||
curl_socket_t sfd;
|
||||
CURLcode result;
|
||||
struct connectdata *c = NULL;
|
||||
|
||||
result = easy_connection(data, &sfd, &c);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if(!data->conn)
|
||||
/* on first invoke, the transfer has been detached from the connection and
|
||||
needs to be reattached */
|
||||
Curl_attach_connection(data, c);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
#endif /* USE_WEBSOCKETS */
|
||||
|
||||
/*
|
||||
* Sends data over the connected socket.
|
||||
*
|
||||
|
@ -30,6 +30,10 @@
|
||||
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
|
||||
size_t buflen, ssize_t *n);
|
||||
|
||||
#ifdef USE_WEBSOCKETS
|
||||
CURLcode Curl_connect_only_attach(struct Curl_easy *data);
|
||||
#endif
|
||||
|
||||
#ifdef CURLDEBUG
|
||||
CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
|
||||
#endif
|
||||
|
@ -212,10 +212,6 @@ struct HTTP {
|
||||
HTTPSEND_BODY /* sending body */
|
||||
} sending;
|
||||
|
||||
#ifdef USE_WEBSOCKETS
|
||||
struct websocket ws;
|
||||
#endif
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
void *h2_ctx; /* HTTP/2 implementation context */
|
||||
void *h3_ctx; /* HTTP/3 implementation context */
|
||||
|
@ -271,10 +271,8 @@ static CURLcode chop_write(struct Curl_easy *data,
|
||||
if(type & CLIENTWRITE_BODY) {
|
||||
#ifdef USE_WEBSOCKETS
|
||||
if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) {
|
||||
struct HTTP *ws = data->req.p.http;
|
||||
writebody = Curl_ws_writecb;
|
||||
ws->ws.data = data;
|
||||
writebody_ptr = ws;
|
||||
writebody_ptr = data;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -1030,7 +1030,7 @@ struct connectdata {
|
||||
struct mqtt_conn mqtt;
|
||||
#endif
|
||||
#ifdef USE_WEBSOCKETS
|
||||
struct ws_conn ws;
|
||||
struct websocket *ws;
|
||||
#endif
|
||||
} proto;
|
||||
|
||||
|
56
lib/ws.h
56
lib/ws.h
@ -33,28 +33,44 @@
|
||||
#define REQTYPE struct dynbuf
|
||||
#endif
|
||||
|
||||
/* this is the largest single fragment size we support */
|
||||
#define MAX_WS_SIZE 65535
|
||||
|
||||
/* part of 'struct HTTP', when used in the 'struct SingleRequest' in the
|
||||
Curl_easy struct */
|
||||
struct websocket {
|
||||
bool contfragment; /* set TRUE if the previous fragment sent was not final */
|
||||
unsigned char mask[4]; /* 32 bit mask for this connection */
|
||||
struct Curl_easy *data; /* used for write callback handling */
|
||||
struct dynbuf buf;
|
||||
size_t usedbuf; /* number of leading bytes in 'buf' the most recent complete
|
||||
websocket frame uses */
|
||||
struct curl_ws_frame frame; /* the struct used for frame state */
|
||||
size_t stillblen; /* number of bytes left in the buffer to deliver in
|
||||
the next curl_ws_recv() call */
|
||||
const char *stillb; /* the stillblen pending bytes are here */
|
||||
curl_off_t sleft; /* outstanding number of payload bytes left to send */
|
||||
unsigned int xori; /* xor index */
|
||||
/* a client-side WS frame decoder, parsing frame headers and
|
||||
* payload, keeping track of current position and stats */
|
||||
enum ws_dec_state {
|
||||
WS_DEC_INIT,
|
||||
WS_DEC_HEAD,
|
||||
WS_DEC_PAYLOAD
|
||||
};
|
||||
|
||||
struct ws_conn {
|
||||
struct dynbuf early; /* data already read when switching to ws */
|
||||
struct ws_decoder {
|
||||
int frame_age; /* zero */
|
||||
int frame_flags; /* See the CURLWS_* defines */
|
||||
curl_off_t payload_offset; /* the offset parsing is at */
|
||||
curl_off_t payload_len;
|
||||
unsigned char head[10];
|
||||
int head_len, head_total;
|
||||
enum ws_dec_state state;
|
||||
};
|
||||
|
||||
/* a client-side WS frame encoder, generating frame headers and
|
||||
* converting payloads, tracking remaining data in current frame */
|
||||
struct ws_encoder {
|
||||
curl_off_t payload_len; /* payload length of current frame */
|
||||
curl_off_t payload_remain; /* remaining payload of current */
|
||||
unsigned int xori; /* xor index */
|
||||
unsigned char mask[4]; /* 32 bit mask for this connection */
|
||||
unsigned char firstbyte; /* first byte of frame we encode */
|
||||
bool contfragment; /* set TRUE if the previous fragment sent was not final */
|
||||
};
|
||||
|
||||
/* A websocket connection with en- and decoder that treat frames
|
||||
* and keep track of boundaries. */
|
||||
struct websocket {
|
||||
struct Curl_easy *data; /* used for write callback handling */
|
||||
struct ws_decoder dec; /* decode of we frames */
|
||||
struct ws_encoder enc; /* decode of we frames */
|
||||
struct bufq recvbuf; /* raw data from the server */
|
||||
struct bufq sendbuf; /* raw data to be sent to the server */
|
||||
struct curl_ws_frame frame; /* the current WS FRAME received */
|
||||
};
|
||||
|
||||
CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req);
|
||||
|
@ -67,6 +67,20 @@ static int recv_pong(CURL *curl, const char *exected_payload)
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
static int recv_any(CURL *curl)
|
||||
{
|
||||
size_t rlen;
|
||||
struct curl_ws_frame *meta;
|
||||
char buffer[256];
|
||||
CURLcode result = curl_ws_recv(curl, buffer, sizeof(buffer), &rlen, &meta);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
fprintf(stderr, "recv_any: got %u bytes rflags %x\n", (int)rlen,
|
||||
meta->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* just close the connection */
|
||||
static void websocket_close(CURL *curl)
|
||||
{
|
||||
@ -82,6 +96,7 @@ static void websocket(CURL *curl)
|
||||
int i = 0;
|
||||
fprintf(stderr, "ws: websocket() starts\n");
|
||||
do {
|
||||
recv_any(curl);
|
||||
fprintf(stderr, "Send ping\n");
|
||||
if(ping(curl, "foobar"))
|
||||
return;
|
||||
|
Loading…
x
Reference in New Issue
Block a user