mirror of
https://github.com/curl/curl.git
synced 2025-09-27 06:26:50 +03:00
DONE: consider callback-aborted transfers premature
This bug report properly identified that when doing SMTP and aborting the transfer with a callback, it must be considered aborted prematurely by the code to avoid QUIT etc to be attempted as that would cause a hang. The new test case 1507 verifies this behavior. Reported by: Patricia Muscalu Bug: http://curl.haxx.se/bug/view.cgi?id=1184
This commit is contained in:
parent
07f97809b8
commit
72688317ad
|
@ -5219,6 +5219,13 @@ CURLcode Curl_done(struct connectdata **connp,
|
||||||
conn->dns_entry = NULL;
|
conn->dns_entry = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(status == CURLE_ABORTED_BY_CALLBACK)
|
||||||
|
/* When we're aborted due to a callback return code it basically have to
|
||||||
|
be counted as premature as there is trouble ahead if we don't. We have
|
||||||
|
many callbacks and protocols work differently, we could potentially do
|
||||||
|
this more fine-grained in the future. */
|
||||||
|
premature = TRUE;
|
||||||
|
|
||||||
/* this calls the protocol-specific function pointer previously set */
|
/* this calls the protocol-specific function pointer previously set */
|
||||||
if(conn->handler->done)
|
if(conn->handler->done)
|
||||||
result = conn->handler->done(conn, status, premature);
|
result = conn->handler->done(conn, status, premature);
|
||||||
|
|
|
@ -93,7 +93,7 @@ test1379 test1380 test1381 test1382 test1383 test1384 test1385 test1386 \
|
||||||
test1387 test1388 test1389 test1390 test1391 test1392 test1393 \
|
test1387 test1388 test1389 test1390 test1391 test1392 test1393 \
|
||||||
test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \
|
test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \
|
||||||
test1408 test1409 test1410 test1411 test1412 test1413 \
|
test1408 test1409 test1410 test1411 test1412 test1413 \
|
||||||
test1500 test1501 test1502 test1503 test1504 test1505 test1506 \
|
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
|
||||||
test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \
|
test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \
|
||||||
test2008 test2009 test2010 test2011 test2012 test2013 test2014 test2015 \
|
test2008 test2009 test2010 test2011 test2012 test2013 test2014 test2015 \
|
||||||
test2016 test2017 test2018 test2019 test2020 test2021 test2022 \
|
test2016 test2017 test2018 test2019 test2020 test2021 test2022 \
|
||||||
|
|
51
tests/data/test1507
Normal file
51
tests/data/test1507
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<testcase>
|
||||||
|
<info>
|
||||||
|
<keywords>
|
||||||
|
SMTP
|
||||||
|
multi
|
||||||
|
</keywords>
|
||||||
|
</info>
|
||||||
|
|
||||||
|
#
|
||||||
|
# Server-side
|
||||||
|
<reply>
|
||||||
|
</reply>
|
||||||
|
|
||||||
|
#
|
||||||
|
# Client-side
|
||||||
|
<client>
|
||||||
|
<server>
|
||||||
|
smtp
|
||||||
|
</server>
|
||||||
|
<tool>
|
||||||
|
lib1507
|
||||||
|
</tool>
|
||||||
|
|
||||||
|
# based on bug report #1184
|
||||||
|
<name>
|
||||||
|
SMTP with multi interface and CURLE_ABORTED_BY_CALLBACK
|
||||||
|
</name>
|
||||||
|
<stdin>
|
||||||
|
From: different
|
||||||
|
To: another
|
||||||
|
|
||||||
|
body
|
||||||
|
</stdin>
|
||||||
|
<command>
|
||||||
|
smtp://%HOSTIP:%SMTPPORT/user
|
||||||
|
</command>
|
||||||
|
</client>
|
||||||
|
|
||||||
|
#
|
||||||
|
# Verify data after the test has been "shot"
|
||||||
|
<verify>
|
||||||
|
<protocol>
|
||||||
|
EHLO user
|
||||||
|
MAIL FROM:<1507-realuser@example.com>
|
||||||
|
RCPT TO:<1507-recipient@example.com>
|
||||||
|
DATA
|
||||||
|
</protocol>
|
||||||
|
<upload>
|
||||||
|
</upload>
|
||||||
|
</verify>
|
||||||
|
</testcase>
|
|
@ -23,7 +23,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
|
||||||
lib582 lib583 lib585 lib586 lib587 \
|
lib582 lib583 lib585 lib586 lib587 \
|
||||||
lib590 lib591 lib597 lib598 lib599 \
|
lib590 lib591 lib597 lib598 lib599 \
|
||||||
\
|
\
|
||||||
lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506
|
lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507
|
||||||
|
|
||||||
chkhostname_SOURCES = chkhostname.c ../../lib/curl_gethostname.c
|
chkhostname_SOURCES = chkhostname.c ../../lib/curl_gethostname.c
|
||||||
chkhostname_LDADD = @CURL_NETWORK_LIBS@
|
chkhostname_LDADD = @CURL_NETWORK_LIBS@
|
||||||
|
@ -312,3 +312,7 @@ lib1505_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1505
|
||||||
lib1506_SOURCES = lib1506.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
lib1506_SOURCES = lib1506.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||||
lib1506_LDADD = $(TESTUTIL_LIBS)
|
lib1506_LDADD = $(TESTUTIL_LIBS)
|
||||||
lib1506_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1506
|
lib1506_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1506
|
||||||
|
|
||||||
|
lib1507_SOURCES = lib1507.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||||
|
lib1507_LDADD = $(TESTUTIL_LIBS)
|
||||||
|
lib1507_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1507
|
||||||
|
|
167
tests/libtest/lib1507.c
Normal file
167
tests/libtest/lib1507.c
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2013, 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 http://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"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the list of basic details you need to tweak to get things right.
|
||||||
|
*/
|
||||||
|
#define USERNAME "user@example.com"
|
||||||
|
#define PASSWORD "123qwerty"
|
||||||
|
#define RECIPIENT "<1507-recipient@example.com>"
|
||||||
|
#define MAILFROM "<1507-realuser@example.com>"
|
||||||
|
|
||||||
|
#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000
|
||||||
|
|
||||||
|
static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
(void)size;
|
||||||
|
(void)nmemb;
|
||||||
|
(void)userp;
|
||||||
|
return CURL_READFUNC_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct timeval tvnow(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** time() returns the value of time in seconds since the Epoch.
|
||||||
|
*/
|
||||||
|
struct timeval now;
|
||||||
|
now.tv_sec = (long)time(NULL);
|
||||||
|
now.tv_usec = 0;
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long tvdiff(struct timeval newer, struct timeval older)
|
||||||
|
{
|
||||||
|
return (newer.tv_sec-older.tv_sec)*1000+
|
||||||
|
(newer.tv_usec-older.tv_usec)/1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test(char *URL)
|
||||||
|
{
|
||||||
|
CURL *curl;
|
||||||
|
CURLM *mcurl;
|
||||||
|
int still_running = 1;
|
||||||
|
struct timeval mp_start;
|
||||||
|
struct curl_slist* rcpt_list = NULL;
|
||||||
|
|
||||||
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
|
|
||||||
|
curl = curl_easy_init();
|
||||||
|
if(!curl)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
mcurl = curl_multi_init();
|
||||||
|
if(!mcurl)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
rcpt_list = curl_slist_append(rcpt_list, RECIPIENT);
|
||||||
|
/* more addresses can be added here
|
||||||
|
rcpt_list = curl_slist_append(rcpt_list, "<others@example.com>");
|
||||||
|
*/
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, URL);
|
||||||
|
#if 0
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERNAME, USERNAME);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PASSWORD, PASSWORD);
|
||||||
|
#endif
|
||||||
|
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, MAILFROM);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt_list);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||||
|
curl_multi_add_handle(mcurl, curl);
|
||||||
|
|
||||||
|
mp_start = tvnow();
|
||||||
|
|
||||||
|
/* we start some action by calling perform right away */
|
||||||
|
curl_multi_perform(mcurl, &still_running);
|
||||||
|
|
||||||
|
while(still_running) {
|
||||||
|
struct timeval timeout;
|
||||||
|
int rc; /* select() return code */
|
||||||
|
|
||||||
|
fd_set fdread;
|
||||||
|
fd_set fdwrite;
|
||||||
|
fd_set fdexcep;
|
||||||
|
int maxfd = -1;
|
||||||
|
|
||||||
|
long curl_timeo = -1;
|
||||||
|
|
||||||
|
FD_ZERO(&fdread);
|
||||||
|
FD_ZERO(&fdwrite);
|
||||||
|
FD_ZERO(&fdexcep);
|
||||||
|
|
||||||
|
/* set a suitable timeout to play around with */
|
||||||
|
timeout.tv_sec = 1;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
curl_multi_timeout(mcurl, &curl_timeo);
|
||||||
|
if(curl_timeo >= 0) {
|
||||||
|
timeout.tv_sec = curl_timeo / 1000;
|
||||||
|
if(timeout.tv_sec > 1)
|
||||||
|
timeout.tv_sec = 1;
|
||||||
|
else
|
||||||
|
timeout.tv_usec = (curl_timeo % 1000) * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get file descriptors from the transfers */
|
||||||
|
curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
|
||||||
|
|
||||||
|
/* In a real-world program you OF COURSE check the return code of the
|
||||||
|
function calls. On success, the value of maxfd is guaranteed to be
|
||||||
|
greater or equal than -1. We call select(maxfd + 1, ...), specially in
|
||||||
|
case of (maxfd == -1), we call select(0, ...), which is basically equal
|
||||||
|
to sleep. */
|
||||||
|
|
||||||
|
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
|
||||||
|
|
||||||
|
if (tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) {
|
||||||
|
fprintf(stderr, "ABORTING TEST, since it seems "
|
||||||
|
"that it would have run forever.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(rc) {
|
||||||
|
case -1:
|
||||||
|
/* select error */
|
||||||
|
break;
|
||||||
|
case 0: /* timeout */
|
||||||
|
default: /* action */
|
||||||
|
curl_multi_perform(mcurl, &still_running);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_slist_free_all(rcpt_list);
|
||||||
|
curl_multi_remove_handle(mcurl, curl);
|
||||||
|
curl_multi_cleanup(mcurl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
curl_global_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user