diff options
author | Daniel Stenberg <daniel@haxx.se> | 2023-01-13 13:34:18 +0100 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2023-01-13 15:35:50 +0100 |
commit | abae4e31a2db1ae5c552b485ddd12ee4673398ee (patch) | |
tree | 7b8ac961c5e78ad9a0188d4c46cc091a504debba | |
parent | 521da2dbd3d010a14be14b427c0630f4e91662d8 (diff) | |
download | curl-abae4e31a2db1ae5c552b485ddd12ee4673398ee.tar.gz |
ws: fix autoping handling
Reported-by: Alexey Savchuk
Fixes #10289
Closes #10294
-rw-r--r-- | lib/ws.c | 73 |
1 files changed, 43 insertions, 30 deletions
@@ -183,12 +183,12 @@ static void ws_decode_shift(struct Curl_easy *data, size_t spent) /* ws_decode() decodes a binary frame into structured WebSocket data, - wpkt - the incoming raw data. If NULL, work on the already buffered data. - ilen - the size of the provided data, perhaps too little, perhaps too much - out - stored pointed to extracted data + data - the transfer + inbuf - incoming raw data. If NULL, work on the already buffered data. + inlen - size of the provided data, perhaps too little, perhaps too much + headlen - stored length of the frame header olen - stored length of the extracted data oleft - number of unread bytes pending to that belongs to this frame - more - if there is more data in there flags - stored bitmask about the frame Returns CURLE_AGAIN if there is only a partial frame in the buffer. Then it @@ -339,9 +339,6 @@ size_t Curl_ws_writecb(char *buffer, size_t size /* 1 */, result = ws_decode(data, wsbuf, buflen, &headlen, &write_len, &fb_left, &recvflags); - consumed += headlen; - wsbuf += headlen; - buflen -= headlen; if(result == CURLE_AGAIN) /* insufficient amount of data, keep it for later. * we pretend to have written all since we have a copy */ @@ -350,6 +347,10 @@ size_t Curl_ws_writecb(char *buffer, size_t size /* 1 */, infof(data, "WS: decode error %d", (int)result); return nitems - 1; } + consumed += headlen; + wsbuf += headlen; + buflen -= headlen; + /* New frame. store details about the frame to be reachable with curl_ws_meta() from within the write callback */ ws->ws.frame.age = 0; @@ -392,7 +393,6 @@ size_t Curl_ws_writecb(char *buffer, size_t size /* 1 */, return nitems; } - CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer, size_t buflen, size_t *nread, struct curl_ws_frame **metap) @@ -409,7 +409,7 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer, return result; while(!done) { - size_t write_len; + size_t datalen; unsigned int recvflags; if(!wsp->stillblen) { @@ -433,7 +433,7 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer, curl_off_t oleft; /* detect new frame */ result = ws_decode(data, (unsigned char *)wsp->stillb, wsp->stillblen, - &headlen, &write_len, &oleft, &recvflags); + &headlen, &datalen, &oleft, &recvflags); if(result == CURLE_AGAIN) /* a packet fragment only */ break; @@ -447,38 +447,45 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer, } else { /* existing frame, remaining payload handling */ - write_len = wsp->frame.bytesleft; - if(write_len > wsp->stillblen) - write_len = wsp->stillblen; + datalen = wsp->frame.bytesleft; + if(datalen > wsp->stillblen) + datalen = wsp->stillblen; } /* auto-respond to PINGs */ if((wsp->frame.flags & CURLWS_PING) && !wsp->frame.bytesleft) { - infof(data, "WS: auto-respond to PING with a PONG"); + size_t nsent = 0; + infof(data, "WS: auto-respond to PING with a PONG, %zu bytes payload", + datalen); /* send back the exact same content as a PONG */ - result = curl_ws_send(data, wsp->stillb, write_len, - &write_len, 0, CURLWS_PONG); + result = curl_ws_send(data, wsp->stillb, datalen, &nsent, 0, + CURLWS_PONG); if(result) return result; + infof(data, "WS: bytesleft %zu datalen %zu", + wsp->frame.bytesleft, datalen); + /* we handled the data part of the PING, advance over that */ + wsp->stillb += nsent; + wsp->stillblen -= nsent; } - else if(write_len || !wsp->frame.bytesleft) { - if(write_len > buflen) - write_len = buflen; + 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, write_len); - *nread = write_len; + memcpy(buffer, wsp->stillb, datalen); + *nread = datalen; done = TRUE; - } - if(write_len) { + /* update buffer and frame info */ - wsp->frame.offset += write_len; - DEBUGASSERT(wsp->frame.bytesleft >= (curl_off_t)write_len); + wsp->frame.offset += datalen; + DEBUGASSERT(wsp->frame.bytesleft >= (curl_off_t)datalen); if(wsp->frame.bytesleft) - wsp->frame.bytesleft -= write_len; - DEBUGASSERT(write_len <= wsp->stillblen); - wsp->stillblen -= write_len; + wsp->frame.bytesleft -= datalen; + DEBUGASSERT(datalen <= wsp->stillblen); + wsp->stillblen -= datalen; if(wsp->stillblen) - wsp->stillb += write_len; + wsp->stillb += datalen; else wsp->stillb = NULL; } @@ -686,8 +693,14 @@ CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer, infof(data, "WS: wanted to send %zu bytes, sent %zu bytes", headlen + buflen, written); - *sent = written; + if(!result) { + /* the *sent number only counts "payload", excluding the header */ + if((size_t)written > headlen) + *sent = written - headlen; + else + *sent = 0; + } return result; } |