From 452203341d6e97b8f52f9a886046d9fdb96346a9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 27 Mar 2017 12:14:57 +0200 Subject: pause: handle mixed types of data when paused When receiving chunked encoded data with trailers, and the write callback returns PAUSE, there might be both body and header to store to resend on unpause. Previously libcurl returned error for that case. Added test case 1540 to verify. Reported-by: Stephen Toub Fixes #1354 Closes #1357 --- tests/data/Makefile.inc | 1 + tests/data/test1540 | 64 ++++++++++++++++++++++++ tests/libtest/Makefile.inc | 5 ++ tests/libtest/lib1540.c | 121 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 tests/data/test1540 create mode 100644 tests/libtest/lib1540.c (limited to 'tests') diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc index edeb9000c..e908c12b9 100644 --- a/tests/data/Makefile.inc +++ b/tests/data/Makefile.inc @@ -163,6 +163,7 @@ test1520 \ \ test1525 test1526 test1527 test1528 test1529 test1530 test1531 test1532 \ test1533 test1534 test1535 test1536 \ +test1540 \ \ test1600 test1601 test1602 test1603 test1604 test1605 \ \ diff --git a/tests/data/test1540 b/tests/data/test1540 new file mode 100644 index 000000000..3277f550f --- /dev/null +++ b/tests/data/test1540 @@ -0,0 +1,64 @@ + + + +HTTP +HTTP GET +CURLPAUSE_RECV +chunked encoding +Trailer: + + + +# Server-side + + +HTTP/1.1 200 OK swsclose +Transfer-Encoding: chunked +Trailer: MyCoolTrailerHeader + +4 +data +5 +d474 + +0 +MyCoolTrailerHeader: amazingtrailer + + + +HTTP/1.1 200 OK swsclose +Transfer-Encoding: chunked +Trailer: MyCoolTrailerHeader + +Got 4 bytes but pausing! +datad474 +MyCoolTrailerHeader: amazingtrailer + + + +# Client-side + + +http + + +lib1540 + + +chunked with trailers and pausing the receive + + +http://%HOSTIP:%HTTPPORT/1540 + + + +# Verify data after the test has been "shot" + + +GET /1540 HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Accept: */* + + + + diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index 66628aae1..d85956d8b 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -25,6 +25,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \ lib1520 \ lib1525 lib1526 lib1527 lib1528 lib1529 lib1530 lib1531 lib1532 lib1533 \ lib1534 lib1535 lib1536 \ + lib1540 \ lib1900 \ lib2033 @@ -412,6 +413,10 @@ lib1536_SOURCES = lib1536.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib1536_LDADD = $(TESTUTIL_LIBS) lib1536_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1536 +lib1540_SOURCES = lib1540.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib1540_LDADD = $(TESTUTIL_LIBS) +lib1540_CPPFLAGS = $(AM_CPPFLAGS) + lib1900_SOURCES = lib1900.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib1900_LDADD = $(TESTUTIL_LIBS) lib1900_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/tests/libtest/lib1540.c b/tests/libtest/lib1540.c new file mode 100644 index 000000000..86ba085ca --- /dev/null +++ b/tests/libtest/lib1540.c @@ -0,0 +1,121 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, 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.haxx.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. + * + ***************************************************************************/ +#include "test.h" + +#include "testutil.h" +#include "warnless.h" +#include "memdebug.h" + +struct transfer_status { + CURL *easy; + int halted; + int counter; /* count write callback invokes */ + int please; /* number of times xferinfo is called while halted */ +}; + +static int please_continue(void *userp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow) +{ + struct transfer_status *st = (struct transfer_status *)userp; + (void)dltotal; + (void)dlnow; + (void)ultotal; + (void)ulnow; + if(st->halted) { + st->please++; + if(st->please == 2) { + /* waited enough, unpause! */ + curl_easy_pause(st->easy, CURLPAUSE_CONT); + } + } + fprintf(stderr, "xferinfo: paused %d\n", st->halted); + return 0; /* go on */ +} + +static size_t header_callback(void *ptr, size_t size, size_t nmemb, + void *userp) +{ + size_t len = size * nmemb; + (void)userp; + (void)fwrite(ptr, size, nmemb, stdout); + return len; +} + +static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userp) +{ + struct transfer_status *st = (struct transfer_status *)userp; + size_t len = size * nmemb; + st->counter++; + if(st->counter > 1) { + /* the first call puts us on pause, so subsequent calls are after + unpause */ + fwrite(ptr, size, nmemb, stdout); + return len; + } + printf("Got %d bytes but pausing!\n", (int)len); + st->halted = 1; + return CURL_WRITEFUNC_PAUSE; +} + +#define TEST_HANG_TIMEOUT 60 * 1000 + +int test(char *URL) +{ + CURL *curls = NULL; + int i = 0; + int res = 0; + struct transfer_status st; + + start_test_timing(); + + memset(&st, 0, sizeof(st)); + + global_init(CURL_GLOBAL_ALL); + + easy_init(curls); + st.easy = curls; /* to allow callbacks access */ + + easy_setopt(curls, CURLOPT_URL, URL); + easy_setopt(curls, CURLOPT_WRITEFUNCTION, write_callback); + easy_setopt(curls, CURLOPT_WRITEDATA, &st); + easy_setopt(curls, CURLOPT_HEADERFUNCTION, header_callback); + easy_setopt(curls, CURLOPT_HEADERDATA, &st); + + easy_setopt(curls, CURLOPT_XFERINFOFUNCTION, please_continue); + easy_setopt(curls, CURLOPT_XFERINFODATA, &st); + easy_setopt(curls, CURLOPT_NOPROGRESS, 0L); + + res = curl_easy_perform(curls); + +test_cleanup: + + curl_easy_cleanup(curls); + curl_global_cleanup(); + + if(res) + i = res; + + return i; /* return the final return code */ +} -- cgit v1.2.3