Now supports "Transfer-Encoding: chunked" for HTTP PUT operations where the
authorDaniel Stenberg <daniel@haxx.se>
Mon, 11 Nov 2002 08:40:37 +0000 (08:40 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 11 Nov 2002 08:40:37 +0000 (08:40 +0000)
size of the uploaded file is unknown.

lib/http.c
lib/transfer.c
lib/url.c
lib/urldata.h

index 35cae48..460ce0a 100644 (file)
@@ -485,6 +485,7 @@ CURLcode Curl_http(struct connectdata *conn)
   struct Cookie *co=NULL; /* no cookies from start */
   char *ppath = conn->ppath; /* three previous function arguments */
   char *host = conn->name;
+  const char *te = ""; /* tranfer-encoding */
 
   if(!conn->proto.http) {
     /* Only allocate this struct if we don't already have it! */
@@ -546,6 +547,14 @@ CURLcode Curl_http(struct connectdata *conn)
     conn->allocptr.cookie = aprintf("Cookie: %s\015\012", data->set.cookie);
   }
 
+  if(conn->upload_chunky) {
+    if(!checkheaders(data, "Transfer-Encoding:")) {
+      te = "Transfer-Encoding: chunked\r\n";
+    }
+    /* else
+       our header was already added, what to do now? */
+  }
+
   if(data->cookies) {
     co = Curl_cookie_getlist(data->cookies,
                              host, ppath,
@@ -717,7 +726,8 @@ CURLcode Curl_http(struct connectdata *conn)
                 "%s" /* pragma */
                 "%s" /* accept */
                 "%s" /* accept-encoding */
-                "%s", /* referer */
+                "%s" /* referer */
+                "%s",/* transfer-encoding */
 
                 data->set.customrequest?data->set.customrequest:
                 (data->set.no_body?"HEAD":
@@ -739,7 +749,8 @@ CURLcode Curl_http(struct connectdata *conn)
                 http->p_accept?http->p_accept:"",
                 (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)?
                 conn->allocptr.accept_encoding:"", /* 08/28/02 jhrg */
-                (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> <CRLF> */
+                (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> <CRLF> */,
+                te
                 );
 
     if(co) {
index 7c9dda7..58ae8c9 100644 (file)
@@ -899,11 +899,46 @@ CURLcode Curl_readwrite(struct connectdata *conn,
       /* only read more data if there's no upload data already
          present in the upload buffer */
       if(0 == conn->upload_present) {
+        size_t buffersize = BUFSIZE;
         /* init the "upload from here" pointer */
         conn->upload_fromhere = k->uploadbuf;
 
-        nread = data->set.fread(conn->upload_fromhere, 1,
-                                BUFSIZE, data->set.in);
+        if(!k->upload_done) {
+
+          if(conn->upload_chunky) {
+            /* if chunked Transfer-Encoding */
+            buffersize -= (8 + 2 + 2);   /* 32bit hex + CRLF + CRLF */
+            conn->upload_fromhere += 10; /* 32bit hex + CRLF */
+          }
+
+          nread = data->set.fread(conn->upload_fromhere, 1,
+                                  buffersize, data->set.in);
+          
+          if(conn->upload_chunky) {
+            /* if chunked Transfer-Encoding */
+            char hexbuffer[9];
+            int hexlen = snprintf(hexbuffer, sizeof(hexbuffer),
+                                  "%x\r\n", nread);
+            /* move buffer pointer */
+            conn->upload_fromhere -= hexlen;
+            nread += hexlen;
+
+            /* copy the prefix to the buffer */
+            memcpy(conn->upload_fromhere, hexbuffer, hexlen);
+            if(nread>0) {
+              /* append CRLF to the data */
+              memcpy(conn->upload_fromhere +
+                     nread, "\r\n", 2);
+              nread+=2;
+            }
+            else {
+              /* mark this as done once this chunk is transfered */
+              k->upload_done = TRUE;
+            }
+          }
+        }
+        else
+          nread = 0; /* we're done uploading/reading */
 
         /* the signed int typecase of nread of for systems that has
            unsigned size_t */
@@ -967,6 +1002,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
         /* we've uploaded that buffer now */
         conn->upload_fromhere = k->uploadbuf;
         conn->upload_present = 0; /* no more bytes left */
+
+        if(k->upload_done) {
+          /* switch off writing, we're done! */
+          k->keepon &= ~KEEP_WRITE; /* we're done writing */
+          FD_ZERO(&k->wkeepfd);
+        }
       }
 
       if(data->set.verbose)
index 92c4dd9..0274cb0 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -1769,6 +1769,16 @@ static CURLcode CreateConnection(struct SessionHandle *data,
      is later set "for real" using Curl_pgrsStartNow(). */
   conn->data->progress.start = conn->created; 
 
+  conn->upload_chunky =
+    ((conn->protocol&PROT_HTTP) &&
+     data->set.upload &&
+     (data->set.infilesize == -1) &&
+     (data->set.httpversion != CURL_HTTP_VERSION_1_0))?
+    /* HTTP, upload, unknown file size and not HTTP 1.0 */
+    TRUE:
+  /* else, no chunky upload */
+  FALSE;
+
   /***********************************************************
    * We need to allocate memory to store the path in. We get the size of the
    * full URL to be sure, and we need to make it at least 256 bytes since
index e521d32..523b58f 100644 (file)
@@ -285,6 +285,8 @@ struct Curl_transfer_keeper {
   fd_set wkeepfd;
   int keepon;
 
+  bool upload_done; /* set to TRUE when doing chunked transfer-encoding upload
+                       and we're uploading the last chunk */
 };
 
 
@@ -450,6 +452,9 @@ struct connectdata {
 
   bool do_more; /* this is set TRUE if the ->curl_do_more() function is
                    supposed to be called, after ->curl_do() */
+
+  bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding
+                         on upload */
 };
 
 /* The end of connectdata. 08/27/02 jhrg */