cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: [PATCH] Addition of trailer headers in HTTP requests generated by libcurl

From: Chrysovaladis Datsios <cdatsios_at_gmail.com>
Date: Mon, 28 Jan 2013 11:45:55 +0200

> I don't see how this has changed. It will trigger in some cases when the
> payload happens to match "0\r\n".
>
Now only when a trailerheader_callback has been set will enable any
further check for the last chunk and the addition of the trailer
headers as a payload.

Also, only the CURLOPT_HTTPTRAILERFUNCTION option is kept. Following
are the documentation, code example and diff as formed after the last
changes:

+------------------------------+
| documentation |
+------------------------------+

curl_easy_setopt() option: CURLOPT_HTTPTRAILERFUNCTION

Pass a pointer to a function that matches the following prototype: int
function(struct curl_slist *trailer_headers); 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 field" and the
actual header name as "header value". Inside the callback function the
trailer_headers list have to be created using the curl_slist_append(3)
function.

        
+----------------------------------------------+
| code example: |
| PUT request with trailer header |
+----------------------------------------------+
#include <stdio.h>
#include <curl/curl.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(void)
{
  CURL *curl;
  CURLcode res;
  int filecode;
  FILE *fd;
  struct curl_slist *custom_http_hdrs=NULL;

  fd = fopen("video_0001", "rb"); /* open file to upload */
  if(!fd) {

    return 1; /* can't continue */
  }

  /* Read callback function */
  size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) {
    size_t retcode;

    retcode = fread(ptr, size, nmemb, stream);
    if(!retcode) {
      if(ferror(stream))
        filecode = 1;
      if(feof(stream))
        filecode = 0;
    }
    return retcode;
  }

  /* callback function creating the trailer headers list*/
  struct curl_slist * trailerheader_callback(CURL *handle, struct
curl_slist *trailer_headers) {

    if(!filecode)
      trailer_headers = curl_slist_append(trailer_headers, "mytrailer: EOF");
    else
      trailer_headers = curl_slist_append(trailer_headers, "mytrailer: error");

    return trailer_headers;
   }

  curl = curl_easy_init();
  if(curl) {

    curl_easy_setopt(curl, CURLOPT_URL, "http://10.8.60.209/myfile");

    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    curl_easy_setopt(curl, CURLOPT_READDATA, fd);
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);

        /* Chunked transfer-encoding must be used */
    custom_http_hdrs = curl_slist_append(custom_http_hdrs,
"Transfer-Encoding: chunked");
        
        /* The trailer header name is passed as a custom header */
    custom_http_hdrs = curl_slist_append(custom_http_hdrs, "Trailer:
mytrailer");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, custom_http_hdrs);

    /* Function trailerheader_callback will be used as callback function */
    curl_easy_setopt(curl, CURLOPT_HTTPTRAILERFUNCTION, trailerheader_callback);

    res = curl_easy_perform(curl);

    if(res != CURLE_OK) {
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));

    }
    fclose(fd);
    curl_slist_free_all(custom_http_hdrs);
    curl_easy_cleanup(curl);
  }
  return 0;
}

+----------------------------------------------------------------------------+
| code diff: |
| This are the diffs from the original library: curl-7.28.1 |
+----------------------------------------------------------------------------+

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-01-28 10:56:46.014484976 +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,
+ struct curl_slist *trailer_headers);
+
 typedef enum {
   CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */
   CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
@@ -1536,6 +1540,9 @@
   /* set the SMTP auth originator */
   CINIT(MAIL_AUTH, OBJECTPOINT, 217),

+ /* Function that will be called to set the final values to trailer headers */
+ CINIT(HTTPTRAILERFUNCTION, FUNCTIONPOINT, 218),
+
   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-01-28 10:56:56.962347342 +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_HTTPTRAILERFUNCTION) \
+ 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,
@@ -426,6 +432,12 @@
   (__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))
+typedef struct curl_slist * (_curl_trailerheaders_callback1)(CURL *,
+ struct curl_slist *);
+
 /* 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-01-28 10:58:21.005290781 +0200
@@ -929,6 +929,42 @@
          that instead of reading more data */
     }

+ /* If trailer headers callback function do exist*/
+ if(data->set.is_trailerheaders_set && k->upload_chunky == true) {
+ /* If this is the last chunk */
+ if(data->req.upload_present == 5 &&
+ !strncmp(data->req.upload_fromhere, "0\r\n", 3) ) {
+
+ /* The calback function that adds trailer header values */
+ data->set.trailer_headers = (data->set.trailerheaders_func)(data,
+ data->set.trailer_headers);
+ if(data->set.trailer_headers) {
+ Curl_send_buffer *trailer_buffer = Curl_add_buffer_init();
+ result = Curl_add_bufferf(trailer_buffer, "0\r\n");
+ if(result)
+ return result;
+
+ char *ptr;
+ struct curl_slist *trailer_headers=data->set.trailer_headers;
+ while(trailer_headers) {
+ ptr = strchr(trailer_headers->data, ':');
+ if(ptr) {
+ result = Curl_add_bufferf(trailer_buffer, "%s\r\n",
+ trailer_headers->data);
+ if(result)
+ return result;
+ }
+ trailer_headers = trailer_headers->next;
+ }
+ result = Curl_add_bufferf(trailer_buffer, "\r\n");
+ if(result)
+ return result;
+ data->req.upload_fromhere = trailer_buffer->buffer;
+ data->req.upload_present = trailer_buffer->size_used;
+ }
+ }
+ }
+
     /* write to socket (send away data) */
     result = Curl_write(conn,
                         conn->writesockfd, /* socket to send to */
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-01-28 10:57:42.629773225 +0200
@@ -1261,6 +1261,18 @@
     data->set.headers = va_arg(param, struct curl_slist *);
     break;

+ case CURLOPT_HTTPTRAILERFUNCTION:
+ /*
+ * 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_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-01-28 10:57:51.541661189 +0200
@@ -1429,6 +1429,10 @@
   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 */
+ 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 +1470,7 @@
                                 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(?) */
diff -ur curl_orig/src/tool_cfgable.h curl_new/src/tool_cfgable.h
--- curl_orig/src/tool_cfgable.h 2012-08-08 23:45:18.000000000 +0300
+++ curl_new/src/tool_cfgable.h 2013-01-28 10:57:15.346116228 +0200
@@ -150,6 +150,7 @@
   curl_TimeCond timecond;
   time_t condtime;
   struct curl_slist *headers;
+ struct curl_slist *trailer_headers;
   struct curl_httppost *httppost;
   struct curl_httppost *last_post;
   struct curl_slist *telnet_options;
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2013-01-28