On Sun, 3 Jul 2011, Daniel Stenberg wrote:
https://sourceforge.net/tracker/?func=detail&aid=3352341&group_id=976&atid=100976
Great. I'm working on this, a bit slowly due to vacation times here...
Hey,
Here's a patch attached that seems to work for my test cases I've made up for
this. It'd be great to hear how it works against your live case...
--
/ daniel.haxx.se
From 3548d762c90d2e807fd6ba7e254c4a130fea83d6 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <[email protected]>
Date: Mon, 4 Jul 2011 22:16:07 +0200
Subject: [PATCH 1/3] expect 100: correct handling of error responses when
posting data
When libcurl has said to the server that there's a POST or PUT coming
(with a content-length and all) it has to either deliver that amount of
data or it needs to close the connection before trying a second request.
Adds test case 1129.
Bug: http://curl.haxx.se/mail/lib-2011-06/0191.html
Reported by: Steven Parkes
---
lib/http.c | 60 ++++++++++++++++++++++++-------
lib/urldata.h | 6 +++-
tests/data/test1129 | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 148 insertions(+), 15 deletions(-)
create mode 100644 tests/data/test1129
diff --git a/lib/http.c b/lib/http.c
index 92f7c02..4d1d072 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -416,15 +416,15 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
/* This is not NTLM or NTLM with many bytes left to send: close
*/
conn->bits.close = TRUE;
- data->req.size = 0; /* don't download any more than 0 bytes */
-
/* There still is data left to send, but this connection is marked for
closure so we can safely do the rewind right now */
}
- if(bytessent)
+ if(bytessent) {
/* we rewind now at once since if we already sent something */
+ conn->rewindcount += bytessent;
return Curl_readrewind(conn);
+ }
return CURLE_OK;
}
@@ -480,6 +480,10 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
code = http_perhapsrewind(conn);
if(code)
return code;
+ if(conn->bits.close)
+ /* if asked to close the connection, we don't download anymore
+ data either */
+ data->req.size = 0;
}
}
@@ -2779,17 +2783,6 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
}
}
- if(417 == k->httpcode) {
- /*
- * we got: "417 Expectation Failed" this means:
- * we have made a HTTP call and our Expect Header
- * seems to cause a problem => abort the write operations
- * (or prevent them from starting).
- */
- k->exp100 = EXP100_FAILED;
- k->keepon &= ~KEEP_SEND;
- }
-
/*
* When all the headers have been parsed, see if we should give
* up and return an error.
@@ -2829,6 +2822,41 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
if(result)
return result;
+ if(!data->req.newurl && /* a new request is not already fixed */
+ !conn->rewindcount && /* not rewound yet */
+ (data->state.expect100header && (k->httpcode >= 300))) {
+ /*
+ * General, not specific, treatment of errors including : "417
+ * Expectation Failed", while waiting for 100.
+ */
+
+ data->state.expect100header = FALSE; /* no more */
+ switch(data->set.httpreq) {
+ case HTTPREQ_PUT:
+ case HTTPREQ_POST:
+ case HTTPREQ_GET:
+ case HTTPREQ_POST_FORM:
+ /* we got an error response while waiting for 100, now if we said
+ we'd POST or PUT we might have a request body to handle */
+ result = http_perhapsrewind(conn);
+ if(result)
+ return result;
+ if(!conn->bits.close)
+ /* enable the write bit, we're not waiting anymore */
+ k->keepon |= KEEP_SEND;
+ else {
+ /* stop the sending, but keep reading the response */
+ k->upload_done = TRUE;
+ k->exp100 = EXP100_FAILED;
+ k->keepon &= ~KEEP_SEND;
+ }
+
+ break;
+ default: /* default label present to avoid compiler warnings */
+ break;
+ }
+ }
+
if(conn->bits.rewindaftersend) {
/* We rewind after a complete send, so thus we continue
sending now */
@@ -3312,6 +3340,10 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
result = http_perhapsrewind(conn);
if(result)
return result;
+ if(conn->bits.close)
+ /* if asked to close the connection, we don't download anymore
+ data either */
+ data->req.size = 0;
}
}
}
diff --git a/lib/urldata.h b/lib/urldata.h
index d256968..0f755dc 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -534,7 +534,7 @@ struct SingleRequest {
curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
-1 means unlimited */
- curl_off_t *writebytecountp; /* return number of bytes written or NULL */
+ curl_off_t *writebytecountp; /* return number of bytes written or NULL */
curl_off_t bytecount; /* total number of bytes read */
curl_off_t writebytecount; /* number of bytes written */
@@ -894,6 +894,10 @@ struct connectdata {
curl_seek_callback seek_func; /* function that seeks the input */
void *seek_client; /* pointer to pass to the seek() above */
+ curl_off_t rewindcount; /* counts how many bytes that were sent and
+ then rewound back so that they can be sent
+ again */
+
/*************** Request - specific items ************/
/* previously this was in the urldata struct */
diff --git a/tests/data/test1129 b/tests/data/test1129
new file mode 100644
index 0000000..85793cb
--- /dev/null
+++ b/tests/data/test1129
@@ -0,0 +1,97 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP POST
+Expect: 100-continue
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data nocheck="yes">
+HTTP/1.1 404 NOOOOOOOOO
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Length: 6
+Content-Type: text/html
+
+-foo-
+</data>
+
+<data1>
+HTTP/1.1 404 NEITHER
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Length: 6
+Content-Type: text/html
+
+-foo-
+</data1>
+
+# we use skip to make the test server never read the full payload off
+# the socket and instead return the response at once
+<servercmd>
+skip: 1025
+</servercmd>
+</reply>
+
+#
+# Client-side
+<client>
+# 1025 x 'x'
+<file name="log/file1129">
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+</file>
+<server>
+http
+</server>
+ <name>
+HTTP POST expect 100-continue with a 404
+ </name>
+ <command option="no-output">
+-d @log/file1129 http://%HOSTIP:%HTTPPORT/1129 http://%HOSTIP:%HTTPPORT/11290001
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<stdout>
+HTTP/1.1 404 NOOOOOOOOO
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Length: 6
+Content-Type: text/html
+
+-foo-
+HTTP/1.1 404 NEITHER
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Length: 6
+Content-Type: text/html
+
+-foo-
+</stdout>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol>
+POST /1129 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 1025
+Content-Type: application/x-www-form-urlencoded
+Expect: 100-continue
+
+POST /11290001 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 1025
+Content-Type: application/x-www-form-urlencoded
+Expect: 100-continue
+
+</protocol>
+</verify>
+</testcase>
--
1.7.5.4
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html