curl-library
Re: [PATCH] Addition of trailer headers in HTTP requests generated by libcurl
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