| 1. PUT/POST without a known auth to use (possibly no auth required): | |
| (When explicitly set to use a multi-pass auth when doing a POST/PUT, | |
| libcurl should immediately go the Content-Length: 0 bytes route to avoid | |
| the first send all data phase, step 2. If told to use a single-pass auth, | |
| goto step 3.) | |
| Issue the proper PUT/POST request immediately, with the correct | |
| Content-Length and Expect: headers. | |
| If a 100 response is received or the wait for one times out, start sending | |
| the request-body. | |
| If a 401 (or 407 when talking through a proxy) is received, then: | |
| If we have "more than just a little" data left to send, close the | |
| connection. Exactly what "more than just a little" means will have to be | |
| determined. Possibly the current transfer speed should be taken into | |
| account as well. | |
| NOTE: if the size of the POST data is less than MAX_INITIAL_POST_SIZE (when | |
| CURLOPT_POSTFIELDS is used), libcurl will send everything in one single | |
| write() (all request-headers and request-body) and thus it will | |
| unconditionally send the full post data here. | |
| 2. PUT/POST with multi-pass auth but not yet completely negotiated: | |
| Send a PUT/POST request, we know that it will be rejected and thus we claim | |
| Content-Length zero to avoid having to send the request-body. (This seems | |
| to be what IE does.) | |
| 3. PUT/POST as the last step in the auth negotiation, that is when we have | |
| what we believe is a completed negotiation: | |
| Send a full and proper PUT/POST request (again) with the proper | |
| Content-Length and a following request-body. | |
| NOTE: this may very well be the second (or even third) time the whole or at | |
| least parts of the request body is sent to the server. Since the data may | |
| be provided to libcurl with a callback, we need a way to tell the app that | |
| the upload is to be restarted so that the callback will provide data from | |
| the start again. This requires an API method/mechanism that libcurl | |
| doesn't have today. See below. | |
| Data Rewind | |
| It will be troublesome for some apps to deal with a rewind like this in all | |
| circumstances. I'm thinking for example when using 'curl' to upload data | |
| from stdin. If libcurl ends up having to rewind the reading for a request | |
| to succeed, of course a lack of this callback or if it returns failure, will | |
| cause the request to fail completely. | |
| The new callback is set with CURLOPT_IOCTLFUNCTION (in an attempt to add a | |
| more generic function that might be used for other IO-related controls in | |
| the future): | |
| curlioerr curl_ioctl(CURL *handle, curliocmd cmd, void *clientp); | |
| And in the case where the read is to be rewinded, it would be called with a | |
| cmd named CURLIOCMD_RESTARTREAD. The callback would then return CURLIOE_OK, | |
| if things are fine, or CURLIOE_FAILRESTART if not. | |
| Backwards Compatibility | |
| The approach used until now, that issues a HEAD on the given URL to trigger | |
| the auth negotiation could still be supported and encouraged, but it would | |
| be up to the app to first fetch a URL with GET/HEAD to negotiate on, since | |
| then a following PUT/POST wouldn't need to negotiate authentication and | |
| thus avoid double-sending data. | |
| Optionally, we keep the current approach if some option is set | |
| (CURLOPT_HEADBEFOREAUTH or similar), since it seems to work fairly well for | |
| POST on most servers. |