ZF-6678: Zend_Http_Client_Adapter_Curl returning HTTP headers in body

Description

When an HTTP server responds with "HTTP/1.1 100 Continue", it can also contain additional headers before the next "HTTP/1.1 ****". This isn't handled properly by Zend_Http_Client_Adapter_Curl::write(). Near the end of the method, it just strips "HTTP/1.1 100 Continue\r\n\r\n" from the response. Instead, the response should be removed until it finds the next "HTTP/1.1 ****" in the response.

The problem this creates is that the response object contains the second set of headers in the body. I found this problem when trying to use the cURL adapter with UPS web services.

Comments

Assigning to Benjamin Eberlei (who authored the curl adapter)

Hm, that is a hard one.

The API of Zend Http makes it hard to work with Curl 100 states. I see what i can come up with :-)

The attached patch resolves the issue.

Can you send me an example HTTP ping pong that executes parts of the patched code? I have applied the patch locally and it seems not to interfere with the tests (all still passing). The new code also executes for several tests, but all those worked before also. I need an example of how i get the old code to fail :-)

Here's the HTTP response that was causing the problem:

HTTP/1.1 100 Continue Expires: Mon, 01 Jun 2009 15:10:45 GMT Cache-Control: max-age=0, no-cache, no-store Pragma: no-cache

HTTP/1.1 200 OK Server: Apache/2.0.52 (Red Hat) mod_ssl/2.0.52 OpenSSL/0.9.7a Content-Length: 9226 Content-Type: text/xml Expires: Mon, 01 Jun 2009 15:10:46 GMT Cache-Control: max-age=0, no-cache, no-store Pragma: no-cache Date: Mon, 01 Jun 2009 15:10:46 GMT Connection: keep-alive

<?xml version="1.0" ?> The rest of the body goes here...

This issue is more broad than just the HTTP/1.1 100 Continue case. You can get similar problems when trying to use the curl adapter to perform HTTP Digest Authentication. Curl will make a first request to the server to poll it for the appropriate nonce value to perform that hash. After this it sends another request with the appropriate credentials. Curl returns both sets of headers however, one for the 401 Authorization Required and then a second for the 220 OK response.

Zend_Http_Client is including the second 200 OK response headers as part of the response body since they are after the first double newlines. Additionally Zend_Http_Client is interpreting the first HTTP/1.1 401 as the response and falsely indicating that there was an error.

Here is some code that can reproduce the problem:

$curl_adapter = new Zend_Http_Client_Adapter_Curl();

$curl_adapter->setCurlOption(CURLOPT_HTTPAUTH,CURLAUTH_ANY); $curl_adapter->setCurlOption(CURLOPT_USERPWD,"user:password");

$http_client = new Zend_Http_Client('http://domain.com/digest/auth/url'); $http_client->setAdapter($curl_adapter);

$response = $http_client->request();

The provided path will only fix the HTTP/1.1 100 Continue case since it specifically looks for the 100 code to remove. A more general solution is required as it appears Curl returns the headers for every request it makes.

Attached a more general solution.

Applied Jordans patchs, fixed in r16035 and merged back into 1.8 release branch. Thank you!