This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author IcicleSpider
Recipients Carl.Nobile, IcicleSpider, cdwave, edevil, jjlee, martin.panter, nikratio, nnorwitz, orsenthil, rharris, terry.reedy
Date 2016-04-03.08:19:30
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1459671571.54.0.143414866831.issue1346874@psf.upfronthosting.co.za>
In-reply-to
Content
Martin,

My understanding of the intention of the "Expect: 100-continue" header would address being able to receive an error response that is determined solely from the http request headers sent. So I do think that that would be the proper way to address that other issue, and without having to worry about sending and receiving data at once.

However, what I am running into is a different issue caused by the same root cause of not properly handling "Expect: 100-continue" header in the client.

In my case, what is occurring is the URL being called is configured to require an SSL client certificate. Apache is only able to determine that the client certificate is required after the http request headers are sent. Once Apache has the headers and determines that the client certificate is required, the ssl connection is renegotiated. While performing this renegotiation, Apache holds the request data in progress in a "SSLRenegBuffer". If the data sent is larger then the SSLRenegBufferSize configuration, then Apache will fail the request as being to large.

With the current HttpsConnection, the sequence of events leading to the failure are:

1. HttpsConnection sends all the headers, including the Expect: 100-continue header, and sends all the 128K of data as fast as the socket allows.
2. Apache receives the request headers and looks at the request URL and determines that a client certificate is required, precipitating a ssl renegotiation.
3. Apache attempts to buffer the data received so far so that the ssl renegotiation can occur. However, the body of the request has already been sent and it is larger then SSLRenegBufferSize.
4. Apache fails the request as being to large.
5. HttpsConnection gets the error response about too large of a request.

I have created my own fork of httplib.py that does proper Expect: 100-continue handling, requesting in the following successful steps:

1. HttpsConnection sends all headers, including the Expect: 100-continue header. The Expect: 100-continue header was detected, so HttpsConnection does not send the body yet.
2. HttpsConnection waits for a response.
3. Apache httpd receives the headers and detects that the request url requires a client certificate.
4. The ssl connection is renegotiated using the client certificate.
5. Apache sends the response status of 100. This is the only header sent, in addition to a blank line.
6. HttpsConnection receives the response status 100, which means all is good to go.
7. HttpsConnection sends the body of the request.
8. Apache gets the request body, which now can be very, very large, because it does not have to be held in the SSLRenegBuffer.
9. Apache processes request and returns the response.
10. HttpsConnection receives the response and processes.

Note that if Apache detected some error detected with the headers, then the sequence would go like so:

1. HttpsConnection sends all headers, including the Expect: 100-continue header. The Expect: 100-continue header was detected, so HttpsConnection does not send the body yet.
2. HttpsConnection waits for a response.
3. Apache httpd receives the headers and detects some kind of error. Maybe the URL is not handled at all.
4. Apache sends the error response.
5. HttpsConnection receives the error response and uses that as the final response of the request. The body of the request is never sent at all.

One unexpected side effect of using the Expect: 100-continue header I found was that requests smaller then the SSLRenegBufferSize were handled by Apache almost 3 times faster then without the Expect: 100-continue header. I assume this is because Apache does have to mess around with all the extra overhead of staging the request in the SSLRenegBuffer, but can instead route the body of the request directly to the request handler.
History
Date User Action Args
2016-04-03 08:19:31IcicleSpidersetrecipients: + IcicleSpider, nnorwitz, terry.reedy, jjlee, orsenthil, cdwave, rharris, edevil, nikratio, Carl.Nobile, martin.panter
2016-04-03 08:19:31IcicleSpidersetmessageid: <1459671571.54.0.143414866831.issue1346874@psf.upfronthosting.co.za>
2016-04-03 08:19:31IcicleSpiderlinkissue1346874 messages
2016-04-03 08:19:30IcicleSpidercreate