Hiya,

Thanks for the patch. Now we're getting somewhere. This version is much better than previous versions!

I do have a few questions and tips:

 0 - you didn't really follow our code style when it comes to indenting. A
     minor nit, but still...

 1 - Can you think of a good reason why the callback would need to get the
     struct curl_slist * as its second argument? Won't that always just be
     NULL?

 2 - since the trailer headers now are set by a return code from a callback,
     I don't think they should be part of the 'struct UserDefined' anymore.
     In fact, is there a point to have it stored within the SessionHandle
     struct at all?

 3 - the memcpy() functions invoked after the callback has returned its list
     of headers are not checking that the destination is big enough. It
     uses the data set by the callback which risk overflowing the upload
     buffer...

 4 - I asked you before, but why is_trailerheaders_set? You can just as well
     save 5 lines of code and some memory by checking 'trailerheaders_func'
     instead!

 5 - you modified a file in src/ without purpose.

See attached file for my cleaned up version of your patch.

--

 / daniel.haxx.se
From be865581d4667814ea11d82099519cd2cd0ddfd3 Mon Sep 17 00:00:00 2001
From: Chrysovaladis Datsios <cdats...@gmail.com>
Date: Thu, 14 Feb 2013 14:24:10 +0100
Subject: [PATCH] CURLOPT_TRAILERFUNCTION: support chunked-encoding request
 trailers

curl_easy_setopt() option: CURLOPT_TRAILERFUNCTION

Pass a pointer to a function that matches the following prototype:
struct curl_slist* function(CURL *handle, struct curl_slist
*trailer_headers, void *userdata); This function gets called by libcurl
when it is to send the last chunk of (zero payload)data to the
peer. Chunked transfer-encoding must be used. The pointer to the
trailer_headers points to a linked list of type struct curl_slist that
must contain the trailer headers. The trailer header names have to be
set in advance as custom headers using the CURLOPT_HTTPHEADER option
with "Trailer" as "header name_field" and the actual header name as
"header value_field". Inside the callback function the trailer_headers
list have to be created using the curl_slist_append(3) function. The
callback function returns a pointer to the trailer_headers list. The
user also can pass in a custom pointer to the callback, this is done by
the associated CURLOPT_TRAILERDATA option.

curl_easy_setopt() option: CURLOPT_TRAILERDATA Data pointer to pass to
the trailer function. If you use the CURLOPT_TRAILERFUNCTION option,
this is the pointer you'll get as input.
---
 include/curl/curl.h          |   13 ++++++++++++-
 include/curl/typecheck-gcc.h |   16 ++++++++++++++++
 lib/transfer.c               |   35 +++++++++++++++++++++++++++++++++--
 lib/url.c                    |   19 +++++++++++++++++++
 lib/urldata.h                |    6 ++++++
 5 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/include/curl/curl.h b/include/curl/curl.h
index 5b39a24..5bc0b55 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <dan...@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <dan...@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
@@ -308,6 +308,12 @@ typedef size_t (*curl_read_callback)(char *buffer,
                                       size_t nitems,
                                       void *instream);
 
+/* pointer to function curl_trailerheaders_callback */
+typedef struct curl_slist *
+  (*curl_trailerheaders_callback)(CURL *handle,
+                                  struct curl_slist *trailer_headers,
+                                  void *userdata);
+
 typedef enum  {
   CURLSOCKTYPE_IPCXN,  /* socket created for a specific IP connection */
   CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
@@ -1536,6 +1542,11 @@ typedef enum {
   /* set the SMTP auth originator */
   CINIT(MAIL_AUTH, OBJECTPOINT, 217),
 
+  /* Function that will be called to set the final values to trailer headers */
+  CINIT(TRAILERFUNCTION, FUNCTIONPOINT, 218),
+  /* Data passed to the trailer headers callback function */
+  CINIT(TRAILERDATA, OBJECTPOINT, 219),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h
index f8917e8..811e40d 100644
--- a/include/curl/typecheck-gcc.h
+++ b/include/curl/typecheck-gcc.h
@@ -57,6 +57,9 @@ __extension__ ({                                                              \
     if((_curl_opt) == CURLOPT_READFUNCTION)                                   \
       if(!_curl_is_read_cb(value))                                            \
         _curl_easy_setopt_err_read_cb();                                      \
+    if((_curl_opt) == CURLOPT_TRAILERFUNCTION)                                \
+      if(!_curl_is_trailerheaders_cb(value))                                  \
+        _curl_easy_setopt_err_trailerheaders_cb();                            \
     if((_curl_opt) == CURLOPT_IOCTLFUNCTION)                                  \
       if(!_curl_is_ioctl_cb(value))                                           \
         _curl_easy_setopt_err_ioctl_cb();                                     \
@@ -157,6 +160,9 @@ _CURL_WARNING(_curl_easy_setopt_err_write_callback,
   "curl_easy_setopt expects a curl_write_callback argument for this option")
 _CURL_WARNING(_curl_easy_setopt_err_read_cb,
   "curl_easy_setopt expects a curl_read_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_trailerheaders_cb,
+              "curl_easy_setopt expects a "
+              "curl_trailerheaders_callback argument for this option")
 _CURL_WARNING(_curl_easy_setopt_err_ioctl_cb,
   "curl_easy_setopt expects a curl_ioctl_callback argument for this option")
 _CURL_WARNING(_curl_easy_setopt_err_sockopt_cb,
@@ -294,6 +300,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
    (option) == CURLOPT_INTERLEAVEDATA ||                                      \
    (option) == CURLOPT_CHUNK_DATA ||                                          \
    (option) == CURLOPT_FNMATCH_DATA ||                                        \
+   (option) == CURLOPT_TRAILERDATA ||                                         \
    0)
 
 /* evaluates to true if option takes a POST data argument (void* or char*) */
@@ -426,6 +433,15 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
   (__builtin_types_compatible_p(__typeof__(func), type) ||                    \
    __builtin_types_compatible_p(__typeof__(func), type*))
 
+/* evaluates to true if expr is of type curl_trailerheaders_callback */
+#define _curl_is_trailerheaders_cb(expr)                                      \
+  (_curl_callback_compatible(expr, _curl_trailerheaders_callback1) ||         \
+   _curl_callback_compatible(expr, _curl_trailerheaders_callback2))
+typedef struct curl_slist * (_curl_trailerheaders_callback1)(CURL *,
+                                            struct curl_slist *, void*);
+typedef struct curl_slist * (_curl_trailerheaders_callback2)(CURL *,
+                                            struct curl_slist *, const void*);
+
 /* evaluates to true if expr is of type curl_read_callback or "similar" */
 #define _curl_is_read_cb(expr)                                          \
   (_curl_is_NULL(expr) ||                                                     \
diff --git a/lib/transfer.c b/lib/transfer.c
index 330b37a..2b4501a 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -98,6 +98,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
   struct SessionHandle *data = conn->data;
   size_t buffersize = (size_t)bytes;
   int nread;
+  size_t trlen = 0;
 #ifdef CURL_DOES_CONVERSIONS
   bool sending_http_headers = FALSE;
 
@@ -187,8 +188,38 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
     /* copy the prefix to the buffer, leaving out the NUL */
     memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
 
+    /* If is the last chunk, here put the trailer headers if any */
+    if((nread - hexlen) == 0) {
+      if(data->set.is_trailerheaders_set == 1) {
+        /* The calback function that adds trailer header values */
+        data->set.trailer_headers =
+          (data->set.trailerheaders_func)(data,
+                                          data->set.trailer_headers,
+                                          data->set.trailer_udata);
+        if(data->set.trailer_headers) {
+          char *ptr;
+          struct curl_slist *trailer_headers=data->set.trailer_headers;
+          trlen = 0;
+          while(trailer_headers) {
+            /* header name_field : header value_field */
+            ptr = strchr(trailer_headers->data, ':');
+            if(ptr) {
+              memcpy(data->req.upload_fromhere + nread + trlen,
+                     trailer_headers->data, strlen(trailer_headers->data));
+              trlen += strlen(trailer_headers->data);
+
+              memcpy(data->req.upload_fromhere + nread + trlen,
+                     endofline_network, strlen(endofline_network));
+              trlen += strlen(endofline_native);
+            }
+            trailer_headers = trailer_headers->next;
+          }
+        }
+      }
+    }
+
     /* always append ASCII CRLF to the data */
-    memcpy(data->req.upload_fromhere + nread,
+    memcpy(data->req.upload_fromhere + nread + trlen,
            endofline_network,
            strlen(endofline_network));
 
@@ -225,7 +256,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
   }
 #endif /* CURL_DOES_CONVERSIONS */
 
-  *nreadp = nread;
+  *nreadp = nread + (int)trlen;
 
   return CURLE_OK;
 }
diff --git a/lib/url.c b/lib/url.c
index f9ce3ce..e68bf7e 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -1059,6 +1059,25 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     data->set.headers = va_arg(param, struct curl_slist *);
     break;
 
+  case CURLOPT_TRAILERFUNCTION:
+    /*
+     * Set final values of trailer headers callback
+     */
+    data->set.trailerheaders_func = va_arg(param,
+                                           curl_trailerheaders_callback);
+    if(!data->set.trailerheaders_func)
+      data->set.is_trailerheaders_set = 0;
+    else
+      data->set.is_trailerheaders_set = 1;
+    break;
+
+  case CURLOPT_TRAILERDATA:
+    /*
+     * Custom data to pass to the trailer headers callback
+     */
+    data->set.trailer_udata = va_arg(param, void *);
+    break;
+
   case CURLOPT_HTTP200ALIASES:
     /*
      * Set a list of aliases for HTTP 200 in response header
diff --git a/lib/urldata.h b/lib/urldata.h
index d564ae1..3e40055 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1429,6 +1429,11 @@ struct UserDefined {
   curl_read_callback fread_func;     /* function that reads the input */
   int is_fread_set; /* boolean, has read callback been set to non-NULL? */
   int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */
+  curl_trailerheaders_callback trailerheaders_func; /* function that sets
+                                        the final values at trailer headers */
+  void* trailer_udata; /* pointer, pass user data to trailerheaders callback */
+  int is_trailerheaders_set; /* boolean, has trailerheaders callback
+                                set to non-NULL? */
   curl_progress_callback fprogress;  /* function for progress information */
   curl_debug_callback fdebug;      /* function that write informational data */
   curl_ioctl_callback ioctl_func;  /* function for I/O control */
@@ -1466,6 +1471,7 @@ struct UserDefined {
                                 download */
   curl_off_t set_resume_from;  /* continue [ftp] transfer from here */
   struct curl_slist *headers; /* linked list of extra headers */
+  struct curl_slist *trailer_headers; /* linked list of trailer headers */
   struct curl_httppost *httppost;  /* linked list of POST data */
   bool cookiesession;   /* new cookie session? */
   bool crlf;            /* convert crlf on ftp upload(?) */
-- 
1.7.10.4

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to