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;
|
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.
|
* Sends data over the connected socket.
|
||||||
*
|
*
|
||||||
|
@ -30,6 +30,10 @@
|
|||||||
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
|
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
|
||||||
size_t buflen, ssize_t *n);
|
size_t buflen, ssize_t *n);
|
||||||
|
|
||||||
|
#ifdef USE_WEBSOCKETS
|
||||||
|
CURLcode Curl_connect_only_attach(struct Curl_easy *data);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CURLDEBUG
|
#ifdef CURLDEBUG
|
||||||
CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
|
CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
|
||||||
#endif
|
#endif
|
||||||
|
@ -212,10 +212,6 @@ struct HTTP {
|
|||||||
HTTPSEND_BODY /* sending body */
|
HTTPSEND_BODY /* sending body */
|
||||||
} sending;
|
} sending;
|
||||||
|
|
||||||
#ifdef USE_WEBSOCKETS
|
|
||||||
struct websocket ws;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CURL_DISABLE_HTTP
|
#ifndef CURL_DISABLE_HTTP
|
||||||
void *h2_ctx; /* HTTP/2 implementation context */
|
void *h2_ctx; /* HTTP/2 implementation context */
|
||||||
void *h3_ctx; /* HTTP/3 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) {
|
if(type & CLIENTWRITE_BODY) {
|
||||||
#ifdef USE_WEBSOCKETS
|
#ifdef USE_WEBSOCKETS
|
||||||
if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) {
|
if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) {
|
||||||
struct HTTP *ws = data->req.p.http;
|
|
||||||
writebody = Curl_ws_writecb;
|
writebody = Curl_ws_writecb;
|
||||||
ws->ws.data = data;
|
writebody_ptr = data;
|
||||||
writebody_ptr = ws;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -1030,7 +1030,7 @@ struct connectdata {
|
|||||||
struct mqtt_conn mqtt;
|
struct mqtt_conn mqtt;
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_WEBSOCKETS
|
#ifdef USE_WEBSOCKETS
|
||||||
struct ws_conn ws;
|
struct websocket *ws;
|
||||||
#endif
|
#endif
|
||||||
} proto;
|
} proto;
|
||||||
|
|
||||||
|
56
lib/ws.h
56
lib/ws.h
@ -33,28 +33,44 @@
|
|||||||
#define REQTYPE struct dynbuf
|
#define REQTYPE struct dynbuf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* this is the largest single fragment size we support */
|
/* a client-side WS frame decoder, parsing frame headers and
|
||||||
#define MAX_WS_SIZE 65535
|
* payload, keeping track of current position and stats */
|
||||||
|
enum ws_dec_state {
|
||||||
/* part of 'struct HTTP', when used in the 'struct SingleRequest' in the
|
WS_DEC_INIT,
|
||||||
Curl_easy struct */
|
WS_DEC_HEAD,
|
||||||
struct websocket {
|
WS_DEC_PAYLOAD
|
||||||
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 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ws_conn {
|
struct ws_decoder {
|
||||||
struct dynbuf early; /* data already read when switching to ws */
|
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);
|
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;
|
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 */
|
/* just close the connection */
|
||||||
static void websocket_close(CURL *curl)
|
static void websocket_close(CURL *curl)
|
||||||
{
|
{
|
||||||
@ -82,6 +96,7 @@ static void websocket(CURL *curl)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
fprintf(stderr, "ws: websocket() starts\n");
|
fprintf(stderr, "ws: websocket() starts\n");
|
||||||
do {
|
do {
|
||||||
|
recv_any(curl);
|
||||||
fprintf(stderr, "Send ping\n");
|
fprintf(stderr, "Send ping\n");
|
||||||
if(ping(curl, "foobar"))
|
if(ping(curl, "foobar"))
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user