From ae2c3d5ec279f994f8a3862cfb1683837acc1eb4 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Sat, 12 Nov 2016 14:19:29 +0100
Subject: [PATCH] curl: add --fail-early

Exit with an error on the first transfer error instead of continuing to
do the rest of the URLs.
---
 docs/curl.1             | 15 +++++++++++++++
 src/tool_cfgable.h      |  2 +-
 src/tool_getparam.c     | 11 +++++++++--
 src/tool_operate.c      |  4 ++--
 tests/data/Makefile.inc |  2 +-
 tests/data/test1247     | 38 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 66 insertions(+), 6 deletions(-)
 create mode 100644 tests/data/test1247

diff --git a/docs/curl.1 b/docs/curl.1
index 8434d6b..9d9df43 100644
--- a/docs/curl.1
+++ b/docs/curl.1
@@ -618,10 +618,25 @@ If this option is enabled and the server sends an invalid (e.g. expired)
 response, if the response suggests that the server certificate has been revoked,
 or no response at all is received, the verification fails.
 
 This is currently only implemented in the OpenSSL, GnuTLS and NSS backends.
 (Added in 7.41.0)
+.IP "--fail-early"
+Fail and exit on first detected error.
+
+When curl is used to do multiple transfers on the command line, it will
+attempt to operate on each given URL, one by one. By default, it will ignore
+errors if there are more URLs given and the last URL's success will determine
+the error code curl returns. So early failures will be "hidden" by subsequent
+successful transfers.
+
+Using this option, curl will instead return an error on the first transfers
+that fails, independent on the amount of more URLs that are given on the
+command line. This way, no transfer failures go undetected by scripts and
+similar.
+
+(Added in 7.52.0)
 .IP "--false-start"
 
 (SSL) Tells curl to use false start during the TLS handshake. False start is a
 mode where a TLS client will start sending application data before verifying
 the server's Finished message, thus saving a round trip when performing a full
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
index 9f4dbba..e72fab1 100644
--- a/src/tool_cfgable.h
+++ b/src/tool_cfgable.h
@@ -237,11 +237,11 @@ struct GlobalConfig {
   bool trace_fopened;
   trace tracetype;
   bool tracetime;                 /* include timestamp? */
   int progressmode;               /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */
   char *libcurl;                  /* Output libcurl code to this file name */
-
+  bool fail_early;                /* exit on first transfer error */
   struct OperationConfig *first;
   struct OperationConfig *current;
   struct OperationConfig *last;   /* Always last in the struct */
 };
 
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
index d1888a2..1f89fbc 100644
--- a/src/tool_getparam.c
+++ b/src/tool_getparam.c
@@ -229,10 +229,11 @@ static const struct LongShort aliases[]= {
   {"Eq", "cert-status",              FALSE},
   {"Er", "false-start",              FALSE},
   {"Es", "ssl-no-revoke",            FALSE},
   {"Et", "tcp-fastopen",             FALSE},
   {"f",  "fail",                     FALSE},
+  {"fa", "fail-early",               FALSE},
   {"F",  "form",                     TRUE},
   {"Fs", "form-string",              TRUE},
   {"g",  "globoff",                  FALSE},
   {"G",  "get",                      FALSE},
   {"h",  "help",                     FALSE},
@@ -1436,12 +1437,18 @@ ParameterError getparameter(char *flag,    /* f or -long-flag */
         cleanarg(nextarg);
       }
       }
       break;
     case 'f':
-      /* fail hard on errors  */
-      config->failonerror = toggle;
+      switch(subletter) {
+      case 'a': /* --fail-early */
+        global->fail_early = toggle;
+        break;
+      default:
+        /* fail hard on errors  */
+        config->failonerror = toggle;
+      }
       break;
     case 'F':
       /* "form data" simulation, this is a little advanced so lets do our best
          to sort this out slowly and carefully */
       if(formparse(config,
diff --git a/src/tool_operate.c b/src/tool_operate.c
index d467b0d..c44f214 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -1803,13 +1803,13 @@ static CURLcode operate_do(struct GlobalConfig *global,
     Curl_safefree(urlnode->outfile);
     Curl_safefree(urlnode->infile);
     urlnode->flags = 0;
 
     /*
-    ** Bail out upon critical errors
+    ** Bail out upon critical errors or --fail-early
     */
-    if(is_fatal_error(result))
+    if(is_fatal_error(result) || (result && global->fail_early))
       goto quit_curl;
 
   } /* for-loop through all URLs */
 
   /*
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
index e5a9e1f..a2ece3d 100644
--- a/tests/data/Makefile.inc
+++ b/tests/data/Makefile.inc
@@ -125,11 +125,11 @@ test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \
 test1208 test1209 test1210 test1211 test1212 test1213 test1214 test1215 \
 test1216 test1217 test1218 test1219 \
 test1220 test1221 test1222 test1223 test1224 test1225 test1226 test1227 \
 test1228 test1229 test1230 test1231 test1232 test1233 test1234 test1235 \
 test1236 test1237 test1238 test1239 test1240 test1241 test1242 test1243 \
-test1244 test1245 test1246 \
+test1244 test1245 test1246 test1247 \
 \
 test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \
 test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \
 test1316 test1317 test1318 test1319 test1320 test1321 test1322          \
          test1325 test1326 test1327 test1328 test1329 test1330 test1331 \
diff --git a/tests/data/test1247 b/tests/data/test1247
new file mode 100644
index 0000000..48c5ccd
--- /dev/null
+++ b/tests/data/test1247
@@ -0,0 +1,38 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+--fail-early
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data>
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+none
+</server>
+ <name>
+--fail-early
+ </name>
+ <command>
+--fail-early h1234://%HOSTIP:%HTTPPORT/1247 http://%HOSTIP:%HTTPPORT/1247
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+# Protocol "h1234" not supported or disabled in libcurl
+<errorcode>
+1
+</errorcode>
+</verify>
+</testcase>
-- 
2.10.2

