aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/url.c7
-rw-r--r--tests/data/Makefile.am2
-rw-r--r--tests/data/test150751
-rw-r--r--tests/libtest/Makefile.inc6
-rw-r--r--tests/libtest/lib1507.c167
5 files changed, 231 insertions, 2 deletions
diff --git a/lib/url.c b/lib/url.c
index 918ce58c3..df70b69da 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -5219,6 +5219,13 @@ CURLcode Curl_done(struct connectdata **connp,
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 */
if(conn->handler->done)
result = conn->handler->done(conn, status, premature);
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index d82534dc8..ae59643af 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -93,7 +93,7 @@ test1379 test1380 test1381 test1382 test1383 test1384 test1385 test1386 \
test1387 test1388 test1389 test1390 test1391 test1392 test1393 \
test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \
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 \
test2008 test2009 test2010 test2011 test2012 test2013 test2014 test2015 \
test2016 test2017 test2018 test2019 test2020 test2021 test2022 \
diff --git a/tests/data/test1507 b/tests/data/test1507
new file mode 100644
index 000000000..76ec5320d
--- /dev/null
+++ b/tests/data/test1507
@@ -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>
diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc
index 82c265d08..41bb45fa5 100644
--- a/tests/libtest/Makefile.inc
+++ b/tests/libtest/Makefile.inc
@@ -23,7 +23,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
lib582 lib583 lib585 lib586 lib587 \
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_LDADD = @CURL_NETWORK_LIBS@
@@ -312,3 +312,7 @@ lib1505_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1505
lib1506_SOURCES = lib1506.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1506_LDADD = $(TESTUTIL_LIBS)
lib1506_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1506
+
+lib1507_SOURCES = lib1507.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
+lib1507_LDADD = $(TESTUTIL_LIBS)
+lib1507_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1507
diff --git a/tests/libtest/lib1507.c b/tests/libtest/lib1507.c
new file mode 100644
index 000000000..7c4e6ed06
--- /dev/null
+++ b/tests/libtest/lib1507.c
@@ -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;
+}
+
+