﻿diff -ur curl_orig/include/curl/curl.h curl_new/include/curl/curl.h
--- curl_orig/include/curl/curl.h	2012-09-26 12:46:15.000000000 +0300
+++ curl_new/include/curl/curl.h	2013-02-21 09:47:24.281804155 +0200
@@ -308,6 +308,10 @@
                                       size_t nitems,
                                       void *instream);
 
+/* pointer to function curl_trailerheaders_callback */
+typedef struct curl_slist * (*curl_trailerheaders_callback)(CURL *handle,
+                                      void *userdata);
+
 typedef enum  {
   CURLSOCKTYPE_IPCXN,  /* socket created for a specific IP connection */
   CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
@@ -1536,6 +1540,11 @@
   /* 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 -ur curl_orig/include/curl/typecheck-gcc.h curl_new/include/curl/typecheck-gcc.h
--- curl_orig/include/curl/typecheck-gcc.h	2012-04-25 18:29:20.000000000 +0300
+++ curl_new/include/curl/typecheck-gcc.h	2013-02-21 09:47:52.763680269 +0200
@@ -57,6 +57,9 @@
     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_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 @@
    (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,14 @@
   (__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 *, void*);
+typedef struct curl_slist * (_curl_trailerheaders_callback2)(CURL *,
+                                                               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 -ur curl_orig/lib/transfer.c curl_new/lib/transfer.c
--- curl_orig/lib/transfer.c	2012-11-13 23:02:16.000000000 +0200
+++ curl_new/lib/transfer.c	2013-02-21 09:50:36.443423563 +0200
@@ -104,6 +104,7 @@
   struct SessionHandle *data = conn->data;
   size_t buffersize = (size_t)bytes;
   int nread;
+  int trlen = 0;
 #ifdef CURL_DOES_CONVERSIONS
   bool sending_http_headers = FALSE;
 
@@ -193,8 +194,45 @@
     /* 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.trailerheaders_func) {
+        /* The calback function that adds trailer header values */
+        conn->trailer_headers = (data->set.trailerheaders_func)(data,
+                                                   data->set.trailer_udata);
+        if(conn->trailer_headers) {
+          char *ptr;
+          struct curl_slist *trailer_headers=conn->trailer_headers;
+          char * trailer_headers_data = (char *)calloc(CURL_MAX_HTTP_HEADER,
+                                                                sizeof(char));
+          trlen = 0;
+          memcpy(trailer_headers_data, hexbuffer, hexlen);
+          while(trailer_headers) {
+            /* header name_field : header value_field */
+            ptr = strchr(trailer_headers->data, ':');
+            if(ptr) {
+              if(strlen(trailer_headers_data) + strlen(trailer_headers->data)
+                         + strlen(endofline_network) < CURL_MAX_HTTP_HEADER) {
+                memcpy(trailer_headers_data + nread + trlen,
+                      trailer_headers->data, strlen(trailer_headers->data));
+                trlen += (int)strlen(trailer_headers->data);
+                memcpy(trailer_headers_data + nread + trlen,
+                         endofline_network, strlen(endofline_network));
+                trlen += (int)strlen(endofline_native);
+              }
+            }
+            trailer_headers = trailer_headers->next;
+          }
+          data->req.upload_fromhere = realloc(NULL,
+                    strlen(trailer_headers_data) + strlen(endofline_network));
+          memcpy(data->req.upload_fromhere,
+                        trailer_headers_data, strlen(trailer_headers_data));
+        }
+      }
+    }
+
     /* 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));
 
@@ -231,7 +269,7 @@
   }
 #endif /* CURL_DOES_CONVERSIONS */
 
-  *nreadp = nread;
+  *nreadp = nread + trlen;
 
   return CURLE_OK;
 }
diff -ur curl_orig/lib/url.c curl_new/lib/url.c
--- curl_orig/lib/url.c	2012-11-18 16:08:45.000000000 +0200
+++ curl_new/lib/url.c	2013-02-21 09:49:42.789283751 +0200
@@ -1261,6 +1261,21 @@
     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);
+    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 -ur curl_orig/lib/urldata.h curl_new/lib/urldata.h
--- curl_orig/lib/urldata.h	2012-11-13 23:02:16.000000000 +0200
+++ curl_new/lib/urldata.h	2013-02-21 09:49:58.709039714 +0200
@@ -975,6 +975,8 @@
   int trlMax;    /* allocated buffer size */
   int trlPos;    /* index of where to store data */
 
+  struct curl_slist *trailer_headers; /* linked list of trailer headers */
+
   union {
     struct ftp_conn ftpc;
     struct ssh_conn sshc;
@@ -1429,6 +1431,9 @@
   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 */
   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 */