]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
Fix dynamic CURLOPT_POSTFIELDS bug: back to static.
authorPatrick Monnerat <Patrick.Monnerat@datasphere.ch>
Mon, 15 Oct 2007 18:32:01 +0000 (18:32 +0000)
committerPatrick Monnerat <Patrick.Monnerat@datasphere.ch>
Mon, 15 Oct 2007 18:32:01 +0000 (18:32 +0000)
CURLOPT_COPYPOSTFIELDS option added for dynamic.
Fix some OS400 features.

CHANGES
docs/libcurl/curl_easy_setopt.3
include/curl/curl.h
lib/config-os400.h
lib/http.c
lib/transfer.c
lib/url.c
lib/urldata.h
packages/OS400/README.OS400
packages/OS400/ccsidcurl.c

diff --git a/CHANGES b/CHANGES
index 56f7c79f9dd73f2c5650acc2383a8b6147cc751f..07841de2a157a22e838410d356ebd3b18168668c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,10 @@
 
                                   Changelog
 
+Patrick M (15 October 2007)
+- Fixed the dynamic CURLOPT_POSTFIELDS problem: this option is now static again
+  and option CURLOPT_COPYPOSTFIELDS has been added to support dynamic mode.
+
 Patrick M (12 October 2007)
 - Added per-protocol callback static tables, replacing callback ptr storage
   in the connectdata structure by a single handler table ptr.
index 7c546d6a62624db048cec26498c71064832228ce..b5a0b270e9d20a8ba1f8f8400d46015dce79cc77 100644 (file)
@@ -386,8 +386,7 @@ POST/PUT and a 401 or 407 is received immediately afterwards.
 .SH NETWORK OPTIONS
 .IP CURLOPT_URL
 The actual URL to deal with. The parameter should be a char * to a zero
-terminated string. The string must remain present until curl no longer needs
-it, as it doesn't copy the string.
+terminated string.
 
 If the given URL lacks the protocol part ("http://" or "ftp://" etc), it will
 attempt to guess which protocol to use based on the given host name. If the
@@ -662,14 +661,16 @@ also make the library use the a "Content-Type:
 application/x-www-form-urlencoded" header. (This is by far the most commonly
 used POST method).
 
-Use the \fICURLOPT_POSTFIELDS\fP option to specify what data to post and
-\fICURLOPT_POSTFIELDSIZE\fP to set the data size.
+Use one of \fICURLOPT_POSTFIELDS\fP or \fICURLOPT_COPYPOSTFIELDS\fP options to
+specify what data to post and \fICURLOPT_POSTFIELDSIZE\fP or
+\fICURLOPT_POSTFIELDSIZE_LARGE\fP to set the data size.
 
 Optionally, you can provide data to POST using the \fICURLOPT_READFUNCTION\fP
 and \fICURLOPT_READDATA\fP options but then you must make sure to not set
 \fICURLOPT_POSTFIELDS\fP to anything but NULL. When providing data with a
 callback, you must transmit it using chunked transfer-encoding or you must set
-the size of the data with the \fICURLOPT_POSTFIELDSIZE\fP option.
+the size of the data with the \fICURLOPT_POSTFIELDSIZE\fP or
+\fICURLOPT_POSTFIELDSIZE_LARGE\fP option.
 
 You can override the default POST Content-Type: header by setting your own
 with \fICURLOPT_HTTPHEADER\fP.
@@ -690,11 +691,14 @@ If you issue a POST request and then want to make a HEAD or GET using the same
 re-used handle, you must explicitly set the new request type using
 \fICURLOPT_NOBODY\fP or \fICURLOPT_HTTPGET\fP or similar.
 .IP CURLOPT_POSTFIELDS
-Pass a char * as parameter, which should be the full data to post in an HTTP
+Pass a void * as parameter, which should be the full data to post in an HTTP
 POST operation. You must make sure that the data is formatted the way you want
 the server to receive it. libcurl will not convert or encode it for you. Most
 web servers will assume this data to be url-encoded. Take note.
 
+The pointed data are NOT copied by the library: as a consequence, they must
+be preserved by the calling application until the transfer finishes.
+
 This POST is a normal application/x-www-form-urlencoded kind (and libcurl will
 set that Content-Type by default when this option is used), which is the most
 commonly used one by HTML forms. See also the \fICURLOPT_POST\fP. Using
@@ -721,6 +725,21 @@ Pass a curl_off_t as parameter. Use this to set the size of the
 \fICURLOPT_POSTFIELDS\fP data to prevent libcurl from doing strlen() on the
 data to figure out the size. This is the large file version of the
 \fICURLOPT_POSTFIELDSIZE\fP option. (Added in 7.11.1)
+.IP CURLOPT_COPYPOSTFIELDS
+Pass a char * as parameter, which should be the full data to post in an HTTP
+POST operation. It behaves has the \fICURLOPT_POSTFIELDS\fP option, but the
+original data are copied by the library, allowing the application to overwrite
+the original data after setting this option.
+
+Because data are copied, care must be taken when using this option in
+conjunction with \fICURLOPT_POSTFIELDSIZE\fP or
+\fICURLOPT_POSTFIELDSIZE_LARGE\fP: If the size has not been set prior to
+\fICURLOPT_COPYPOSTFIELDS\fP, the data are assumed to be a null-terminated
+string; else the stored size informs the library about the data byte count to
+copy. In any case, the size must not be changed after
+\fICURLOPT_COPYPOSTFIELDS\fP, unless another \fICURLOPT_POSTFIELDS\fP or
+\fICURLOPT_COPYPOSTFIELDS\fP option is issued.
+
 .IP CURLOPT_HTTPPOST
 Tells libcurl you want a multipart/formdata HTTP POST to be made and you
 instruct what data to pass on to the server.  Pass a pointer to a linked list
index 5bd6b3feb8fe4f6af7278a02c481d068177cb3e6..6a7a71963a0ee6f26a37a4793b19d11094552578 100644 (file)
@@ -659,7 +659,7 @@ typedef enum {
    */
   CINIT(INFILESIZE, LONG, 14),
 
-  /* POST input fields. */
+  /* POST static input fields. */
   CINIT(POSTFIELDS, OBJECTPOINT, 15),
 
   /* Set the referer page (needed by some CGIs) */
@@ -1156,6 +1156,9 @@ typedef enum {
   CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163),
   CINIT(OPENSOCKETDATA, OBJECTPOINT, 164),
 
+  /* POST volatile input fields. */
+  CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index 6eccff1e797d5dffd13f0feb9261e8fe19f5082c..5e30e435dee4b7303bb5e283a3726270c49d542c 100644 (file)
 /* The size of a `long double', as computed by sizeof. */
 #define SIZEOF_LONG_DOUBLE      8
 
+/* Define if 64 bit integers are supported. */
+#define HAVE_LONGLONG
+
 /* The size of a `long long', as computed by sizeof. */
 #define SIZEOF_LONG_LONG        8
 
index 9839912d73b3571a2e56ff5a1f0f4300a41d36d5..d3954338f21eb9285405703fde57a00d558668c3 100644 (file)
@@ -2554,8 +2554,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
         /* figure out the size of the postfields */
         postsize = (data->set.postfieldsize != -1)?
           data->set.postfieldsize:
-          (data->set.str[STRING_POSTFIELDS]?
-           (curl_off_t)strlen(data->set.str[STRING_POSTFIELDS]):0);
+          (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
 
       if(!conn->bits.upload_chunky) {
         /* We only set Content-Length and allow a custom Content-Length if
@@ -2580,7 +2579,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
           return result;
       }
 
-      if(data->set.str[STRING_POSTFIELDS]) {
+      if(data->set.postfields) {
 
         /* for really small posts we don't use Expect: headers at all, and for
            the somewhat bigger ones we allow the app to disable it */
@@ -2608,7 +2607,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
           if(!conn->bits.upload_chunky) {
             /* We're not sending it 'chunked', append it to the request
                already now to reduce the number if send() calls */
-            result = add_buffer(req_buffer, data->set.str[STRING_POSTFIELDS],
+            result = add_buffer(req_buffer, data->set.postfields,
                                 (size_t)postsize);
             included_body = postsize;
           }
@@ -2616,7 +2615,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
             /* Append the POST data chunky-style */
             result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
             if(CURLE_OK == result)
-              result = add_buffer(req_buffer, data->set.str[STRING_POSTFIELDS],
+              result = add_buffer(req_buffer, data->set.postfields,
                                   (size_t)postsize);
             if(CURLE_OK == result)
               result = add_buffer(req_buffer,
@@ -2630,7 +2629,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
         else {
           /* A huge POST coming up, do data separate from the request */
           http->postsize = postsize;
-          http->postdata = data->set.str[STRING_POSTFIELDS];
+          http->postdata = data->set.postfields;
 
           http->sending = HTTPSEND_BODY;
 
index 831cb3e98ab617357f0a1f5bfae03844c5ad1e73..d36f55f799d15fc1d2579609a62af9f07d74d9d5 100644 (file)
@@ -233,7 +233,7 @@ CURLcode Curl_readrewind(struct connectdata *conn)
   /* We have sent away data. If not using CURLOPT_POSTFIELDS or
      CURLOPT_HTTPPOST, call app to rewind
   */
-  if(data->set.str[STRING_POSTFIELDS] ||
+  if(data->set.postfields ||
      (data->set.httpreq == HTTPREQ_POST_FORM))
     ; /* do nothing */
   else {
index e6b0d7f273659da6c8262833e5ecac369efff5ff..35dce95411ebe88539039fb2749256f6408cfaea 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -771,6 +771,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
                      va_list param)
 {
   char *argptr;
+  curl_off_t bigsize;
   CURLcode result = CURLE_OK;
 
   switch(option) {
@@ -1029,12 +1030,52 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
       data->set.httpreq = HTTPREQ_GET;
     break;
 
-  case CURLOPT_POSTFIELDS:
+  case CURLOPT_COPYPOSTFIELDS:
     /*
      * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
+     * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to
+     *  CURLOPT_COPYPOSTFIELDS and not altered later.
      */
-    result = Curl_setstropt(&data->set.str[STRING_POSTFIELDS],
-                            va_arg(param, char *));
+    argptr = va_arg(param, char *);
+
+    if (!argptr || data->set.postfieldsize == -1)
+      result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr);
+    else {
+      /*
+       *  Check that request length does not overflow the size_t type.
+       */
+
+      if ((curl_off_t) ((size_t) data->set.postfieldsize) !=
+          data->set.postfieldsize ||
+          data->set.postfieldsize < (curl_off_t) 0 ||
+          (size_t) data->set.postfieldsize < (size_t) 0)
+        result = CURLE_OUT_OF_MEMORY;
+      else {
+        char * p;
+
+        (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+        p = malloc(data->set.postfieldsize);
+
+        if (!p)
+          result = CURLE_OUT_OF_MEMORY;
+        else {
+          memcpy(p, argptr, data->set.postfieldsize);
+          data->set.str[STRING_COPYPOSTFIELDS] = p;
+       }
+      }
+    }
+
+    data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
+    data->set.httpreq = HTTPREQ_POST;
+    break;
+
+  case CURLOPT_POSTFIELDS:
+    /*
+     * Like above, but use static data instead of copying it.
+     */
+    data->set.postfields = va_arg(param, void *);
+    /* Release old copied data. */
+    (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
     data->set.httpreq = HTTPREQ_POST;
     break;
 
@@ -1043,7 +1084,16 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * The size of the POSTFIELD data to prevent libcurl to do strlen() to
      * figure it out. Enables binary posts.
      */
-    data->set.postfieldsize = va_arg(param, long);
+    bigsize = va_arg(param, long);
+
+    if (data->set.postfieldsize < bigsize &&
+        data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+      /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+      (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+      data->set.postfields = NULL;
+      }
+
+    data->set.postfieldsize = bigsize;
     break;
 
   case CURLOPT_POSTFIELDSIZE_LARGE:
@@ -1051,7 +1101,16 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * The size of the POSTFIELD data to prevent libcurl to do strlen() to
      * figure it out. Enables binary posts.
      */
-    data->set.postfieldsize = va_arg(param, curl_off_t);
+    bigsize = va_arg(param, curl_off_t);
+
+    if (data->set.postfieldsize < bigsize &&
+        data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+      /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+      (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+      data->set.postfields = NULL;
+      }
+
+    data->set.postfieldsize = bigsize;
     break;
 
   case CURLOPT_HTTPPOST:
index ef685e183acc62e2b80f59a209c5101303957dc1..8ee1d1989924e65154f35f7aad60b49a5bd193fd 100644 (file)
@@ -1286,7 +1286,7 @@ enum dupstring {
   STRING_KRB_LEVEL,       /* krb security level */
   STRING_NETRC_FILE,      /* if not NULL, use this instead of trying to find
                              $HOME/.netrc */
-  STRING_POSTFIELDS,      /* if POST, set the fields' values here */
+  STRING_COPYPOSTFIELDS,  /* if POST, set the fields' values here */
   STRING_PROXY,           /* proxy to use */
   STRING_PROXYUSERPWD,    /* Proxy <user:password>, if used */
   STRING_SET_RANGE,       /* range, if used */
@@ -1326,6 +1326,7 @@ struct UserDefined {
   bool post301;      /* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a 301 */
   bool free_referer; /* set TRUE if 'referer' points to a string we
                         allocated */
+  void *postfields;  /* if POST, set the fields' values here */
   curl_off_t postfieldsize; /* if POST, this might have a size to use instead
                                of strlen(), and then the data *may* be binary
                                (contain zero bytes) */
index eb5b940ac18e57c9ce350a6d674c7ac2f5b1148e..3dad3ab5dfc9e8d17ce343b32410d499676a3f28 100644 (file)
@@ -81,7 +81,7 @@ options:
         CURLOPT_KEYPASSWD
         CURLOPT_KRBLEVEL
         CURLOPT_NETRC_FILE
-        CURLOPT_POSTFIELDS
+        CURLOPT_COPYPOSTFIELDS
         CURLOPT_PROXY
         CURLOPT_PROXYUSERPWD
         CURLOPT_RANDOM_FILE
@@ -102,6 +102,10 @@ options:
   Else it is the same as for curl_easy_setopt().
   Note that CURLOPT_ERRORBUFFER is not in the list above, since it gives the
 address of an (empty) character buffer, not the address of a string.
+CURLOPT_POSTFIELDS stores the address of static binary data (of type void *) and
+thus is not converted. If CURLOPT_COPYPOSTFIELDS is issued after
+CURLOPT_POSTFIELDSIZE != -1, the data size is adjusted according to the
+CCSID conversion result length.
 
 _ curl_formadd_ccsid()
   In the variable argument list, string pointers should be followed by a (long)
index ad8f0fa7c3ef6d3616e1729689037ab0dcd4555a..78ff74d95a16e496696881f56dae2c15699fedd1 100644 (file)
 
 #include "os400sys.h"
 
+#ifndef SIZE_MAX
+#define SIZE_MAX        ((size_t) ~0)   /* Is unsigned on OS/400. */
+#endif
+
 
 #define ASCII_CCSID     819     /* Use ISO-8859-1 as ASCII. */
+#define NOCONV_CCSID    65535   /* No conversion. */
 #define ICONV_ID_SIZE   32      /* Size of iconv_open() code identifier. */
 #define ICONV_OPEN_ERROR(t)     ((t).return_value == -1)
 
@@ -62,7 +67,7 @@ makeOS400IconvCode(char buf[ICONV_ID_SIZE], unsigned int ccsid)
 
   ccsid &= 0xFFFF;
 
-  if (ccsid == 65535)
+  if (ccsid == NOCONV_CCSID)
     ccsid = ASCII_CCSID;
 
   memset(buf, 0, ICONV_ID_SIZE);
@@ -1004,7 +1009,10 @@ curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...)
   va_list arg;
   struct SessionHandle * data;
   char * s;
+  char * cp;
   unsigned int ccsid;
+  size_t len;
+  curl_off_t pfsize;
   static char testwarn = 1;
 
   /* Warns if this procedure has not been updated when the dupstring enum
@@ -1042,7 +1050,6 @@ curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...)
   case CURLOPT_KEYPASSWD:
   case CURLOPT_KRBLEVEL:
   case CURLOPT_NETRC_FILE:
-  case CURLOPT_POSTFIELDS:
   case CURLOPT_PROXY:
   case CURLOPT_PROXYUSERPWD:
   case CURLOPT_RANDOM_FILE:
@@ -1079,6 +1086,66 @@ curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...)
 
     break;
 
+  case CURLOPT_COPYPOSTFIELDS:
+    /* Special case: byte count may have been given by CURLOPT_POSTFIELDSIZE
+       prior to this call. In this case, convert the given byte count and
+       replace the length according to the conversion result. */
+    s = va_arg(arg, char *);
+    ccsid = va_arg(arg, unsigned int);
+
+    pfsize = data->set.postfieldsize;
+
+    if (!s || !pfsize || ccsid == NOCONV_CCSID || ccsid == ASCII_CCSID) {
+      result = curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, s);
+      break;
+      }
+
+    if (pfsize == -1) {
+      /* Data is null-terminated. */
+      s = dynconvert(ASCII_CCSID, s, -1, ccsid);
+
+      if (!s) {
+        result = CURLE_OUT_OF_MEMORY;
+        break;
+        }
+      }
+    else {
+      /* Data length specified. */
+
+      if (pfsize < 0 || pfsize > SIZE_MAX) {
+        result = CURLE_OUT_OF_MEMORY;
+        break;
+        }
+
+      len = pfsize;
+      pfsize = len * MAX_CONV_EXPANSION;
+
+      if (pfsize > SIZE_MAX)
+        pfsize = SIZE_MAX;
+
+      cp = malloc(pfsize);
+
+      if (!cp) {
+        result = CURLE_OUT_OF_MEMORY;
+        break;
+        }
+
+      pfsize = convert(cp, pfsize, ASCII_CCSID, s, len, ccsid);
+
+      if (pfsize < 0) {
+        free(cp);
+        result = CURLE_OUT_OF_MEMORY;
+        break;
+        }
+
+      data->set.postfieldsize = pfsize;         /* Replace data size. */
+      s = cp;
+      }
+
+    result = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, s);
+    data->set.str[STRING_COPYPOSTFIELDS] = s;   /* Give to library. */
+    break;
+
   case CURLOPT_ERRORBUFFER:                     /* This is an output buffer. */
   default:
     result = Curl_setopt(data, tag, arg);