{"thread":{"id":"18683","subject":"[PATCH] Allow curl to rewind the read buffers","startedAt":"2009-04-01T15:10:09Z","lastAt":"2009-04-02T07:03:39Z","messageCount":5,"participants":["Martin Storsjö","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"110144","messageId":"Pine.LNX.4.64.0904011809080.5901@localhost.localdomain","threadId":"18683","inReplyTo":null,"subject":"[PATCH] Allow curl to rewind the read buffers","fromName":"Martin Storsjö","fromEmail":"martin@martin.st","sentAt":"2009-04-01T15:10:09Z","receivedAt":"2009-04-01T15:10:09Z","isPatch":true,"sender":{"key":"martin@martin.st","avatar":"https://avatars.githubusercontent.com/u/69727?v=4"},"body":"Rewinding of the read buffers may be needed when doing HTTP PUT or POST\n(or PROPFIND) with multi-pass authentication methods.\n\nDepending on the HTTP server, the read buffers may or may not need\nrewinding. (Apache returns a 401 error immediately before any data has\nbeen read from the buffers, while Lighttpd doesn't reply until all data\nhas been sent.)\n\nSigned-off-by: Martin Storsjo <martin@martin.st>\n---\n http-push.c |   24 ++++++++++++++++++++++++\n http.c      |   19 +++++++++++++++++++\n http.h      |    7 +++++++\n 3 files changed, 50 insertions(+), 0 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 6ce5a1d..7dc0dd4 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -567,6 +567,10 @@ static void start_put(struct transfer_request *request)\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.buf.len);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &request->buffer);\n+#endif\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n \tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);\n \tcurl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);\n@@ -1267,6 +1271,10 @@ static struct remote_lock *lock_remote(const char *path, long timeout)\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n+#endif\n \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n@@ -1508,6 +1516,10 @@ static void remote_ls(const char *path, int flags,\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n+#endif\n \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n@@ -1584,6 +1596,10 @@ static int locking_available(void)\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n+#endif\n \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, repo->url);\n@@ -1766,6 +1782,10 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n+#endif\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n \tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);\n@@ -1910,6 +1930,10 @@ static void update_remote_info_refs(struct remote_lock *lock)\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &buffer);\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.buf.len);\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &buffer);\n+#endif\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);\ndiff --git a/http.c b/http.c\nindex eae74aa..3e8d548 100644\n--- a/http.c\n+++ b/http.c\n@@ -44,6 +44,25 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *buffer_)\n \treturn size;\n }\n \n+#ifndef NO_CURL_IOCTL\n+curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp)\n+{\n+\tstruct buffer *buffer = clientp;\n+\n+\tswitch (cmd) {\n+\tcase CURLIOCMD_NOP:\n+\t\treturn CURLIOE_OK;\n+\n+\tcase CURLIOCMD_RESTARTREAD:\n+\t\tbuffer->posn = 0;\n+\t\treturn CURLIOE_OK;\n+\n+\tdefault:\n+\t\treturn CURLIOE_UNKNOWNCMD;\n+\t}\n+}\n+#endif\n+\n size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *buffer_)\n {\n \tsize_t size = eltsize * nmemb;\ndiff --git a/http.h b/http.h\nindex 905b462..26abebe 100644\n--- a/http.h\n+++ b/http.h\n@@ -37,6 +37,10 @@\n #define CURLE_HTTP_RETURNED_ERROR CURLE_HTTP_NOT_FOUND\n #endif\n \n+#if LIBCURL_VERSION_NUM < 0x070c03\n+#define NO_CURL_IOCTL\n+#endif\n+\n struct slot_results\n {\n \tCURLcode curl_result;\n@@ -67,6 +71,9 @@ struct buffer\n extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *strbuf);\n extern size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf);\n extern size_t fwrite_null(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf);\n+#ifndef NO_CURL_IOCTL\n+extern curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp);\n+#endif\n \n /* Slot lifecycle functions */\n extern struct active_request_slot *get_active_slot(void);\n-- \n1.6.0.2\n"},{"id":"110150","messageId":"7vbprg1h3m.fsf@gitster.siamese.dyndns.org","threadId":"18683","inReplyTo":"Pine.LNX.4.64.0904011809080.5901@localhost.localdomain","subject":"Re: [PATCH] Allow curl to rewind the read buffers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-04-01T16:19:57Z","receivedAt":"2009-04-01T16:19:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Martin Storsjö <martin@martin.st> writes:\n\n> Rewinding of the read buffers may be needed when doing HTTP PUT or POST\n> (or PROPFIND) with multi-pass authentication methods.\n\nIt may be obvious to people proficient in cURL, but I had to guess that\nyou perhaps meant to say \"when using multi-pass authentication methods,\ncURL library may need to rewind the read buffers (depending on what is fed\nby the server), and in order to allow the library to do so, we need to\ntell it how by providing the way to manipulate the buffers we supply with\nthese IOCTL callbacks.\"\n\nDo I understand you correctly?\n\nMy point is that the your two-line statement of fact (with a bit more\nexplanation of the fact that follows) was clear but it was unclear to me\nhow that fact translates to the need of what the patch does.  We would\nwant the commit log message to be helpful to people who look at the code 6\nmonths down the line and wonder why these lines were added.\n\nPlease do not make me guess.  I won't claim that other people would be\neven less clueful than I am, but I am reasonably sure that more than half\nof the people who read this patch would share my uneasiness of not clearly\nreading how your statement of fact leads to your conclusion.\n\nThanks.\n"},{"id":"110152","messageId":"Pine.LNX.4.64.0904011943560.5901@localhost.localdomain","threadId":"18683","inReplyTo":"7vbprg1h3m.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Allow curl to rewind the read buffers","fromName":"Martin Storsjö","fromEmail":"martin@martin.st","sentAt":"2009-04-01T16:46:41Z","receivedAt":"2009-04-01T16:46:41Z","isPatch":true,"sender":{"key":"martin@martin.st","avatar":"https://avatars.githubusercontent.com/u/69727?v=4"},"body":"On Wed, 1 Apr 2009, Junio C Hamano wrote:\n\n> It may be obvious to people proficient in cURL, but I had to guess that\n> you perhaps meant to say \"when using multi-pass authentication methods,\n> cURL library may need to rewind the read buffers (depending on what is fed\n> by the server), and in order to allow the library to do so, we need to\n> tell it how by providing the way to manipulate the buffers we supply with\n> these IOCTL callbacks.\"\n> \n> Do I understand you correctly?\n\nYeah, that's exactly correct.\n\n> My point is that the your two-line statement of fact (with a bit more\n> explanation of the fact that follows) was clear but it was unclear to me\n> how that fact translates to the need of what the patch does.  We would\n> want the commit log message to be helpful to people who look at the code 6\n> months down the line and wonder why these lines were added.\n\nThe original commit comment was a bit vague in retrospect, yes. I'll reply \nwith an updated version soon.\n\nThanks!\n\n// Martin\n"},{"id":"110153","messageId":"Pine.LNX.4.64.0904011946510.5901@localhost.localdomain","threadId":"18683","inReplyTo":"7vbprg1h3m.fsf@gitster.siamese.dyndns.org","subject":"[PATCH] Allow curl to rewind the read buffers","fromName":"Martin Storsjö","fromEmail":"martin@martin.st","sentAt":"2009-04-01T16:48:24Z","receivedAt":"2009-04-01T16:48:24Z","isPatch":true,"sender":{"key":"martin@martin.st","avatar":"https://avatars.githubusercontent.com/u/69727?v=4"},"body":"When using multi-pass authentication methods, the curl library may\nneed to rewind the read buffers (depending on how much already has\nbeen fed to the server) used for providing data to HTTP PUT, POST or\nPROPFIND, and in order to allow the library to do so, we need to tell\nit how by providing either an ioctl callback or a seek callback.\n\nThis patch adds an ioctl callback, which should be usable on older\ncurl versions (since 7.12.3) than the seek callback (introduced in\ncurl 7.18.0).\n\nSome HTTP servers (such as Apache) give an 401 error reply immediately\nafter receiving the headers (so no data has been read from the read\nbuffers, and thus no rewinding is needed), but other servers (such\nas Lighttpd) only replies after the whole request has been sent and\nall data has been read from the read buffers, making rewinding necessary.\n\nSigned-off-by: Martin Storsjo <martin@martin.st>\n---\n\nUpdated comment to better describe the potential need for this.\n\n http-push.c |   24 ++++++++++++++++++++++++\n http.c      |   19 +++++++++++++++++++\n http.h      |    7 +++++++\n 3 files changed, 50 insertions(+), 0 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 6ce5a1d..7dc0dd4 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -567,6 +567,10 @@ static void start_put(struct transfer_request *request)\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.buf.len);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &request->buffer);\n+#endif\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n \tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);\n \tcurl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);\n@@ -1267,6 +1271,10 @@ static struct remote_lock *lock_remote(const char *path, long timeout)\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n+#endif\n \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n@@ -1508,6 +1516,10 @@ static void remote_ls(const char *path, int flags,\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n+#endif\n \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n@@ -1584,6 +1596,10 @@ static int locking_available(void)\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n+#endif\n \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, repo->url);\n@@ -1766,6 +1782,10 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n+#endif\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n \tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);\n@@ -1910,6 +1930,10 @@ static void update_remote_info_refs(struct remote_lock *lock)\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &buffer);\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.buf.len);\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n+#ifndef NO_CURL_IOCTL\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &buffer);\n+#endif\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);\ndiff --git a/http.c b/http.c\nindex eae74aa..3e8d548 100644\n--- a/http.c\n+++ b/http.c\n@@ -44,6 +44,25 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *buffer_)\n \treturn size;\n }\n \n+#ifndef NO_CURL_IOCTL\n+curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp)\n+{\n+\tstruct buffer *buffer = clientp;\n+\n+\tswitch (cmd) {\n+\tcase CURLIOCMD_NOP:\n+\t\treturn CURLIOE_OK;\n+\n+\tcase CURLIOCMD_RESTARTREAD:\n+\t\tbuffer->posn = 0;\n+\t\treturn CURLIOE_OK;\n+\n+\tdefault:\n+\t\treturn CURLIOE_UNKNOWNCMD;\n+\t}\n+}\n+#endif\n+\n size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *buffer_)\n {\n \tsize_t size = eltsize * nmemb;\ndiff --git a/http.h b/http.h\nindex 905b462..26abebe 100644\n--- a/http.h\n+++ b/http.h\n@@ -37,6 +37,10 @@\n #define CURLE_HTTP_RETURNED_ERROR CURLE_HTTP_NOT_FOUND\n #endif\n \n+#if LIBCURL_VERSION_NUM < 0x070c03\n+#define NO_CURL_IOCTL\n+#endif\n+\n struct slot_results\n {\n \tCURLcode curl_result;\n@@ -67,6 +71,9 @@ struct buffer\n extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *strbuf);\n extern size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf);\n extern size_t fwrite_null(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf);\n+#ifndef NO_CURL_IOCTL\n+extern curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp);\n+#endif\n \n /* Slot lifecycle functions */\n extern struct active_request_slot *get_active_slot(void);\n-- \n1.6.0.2\n"},{"id":"110198","messageId":"7vwsa3h704.fsf@gitster.siamese.dyndns.org","threadId":"18683","inReplyTo":"Pine.LNX.4.64.0904011946510.5901@localhost.localdomain","subject":"Re: [PATCH] Allow curl to rewind the read buffers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-04-02T07:03:39Z","receivedAt":"2009-04-02T07:03:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Martin Storsjö <martin@martin.st> writes:\n\n> When using multi-pass authentication methods, the curl library may\n> need to rewind the read buffers (depending on how much already has\n> been fed to the server) used for providing data to HTTP PUT, POST or\n> PROPFIND, and in order to allow the library to do so, we need to tell\n> it how by providing either an ioctl callback or a seek callback.\n>\n> This patch adds an ioctl callback, which should be usable on older\n> curl versions (since 7.12.3) than the seek callback (introduced in\n> curl 7.18.0).\n>\n> Some HTTP servers (such as Apache) give an 401 error reply immediately\n> after receiving the headers (so no data has been read from the read\n> buffers, and thus no rewinding is needed), but other servers (such\n> as Lighttpd) only replies after the whole request has been sent and\n> all data has been read from the read buffers, making rewinding necessary.\n>\n> Signed-off-by: Martin Storsjo <martin@martin.st>\n\nLooks good, thanks.\n\nMike, how does this interact with your effort for defining a simplified\ndependency rules on libcurl versions? \n\n> Updated comment to better describe the potential need for this.\n>\n>  http-push.c |   24 ++++++++++++++++++++++++\n>  http.c      |   19 +++++++++++++++++++\n>  http.h      |    7 +++++++\n>  3 files changed, 50 insertions(+), 0 deletions(-)\n>\n> diff --git a/http-push.c b/http-push.c\n> index 6ce5a1d..7dc0dd4 100644\n> --- a/http-push.c\n> +++ b/http-push.c\n> @@ -567,6 +567,10 @@ static void start_put(struct transfer_request *request)\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.buf.len);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n> +#ifndef NO_CURL_IOCTL\n> +\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n> +\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &request->buffer);\n> +#endif\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);\n> @@ -1267,6 +1271,10 @@ static struct remote_lock *lock_remote(const char *path, long timeout)\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n> +#ifndef NO_CURL_IOCTL\n> +\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n> +\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n> +#endif\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n> @@ -1508,6 +1516,10 @@ static void remote_ls(const char *path, int flags,\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n> +#ifndef NO_CURL_IOCTL\n> +\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n> +\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n> +#endif\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n> @@ -1584,6 +1596,10 @@ static int locking_available(void)\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n> +#ifndef NO_CURL_IOCTL\n> +\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n> +\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n> +#endif\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_URL, repo->url);\n> @@ -1766,6 +1782,10 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n> +#ifndef NO_CURL_IOCTL\n> +\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n> +\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);\n> +#endif\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);\n>  \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);\n> @@ -1910,6 +1930,10 @@ static void update_remote_info_refs(struct remote_lock *lock)\n>  \t\tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &buffer);\n>  \t\tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.buf.len);\n>  \t\tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n> +#ifndef NO_CURL_IOCTL\n> +\t\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);\n> +\t\tcurl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &buffer);\n> +#endif\n>  \t\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n>  \t\tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);\n>  \t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);\n> diff --git a/http.c b/http.c\n> index eae74aa..3e8d548 100644\n> --- a/http.c\n> +++ b/http.c\n> @@ -44,6 +44,25 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *buffer_)\n>  \treturn size;\n>  }\n>  \n> +#ifndef NO_CURL_IOCTL\n> +curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp)\n> +{\n> +\tstruct buffer *buffer = clientp;\n> +\n> +\tswitch (cmd) {\n> +\tcase CURLIOCMD_NOP:\n> +\t\treturn CURLIOE_OK;\n> +\n> +\tcase CURLIOCMD_RESTARTREAD:\n> +\t\tbuffer->posn = 0;\n> +\t\treturn CURLIOE_OK;\n> +\n> +\tdefault:\n> +\t\treturn CURLIOE_UNKNOWNCMD;\n> +\t}\n> +}\n> +#endif\n> +\n>  size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *buffer_)\n>  {\n>  \tsize_t size = eltsize * nmemb;\n> diff --git a/http.h b/http.h\n> index 905b462..26abebe 100644\n> --- a/http.h\n> +++ b/http.h\n> @@ -37,6 +37,10 @@\n>  #define CURLE_HTTP_RETURNED_ERROR CURLE_HTTP_NOT_FOUND\n>  #endif\n>  \n> +#if LIBCURL_VERSION_NUM < 0x070c03\n> +#define NO_CURL_IOCTL\n> +#endif\n> +\n>  struct slot_results\n>  {\n>  \tCURLcode curl_result;\n> @@ -67,6 +71,9 @@ struct buffer\n>  extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *strbuf);\n>  extern size_t fwrite_buffer(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf);\n>  extern size_t fwrite_null(const void *ptr, size_t eltsize, size_t nmemb, void *strbuf);\n> +#ifndef NO_CURL_IOCTL\n> +extern curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp);\n> +#endif\n>  \n>  /* Slot lifecycle functions */\n>  extern struct active_request_slot *get_active_slot(void);\n> -- \n> 1.6.0.2\n"}]}