> 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