I bumped into this one when trying to compare hashes of the message body while implementing HMAC authentication on an nginx /python server.
The drupal_http_request() function adds addition CRLFs before and after the body. We found this because file_get_contents() using stream_context_set_option didn't cause this to happen.
see:
http://tools.ietf.org/html/rfc2616#page-31
generic-message = start-line
*(message-header CRLF)
CRLF
[ message-body ]
start-line = Request-Line | Status-Line
and http://www.tcpipguide.com/free/t_HTTPRequestMessageFormat.htm
--- common.inc (revision 3505)
+++ common.inc (working copy)
@@ -498,9 +498,9 @@
$request = $method .' '. $path ." HTTP/1.0\r\n";
$request .= implode("\r\n", $defaults);
- $request .= "\r\n\r\n";
+ $request .= "\r\n";
if ($data) {
- $request .= $data ."\r\n";
+ $request .= $data;
}
$result->request = $request;
Comment | File | Size | Author |
---|---|---|---|
#24 | common.inc_.diff | 837 bytes | jlkreiss |
#22 | 345167-drupal-http-request-body-D7.patch | 1000 bytes | Dave Reid |
#20 | 345167-drupal-http-request-body-D7.patch | 1008 bytes | Dave Reid |
#18 | 345167-drupal-http-request-body-D7.patch | 823 bytes | Dave Reid |
#14 | do345167-drupal_http_request_body-6x-10.patch | 670 bytes | pwolanin |
Comments
Comment #1
JacobSingh CreditAttribution: JacobSingh commentedsorry, lost the screenshot in the filter:
http://img.skitch.com/20081210-rac3y35j8mctj6qx1bc33dcpbe.jpg
Comment #2
pwolanin CreditAttribution: pwolanin commentedAlso, there is a bug here that strlen() may not return the correct length, due to mbstring.func_overload. Comments on the PHP site suggest getting the byte count using
mb_strlen($string, '8bit');
if it is available.Comment #3
pwolanin CreditAttribution: pwolanin commentedHere's Jacob's missing screenshot:
Comment #4
Heine CreditAttribution: Heine commentedFirst of all, drupal_http_request only supports HTTP 1.0 (RFC 1945).
The proposed patch is incorrect because implode creates for
array('line1' => 'value', 'line2' => 'value', 'line3' => 'value')
the following request part (spaces/linebreaks for clarity only):The next few lines then make this
After
$request .= "\r\n\r\n";
we have:Then we add the body.
Can the extra CRLF between header and body you noticed originate from a header value that already had a CRLF?
The CRLF after the entity body is forbidden by the BNF in RFC 1945 (4.1. Full request). drupal_http_request was added in revision 1.304, but I was unable to find the associated issue, so I do not know why the CRLF was added.
Attached patch removes the CRLF epilogue and also allows sending '0' as data.
Comment #5
JacobSingh CreditAttribution: JacobSingh commentedah, indeed. I think a client lib I was using was pre-adding the \r\n on the last header.
Thanks, patch looks good to me.
Comment #6
Heine CreditAttribution: Heine commentedPatch is against 7
Comment #7
keith.smith CreditAttribution: keith.smith commentedComment #8
pwolanin CreditAttribution: pwolanin commentedLooks good, but maybe we should just check isset()?
Comment #9
keith.smith CreditAttribution: keith.smith commentedComment #10
Dave ReidWe should check if (isset($data)) since it may be null. That will still allow '0' to be sent as data.
Comment #11
pwolanin CreditAttribution: pwolanin commentedhere's a 6.x backport.
Comment #12
Heine CreditAttribution: Heine commentedNULL will be cast to an empty string; why the need for isset?
Comment #13
Dave ReidCross-posted. :)
Comment #14
pwolanin CreditAttribution: pwolanin commentedactually, talking with Heine, his version is probably better, since it's simpler and the NULL to string cast causes no problems.
here's a 6.x verison of his.
Comment #15
pwolanin CreditAttribution: pwolanin commentedpatch in #14 also applies to 5.x
Comment #16
Gábor HojtsyCommitted to 6.x. Moving back to 7.x, let's get this in there really :)
Comment #18
Dave ReidReposting with a better patch name so it gets picked up by the testing bot. This is also the same as patch #4.
Comment #19
Dave ReidShould we also maybe run a trim() or a preg_replace on the header values sent by drupal_http_request so we don't get extra line feeds where they shouldn't be (prevent the problem from #5)?
In drupal_http_request():
That should probably be a separate issue, I know, but I just wanted to get some initial feedback.
Comment #20
Dave ReidWell, from reading RCF 1945, it says that "Header fields can be extended over multiple lines by preceding each extra line with at least one SP or HT, though this is not recommended." trim() would be the appropriate since it will remove any line returns or spaces from the ends of the header value string.
Comment #22
Dave ReidCompletely messed the last patch up...trying again.
Comment #23
Dave ReidStatus back to code needs review.
Comment #24
jlkreiss CreditAttribution: jlkreiss commentedI dive into this issue, having a problem very close to it:
The code in drupal_http_request adds a default "Content-Length" header that takes strlen($data) as value.
Thus, when issuing a simple GET request with no body content, we still have this "Content-Length: 0" header.
That's a problem for some servers hardened by Apache mod_security who blindly reject GET requests with a Content-Length header (see example here: http://www.modsecurity.org/documentation/modsecurity-apache/1.9.3/html-m... , third rule from the end).
As a result, Aggregator is unable to retrieve a feed from this site : http://attacvillefranche.ouvaton.org/backend.php3 , for example (gets a 403 Forbidden response, due to mod_security rejecting the request).
Examining HTTP/1.0 RFC, I didn't find anything that forbids us to have a Content-Length field with no body following it, but given that it may cause problems with some servers and that it lacks coherence, I would suggest to clean up the code...
I propose to test $data before adding the default "Content-Length" header (see diff attachment).
Sorry for my english and my inexisting programming skills, I hope you nevertheless will find my comment usefull...
Comment #25
keith.smith CreditAttribution: keith.smith commentedComment #26
pwolanin CreditAttribution: pwolanin commentedI think you can make this simple
if($data)
- there is no need to compare to an empty string.Comment #27
Dries CreditAttribution: Dries commentedI committed the patch in #22 but not the patch in #24. They seem to do different things. Let's keep talking about the patch in #24. (Ideally, we would create a new issue for #24).
Comment #28
Dave ReidAgreed, #24 should be a separate issue.