gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnurl] 127/256: mime: use in curl cli tool instead of form


From: gnunet
Subject: [GNUnet-SVN] [gnurl] 127/256: mime: use in curl cli tool instead of form API.
Date: Fri, 06 Oct 2017 19:43:38 +0200

This is an automated email from the git hooks/post-receive script.

ng0 pushed a commit to branch master
in repository gnurl.

commit fec7a858b88c86e97e5dc96414a01feb21a2b661
Author: Patrick Monnerat <address@hidden>
AuthorDate: Sat Sep 2 18:17:33 2017 +0100

    mime: use in curl cli tool instead of form API.
    
    Extended -F option syntax to support multipart mail messages.
    -F keyword headers= added to include custom headers in parts.
    Documentation upgraded.
---
 docs/cmdline-opts/form-string.d |   4 +-
 docs/cmdline-opts/form.d        |  66 +++-
 src/Makefile.inc                |   2 -
 src/tool_cfgable.c              |   8 +-
 src/tool_cfgable.h              |   4 +-
 src/tool_easysrc.c              |   4 +-
 src/tool_easysrc.h              |   4 +-
 src/tool_formparse.c            | 656 ++++++++++++++++++++++++++++++----------
 src/tool_formparse.h            |   6 +-
 src/tool_getparam.c             |   6 +-
 src/tool_help.c                 |   4 +-
 src/tool_mfiles.c               | 127 --------
 src/tool_mfiles.h               |  46 ---
 src/tool_operate.c              |   4 +-
 src/tool_sdecls.h               |   4 +-
 src/tool_setopt.c               | 267 +++++++++++-----
 src/tool_setopt.h               |  12 +-
 17 files changed, 768 insertions(+), 456 deletions(-)

diff --git a/docs/cmdline-opts/form-string.d b/docs/cmdline-opts/form-string.d
index 80790553c..49d0d44ef 100644
--- a/docs/cmdline-opts/form-string.d
+++ b/docs/cmdline-opts/form-string.d
@@ -1,6 +1,6 @@
 Long: form-string
-Help: Specify HTTP multipart POST data
-Protocols: HTTP
+Help: Specify multipart MIME data
+Protocols: HTTP SMTP IMAP
 Arg: <name=string>
 See-also: form
 ---
diff --git a/docs/cmdline-opts/form.d b/docs/cmdline-opts/form.d
index 87a7d0766..14261d3ad 100644
--- a/docs/cmdline-opts/form.d
+++ b/docs/cmdline-opts/form.d
@@ -1,21 +1,26 @@
 Long: form
 Short: F
 Arg: <name=content>
-Help: Specify HTTP multipart POST data
-Protocols: HTTP
+Help: Specify multipart MIME data
+Protocols: HTTP SMTP IMAP
 Mutexed: data head upload
 ---
-This lets curl emulate a filled-in form in which a user has pressed the submit
-button. This causes curl to POST data using the Content-Type
-multipart/form-data according to RFC 2388. This enables uploading of binary
+For HTTP protocol family, this lets curl emulate a filled-in form in which a
+user has pressed the submit button. This causes curl to POST data using the
+Content-Type multipart/form-data according to RFC 2388.
+
+For SMTP and IMAP protocols, this is the mean to compose a multipart mail
+message to transmit.
+
+This enables uploading of binary
 files etc. To force the 'content' part to be a file, prefix the file name with
 an @ sign. To just get the content part from a file, prefix the file name with
 the symbol <. The difference between @ and < is then that @ makes a file get
 attached in the post as a file upload, while the < makes a text field and just
 get the contents for that text field from a file.
 
-Example: to send an image to a server, where \&'profile' is the name of the
-form-field to which portrait.jpg will be the input:
+Example: to send an image to an HTTP server, where \&'profile' is the name of
+the form-field to which portrait.jpg will be the input:
 
  curl -F address@hidden https://example.com/upload.cgi
 
@@ -49,6 +54,53 @@ or
 Note that if a filename/path is quoted by double-quotes, any double-quote
 or backslash within the filename must be escaped by backslash.
 
+You can add custom headers to the field by setting headers=, like
+
+  curl -F "submit=OK;headers=\\"X-submit-type: OK\\"" example.com
+
+or
+
+  curl -F "submit=OK;address@hidden" example.com
+
+The headers= keyword may appear more that once and above notes about quoting
+apply. When headers are read from a file, Empty lines and lines starting
+with '#' are comments and ignored; each header can be folded by splitting
+between two words and starting the continuation line with a space; embedded
+carriage-returns and trailing spaces are stripped.
+Here is an example of a header file contents:
+
+  # This file contain two headers.
+.br
+  X-header-1: this is a header
+
+  # The following header is folded.
+.br
+  X-header-2: this is
+.br
+   another header
+
+
+To support sending multipart mail messages, the syntax is extended as follows:
+.br
+- name can be omitted: the equal sign is the first character of the argument,
+.br
+- if data starts with '(', this signals to start a new multipart: it can be
+followed by a content type specification.
+.br
+- a multipart can be terminated with a '=)' argument.
+
+Example: the following command sends an SMTP mime e-mail consisting in an
+inline part in two alternative formats: plain text and HTML. It attaches a
+text file:
+
+ curl -F '=(;type=multipart/alternative' \\
+.br
+         -F '=plain text message' \\
+.br
+         -F '= <body>HTML message</body>;type=text/html' \\
+.br
+      -F '=)' -F 'address@hidden' ...  smtp://example.com
+
 See further examples and details in the MANUAL.
 
 This option can be used multiple times.
diff --git a/src/Makefile.inc b/src/Makefile.inc
index 5074f8fc6..45b4967f6 100644
--- a/src/Makefile.inc
+++ b/src/Makefile.inc
@@ -45,7 +45,6 @@ CURL_CFILES = \
        tool_libinfo.c \
        tool_main.c \
        tool_metalink.c \
-       tool_mfiles.c \
        tool_msgs.c \
        tool_operate.c \
        tool_operhlp.c \
@@ -86,7 +85,6 @@ CURL_HFILES = \
        tool_libinfo.h \
        tool_main.h \
        tool_metalink.h \
-       tool_mfiles.h \
        tool_msgs.h \
        tool_operate.h \
        tool_operhlp.h \
diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c
index 675e88b45..755195ced 100644
--- a/src/tool_cfgable.c
+++ b/src/tool_cfgable.c
@@ -140,11 +140,11 @@ static void free_config_fields(struct OperationConfig 
*config)
   curl_slist_free_all(config->headers);
   curl_slist_free_all(config->proxyheaders);
 
-  if(config->httppost) {
-    curl_formfree(config->httppost);
-    config->httppost = NULL;
+  if(config->mimepost) {
+    curl_mime_free(config->mimepost);
+    config->mimepost = NULL;
   }
-  config->last_post = NULL;
+  config->mimecurrent = NULL;
 
   curl_slist_free_all(config->telnet_options);
   curl_slist_free_all(config->resolve);
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
index 2b436657f..23943fe7b 100644
--- a/src/tool_cfgable.h
+++ b/src/tool_cfgable.h
@@ -170,8 +170,8 @@ struct OperationConfig {
   time_t condtime;
   struct curl_slist *headers;
   struct curl_slist *proxyheaders;
-  struct curl_httppost *httppost;
-  struct curl_httppost *last_post;
+  curl_mime *mimepost;
+  curl_mime *mimecurrent;
   struct curl_slist *telnet_options;
   struct curl_slist *resolve;
   struct curl_slist *connect_to;
diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c
index c2dccf9fb..602409d14 100644
--- a/src/tool_easysrc.c
+++ b/src/tool_easysrc.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -42,7 +42,7 @@ struct slist_wc *easysrc_data = NULL; /* Build slists, forms 
etc. */
 struct slist_wc *easysrc_code = NULL; /* Setopt calls */
 struct slist_wc *easysrc_toohard = NULL; /* Unconvertible setopt */
 struct slist_wc *easysrc_clean = NULL;  /* Clean up allocated data */
-int easysrc_form_count = 0;
+int easysrc_mime_count = 0;
 int easysrc_slist_count = 0;
 
 static const char *const srchead[]={
diff --git a/src/tool_easysrc.h b/src/tool_easysrc.h
index 54607b861..fd799ab84 100644
--- a/src/tool_easysrc.h
+++ b/src/tool_easysrc.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -32,7 +32,7 @@ extern struct slist_wc *easysrc_code; /* Setopt calls etc. */
 extern struct slist_wc *easysrc_toohard; /* Unconvertible setopt */
 extern struct slist_wc *easysrc_clean;  /* Clean up (reverse order) */
 
-extern int easysrc_form_count;  /* Number of curl_httppost variables */
+extern int easysrc_mime_count;  /* Number of curl_mime variables */
 extern int easysrc_slist_count; /* Number of curl_slist variables */
 
 extern CURLcode easysrc_init(void);
diff --git a/src/tool_formparse.c b/src/tool_formparse.c
index 952377c49..cf19c0508 100644
--- a/src/tool_formparse.c
+++ b/src/tool_formparse.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -21,6 +21,7 @@
  ***************************************************************************/
 #include "tool_setup.h"
 
+#include "mime.h"
 #include "strcase.h"
 
 #define ENABLE_CURLX_PRINTF
@@ -29,7 +30,6 @@
 
 #include "tool_cfgable.h"
 #include "tool_convert.h"
-#include "tool_mfiles.h"
 #include "tool_msgs.h"
 #include "tool_formparse.h"
 
@@ -94,6 +94,259 @@ static char *get_param_word(char **str, char **end_pos)
   return word_begin;
 }
 
+/* Append slist item and return -1 if failed. */
+static int slist_append(struct curl_slist **plist, const char *data)
+{
+  struct curl_slist *s = curl_slist_append(*plist, data);
+
+  if(!s)
+    return -1;
+
+  *plist = s;
+  return 0;
+}
+
+/* Read headers from a file and append to list. */
+static int read_field_headers(struct OperationConfig *config,
+                              const char *filename, FILE *fp,
+                              struct curl_slist **pheaders)
+{
+  size_t hdrlen = 0;
+  size_t pos = 0;
+  int c;
+  bool incomment = FALSE;
+  int lineno = 1;
+  char hdrbuf[999]; /* Max. header length + 1. */
+
+  for(;;) {
+    c = getc(fp);
+    if(c == EOF || (!pos && !ISSPACE(c))) {
+      /* Strip and flush the current header. */
+      while(hdrlen && ISSPACE(hdrbuf[hdrlen - 1]))
+        hdrlen--;
+      if(hdrlen) {
+        hdrbuf[hdrlen] = '\0';
+        if(slist_append(pheaders, hdrbuf)) {
+          fprintf(config->global->errors,
+                  "Out of memory for field headers!\n");
+          return -1;
+        }
+        hdrlen = 0;
+      }
+    }
+
+    switch(c) {
+    case EOF:
+      if(ferror(fp)) {
+        fprintf(config->global->errors,
+                "Header file %s read error: %s\n", filename, strerror(errno));
+        return -1;
+      }
+      return 0;    /* Done. */
+    case '\r':
+      continue;    /* Ignore. */
+    case '\n':
+      pos = 0;
+      incomment = FALSE;
+      lineno++;
+      continue;
+    case '#':
+      if(!pos)
+        incomment = TRUE;
+      break;
+    }
+
+    pos++;
+    if(!incomment) {
+      if(hdrlen == sizeof hdrbuf - 1) {
+        warnf(config->global, "File %s line %d: header too long (truncated)\n",
+              filename, lineno);
+        c = ' ';
+      }
+      if(hdrlen <= sizeof hdrbuf - 1)
+        hdrbuf[hdrlen++] = (char) c;
+    }
+  }
+  /* NOTREACHED */
+}
+
+static int get_param_part(struct OperationConfig *config, char **str,
+                          char **pdata, char **ptype, char **pfilename,
+                          struct curl_slist **pheaders)
+{
+  char *p = *str;
+  char *type = NULL;
+  char *filename = NULL;
+  char *endpos;
+  char *tp;
+  char sep;
+  char type_major[128] = "";
+  char type_minor[128] = "";
+  char *endct = NULL;
+  struct curl_slist *headers = NULL;
+
+  if(ptype)
+    *ptype = NULL;
+  if(pfilename)
+    *pfilename = NULL;
+  if(pheaders)
+    *pheaders = NULL;
+  while(ISSPACE(*p))
+    p++;
+  tp = p;
+  *pdata = get_param_word(&p, &endpos);
+  /* If not quoted, strip trailing spaces. */
+  if(*pdata == tp)
+    while(endpos > *pdata && ISSPACE(endpos[-1]))
+      endpos--;
+  sep = *p;
+  *endpos = '\0';
+  while(sep == ';') {
+    while(ISSPACE(*++p))
+      ;
+
+    if(!endct && checkprefix("type=", p)) {
+      for(p += 5; ISSPACE(*p); p++)
+        ;
+      /* set type pointer */
+      type = p;
+
+      /* verify that this is a fine type specifier */
+      if(2 != sscanf(type, "%127[^/ ]/%127[^;, \n]", type_major, type_minor)) {
+        warnf(config->global, "Illegally formatted content-type field!\n");
+        curl_slist_free_all(headers);
+        return -1; /* illegal content-type syntax! */
+      }
+
+      /* now point beyond the content-type specifier */
+      endpos = type + strlen(type_major) + strlen(type_minor) + 1;
+      for(p = endpos; ISSPACE(*p); p++)
+        ;
+      while(*p && *p != ';' && *p != ',')
+        p++;
+      endct = p;
+      sep = *p;
+    }
+    else if(checkprefix("filename=", p)) {
+      if(endct) {
+        *endct = '\0';
+        endct = NULL;
+      }
+      for(p += 9; ISSPACE(*p); p++)
+        ;
+      tp = p;
+      filename = get_param_word(&p, &endpos);
+      /* If not quoted, strip trailing spaces. */
+      if(filename == tp)
+        while(endpos > filename && ISSPACE(endpos[-1]))
+          endpos--;
+      sep = *p;
+      *endpos = '\0';
+    }
+    else if(checkprefix("headers=", p)) {
+      if(endct) {
+        *endct = '\0';
+        endct = NULL;
+      }
+      p += 8;
+      if(*p == '@' || *p == '<') {
+        char *hdrfile;
+        FILE *fp;
+        /* Read headers from a file. */
+
+        do {
+          p++;
+        } while(ISSPACE(*p));
+        tp = p;
+        hdrfile = get_param_word(&p, &endpos);
+        /* If not quoted, strip trailing spaces. */
+        if(hdrfile == tp)
+          while(endpos > hdrfile && ISSPACE(endpos[-1]))
+            endpos--;
+        sep = *p;
+        *endpos = '\0';
+        /* TODO: maybe special fopen for VMS? */
+        fp = fopen(hdrfile, FOPEN_READTEXT);
+        if(!fp)
+          warnf(config->global, "Cannot read from %s: %s\n", hdrfile,
+                strerror(errno));
+        else {
+          int i = read_field_headers(config, hdrfile, fp, &headers);
+
+          fclose(fp);
+          if(i) {
+            curl_slist_free_all(headers);
+            return -1;
+          }
+        }
+      }
+      else {
+        char *hdr;
+
+        while(ISSPACE(*p))
+          p++;
+        tp = p;
+        hdr = get_param_word(&p, &endpos);
+        /* If not quoted, strip trailing spaces. */
+        if(hdr == tp)
+          while(endpos > hdr && ISSPACE(endpos[-1]))
+            endpos--;
+        sep = *p;
+        *endpos = '\0';
+        if(slist_append(&headers, hdr)) {
+          fprintf(config->global->errors, "Out of memory for field header!\n");
+          curl_slist_free_all(headers);
+          return -1;
+        }
+      }
+    }
+    else {
+      /* unknown prefix, skip to next block */
+      char *unknown = get_param_word(&p, &endpos);
+
+      sep = *p;
+      if(endct)
+        endct = p;
+      else {
+        *endpos = '\0';
+         if(*unknown)
+           warnf(config->global, "skip unknown form field: %s\n", unknown);
+      }
+    }
+  }
+
+  /* Terminate and strip content type. */
+  if(type) {
+    if(!endct)
+      endct = type + strlen(type);
+    while(endct > type && ISSPACE(endct[-1]))
+      endct--;
+    *endct = '\0';
+  }
+
+  if(ptype)
+    *ptype = type;
+  else if(type)
+    warnf(config->global, "Field content type not allowed here: %s\n", type);
+
+  if(pfilename)
+    *pfilename = filename;
+  else if(filename)
+    warnf(config->global,
+          "Field file name not allowed here: %s\n", filename);
+
+  if(pheaders)
+    *pheaders = headers;
+  else if(headers) {
+    warnf(config->global,
+          "Field headers not allowed here: %s\n", headers->data);
+    curl_slist_free_all(headers);
+  }
+
+  *str = p;
+  return sep & 0xFF;
+}
+
 /***************************************************************************
  *
  * formparse()
@@ -143,219 +396,302 @@ static char *get_param_word(char **str, char **end_pos)
 
 int formparse(struct OperationConfig *config,
               const char *input,
-              struct curl_httppost **httppost,
-              struct curl_httppost **last_post,
+              curl_mime **mimepost,
+              curl_mime **mimecurrent,
               bool literal_value)
 {
-  /* nextarg MUST be a string in the format 'name=contents' and we'll
+  /* input MUST be a string in the format 'name=contents' and we'll
      build a linked list with the info */
-  char name[256];
+  char *name = NULL;
   char *contents = NULL;
-  char type_major[128] = "";
-  char type_minor[128] = "";
   char *contp;
+  char *data;
   char *type = NULL;
-  char *sep;
-
-  if((1 == sscanf(input, "%255[^=]=", name)) &&
-     ((contp = strchr(input, '=')) != NULL)) {
-    /* the input was using the correct format */
-
-    /* Allocate the contents */
-    contents = strdup(contp+1);
-    if(!contents) {
-      fprintf(config->global->errors, "out of memory\n");
+  char *filename = NULL;
+  struct curl_slist *headers = NULL;
+  curl_mimepart *part = NULL;
+  CURLcode res;
+  int sep = '\0';
+
+  /* Allocate the main mime structure if needed. */
+  if(!*mimepost) {
+    *mimepost = curl_mime_init(config->easy);
+    if(!*mimepost) {
+      warnf(config->global, "curl_mime_init failed!\n");
       return 1;
     }
-    contp = contents;
+    *mimecurrent = *mimepost;
+  }
 
-    if('@' == contp[0] && !literal_value) {
+  /* Make a copy we can overwrite. */
+  contents = strdup(input);
+  if(!contents) {
+    fprintf(config->global->errors, "out of memory\n");
+    return 2;
+  }
 
-      /* we use the @-letter to indicate file name(s) */
+  /* Scan for the end of the name. */
+  contp = strchr(contents, '=');
+  if(contp) {
+    if(contp > contents)
+      name = contents;
+    *contp++ = '\0';
+
+    if(*contp == '(' && !literal_value) {
+      curl_mime *subparts;
+
+      /* Starting a multipart. */
+      sep = get_param_part(config, &contp, &data, &type, NULL, &headers);
+      if(sep < 0) {
+        Curl_safefree(contents);
+        return 3;
+      }
+      subparts = curl_mime_init(config->easy);
+      if(!subparts) {
+        warnf(config->global, "curl_mime_init failed!\n");
+        curl_slist_free_all(headers);
+        Curl_safefree(contents);
+        return 4;
+      }
+      part = curl_mime_addpart(*mimecurrent);
+      if(!part) {
+        warnf(config->global, "curl_mime_addpart failed!\n");
+        curl_mime_free(subparts);
+        curl_slist_free_all(headers);
+        Curl_safefree(contents);
+        return 5;
+      }
+      if(curl_mime_subparts(part, subparts)) {
+        warnf(config->global, "curl_mime_subparts failed!\n");
+        curl_mime_free(subparts);
+        curl_slist_free_all(headers);
+        Curl_safefree(contents);
+        return 6;
+      }
+      *mimecurrent = subparts;
+      if(curl_mime_headers(part, headers, 1)) {
+        warnf(config->global, "curl_mime_headers failed!\n");
+        curl_slist_free_all(headers);
+        Curl_safefree(contents);
+        return 7;
+      }
+      if(curl_mime_type(part, type)) {
+        warnf(config->global, "curl_mime_type failed!\n");
+        Curl_safefree(contents);
+        return 8;
+      }
+    }
+    else if(!name && !strcmp(contp, ")") && !literal_value) {
+      /* Ending a mutipart. */
+      if(*mimecurrent == *mimepost) {
+        warnf(config->global, "no multipart to terminate!\n");
+        Curl_safefree(contents);
+        return 9;
+        }
+      *mimecurrent = (*mimecurrent)->parent->parent;
+    }
+    else if('@' == contp[0] && !literal_value) {
 
-      struct multi_files *multi_start = NULL;
-      struct multi_files *multi_current = NULL;
+      /* we use the @-letter to indicate file name(s) */
 
-      char *ptr = contp;
-      char *end = ptr + strlen(ptr);
+      curl_mime *subparts = NULL;
 
       do {
         /* since this was a file, it may have a content-type specifier
            at the end too, or a filename. Or both. */
-        char *filename = NULL;
-        char *word_end;
-        bool semicolon;
-
-        type = NULL;
-
-        ++ptr;
-        contp = get_param_word(&ptr, &word_end);
-        semicolon = (';' == *ptr) ? TRUE : FALSE;
-        *word_end = '\0'; /* terminate the contp */
-
-        /* have other content, continue parse */
-        while(semicolon) {
-          /* have type or filename field */
-          ++ptr;
-          while(*ptr && (ISSPACE(*ptr)))
-            ++ptr;
-
-          if(checkprefix("type=", ptr)) {
-            /* set type pointer */
-            type = &ptr[5];
-
-            /* verify that this is a fine type specifier */
-            if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
-                           type_major, type_minor)) {
-              warnf(config->global,
-                    "Illegally formatted content-type field!\n");
-              Curl_safefree(contents);
-              FreeMultiInfo(&multi_start, &multi_current);
-              return 2; /* illegal content-type syntax! */
-            }
-
-            /* now point beyond the content-type specifier */
-            sep = type + strlen(type_major)+strlen(type_minor)+1;
-
-            /* there's a semicolon following - we check if it is a filename
-               specified and if not we simply assume that it is text that
-               the user wants included in the type and include that too up
-               to the next sep. */
-            ptr = sep;
-            if(*sep==';') {
-              if(!checkprefix(";filename=", sep)) {
-                ptr = sep + 1;
-                (void)get_param_word(&ptr, &sep);
-                semicolon = (';' == *ptr) ? TRUE : FALSE;
-              }
-            }
-            else
-              semicolon = FALSE;
+        ++contp;
+        sep = get_param_part(config,
+                             &contp, &data, &type, &filename, &headers);
+        if(sep < 0) {
+          if(subparts != *mimecurrent)
+            curl_mime_free(subparts);
+          Curl_safefree(contents);
+          return 10;
+        }
 
-            if(*sep)
-              *sep = '\0'; /* zero terminate type string */
-          }
-          else if(checkprefix("filename=", ptr)) {
-            ptr += 9;
-            filename = get_param_word(&ptr, &word_end);
-            semicolon = (';' == *ptr) ? TRUE : FALSE;
-            *word_end = '\0';
-          }
+        /* now contp point to comma or string end.
+           If more files to come, make sure we have multiparts. */
+        if(!subparts) {
+          if(sep != ',')    /* If there is a single file. */
+            subparts = *mimecurrent;
           else {
-            /* unknown prefix, skip to next block */
-            char *unknown = NULL;
-            unknown = get_param_word(&ptr, &word_end);
-            semicolon = (';' == *ptr) ? TRUE : FALSE;
-            if(*unknown) {
-              *word_end = '\0';
-              warnf(config->global, "skip unknown form field: %s\n", unknown);
+            subparts = curl_mime_init(config->easy);
+            if(!subparts) {
+              warnf(config->global, "curl_mime_init failed!\n");
+              curl_slist_free_all(headers);
+              Curl_safefree(contents);
+              return 11;
             }
           }
         }
-        /* now ptr point to comma or string end */
 
+        /* Allocate a part for that file. */
+        part = curl_mime_addpart(subparts);
+        if(!part) {
+          warnf(config->global, "curl_mime_addpart failed!\n");
+          if(subparts != *mimecurrent)
+            curl_mime_free(subparts);
+          curl_slist_free_all(headers);
+          Curl_safefree(contents);
+          return 12;
+        }
 
-        /* if type == NULL curl_formadd takes care of the problem */
+        /* Set part headers. */
+        if(curl_mime_headers(part, headers, 1)) {
+          warnf(config->global, "curl_mime_headers failed!\n");
+          if(subparts != *mimecurrent)
+            curl_mime_free(subparts);
+          curl_slist_free_all(headers);
+          Curl_safefree(contents);
+          return 13;
+        }
 
-        if(*contp && !AddMultiFiles(contp, type, filename, &multi_start,
-                          &multi_current)) {
-          warnf(config->global, "Error building form post!\n");
+        /* Setup file in part. */
+        res = curl_mime_filedata(part, data);
+        if(res) {
+          warnf(config->global, "curl_mime_filedata failed!\n");
+          if(res != CURLE_READ_ERROR) {
+            if(subparts != *mimecurrent)
+              curl_mime_free(subparts);
+            Curl_safefree(contents);
+            return 14;
+          }
+        }
+        if(filename && curl_mime_filename(part, filename)) {
+          warnf(config->global, "curl_mime_filename failed!\n");
+          if(subparts != *mimecurrent)
+            curl_mime_free(subparts);
+          Curl_safefree(contents);
+          return 15;
+        }
+        if(type && curl_mime_type(part, type)) {
+          warnf(config->global, "curl_mime_type failed!\n");
+          if(subparts != *mimecurrent)
+            curl_mime_free(subparts);
           Curl_safefree(contents);
-          FreeMultiInfo(&multi_start, &multi_current);
-          return 3;
+          return 16;
         }
 
-        /* *ptr could be '\0', so we just check with the string end */
-      } while(ptr < end); /* loop if there's another file name */
+        /* *contp could be '\0', so we just check with the delimiter */
+      } while(sep); /* loop if there's another file name */
 
       /* now we add the multiple files section */
-      if(multi_start) {
-        struct curl_forms *forms = NULL;
-        struct multi_files *start = multi_start;
-        unsigned int i, count = 0;
-        while(start) {
-          start = start->next;
-          ++count;
-        }
-        forms = malloc((count+1)*sizeof(struct curl_forms));
-        if(!forms) {
-          fprintf(config->global->errors, "Error building form post!\n");
+      if(subparts != *mimecurrent) {
+        part = curl_mime_addpart(*mimecurrent);
+        if(!part) {
+          warnf(config->global, "curl_mime_addpart failed!\n");
+          curl_mime_free(subparts);
           Curl_safefree(contents);
-          FreeMultiInfo(&multi_start, &multi_current);
-          return 4;
+          return 17;
         }
-        for(i = 0, start = multi_start; i < count; ++i, start = start->next) {
-          forms[i].option = start->form.option;
-          forms[i].value = start->form.value;
-        }
-        forms[count].option = CURLFORM_END;
-        FreeMultiInfo(&multi_start, &multi_current);
-        if(curl_formadd(httppost, last_post,
-                        CURLFORM_COPYNAME, name,
-                        CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
-          warnf(config->global, "curl_formadd failed!\n");
-          Curl_safefree(forms);
+        if(curl_mime_subparts(part, subparts)) {
+          warnf(config->global, "curl_mime_subparts failed!\n");
+          curl_mime_free(subparts);
           Curl_safefree(contents);
-          return 5;
+          return 18;
         }
-        Curl_safefree(forms);
       }
     }
     else {
-      struct curl_forms info[4];
-      int i = 0;
-      char *ct = literal_value ? NULL : strstr(contp, ";type=");
-
-      info[i].option = CURLFORM_COPYNAME;
-      info[i].value = name;
-      i++;
-
-      if(ct) {
-        info[i].option = CURLFORM_CONTENTTYPE;
-        info[i].value = &ct[6];
-        i++;
-        ct[0] = '\0'; /* zero terminate here */
-      }
+        /* Allocate a mime part. */
+        part = curl_mime_addpart(*mimecurrent);
+        if(!part) {
+          warnf(config->global, "curl_mime_addpart failed!\n");
+          Curl_safefree(contents);
+          return 19;
+        }
 
-      if(contp[0]=='<' && !literal_value) {
-        info[i].option = CURLFORM_FILECONTENT;
-        info[i].value = contp+1;
-        i++;
-        info[i].option = CURLFORM_END;
+      if(*contp == '<' && !literal_value) {
+        ++contp;
+        sep = get_param_part(config,
+                             &contp, &data, &type, &filename, &headers);
+        if(sep < 0) {
+          Curl_safefree(contents);
+          return 20;
+        }
 
-        if(curl_formadd(httppost, last_post,
-                        CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
-          warnf(config->global, "curl_formadd failed, possibly the file %s is "
-                "bad!\n", contp + 1);
+        /* Set part headers. */
+        if(curl_mime_headers(part, headers, 1)) {
+          warnf(config->global, "curl_mime_headers failed!\n");
+          curl_slist_free_all(headers);
           Curl_safefree(contents);
-          return 6;
+          return 21;
+        }
+
+        /* Setup file in part. */
+        res = curl_mime_filedata(part, data);
+        if(res) {
+          warnf(config->global, "curl_mime_filedata failed!\n");
+          if(res != CURLE_READ_ERROR) {
+            Curl_safefree(contents);
+            return 22;
+          }
         }
       }
       else {
+        if(literal_value)
+          data = contp;
+        else {
+          sep = get_param_part(config,
+                               &contp, &data, &type, &filename, &headers);
+          if(sep < 0) {
+            Curl_safefree(contents);
+            return 23;
+          }
+        }
+
+        /* Set part headers. */
+        if(curl_mime_headers(part, headers, 1)) {
+          warnf(config->global, "curl_mime_headers failed!\n");
+          curl_slist_free_all(headers);
+          Curl_safefree(contents);
+          return 24;
+        }
+
 #ifdef CURL_DOES_CONVERSIONS
-        if(convert_to_network(contp, strlen(contp))) {
+        if(convert_to_network(data, strlen(data))) {
           warnf(config->global, "curl_formadd failed!\n");
           Curl_safefree(contents);
-          return 7;
+          return 25;
         }
 #endif
-        info[i].option = CURLFORM_COPYCONTENTS;
-        info[i].value = contp;
-        i++;
-        info[i].option = CURLFORM_END;
-        if(curl_formadd(httppost, last_post,
-                        CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
-          warnf(config->global, "curl_formadd failed!\n");
+
+        if(curl_mime_data(part, data, -1)) {
+          warnf(config->global, "curl_mime_data failed!\n");
           Curl_safefree(contents);
-          return 8;
+          return 26;
         }
       }
+
+      if(curl_mime_filename(part, filename)) {
+        warnf(config->global, "curl_mime_filename failed!\n");
+        Curl_safefree(contents);
+        return 27;
+      }
+      if(curl_mime_type(part, type)) {
+        warnf(config->global, "curl_mime_type failed!\n");
+        Curl_safefree(contents);
+        return 28;
+      }
+
+      if(sep) {
+        *contp = (char) sep;
+        warnf(config->global,
+              "garbage at end of field specification: %s\n", contp);
+      }
     }
 
+    /* Set part name. */
+    if(name && curl_mime_name(part, name, -1)) {
+      warnf(config->global, "curl_mime_name failed!\n");
+      Curl_safefree(contents);
+      return 29;
+    }
   }
   else {
     warnf(config->global, "Illegally formatted input field!\n");
-    return 1;
+    Curl_safefree(contents);
+    return 30;
   }
   Curl_safefree(contents);
   return 0;
diff --git a/src/tool_formparse.h b/src/tool_formparse.h
index ce7a29256..a52b98d39 100644
--- a/src/tool_formparse.h
+++ b/src/tool_formparse.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -25,8 +25,8 @@
 
 int formparse(struct OperationConfig *config,
               const char *input,
-              struct curl_httppost **httppost,
-              struct curl_httppost **last_post,
+              curl_mime **mimepost,
+              curl_mime **mimecurrent,
               bool literal_value);
 
 #endif /* HEADER_CURL_TOOL_FORMPARSE_H */
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
index 3dd1dec3f..31fc7a1ff 100644
--- a/src/tool_getparam.c
+++ b/src/tool_getparam.c
@@ -1606,11 +1606,11 @@ ParameterError getparameter(const char *flag, /* f or 
-long-flag */
          to sort this out slowly and carefully */
       if(formparse(config,
                    nextarg,
-                   &config->httppost,
-                   &config->last_post,
+                   &config->mimepost,
+                   &config->mimecurrent,
                    (subletter=='s')?TRUE:FALSE)) /* 's' means literal string */
         return PARAM_BAD_USE;
-      if(SetHTTPrequest(config, HTTPREQ_FORMPOST, &config->httpreq))
+      if(SetHTTPrequest(config, HTTPREQ_MIMEPOST, &config->httpreq))
         return PARAM_BAD_USE;
       break;
 
diff --git a/src/tool_help.c b/src/tool_help.c
index 7b982aa96..486f65dc8 100644
--- a/src/tool_help.c
+++ b/src/tool_help.c
@@ -131,9 +131,9 @@ static const struct helptxt helptext[] = {
   {"    --false-start",
    "Enable TLS False Start"},
   {"-F, --form <name=content>",
-   "Specify HTTP multipart POST data"},
+   "Specify multipart MIME data"},
   {"    --form-string <name=string>",
-   "Specify HTTP multipart POST data"},
+   "Specify multipart MIME data"},
   {"    --ftp-account <data>",
    "Account data string"},
   {"    --ftp-alternative-to-user <command>",
diff --git a/src/tool_mfiles.c b/src/tool_mfiles.c
deleted file mode 100644
index d862d4140..000000000
--- a/src/tool_mfiles.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <address@hidden>, 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 "tool_setup.h"
-
-#include "tool_mfiles.h"
-
-#include "memdebug.h" /* keep this as LAST include */
-
-static void AppendNode(struct multi_files **first,
-                       struct multi_files **last,
-                       struct multi_files  *new)
-{
-  DEBUGASSERT(((*first) && (*last)) || ((!*first) && (!*last)));
-
-  if(*last)
-    (*last)->next = new;
-  else
-    *first = new;
-  *last = new;
-}
-
-/*
- * AddMultiFiles: Add a new list node possibly followed with a type_name.
- *
- * multi_first argument is the address of a pointer to the first element
- * of the multi_files linked list. A NULL pointer indicates empty list.
- *
- * multi_last argument is the address of a pointer to the last element
- * of the multi_files linked list. A NULL pointer indicates empty list.
- *
- * Pointers stored in multi_first and multi_last are modified while
- * function is executed. An out of memory condition free's the whole
- * list and returns with pointers stored in multi_first and multi_last
- * set to NULL and a NULL function result.
- *
- * Function returns same pointer as stored at multi_last.
- */
-
-struct multi_files *AddMultiFiles(const char *file_name,
-                                  const char *type_name,
-                                  const char *show_filename,
-                                  struct multi_files **multi_first,
-                                  struct multi_files **multi_last)
-{
-  struct multi_files *multi;
-  struct multi_files *multi_type;
-  struct multi_files *multi_name;
-
-  multi = calloc(1, sizeof(struct multi_files));
-  if(multi) {
-    multi->form.option = CURLFORM_FILE;
-    multi->form.value = file_name;
-    AppendNode(multi_first, multi_last, multi);
-  }
-  else {
-    FreeMultiInfo(multi_first, multi_last);
-    return NULL;
-  }
-
-  if(type_name) {
-    multi_type = calloc(1, sizeof(struct multi_files));
-    if(multi_type) {
-      multi_type->form.option = CURLFORM_CONTENTTYPE;
-      multi_type->form.value = type_name;
-      AppendNode(multi_first, multi_last, multi_type);
-    }
-    else {
-      FreeMultiInfo(multi_first, multi_last);
-      return NULL;
-    }
-  }
-
-  if(show_filename) {
-    multi_name = calloc(1, sizeof(struct multi_files));
-    if(multi_name) {
-      multi_name->form.option = CURLFORM_FILENAME;
-      multi_name->form.value = show_filename;
-      AppendNode(multi_first, multi_last, multi_name);
-    }
-    else {
-      FreeMultiInfo(multi_first, multi_last);
-      return NULL;
-    }
-  }
-
-  return *multi_last;
-}
-
-/*
- * FreeMultiInfo: Free the items of the list.
- */
-
-void FreeMultiInfo(struct multi_files **multi_first,
-                   struct multi_files **multi_last)
-{
-  struct multi_files *next;
-  struct multi_files *item = *multi_first;
-
-  while(item) {
-    next = item->next;
-    Curl_safefree(item);
-    item = next;
-  }
-  *multi_first = NULL;
-  if(multi_last)
-    *multi_last = NULL;
-}
-
diff --git a/src/tool_mfiles.h b/src/tool_mfiles.h
deleted file mode 100644
index 827f40065..000000000
--- a/src/tool_mfiles.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef HEADER_CURL_TOOL_MFILES_H
-#define HEADER_CURL_TOOL_MFILES_H
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <address@hidden>, 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 "tool_setup.h"
-
-/*
- * Structure for storing the information needed to build
- * a multiple files section.
- */
-
-struct multi_files {
-  struct curl_forms   form;
-  struct multi_files *next;
-};
-
-struct multi_files *AddMultiFiles(const char *file_name,
-                                  const char *type_name,
-                                  const char *show_filename,
-                                  struct multi_files **multi_first,
-                                  struct multi_files **multi_last);
-
-void FreeMultiInfo(struct multi_files **multi_first,
-                   struct multi_files **multi_last);
-
-#endif /* HEADER_CURL_TOOL_MFILES_H */
-
diff --git a/src/tool_operate.c b/src/tool_operate.c
index fd9a13921..25ea9c4e6 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -1002,8 +1002,8 @@ static CURLcode operate_do(struct GlobalConfig *global,
             my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
                       config->postfieldsize);
             break;
-          case HTTPREQ_FORMPOST:
-            my_setopt_httppost(curl, CURLOPT_HTTPPOST, config->httppost);
+          case HTTPREQ_MIMEPOST:
+            my_setopt_mimepost(curl, CURLOPT_MIMEPOST, config->mimepost);
             break;
           default:
             break;
diff --git a/src/tool_sdecls.h b/src/tool_sdecls.h
index a56390e59..48dd4aed9 100644
--- a/src/tool_sdecls.h
+++ b/src/tool_sdecls.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -135,7 +135,7 @@ typedef enum {
   HTTPREQ_UNSPEC,  /* first in list */
   HTTPREQ_GET,
   HTTPREQ_HEAD,
-  HTTPREQ_FORMPOST,
+  HTTPREQ_MIMEPOST,
   HTTPREQ_SIMPLEPOST
 } HttpReq;
 
diff --git a/src/tool_setopt.c b/src/tool_setopt.c
index 694d3ffa5..6cb6bb3e3 100644
--- a/src/tool_setopt.c
+++ b/src/tool_setopt.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -30,7 +30,9 @@
 #include "tool_cfgable.h"
 #include "tool_easysrc.h"
 #include "tool_setopt.h"
+#include "tool_convert.h"
 
+#include "mime.h"
 #include "memdebug.h" /* keep this as LAST include */
 
 /* Lookup tables for converting setopt values back to symbols */
@@ -208,14 +210,14 @@ static const NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
 
 /* Escape string to C string syntax.  Return NULL if out of memory.
  * Is this correct for those wacky EBCDIC guys? */
-static char *c_escape(const char *str)
+static char *c_escape(const char *str, ssize_t len)
 {
-  size_t len = 0;
   const char *s;
   unsigned char c;
   char *escaped, *e;
   /* Allocate space based on worst-case */
-  len = strlen(str);
+  if(len < 0)
+    len = strlen(str);
   escaped = malloc(4 * len + 1);
   if(!escaped)
     return NULL;
@@ -371,118 +373,215 @@ CURLcode tool_setopt_bitmask(CURL *curl, struct 
GlobalConfig *config,
   return ret;
 }
 
-/* setopt wrapper for CURLOPT_HTTPPOST */
-CURLcode tool_setopt_httppost(CURL *curl, struct GlobalConfig *config,
-                              const char *name, CURLoption tag,
-                              struct curl_httppost *post)
+/* Generate code for a struct curl_slist. */
+static CURLcode libcurl_generate_slist(struct curl_slist *slist, int *slistno)
 {
   CURLcode ret = CURLE_OK;
   char *escaped = NULL;
-  bool skip = FALSE;
 
-  ret = curl_easy_setopt(curl, tag, post);
-  if(!post)
-    skip = TRUE;
+  /* May need several slist variables, so invent name */
+  *slistno = ++easysrc_slist_count;
+
+  DECL1("struct curl_slist *slist%d;", *slistno);
+  DATA1("slist%d = NULL;", *slistno);
+  CLEAN1("curl_slist_free_all(slist%d);", *slistno);
+  CLEAN1("slist%d = NULL;", *slistno);
+  for(; slist; slist = slist->next) {
+    Curl_safefree(escaped);
+    escaped = c_escape(slist->data, -1);
+    if(!escaped)
+      return CURLE_OUT_OF_MEMORY;
+    DATA3("slist%d = curl_slist_append(slist%d, \"%s\");",
+                                       *slistno, *slistno, escaped);
+  }
 
-  if(config->libcurl && !skip && !ret) {
-    struct curl_httppost *pp, *p;
-    int i;
-    /* May use several httppost lists, if multiple POST actions */
-    i = ++ easysrc_form_count;
-    DECL1("struct curl_httppost *post%d;", i);
-    DATA1("post%d = NULL;", i);
-    CLEAN1("curl_formfree(post%d);", i);
-    CLEAN1("post%d = NULL;", i);
-    if(i == 1)
-      DECL0("struct curl_httppost *postend;");
-    DATA0("postend = NULL;");
-    for(p=post; p; p=p->next) {
-      DATA1("curl_formadd(&post%d, &postend,", i);
-      DATA1("             CURLFORM_COPYNAME, \"%s\",", p->name);
-      for(pp=p; pp; pp=pp->more) {
-        /* May be several files uploaded for one name;
-         * these are linked through the 'more' pointer */
+ nomem:
+  Curl_safefree(escaped);
+  return ret;
+}
+
+/* Generate source code for a mime structure. */
+static CURLcode libcurl_generate_mime(curl_mime *mime, int *mimeno)
+{
+  CURLcode ret = CURLE_OK;
+  int i;
+  curl_off_t size;
+  curl_mimepart *part;
+  char *filename;
+  char *escaped = NULL;
+  char *cp;
+  char *data;
+
+  /* May need several mime variables, so invent name */
+  *mimeno = ++easysrc_mime_count;
+
+  DECL1("curl_mime *mime%d;", *mimeno);
+  DATA1("mime%d = NULL;", *mimeno);
+  CODE1("mime%d = curl_mime_init(hnd);", *mimeno);
+  CLEAN1("curl_mime_free(mime%d);", *mimeno);
+  CLEAN1("mime%d = NULL;", *mimeno);
+  if(mime->firstpart) {
+    DECL1("curl_mimepart *part%d;", *mimeno);
+    for(part = mime->firstpart; part; part = part->nextpart) {
+      CODE2("part%d = curl_mime_addpart(mime%d);", *mimeno, *mimeno);
+      filename = part->filename;
+      switch(part->kind) {
+      case MIMEKIND_NAMEDFILE:
         Curl_safefree(escaped);
-        escaped = c_escape(pp->contents);
-        if(!escaped) {
-          ret = CURLE_OUT_OF_MEMORY;
-          goto nomem;
-        }
-        if(pp->flags & CURL_HTTPPOST_FILENAME) {
-          /* file upload as for -F @filename */
-          DATA1("             CURLFORM_FILE, \"%s\",", escaped);
-        }
-        else if(pp->flags & CURL_HTTPPOST_READFILE) {
-          /* content from file as for -F <filename */
-          DATA1("             CURLFORM_FILECONTENT, \"%s\",", escaped);
+        escaped = c_escape(part->data, -1);
+        if(!escaped)
+          return CURLE_OUT_OF_MEMORY;
+        CODE2("curl_mime_filedata(part%d, \"%s\");", *mimeno, escaped);
+        if(!filename)
+          CODE1("curl_mime_filename(part%d, NULL);", *mimeno);
+        else {
+          /* Fast check to see if remote file name is base name. */
+          filename = part->data;
+          for(cp = filename; *cp; cp++)
+            if(*cp == '/' || *cp == '\\')
+              filename = cp + 1;
+          if(!part->filename || !strcmp(filename, part->filename))
+            filename = NULL;
+          else
+            filename = part->filename;
         }
-        else
-          DATA1("             CURLFORM_COPYCONTENTS, \"%s\",", escaped);
-        if(pp->showfilename) {
-          Curl_safefree(escaped);
-          escaped = c_escape(pp->showfilename);
-          if(!escaped) {
+        break;
+      case MIMEKIND_FILE:
+        /* Can only be stdin in the current context. */
+        CODE1("curl_mime_file(part%d, \"-\");", *mimeno);
+        break;
+      case MIMEKIND_DATA:
+#ifdef CURL_DOES_CONVERSIONS
+          /* Data is stored in ASCII and we want in in the host character
+             code. Convert it back for output. */
+          data = malloc(part->datasize + 1);
+          if(!data) {
             ret = CURLE_OUT_OF_MEMORY;
             goto nomem;
           }
-          DATA1("             CURLFORM_FILENAME, \"%s\",", escaped);
-        }
-        if(pp->contenttype) {
-          Curl_safefree(escaped);
-          escaped = c_escape(pp->contenttype);
-          if(!escaped) {
-            ret = CURLE_OUT_OF_MEMORY;
+          memcpy(data, part->data, part->datasize + 1);
+          ret = convert_from_network(data, strlen(data));
+          if(ret) {
+            Curl_safefree(data);
             goto nomem;
           }
-          DATA1("             CURLFORM_CONTENTTYPE, \"%s\",", escaped);
-        }
+#else
+        data = part->data;
+#endif
+
+        /* Are there any nul byte in data? */
+        for(cp = data; *cp; cp++)
+          ;
+        size = (cp == data + part->datasize)? (curl_off_t) -1: part->datasize;
+        Curl_safefree(escaped);
+        escaped = c_escape(data, part->datasize);
+        if(data != part->data)
+          Curl_safefree(data);
+        if(!escaped)
+          return CURLE_OUT_OF_MEMORY;
+        CODE3("curl_mime_data(part%d, \"%s\", %" CURL_FORMAT_CURL_OFF_T ");",
+                              *mimeno, escaped, size);
+        break;
+      case MIMEKIND_MULTIPART:
+        ret = libcurl_generate_mime(part->arg, &i);
+        if(ret)
+          goto nomem;
+        CODE2("curl_mime_subparts(part%d, mime%d);", *mimeno, i);
+        CODE1("mime%d = NULL;", i);   /* Avoid freeing in CLEAN sequence. */
+        break;
+      default:
+        /* Other cases not possible in this context. */
+        break;
+      }
+
+      if(filename) {
+        Curl_safefree(escaped);
+        escaped = c_escape(filename, -1);
+        if(!escaped)
+          return CURLE_OUT_OF_MEMORY;
+        CODE2("curl_mime_filename(part%d, \"%s\");", *mimeno, escaped);
+      }
+
+      if(part->name) {
+        Curl_safefree(escaped);
+        escaped = c_escape(part->name, part->namesize);
+        if(!escaped)
+          return CURLE_OUT_OF_MEMORY;
+        for(cp = part->name; *cp; cp++)
+          ;
+        size = (cp == part->name + part->namesize)?
+               (curl_off_t) -1: (curl_off_t) part->namesize;
+        CODE3("curl_mime_name(part%d, \"%s\", %" CURL_FORMAT_CURL_OFF_T ");",
+              *mimeno, escaped, size);
+      }
+
+      if(part->mimetype) {
+        Curl_safefree(escaped);
+        escaped = c_escape(part->mimetype, -1);
+        if(!escaped)
+          return CURLE_OUT_OF_MEMORY;
+        CODE2("curl_mime_type(part%d, \"%s\");", *mimeno, escaped);
+      }
+
+      if(part->userheaders) {
+        int ownership = part->flags & MIME_USERHEADERS_OWNER? 1: 0;
+
+        ret = libcurl_generate_slist(part->userheaders, &i);
+        if(ret)
+          goto nomem;
+        CODE3("curl_mime_headers(part%d, slist%d, %d);",
+              *mimeno, i, ownership);
+        if(ownership)
+          CODE1("slist%d = NULL;", i); /* Prevent freeing in CLEAN sequence. */
       }
-      DATA0("             CURLFORM_END);");
     }
-    CODE2("curl_easy_setopt(hnd, %s, post%d);", name, i);
   }
 
- nomem:
+nomem:
   Curl_safefree(escaped);
   return ret;
 }
 
+/* setopt wrapper for CURLOPT_MIMEPOST */
+CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config,
+                              const char *name, CURLoption tag,
+                              curl_mime *mimepost)
+{
+  CURLcode ret = CURLE_OK;
+
+  ret = curl_easy_setopt(curl, tag, mimepost);
+
+  if(config->libcurl && mimepost && !ret) {
+    int i;
+
+    ret = libcurl_generate_mime(mimepost, &i);
+
+    if(!ret)
+      CODE2("curl_easy_setopt(hnd, %s, mime%d);", name, i);
+  }
+
+nomem:
+  return ret;
+}
+
 /* setopt wrapper for curl_slist options */
 CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config,
                            const char *name, CURLoption tag,
                            struct curl_slist *list)
 {
   CURLcode ret = CURLE_OK;
-  char *escaped = NULL;
-  bool skip = FALSE;
 
   ret = curl_easy_setopt(curl, tag, list);
-  if(!list)
-    skip = TRUE;
 
-  if(config->libcurl && !skip && !ret) {
-    struct curl_slist *s;
+  if(config->libcurl && list && !ret) {
     int i;
-    /* May need several slist variables, so invent name */
-    i = ++ easysrc_slist_count;
-    DECL1("struct curl_slist *slist%d;", i);
-    DATA1("slist%d = NULL;", i);
-    CLEAN1("curl_slist_free_all(slist%d);", i);
-    CLEAN1("slist%d = NULL;", i);
-    for(s=list; s; s=s->next) {
-      Curl_safefree(escaped);
-      escaped = c_escape(s->data);
-      if(!escaped) {
-        ret = CURLE_OUT_OF_MEMORY;
-        goto nomem;
-      }
-      DATA3("slist%d = curl_slist_append(slist%d, \"%s\");", i, i, escaped);
-    }
-    CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i);
+
+    ret = libcurl_generate_slist(list, &i);
+    if(!ret)
+      CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i);
   }
 
  nomem:
-  Curl_safefree(escaped);
   return ret;
 }
 
@@ -569,7 +668,7 @@ CURLcode tool_setopt(CURL *curl, bool str, struct 
GlobalConfig *config,
       REM2("%s set to a %s", name, value);
     else {
       if(escape) {
-        escaped = c_escape(value);
+        escaped = c_escape(value, -1);
         if(!escaped) {
           ret = CURLE_OUT_OF_MEMORY;
           goto nomem;
diff --git a/src/tool_setopt.h b/src/tool_setopt.h
index da67deeb6..f8a52cd75 100644
--- a/src/tool_setopt.h
+++ b/src/tool_setopt.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -85,9 +85,9 @@ CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig 
*config,
 CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config,
                              const char *name, CURLoption tag,
                              const NameValueUnsigned *nv, long lval);
-CURLcode tool_setopt_httppost(CURL *curl, struct GlobalConfig *config,
+CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config,
                               const char *name, CURLoption tag,
-                              struct curl_httppost *httppost);
+                              curl_mime *mimepost);
 CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config,
                            const char *name, CURLoption tag,
                            struct curl_slist *list);
@@ -109,8 +109,8 @@ CURLcode tool_setopt(CURL *curl, bool str, struct 
GlobalConfig *config,
 #define my_setopt_bitmask(x,y,z) \
   SETOPT_CHECK(tool_setopt_bitmask(x, global, #y, y, setopt_nv_ ## y, z))
 
-#define my_setopt_httppost(x,y,z) \
-  SETOPT_CHECK(tool_setopt_httppost(x, global, #y, y, z))
+#define my_setopt_mimepost(x,y,z) \
+  SETOPT_CHECK(tool_setopt_mimepost(x, global, #y, y, z))
 
 #define my_setopt_slist(x,y,z) \
   SETOPT_CHECK(tool_setopt_slist(x, global, #y, y, z))
@@ -138,7 +138,7 @@ CURLcode tool_setopt(CURL *curl, bool str, struct 
GlobalConfig *config,
 #define my_setopt_bitmask(x,y,z) \
   SETOPT_CHECK(curl_easy_setopt(x, y, z))
 
-#define my_setopt_httppost(x,y,z) \
+#define my_setopt_mimepost(x,y,z) \
   SETOPT_CHECK(curl_easy_setopt(x, y, z))
 
 #define my_setopt_slist(x,y,z) \

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]