cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: overriding automatic Expect: 100-continue behavior

From: Andrew Biggs <adb_at_cisco.com>
Date: Tue, 08 Aug 2006 16:18:13 -0600
Thanks for the response Daniel!

At the moment I'm just relying on the output from having set CURLOPT_VERBOSE, but I could set up Ethereal and confirm if you think that would be more reliable.  I've attached some test code which should demonstrate the problem.  When the pszPostData string in the test code contains data that equals or exceeds 1024 bytes, I see the following verbose output:

* About to connect() to 10.94.248.184 port 80
*   Trying 10.94.248.184... * connected
* Connected to 10.94.248.184 (10.94.248.184) port 80
* Server auth using Basic with user 'aspen\cucsvc'
> PROPPATCH /exchange/ut_cugal0/Calendar/portingcugal.eml HTTP/1.1
Authorization: Basic YXNwZW5cY3Vjc3ZjOkJvdWxkM3I=
Host: 10.94.248.184
Accept: text/xml
Depth: infinity
Connection: Keep-Alive
Content-Type: text/xml
Content-Length: 1406
Expect: 100-continue

< HTTP/1.1 400 Bad Request
< Connection: close
< Date: Tue, 08 Aug 2006 22:05:32 GMT
< Server: Microsoft-IIS/6.0
< X-Powered-By: ASP.NET
< Content-Type: text/html
< Content-Length: 1709


Then, if I add "Expect:" to my header list, to remove the auto-generated header, I'll get:

* About to connect() to 10.94.248.184 port 80
*   Trying 10.94.248.184... * connected
* Connected to 10.94.248.184 (10.94.248.184) port 80
* Server auth using Basic with user 'aspen\cucsvc'
> PROPPATCH /exchange/ut_cugal0/Calendar/portingcugal.eml HTTP/1.1
Authorization: Basic YXNwZW5cY3Vjc3ZjOkJvdWxkM3I=
Host: 10.94.248.184
Accept: text/xml
Depth: infinity
Connection: Keep-Alive
Content-Type: text/xml
Content-Length: 1406

< HTTP/1.1 400 Bad Request
< Connection: close
< Date: Tue, 08 Aug 2006 22:13:51 GMT
< Server: Microsoft-IIS/6.0
< X-Powered-By: ASP.NET
< Content-Type: text/html
< Content-Length: 1709


Looks to me like in both cases the client is failing to send the XML content.  It's only if I reduce the size of the pszPostData such that it is less than 1024, that I'll get something like this:

* About to connect() to 10.94.248.184 port 80
*   Trying 10.94.248.184... * connected
* Connected to 10.94.248.184 (10.94.248.184) port 80
* Server auth using Basic with user 'aspen\cucsvc'
> PROPPATCH /exchange/ut_cugal0/Calendar/portingcugal.eml HTTP/1.1
Authorization: Basic YXNwZW5cY3Vjc3ZjOkJvdWxkM3I=
Host: 10.94.248.184
Accept: text/xml
Depth: infinity
Connection: Keep-Alive
Content-Type: text/xml
Content-Length: 976

<?xml version="1.0"?><g:propertyupdate xmlns:g="DAV:"    xmlns:e="http://schemas.microsoft.com/exchange/"    xmlns:mapi="http://schemas.microsoft.com/mapi/"    xmlns:mapit="http://schemas.microsoft.com/mapi/proptag/"    xmlns:x="xml:" xmlns:cal="urn:schemas:calendar:"    xmlns:dt="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"    xmlns:header="urn:schemas:mailheader:"    xmlns:mail="urn:schemas:httpmail:">    <g:set>        <g:prop>            <g:contentclass>urn:content-classes:appointment</g:contentclass>            <e:outlookmessageclass>IPM.Appointment</e:outlookmessageclass>            <cal:instancetype dt:dt='int'>0</cal:instancetype>            <header:to>ut_cugal0</header:to>            <cal:alldayevent dt:dt='boolean'>0</cal:alldayevent>            <mapi:finvited>1</mapi:finvited>            <cal:responserequested dt:dt='boolean'>1</cal:responserequested>            <cal:busystatus>BUSY</cal:busystatus>        </g:prop>    </g:set></g:propertyupdate>
< HTTP/1.1 207 Multi-Status
< Date: Tue, 08 Aug 2006 22:10:12 GMT
< Server: Microsoft-IIS/6.0
< X-Powered-By: ASP.NET
< MS-Exchange-Permanent-URL: http://10.94.248.184/exchange/ut_cugal0/-FlatUrlSpace-/5d807cc696502c4a9a1ad8e35ff3e326-8114/5d807cc696502c4a9a1ad8e35ff3e326-8451
< Repl-UID: <rid:5d807cc696502c4a9a1ad8e35ff3e326000000008451>
< Content-Type: text/xml
< Content-Length: 543
< ResourceTag: <rt:5d807cc696502c4a9a1ad8e35ff3e3260000000084515d807cc696502c4a9a1ad8e35ff3e32600000000c72e>
< MS-WebStorage: 6.5.6944
* Connection #0 to host 10.94.248.184 left intact
<?xml version="1.0"?><a:multistatus xmlns:e="http://schemas.microsoft.com/mapi/" xmlns:d="urn:schemas:mailheader:" xmlns:b="http://schemas.microsoft.com/exchange/" xmlns:c="urn:schemas:calendar:" xmlns:a="DAV:"><a:response><a:href>http://10.94.248.184/exchange/ut_cugal0/Calendar/portingcugal.eml</a:href><a:propstat><a:status>HTTP/1.1 200 OK</a:status><a:prop><a:contentclass/><b:outlookmessageclass/><c:instancetype/><d:to/><c:alldayevent/><e:finvited/><c:responserequested/><c:busystatus/></a:prop></a:propstat></a:response></a:multistatus>


If I'm totally misreading the verbose output, though, let me know.  It just appeared to me that adding the "Expect:" to my header list was just removing the header, and not affecting the behavior.

Thanks!
Andrew


Daniel Stenberg wrote:
On Tue, 8 Aug 2006, Andrew Biggs wrote:

Now to my problem... I'm using libcurl3-7.15.4-1 to talk webdav to an Exchange server, which doesn't seem to like the "Expect: 100-continue" header that libcurl is adding to the request when the submitted data exceeds 1024 bytes.  Turning off the header is easy, I've already added an "Expect:" header which does a nice job of preventing libcurl from adding it automatically.  The problem remains, though, that libcurl still does not transmit the "post-data" (actually, the command is PROPATCH set using CURLOPT_CUSTOMREQUEST) immediately following the request headers.  So, the header is gone, but the behavior remains.  That is, libcurl is still waiting for a 100 Continue from the server before it will sent the data.

Is this expected behavior?  Is there a way to tell libcurl: "look, I know the post-data is a bit long (1435 bytes), just send it all at once anyway please"?

No, it is not the expected behavior. There's code in libcurl (lib/http.c:expect100()) that checks if the header is disabled, and only if it isn't it adds the header and sets the variable that makes it expect a 100 header.

Now, I see a slight flaw in how this is stored and kept state-wise, it will not be properly switched off when a first post is using expect and the second is not when re-using a connection, but I don't think that's what you're seeing, is it?

How can you tell libcurl is waiting for the 100 response?


#include <stdio.h>
#include <string.h>
#include <curl/curl.h>

#define CHECKCC(x) \
    if ((cc = x) != CURLE_OK) { \
        printf("Failed at line %s with code %d. Exiting.\n", __LINE__, cc); \
        return -1; \
    }

const char *pszPostData =
        "<?xml version=\"1.0\"?>"
        "<g:propertyupdate xmlns:g=\"DAV:\""
        " xmlns:e=\"http://schemas.microsoft.com/exchange/\""
        " xmlns:mapi=\"http://schemas.microsoft.com/mapi/\""
        " xmlns:mapit=\"http://schemas.microsoft.com/mapi/proptag/\""
        " xmlns:x=\"xml:\" xmlns:cal=\"urn:schemas:calendar:\""
        " xmlns:dt=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\""
        " xmlns:header=\"urn:schemas:mailheader:\""
        " xmlns:mail=\"urn:schemas:httpmail:\">"
        " <g:set>"
        " <g:prop>"
        " <g:contentclass>urn:content-classes:appointment</g:contentclass>"
        " <e:outlookmessageclass>IPM.Appointment</e:outlookmessageclass>"
        " <cal:instancetype dt:dt='int'>0</cal:instancetype>"
        " <header:to>ut_cugal0</header:to>"
        " <cal:alldayevent dt:dt='boolean'>0</cal:alldayevent>"
        " <mapi:finvited>1</mapi:finvited>"
        " <cal:responserequested dt:dt='boolean'>1</cal:responserequested>"
        " <cal:busystatus>BUSY</cal:busystatus>"
        " <cal:meetingstatus>CONFIRMED</cal:meetingstatus>"
        " <cal:location>Longs Peak, Boulder</cal:location>"
        " <mail:subject>Porting CuGal to Linux</mail:subject>"
        " <mail:htmldescription>Discussion of performance improvements</mail:htmldescription>"
        " <cal:dtstart dt:dt='dateTime.tz'>2006-08-09 12:00:00</cal:dtstart>"
        " <cal:dtend dt:dt='dateTime.tz'>2006-08-09 12:30:00</cal:dtend>"
        " </g:prop>"
        " </g:set>"
    "</g:propertyupdate>\r\n";

size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
    int bytes = size*nmemb;
    char *out= new char[bytes+1];
    memcpy(out,buffer,bytes);
    out[bytes] = 0;
    printf("%s", out);
    return bytes;
}

int main(int argc, char *argv)
{
    CURLcode cc;

    CHECKCC(curl_global_init(CURL_GLOBAL_SSL))

    curl_slist *slist = NULL;
    slist = curl_slist_append(slist, "Accept: text/xml");
    slist = curl_slist_append(slist, "Depth: infinity");
    slist = curl_slist_append(slist, "Connection: Keep-Alive");
    slist = curl_slist_append(slist, "Content-Type: text/xml");
    slist = curl_slist_append(slist, "Expect:");

    CURL *pcurl = curl_easy_init();
    CHECKCC(curl_easy_setopt(pcurl, CURLOPT_VERBOSE, 1))
    CHECKCC(curl_easy_setopt(pcurl, CURLOPT_URL, "http://10.94.248.184/exchange/ut_cugal0/Calendar/portingcugal.eml"))
    CHECKCC(curl_easy_setopt(pcurl, CURLOPT_CUSTOMREQUEST, "PROPPATCH"))
    CHECKCC(curl_easy_setopt(pcurl, CURLOPT_HTTPHEADER, slist))
    CHECKCC(curl_easy_setopt(pcurl, CURLOPT_POSTFIELDS, pszPostData))
    CHECKCC(curl_easy_setopt(pcurl, CURLOPT_POSTFIELDSIZE, strlen(pszPostData)))
    CHECKCC(curl_easy_setopt(pcurl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC))
    CHECKCC(curl_easy_setopt(pcurl, CURLOPT_USERPWD, "aspen\\cucsvc:Bould3r"))
    CHECKCC(curl_easy_setopt(pcurl, CURLOPT_WRITEFUNCTION, write_data))
    CHECKCC(curl_easy_perform(pcurl))
}
Received on 2006-08-09