From: Ethan Wilkes Date: Thu, 27 Feb 2025 22:21:28 +0000 (-0600) Subject: ws: corrected curlws_cont to reflect its documented purpose X-Git-Tag: curl-8_13_0~240 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fa3d1e7d43bf0e4f589aeae737;p=thirdparty%2Fcurl.git ws: corrected curlws_cont to reflect its documented purpose Verified in test 2311 Closes #16512 --- diff --git a/lib/ws.c b/lib/ws.c index 2ce0b48455..369a10d3cd 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -168,6 +168,7 @@ static void ws_dec_reset(struct ws_decoder *dec) dec->payload_len = 0; dec->head_len = dec->head_total = 0; dec->state = WS_DEC_INIT; + dec->fin_bit = TRUE; } static void ws_dec_init(struct ws_decoder *dec) @@ -187,6 +188,8 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, dec->head[0] = *inbuf; Curl_bufq_skip(inraw, 1); + dec->fin_bit = (dec->head[0] & WSBIT_FIN) ? TRUE : FALSE; + if(!ws_frame_rsv_supported(dec->head[0])) { failf(data, "WS: unknown reserved bit in frame header: %x", dec->head[0] & WSBIT_RSV_MASK); @@ -370,11 +373,20 @@ static void update_meta(struct websocket *ws, curl_off_t payload_len, size_t cur_len) { + curl_off_t bytesleft = (payload_len - payload_offset - cur_len); + ws->frame.age = frame_age; ws->frame.flags = frame_flags; ws->frame.offset = payload_offset; ws->frame.len = cur_len; - ws->frame.bytesleft = (payload_len - payload_offset - cur_len); + ws->frame.bytesleft = bytesleft; + + if(!ws->dec.fin_bit || bytesleft > 0) { + ws->frame.flags |= CURLWS_CONT; + } + else { + ws->frame.flags &= ~CURLWS_CONT; + } } /* WebSockets decoding client writer */ diff --git a/lib/ws.h b/lib/ws.h index c96bccab9f..47bb96bb44 100644 --- a/lib/ws.h +++ b/lib/ws.h @@ -43,6 +43,7 @@ struct ws_decoder { unsigned char head[10]; int head_len, head_total; enum ws_dec_state state; + bool fin_bit; }; /* a client-side WS frame encoder, generating frame headers and diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 546d0bd8b4..04ac6b5a59 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -257,7 +257,7 @@ test2100 \ test2200 test2201 test2202 test2203 test2204 test2205 \ \ test2300 test2301 test2302 test2303 test2304 test2305 test2306 test2307 \ -test2308 test2309 test2310 \ +test2308 test2309 test2310 test2311 \ \ test2400 test2401 test2402 test2403 test2404 test2405 test2406 \ \ diff --git a/tests/data/test2311 b/tests/data/test2311 new file mode 100644 index 0000000000..8928b8a118 --- /dev/null +++ b/tests/data/test2311 @@ -0,0 +1,59 @@ + + + +WebSockets + + + +# +# Sends three 4097 bytes TEXT frames, as one single message + + +HTTP/1.1 101 Switching to WebSockets +Server: test-server/fake +Upgrade: websocket +Connection: Upgrade +Something: else +Sec-WebSocket-Accept: HkPsVga7+8LuxM4RGQ5p9tZHeYs= + +%hex[%01%7e%10%01]hex%%repeat[256 x helothisisdaniel]% +%hex[%01%7e%10%01]hex%%repeat[256 x helothisisdaniel]% +%hex[%81%7e%10%01]hex%%repeat[256 x helothisisdaniel]% + +# allow upgrade + +upgrade + + + +# +# Client-side + +# require debug for the forced CURL_ENTROPY + +Debug +ws + + +http + + +WebSocket curl_ws_recv() loop reading three larger frames + + +lib%TESTNUMBER + + +ws://%HOSTIP:%HTTPPORT/%TESTNUMBER %LOGDIR/save%TESTNUMBER + + + +# + + +%repeat[256 x helothisisdaniel]% +%repeat[256 x helothisisdaniel]% +%repeat[256 x helothisisdaniel]% + + + diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index 12cdeb6aea..97b9df73b5 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -74,6 +74,7 @@ LIBTESTPROGS = libauthretry libntlmconnect libprereq \ lib1960 lib1964 \ lib1970 lib1971 lib1972 lib1973 lib1974 lib1975 lib1977 \ lib2301 lib2302 lib2304 lib2305 lib2306 lib2308 lib2309 lib2310 \ + lib2311 \ lib2402 lib2404 lib2405 \ lib2502 \ lib3010 lib3025 lib3026 lib3027 \ @@ -703,6 +704,9 @@ lib2309_LDADD = $(TESTUTIL_LIBS) lib2310_SOURCES = lib2310.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE) $(MULTIBYTE) lib2310_LDADD = $(TESTUTIL_LIBS) +lib2311_SOURCES = lib2311.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE) $(MULTIBYTE) +lib2311_LDADD = $(TESTUTIL_LIBS) + lib2402_SOURCES = lib2402.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib2402_LDADD = $(TESTUTIL_LIBS) diff --git a/tests/libtest/lib2311.c b/tests/libtest/lib2311.c new file mode 100644 index 0000000000..675423d6a2 --- /dev/null +++ b/tests/libtest/lib2311.c @@ -0,0 +1,115 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "test.h" +#include "testtrace.h" +#include "memdebug.h" + +#ifndef CURL_DISABLE_WEBSOCKETS + +/* just close the connection */ +static void websocket_close(CURL *curl) +{ + size_t sent; + CURLcode result = + curl_ws_send(curl, "", 0, &sent, 0, CURLWS_CLOSE); + fprintf(stderr, + "ws: curl_ws_send returned %d, sent %d\n", result, (int)sent); +} + +static void websocket(CURL *curl) +{ + char buffer[256]; + const struct curl_ws_frame *meta; + size_t nread; + size_t i = 0; + FILE *save = fopen(libtest_arg2, FOPEN_WRITETEXT); + if(!save) + return; + + /* Three 4097-bytes frames are expected, 12291 bytes */ + while(true) { + CURLcode result = + curl_ws_recv(curl, buffer, sizeof(buffer), &nread, &meta); + if(result) { + if(result == CURLE_AGAIN) + /* crude busy-loop */ + continue; + fclose(save); + printf("curl_ws_recv returned %d\n", result); + return; + } + printf("%d: nread %zu Age %d Flags %x " + "Offset %" CURL_FORMAT_CURL_OFF_T " " + "Bytesleft %" CURL_FORMAT_CURL_OFF_T "\n", + (int)i, + nread, meta->age, meta->flags, meta->offset, meta->bytesleft); + i += meta->len; + fwrite(buffer, 1, nread, save); + /* exit condition */ + if(!(meta->flags & CURLWS_CONT)) { + break; + } + } + fclose(save); + + websocket_close(curl); + + assert(i == 12291); +} + +CURLcode test(char *URL) +{ + CURL *curl; + CURLcode res = CURLE_OK; + + global_init(CURL_GLOBAL_ALL); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, URL); + + /* use the callback style */ + curl_easy_setopt(curl, CURLOPT_USERAGENT, "websocket/2304"); + libtest_debug_config.nohex = 1; + libtest_debug_config.tracetime = 1; + curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &libtest_debug_config); + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, libtest_debug_cb); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */ + res = curl_easy_perform(curl); + fprintf(stderr, "curl_easy_perform() returned %d\n", res); + if(res == CURLE_OK) + websocket(curl); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + return res; +} + +#else +NO_SUPPORT_BUILT_IN +#endif