summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2023-02-08 14:24:49 +0100
committerDaniel Stenberg <daniel@haxx.se>2023-02-10 08:28:58 +0100
commit2e2e3d16c5c77596a789f6e6a1b30be7fc17360c (patch)
treeee4d94b897e1b3381c61df7fad4c0d6a334dac98 /lib
parent2aed8e179f0675f5b17d75f3904ea7d905f4336a (diff)
downloadcurl-2e2e3d16c5c77596a789f6e6a1b30be7fc17360c.tar.gz
ws: fix recv of larger frames
+ remove 'oleft' from the struct + deal with "overflow data" in a separate dynbuf Reported-by: Mike Duglas Fixes #10438 Closes #10447
Diffstat (limited to 'lib')
-rw-r--r--lib/c-hyper.c2
-rw-r--r--lib/easy.c2
-rw-r--r--lib/http.c2
-rw-r--r--lib/urldata.h3
-rw-r--r--lib/ws.c53
-rw-r--r--lib/ws.h13
6 files changed, 52 insertions, 23 deletions
diff --git a/lib/c-hyper.c b/lib/c-hyper.c
index 74856d9a5..9c7632d35 100644
--- a/lib/c-hyper.c
+++ b/lib/c-hyper.c
@@ -485,7 +485,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
if(k->upgr101 == UPGR101_WS) {
if(http_status == 101) {
/* verify the response */
- result = Curl_ws_accept(data);
+ result = Curl_ws_accept(data, NULL, 0);
if(result)
return result;
}
diff --git a/lib/easy.c b/lib/easy.c
index 2cd1ada4e..db03026c9 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -1228,7 +1228,7 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
return result;
*n = (size_t)n1;
-
+ infof(data, "reached %s:%d", __FILE__, __LINE__);
return CURLE_OK;
}
diff --git a/lib/http.c b/lib/http.c
index 3eba1a375..cb585e72f 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -3909,7 +3909,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
#ifdef USE_WEBSOCKETS
else if(k->upgr101 == UPGR101_WS) {
/* verify the response */
- result = Curl_ws_accept(data);
+ result = Curl_ws_accept(data, k->str, *nread);
if(result)
return result;
k->header = FALSE; /* no more header to parse! */
diff --git a/lib/urldata.h b/lib/urldata.h
index 19c5ac7e3..0e2c04a04 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1015,6 +1015,9 @@ struct connectdata {
#ifndef CURL_DISABLE_MQTT
struct mqtt_conn mqtt;
#endif
+#ifdef USE_WEBSOCKETS
+ struct ws_conn ws;
+#endif
} proto;
struct connectbundle *bundle; /* The bundle we are member of */
diff --git a/lib/ws.c b/lib/ws.c
index fc1237aca..0fc5e56ae 100644
--- a/lib/ws.c
+++ b/lib/ws.c
@@ -115,12 +115,18 @@ CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req)
return result;
}
-CURLcode Curl_ws_accept(struct Curl_easy *data)
+/*
+ * 'nread' is number of bytes of websocket data already in the buffer at
+ * 'mem'.
+ */
+CURLcode Curl_ws_accept(struct Curl_easy *data,
+ const char *mem, size_t nread)
{
struct SingleRequest *k = &data->req;
struct HTTP *ws = data->req.p.http;
struct connectdata *conn = data->conn;
struct websocket *wsp = &data->req.p.http->ws;
+ struct ws_conn *wsc = &conn->proto.ws;
CURLcode result;
/* Verify the Sec-WebSocket-Accept response.
@@ -149,13 +155,21 @@ CURLcode Curl_ws_accept(struct Curl_easy *data)
infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x",
ws->ws.mask[0], ws->ws.mask[1], ws->ws.mask[2], ws->ws.mask[3]);
+ Curl_dyn_init(&wsc->early, data->set.buffer_size);
+ if(nread) {
+ result = Curl_dyn_addn(&wsc->early, mem, nread);
+ if(result)
+ return result;
+ infof(data, "%zu bytes websocket payload", nread);
+ wsp->stillb = Curl_dyn_ptr(&wsc->early);
+ wsp->stillblen = Curl_dyn_len(&wsc->early);
+ }
k->upgr101 = UPGR101_RECEIVED;
if(data->set.connect_only)
/* switch off non-blocking sockets */
(void)curlx_nonblock(conn->sock[FIRSTSOCKET], FALSE);
- wsp->oleft = 0;
return result;
}
@@ -246,6 +260,9 @@ static CURLcode ws_decode(struct Curl_easy *data,
infof(data, "WS: received OPCODE PONG");
*flags |= CURLWS_PONG;
break;
+ default:
+ failf(data, "WS: unknown opcode: %x", opcode);
+ return CURLE_RECV_ERROR;
}
if(inbuf[1] & WSBIT_MASK) {
@@ -419,15 +436,16 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
data->set.buffer_size, &n);
if(result)
return result;
- if(!n)
+ if(!n) {
/* connection closed */
+ infof(data, "connection expectedly closed?");
return CURLE_GOT_NOTHING;
+ }
wsp->stillb = data->state.buffer;
wsp->stillblen = n;
}
- infof(data, "WS: got %u websocket bytes to decode",
- (int)wsp->stillblen);
+ infof(data, "WS: %u bytes left to decode", (int)wsp->stillblen);
if(!wsp->frame.bytesleft) {
size_t headlen;
curl_off_t oleft;
@@ -439,6 +457,11 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
break;
else if(result)
return result;
+ if(datalen > buflen) {
+ size_t diff = datalen - buflen;
+ datalen = buflen;
+ oleft += diff;
+ }
wsp->stillb += headlen;
wsp->stillblen -= headlen;
wsp->frame.offset = 0;
@@ -450,7 +473,13 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
datalen = wsp->frame.bytesleft;
if(datalen > wsp->stillblen)
datalen = wsp->stillblen;
+ if(datalen > buflen)
+ datalen = buflen;
+
+ wsp->frame.offset += wsp->frame.len;
+ wsp->frame.bytesleft -= datalen;
}
+ wsp->frame.len = datalen;
/* auto-respond to PINGs */
if((wsp->frame.flags & CURLWS_PING) && !wsp->frame.bytesleft) {
@@ -469,24 +498,17 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
wsp->stillblen -= nsent;
}
else if(datalen) {
- /* there is payload for the user */
- if(datalen > buflen)
- datalen = buflen;
/* copy the payload to the user buffer */
memcpy(buffer, wsp->stillb, datalen);
*nread = datalen;
done = TRUE;
- /* update buffer and frame info */
- wsp->frame.offset += datalen;
- if(wsp->frame.bytesleft)
- wsp->frame.bytesleft -= datalen;
- DEBUGASSERT(datalen <= wsp->stillblen);
wsp->stillblen -= datalen;
if(wsp->stillblen)
wsp->stillb += datalen;
- else
+ else {
wsp->stillb = NULL;
+ }
}
}
*metap = &wsp->frame;
@@ -724,8 +746,11 @@ CURLcode Curl_ws_disconnect(struct Curl_easy *data,
struct connectdata *conn,
bool dead_connection)
{
+ struct ws_conn *wsc = &conn->proto.ws;
(void)data;
(void)dead_connection;
+ Curl_dyn_free(&wsc->early);
+
/* make sure this is non-blocking to avoid getting stuck in shutdown */
(void)curlx_nonblock(conn->sock[FIRSTSOCKET], TRUE);
return CURLE_OK;
diff --git a/lib/ws.h b/lib/ws.h
index 9775a04b9..176dda470 100644
--- a/lib/ws.h
+++ b/lib/ws.h
@@ -46,27 +46,28 @@ struct websocket {
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 */
- curl_off_t oleft; /* outstanding number of payload bytes left from the
- server */
size_t stillblen; /* number of bytes left in the buffer to deliver in
the next curl_ws_recv() call */
- char *stillb; /* the stillblen pending bytes are here */
+ 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 */
};
-CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req);
-CURLcode Curl_ws_accept(struct Curl_easy *data);
+struct ws_conn {
+ struct dynbuf early; /* data already read when switching to ws */
+};
+CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req);
+CURLcode Curl_ws_accept(struct Curl_easy *data, const char *mem, size_t len);
size_t Curl_ws_writecb(char *buffer, size_t size, size_t nitems, void *userp);
void Curl_ws_done(struct Curl_easy *data);
CURLcode Curl_ws_disconnect(struct Curl_easy *data,
struct connectdata *conn,
bool dead_connection);
-
#else
#define Curl_ws_request(x,y) CURLE_OK
#define Curl_ws_done(x) Curl_nop_stmt
+#define Curl_ws_free(x) Curl_nop_stmt
#endif
#endif /* HEADER_CURL_WS_H */