Imported Upstream version 7.53.1
[platform/upstream/curl.git] / src / tool_operate.c
index 97bb87b..c30b320 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
 #  include <locale.h>
 #endif
 
-#ifdef HAVE_NETINET_TCP_H
-#  include <netinet/tcp.h>
-#endif
-
 #ifdef __VMS
 #  include <fabdef.h>
 #endif
 
-#include "rawstr.h"
+#include "strcase.h"
 
 #define ENABLE_CURLX_PRINTF
 /* use our own printf() functions */
@@ -143,8 +139,8 @@ static bool is_fatal_error(CURLcode code)
  * and CD/DVD images should be either a STREAM_LF format or a fixed format.
  *
  */
-static curl_off_t vms_realfilesize(const char * name,
-                                   const struct_stat * stat_buf)
+static curl_off_t vms_realfilesize(const char *name,
+                                   const struct_stat *stat_buf)
 {
   char buffer[8192];
   curl_off_t count;
@@ -174,8 +170,8 @@ static curl_off_t vms_realfilesize(const char * name,
  *  if not to call a routine to get the correct size.
  *
  */
-static curl_off_t VmsSpecialSize(const char * name,
-                                 const struct_stat * stat_buf)
+static curl_off_t VmsSpecialSize(const char *name,
+                                 const struct_stat *stat_buf)
 {
   switch(stat_buf->st_fab_rfm) {
   case FAB$C_VAR:
@@ -321,7 +317,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
   /* Single header file for all URLs */
   if(config->headerfile) {
     /* open file for output: */
-    if(!curlx_strequal(config->headerfile, "-")) {
+    if(strcmp(config->headerfile, "-")) {
       FILE *newfile = fopen(config->headerfile, "wb");
       if(!newfile) {
         warnf(config->global, "Failed to open %s\n", config->headerfile);
@@ -464,7 +460,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
         urlnum = 1; /* without globbing, this is a single URL */
 
       /* if multiple files extracted to stdout, insert separators! */
-      separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
+      separator= ((!outfiles || !strcmp(outfiles, "-")) && urlnum > 1);
 
       /* Here's looping around each globbed URL */
       for(li = 0 ; li < urlnum; li++) {
@@ -534,7 +530,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
         }
 
         if(((urlnode->flags&GETOUT_USEREMOTE) ||
-            (outfile && !curlx_strequal("-", outfile))) &&
+            (outfile && strcmp("-", outfile))) &&
            (metalink || !config->use_metalink)) {
 
           /*
@@ -653,7 +649,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
           infd = -1;
           if(stat(uploadfile, &fileinfo) == 0) {
             fileinfo.st_size = VmsSpecialSize(uploadfile, &fileinfo);
-            switch (fileinfo.st_fab_rfm) {
+            switch(fileinfo.st_fab_rfm) {
             case FAB$C_VAR:
             case FAB$C_VFC:
             case FAB$C_STMCR:
@@ -715,7 +711,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
           DEBUGASSERT(infd == STDIN_FILENO);
 
           set_binmode(stdin);
-          if(curlx_strequal(uploadfile, ".")) {
+          if(!strcmp(uploadfile, ".")) {
             if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
               warnf(config->global,
                     "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
@@ -800,6 +796,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
 
         /* where to store */
         my_setopt(curl, CURLOPT_WRITEDATA, &outs);
+        my_setopt(curl, CURLOPT_INTERLEAVEDATA, &outs);
         if(metalink || !config->use_metalink)
           /* what call to write */
           my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
@@ -857,20 +854,18 @@ static CURLcode operate_do(struct GlobalConfig *global,
           /* TODO: Make this a run-time check instead of compile-time one. */
 
           my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
+          /* new in libcurl 7.5 */
+          if(config->proxy)
+            my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver);
+
           my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
 
           /* new in libcurl 7.3 */
           my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel?1L:0L);
 
-          /* new in libcurl 7.5 */
-          if(config->proxy)
-            my_setopt_enum(curl, CURLOPT_PROXYTYPE, (long)config->proxyver);
-
-          /* new in libcurl 7.10 */
-          if(config->socksproxy) {
-            my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
-            my_setopt_enum(curl, CURLOPT_PROXYTYPE, (long)config->socksver);
-          }
+          /* new in libcurl 7.52.0 */
+          if(config->preproxy)
+            my_setopt_str(curl, CURLOPT_PRE_PROXY, config->preproxy);
 
           /* new in libcurl 7.10.6 */
           if(config->proxyanyauth)
@@ -999,6 +994,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
           my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, CURL_OFF_T_C(0));
 
         my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
+        my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd);
 
         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
 
@@ -1016,6 +1012,9 @@ static CURLcode operate_do(struct GlobalConfig *global,
 
         if(config->cacert)
           my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
+        if(config->proxy_cacert)
+          my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert);
+
         if(config->capath) {
           result = res_setopt_str(curl, CURLOPT_CAPATH, config->capath);
           if(result == CURLE_NOT_BUILT_IN) {
@@ -1026,17 +1025,44 @@ static CURLcode operate_do(struct GlobalConfig *global,
           else if(result)
             goto show_error;
         }
+        /* For the time being if --proxy-capath is not set then we use the
+           --capath value for it, if any. See #1257 */
+        if(config->proxy_capath || config->capath) {
+          result = res_setopt_str(curl, CURLOPT_PROXY_CAPATH,
+                                  (config->proxy_capath ?
+                                   config->proxy_capath :
+                                   config->capath));
+          if(result == CURLE_NOT_BUILT_IN) {
+            if(config->proxy_capath) {
+              warnf(config->global,
+                    "ignoring --proxy-capath, not supported by libcurl\n");
+            }
+          }
+          else if(result)
+            goto show_error;
+        }
+
         if(config->crlfile)
           my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
+        if(config->proxy_crlfile)
+          my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile);
+        else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */
+          my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile);
 
         if(config->pinnedpubkey)
           my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey);
 
         if(curlinfo->features & CURL_VERSION_SSL) {
           my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
+          my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
           my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
+          my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
+                        config->proxy_cert_type);
           my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
+          my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
           my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
+          my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
+                        config->proxy_key_type);
 
           if(config->insecure_ok) {
             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
@@ -1047,6 +1073,13 @@ static CURLcode operate_do(struct GlobalConfig *global,
             /* libcurl default is strict verifyhost -> 2L   */
             /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
           }
+          if(config->proxy_insecure_ok) {
+            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L);
+            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L);
+          }
+          else {
+            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
+          }
 
           if(config->verifystatus)
             my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
@@ -1055,6 +1088,8 @@ static CURLcode operate_do(struct GlobalConfig *global,
             my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
 
           my_setopt_enum(curl, CURLOPT_SSLVERSION, config->ssl_version);
+          my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION,
+                         config->proxy_ssl_version);
         }
         if(config->path_as_is)
           my_setopt(curl, CURLOPT_PATH_AS_IS, 1L);
@@ -1156,6 +1191,10 @@ static CURLcode operate_do(struct GlobalConfig *global,
         if(config->cipher_list)
           my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
 
+        if(config->proxy_cipher_list)
+          my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST,
+                        config->proxy_cipher_list);
+
         /* new in libcurl 7.9.2: */
         if(config->disable_epsv)
           /* disable it */
@@ -1177,7 +1216,6 @@ static CURLcode operate_do(struct GlobalConfig *global,
           result = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
           if(result)
             goto show_error;
-          my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
         }
 
         /* new in curl 7.10.7, extended in 7.19.4. Modified to use
@@ -1325,6 +1363,15 @@ static CURLcode operate_do(struct GlobalConfig *global,
           if(config->tls_authtype)
             my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
                           config->tls_authtype);
+          if(config->proxy_tls_username)
+            my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME,
+                          config->proxy_tls_username);
+          if(config->proxy_tls_password)
+            my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD,
+                          config->proxy_tls_password);
+          if(config->proxy_tls_authtype)
+            my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE,
+                          config->proxy_tls_authtype);
         }
 
         /* new in 7.22.0 */
@@ -1340,6 +1387,10 @@ static CURLcode operate_do(struct GlobalConfig *global,
             my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask);
         }
 
+        if(config->proxy_ssl_allow_beast)
+          my_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS,
+                    (long)CURLSSLOPT_ALLOW_BEAST);
+
         if(config->mail_auth)
           my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
 
@@ -1355,11 +1406,17 @@ static CURLcode operate_do(struct GlobalConfig *global,
           my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
         }
 
-        /* new in 7.40.0 */
-        if(config->unix_socket_path)
-          my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
-                        config->unix_socket_path);
-
+        /* new in 7.40.0, abstract support added in 7.53.0 */
+        if(config->unix_socket_path) {
+          if(config->abstract_unix_socket) {
+            my_setopt_str(curl, CURLOPT_ABSTRACT_UNIX_SOCKET,
+                          config->unix_socket_path);
+          }
+          else {
+            my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
+                          config->unix_socket_path);
+          }
+        }
         /* new in 7.45.0 */
         if(config->proto_default)
           my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default);
@@ -1441,6 +1498,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
             enum {
               RETRY_NO,
               RETRY_TIMEOUT,
+              RETRY_CONNREFUSED,
               RETRY_HTTP,
               RETRY_FTP,
               RETRY_LAST /* not used */
@@ -1452,6 +1510,13 @@ static CURLcode operate_do(struct GlobalConfig *global,
                (CURLE_FTP_ACCEPT_TIMEOUT == result))
               /* retry timeout always */
               retry = RETRY_TIMEOUT;
+            else if(config->retry_connrefused &&
+                    (CURLE_COULDNT_CONNECT == result)) {
+              long oserrno;
+              curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &oserrno);
+              if(ECONNREFUSED == oserrno)
+                retry = RETRY_CONNREFUSED;
+            }
             else if((CURLE_OK == result) ||
                     (config->failonerror &&
                      (CURLE_HTTP_RETURNED_ERROR == result))) {
@@ -1499,7 +1564,11 @@ static CURLcode operate_do(struct GlobalConfig *global,
 
             if(retry) {
               static const char * const m[]={
-                NULL, "timeout", "HTTP error", "FTP error"
+                NULL,
+                "timeout",
+                "connection refused",
+                "HTTP error",
+                "FTP error"
               };
 
               warnf(config->global, "Transient problem: %s "
@@ -1559,14 +1628,14 @@ static CURLcode operate_do(struct GlobalConfig *global,
               char *effective_url = NULL;
               curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
               if(effective_url &&
-                 curlx_strnequal(effective_url, "http", 4)) {
+                 curl_strnequal(effective_url, "http", 4)) {
                 /* This was HTTP(S) */
                 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
                 if(response != 200 && response != 206) {
                   metalink_next_res = 1;
                   fprintf(global->errors,
                           "Metalink: fetching (%s) from (%s) FAILED "
-                          "(HTTP status code %d)\n",
+                          "(HTTP status code %ld)\n",
                           mlfile->filename, this_url, response);
                 }
               }
@@ -1622,8 +1691,13 @@ static CURLcode operate_do(struct GlobalConfig *global,
           fprintf(global->errors, "curl: (%d) %s\n", result, (errorbuffer[0]) ?
                   errorbuffer : curl_easy_strerror(result));
           if(result == CURLE_SSL_CACERT)
-            fprintf(global->errors, "%s%s",
-                    CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2);
+            fprintf(global->errors, "%s%s%s",
+                    CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2,
+                    ((config->proxy &&
+                      curl_strnequal(config->proxy, "https://", 8)) ?
+                     "HTTPS proxy has similar options --proxy-cacert "
+                     "and --proxy-insecure.\n" :
+                     ""));
         }
 
         /* Fall through comment to 'quit_urls' label */
@@ -1677,20 +1751,65 @@ static CURLcode operate_do(struct GlobalConfig *global,
         }
 #endif
 
-#ifdef HAVE_UTIME
+#if defined(HAVE_UTIME) || \
+    (defined(WIN32) && (CURL_SIZEOF_CURL_OFF_T >= 8))
         /* File time can only be set _after_ the file has been closed */
         if(!result && config->remote_time && outs.s_isreg && outs.filename) {
           /* Ask libcurl if we got a remote file time */
           long filetime = -1;
           curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
           if(filetime >= 0) {
+/* Windows utime() may attempt to adjust our unix gmt 'filetime' by a daylight
+   saving time offset and since it's GMT that is bad behavior. When we have
+   access to a 64-bit type we can bypass utime and set the times directly. */
+#if defined(WIN32) && (CURL_SIZEOF_CURL_OFF_T >= 8)
+            /* 910670515199 is the maximum unix filetime that can be used as a
+               Windows FILETIME without overflow: 30827-12-31T23:59:59. */
+            if(filetime <= CURL_OFF_T_C(910670515199)) {
+              HANDLE hfile = CreateFileA(outs.filename, FILE_WRITE_ATTRIBUTES,
+                                         (FILE_SHARE_READ | FILE_SHARE_WRITE |
+                                          FILE_SHARE_DELETE),
+                                         NULL, OPEN_EXISTING, 0, NULL);
+              if(hfile != INVALID_HANDLE_VALUE) {
+                curl_off_t converted = ((curl_off_t)filetime * 10000000) +
+                                       CURL_OFF_T_C(116444736000000000);
+                FILETIME ft;
+                ft.dwLowDateTime = (DWORD)(converted & 0xFFFFFFFF);
+                ft.dwHighDateTime = (DWORD)(converted >> 32);
+                if(!SetFileTime(hfile, NULL, &ft, &ft)) {
+                  fprintf(config->global->errors,
+                          "Failed to set filetime %ld on outfile: "
+                          "SetFileTime failed: GetLastError %u\n",
+                          filetime, GetLastError());
+                }
+                CloseHandle(hfile);
+              }
+              else {
+                fprintf(config->global->errors,
+                        "Failed to set filetime %ld on outfile: "
+                        "CreateFile failed: GetLastError %u\n",
+                        filetime, GetLastError());
+              }
+            }
+            else {
+              fprintf(config->global->errors,
+                      "Failed to set filetime %ld on outfile: overflow\n",
+                      filetime);
+            }
+#elif defined(HAVE_UTIME)
             struct utimbuf times;
             times.actime = (time_t)filetime;
             times.modtime = (time_t)filetime;
-            utime(outs.filename, &times); /* set the time we got */
+            if(utime(outs.filename, &times)) {
+              fprintf(config->global->errors,
+                      "Failed to set filetime %ld on outfile: errno %d\n",
+                      filetime, errno);
+            }
+#endif
           }
         }
-#endif
+#endif /* defined(HAVE_UTIME) || \
+          (defined(WIN32) && (CURL_SIZEOF_CURL_OFF_T >= 8)) */
 
 #ifdef USE_METALINK
         if(!metalink && config->use_metalink && result == CURLE_OK) {
@@ -1793,9 +1912,9 @@ static CURLcode operate_do(struct GlobalConfig *global,
     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 */
@@ -1842,8 +1961,8 @@ CURLcode operate(struct GlobalConfig *config, int argc, argv_item_t argv[])
 
   /* Parse .curlrc if necessary */
   if((argc == 1) ||
-     (!curlx_strequal(argv[1], "-q") &&
-      !curlx_strequal(argv[1], "--disable"))) {
+     (!curl_strequal(argv[1], "-q") &&
+      !curl_strequal(argv[1], "--disable"))) {
     parseconfig(NULL, config); /* ignore possible failure */
 
     /* If we had no arguments then make sure a url was specified in .curlrc */
@@ -1904,6 +2023,9 @@ CURLcode operate(struct GlobalConfig *config, int argc, argv_item_t argv[])
           result = operate_do(config, config->current);
 
           config->current = config->current->next;
+
+          if(config->current && config->current->easy)
+            curl_easy_reset(config->current->easy);
         }
 
 #ifndef CURL_DISABLE_LIBCURL_OPTION