diff options
author | Patrick Monnerat <patrick@monnerat.net> | 2020-03-06 09:46:39 +0100 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2020-03-07 23:26:00 +0100 |
commit | 96972ec1c00a142e3859efc82a06b0b810527da2 (patch) | |
tree | b87cf6005d4815ee0ab7ff33f4e9d320e0d1cdad /tests/libtest | |
parent | 3dce9849be4f84df83ba342be24ce29f4fbe01d4 (diff) | |
download | curl-96972ec1c00a142e3859efc82a06b0b810527da2.tar.gz |
mime: latch last read callback status.
In case a read callback returns a status (pause, abort, eof,
error) instead of a byte count, drain the bytes read so far but
remember this status for further processing.
Takes care of not losing data when pausing, and properly resume a
paused mime structure when requested.
New tests 670-673 check unpausing cases, with easy or multi
interface and mime or form api.
Fixes #4813
Reported-by: MrdUkk on github
Diffstat (limited to 'tests/libtest')
-rw-r--r-- | tests/libtest/Makefile.inc | 17 | ||||
-rw-r--r-- | tests/libtest/lib643.c | 13 | ||||
-rw-r--r-- | tests/libtest/lib670.c | 259 |
3 files changed, 287 insertions, 2 deletions
diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index 95ef8309b..9652f03fe 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -23,6 +23,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \ lib583 lib585 lib586 lib587 lib589 lib590 lib591 lib597 lib598 lib599 \ lib643 lib644 lib645 lib650 lib651 lib652 lib653 lib654 lib655 lib658 \ lib659 lib661 \ + lib670 lib671 lib672 lib673 \ lib1156 \ lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \ lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 lib1517 \ @@ -348,6 +349,22 @@ lib659_CPPFLAGS = $(AM_CPPFLAGS) lib661_SOURCES = lib661.c $(SUPPORTFILES) lib661_CPPFLAGS = $(AM_CPPFLAGS) +lib670_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib670_LDADD = $(TESTUTIL_LIBS) +lib670_CPPFLAGS = $(AM_CPPFLAGS) -DLIB670 + +lib671_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib671_LDADD = $(TESTUTIL_LIBS) +lib671_CPPFLAGS = $(AM_CPPFLAGS) -DLIB671 + +lib672_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib672_LDADD = $(TESTUTIL_LIBS) +lib672_CPPFLAGS = $(AM_CPPFLAGS) -DLIB672 + +lib673_SOURCES = lib670.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib673_LDADD = $(TESTUTIL_LIBS) +lib673_CPPFLAGS = $(AM_CPPFLAGS) -DLIB673 + lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL) lib1500_LDADD = $(TESTUTIL_LIBS) lib1500_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/tests/libtest/lib643.c b/tests/libtest/lib643.c index 7432dfce8..08c0f2e80 100644 --- a/tests/libtest/lib643.c +++ b/tests/libtest/lib643.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -41,11 +41,20 @@ struct WriteThis { static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) { #ifdef LIB644 + static int count = 0; (void)ptr; (void)size; (void)nmemb; (void)userp; - return CURL_READFUNC_ABORT; + switch(count++) { + case 0: /* Return a single byte. */ + *ptr = '\n'; + return 1; + case 1: /* Request abort. */ + return CURL_READFUNC_ABORT; + } + printf("Wrongly called >2 times\n"); + exit(1); /* trigger major failure */ #else struct WriteThis *pooh = (struct WriteThis *)userp; diff --git a/tests/libtest/lib670.c b/tests/libtest/lib670.c new file mode 100644 index 000000000..2e6040714 --- /dev/null +++ b/tests/libtest/lib670.c @@ -0,0 +1,259 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, 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 <time.h> + +#include "test.h" + +#include "memdebug.h" + +#define PAUSE_TIME 2 + + +static const char name[] = "field"; + +struct ReadThis { + CURL *easy; + time_t origin; + int count; +}; + + +static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) +{ + struct ReadThis *pooh = (struct ReadThis *) userp; + time_t delta; + + if(size * nmemb < 1) + return 0; + + switch(pooh->count++) { + case 0: + *ptr = '\x41'; /* ASCII A. */ + return 1; + case 1: + pooh->origin = time(NULL); + return CURL_READFUNC_PAUSE; + case 2: + delta = time(NULL) - pooh->origin; + *ptr = delta >= PAUSE_TIME? '\x42': '\x41'; /* ASCII A or B. */ + return 1; + case 3: + return 0; + } + fprintf(stderr, "Read callback called after EOF\n"); + exit(1); +} + +#if !defined(LIB670) && !defined(LIB672) +static int xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) +{ + struct ReadThis *pooh = (struct ReadThis *) clientp; + + (void) dltotal; + (void) dlnow; + (void) ultotal; + (void) ulnow; + + if(pooh->origin) { + time_t delta = time(NULL) - pooh->origin; + + if(delta >= 4 * PAUSE_TIME) { + fprintf(stderr, "unpausing failed: drain problem?\n"); + return CURLE_ABORTED_BY_CALLBACK; + } + + if(delta >= PAUSE_TIME) + curl_easy_pause(pooh->easy, CURLPAUSE_CONT); + } + + return 0; +} +#endif + +int test(char *URL) +{ +#if defined(LIB670) || defined(LIB671) + curl_mime *mime = NULL; + curl_mimepart *part; +#else + CURLFORMcode formrc; + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; +#endif +#if defined(LIB670) || defined(LIB672) + CURLM *multi = NULL; + CURLMcode mres; + CURLMsg *msg; + int msgs_left; + int still_running = 0; +#endif + + struct ReadThis pooh; + CURLcode result; + int res = TEST_ERR_FAILURE; + + /* + * Check proper pausing/unpausing from a mime or form read callback. + */ + + if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { + fprintf(stderr, "curl_global_init() failed\n"); + return TEST_ERR_MAJOR_BAD; + } + + pooh.origin = (time_t) 0; + pooh.count = 0; + pooh.easy = curl_easy_init(); + + /* First set the URL that is about to receive our POST. */ + test_setopt(pooh.easy, CURLOPT_URL, URL); + + /* get verbose debug output please */ + test_setopt(pooh.easy, CURLOPT_VERBOSE, 1L); + + /* include headers in the output */ + test_setopt(pooh.easy, CURLOPT_HEADER, 1L); + +#if defined(LIB670) || defined(LIB671) + /* Build the mime tree. */ + mime = curl_mime_init(pooh.easy); + part = curl_mime_addpart(mime); + result = curl_mime_name(part, name); + if(!result) + res = curl_mime_data_cb(part, (curl_off_t) 2, read_callback, + NULL, NULL, &pooh); + + if(result) { + fprintf(stderr, + "Something went wrong when building the mime structure: %d\n", + (int) result); + goto test_cleanup; + } + + /* Bind mime data to its easy handle. */ + if(!res) + test_setopt(pooh.easy, CURLOPT_MIMEPOST, mime); +#else + /* Build the form. */ + formrc = curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, name, + CURLFORM_STREAM, &pooh, + CURLFORM_CONTENTLEN, (curl_off_t) 2, + CURLFORM_END); + if(formrc) { + fprintf(stderr, "curl_formadd() = %d\n", (int) formrc); + goto test_cleanup; + } + + /* We want to use our own read function. */ + test_setopt(pooh.easy, CURLOPT_READFUNCTION, read_callback); + + /* Send a multi-part formpost. */ + test_setopt(pooh.easy, CURLOPT_HTTPPOST, formpost); +#endif + +#if defined(LIB670) || defined(LIB672) + /* Use the multi interface. */ + multi = curl_multi_init(); + mres = curl_multi_add_handle(multi, pooh.easy); + while(!mres) { + struct timeval timeout; + int rc = 0; + fd_set fdread; + fd_set fdwrite; + fd_set fdexcept; + int maxfd = -1; + + mres = curl_multi_perform(multi, &still_running); + if(!still_running || mres != CURLM_OK) + break; + + if(pooh.origin) { + time_t delta = time(NULL) - pooh.origin; + + if(delta >= 4 * PAUSE_TIME) { + fprintf(stderr, "unpausing failed: drain problem?\n"); + res = CURLE_OPERATION_TIMEDOUT; + break; + } + + if(delta >= PAUSE_TIME) + curl_easy_pause(pooh.easy, CURLPAUSE_CONT); + } + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcept); + timeout.tv_sec = 0; + timeout.tv_usec = 1000000 * PAUSE_TIME / 10; + mres = curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcept, &maxfd); + if(mres) + break; +#ifdef _WIN32 + if(maxfd == -1) + Sleep(100); + else +#endif + rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcept, &timeout); + if(rc == -1) { + fprintf(stderr, "Select error\n"); + break; + } + } + + if(mres != CURLM_OK) + for(;;) { + msg = curl_multi_info_read(multi, &msgs_left); + if(!msg) + break; + if(msg->msg == CURLMSG_DONE) { + result = msg->data.result; + res = (int) result; + } + } + + curl_multi_remove_handle(multi, pooh.easy); + curl_multi_cleanup(multi); + +#else + /* Use the easy interface. */ + test_setopt(pooh.easy, CURLOPT_XFERINFODATA, &pooh); + test_setopt(pooh.easy, CURLOPT_XFERINFOFUNCTION, xferinfo); + test_setopt(pooh.easy, CURLOPT_NOPROGRESS, 0L); + result = curl_easy_perform(pooh.easy); + res = (int) result; +#endif + + +test_cleanup: + curl_easy_cleanup(pooh.easy); +#if defined(LIB670) || defined(LIB671) + curl_mime_free(mime); +#else + curl_formfree(formpost); +#endif + + curl_global_cleanup(); + return res; +} |