drupal_http_request - case sensitive HTTP header field names

Aron Novak - September 4, 2008 - 08:48
Project:Drupal
Version:7.x-dev
Component:base system
Category:bug report
Priority:normal
Assigned:Unassigned
Status:needs review
Description

Problem:
http://www.alphagalileo.org/rss_channels/?feed=all . This URL uses redirect.
The redirect happens in this way:

GET /rss_channels/?feed=all HTTP/1.0

User-Agent: Wget/1.10.2 (Red Hat modified)

Accept: */*

Host: www.alphagalileo.org
Connection:
Keep-Alive



HTTP/1.1 307 Temporary Redirect

Connection: close

Date: Thu, 04 Sep 2008 08:25:16 GMT

Server: Microsoft-IIS/6.0

X-Powered-By: ASP.NET

Set-Cookie: CFID=4574600;expires=Sat, 28-Aug-2038 08:25:16 GMT;path=/

Set-Cookie: CFTOKEN=67833421;expires=Sat, 28-Aug-2038 08:25:16 GMT;path=/

location: http://www.alphagalileo.org/rss_channels/all.xml
Content-Type:
text/html; charset=UTF-8
(i just recorded the http traffic with wireshark)

wget handles http response header field names differently as Drupal does. (see resp_header_locate in http.c at wget source code)

Drupal treats these field names case sensitive, wget does the opposite. I read the RFC 2616, but it's not clear me that Drupal does or does not follow the RFC in the question. But for practical reasons it should work as wget.

I attached a patch to fix this issue. It basically makes all the header field names lowercase and fix the places in drupal core where it matters.

AttachmentSizeStatusTest resultOperations
http_case_insensitive_fields.patch4.01 KBIdleFailed: Failed to apply patch.View details | Re-test

#1

Dries - September 5, 2008 - 11:30

Let's write a simpletest for this?

#2

Aron Novak - September 8, 2008 - 07:16

I wrote a test for this bug. I re-rolled the patch, now it contains the test too.

AttachmentSizeStatusTest resultOperations
http_case_insensitive_fields_with_tests.patch5.98 KBIdleFailed: 7200 passes, 4 fails, 0 exceptionsView details | Re-test

#3

Aron Novak - October 27, 2008 - 14:31

I rerolled the patch to make it apply without any notices.

AttachmentSizeStatusTest resultOperations
http_case_insensitive_fields_with_tests_1.patch5.77 KBIdleFailed: Failed to install HEAD.View details | Re-test

#4

System Message - November 16, 2008 - 21:50
Status:needs review» needs work

The last submitted patch failed testing.

#5

lilou - November 17, 2008 - 13:24

#6

System Message - November 25, 2008 - 08:00
Status:needs review» needs work

The last submitted patch failed testing.

#7

Aron Novak - April 6, 2009 - 11:34
Status:needs work» needs review

Rerolled against HEAD.

AttachmentSizeStatusTest resultOperations
http_case_insensitive_fields_with_tests_2.patch6.31 KBIdleFailed: 10679 passes, 7 fails, 0 exceptionsView details | Re-test

#8

System Message - April 6, 2009 - 11:51
Status:needs review» needs work

The last submitted patch failed testing.

#9

mr.baileys - April 6, 2009 - 11:57

Drupal treats these field names case sensitive, wget does the opposite. I read the RFC 2616, but it's not clear me that Drupal does or does not follow the RFC in the question. But for practical reasons it should work as wget.

Message header field names are case insensitive (see Message Headers in RFC 2616), so it looks like wget got it right:

HTTP header fields, which include general-header (section 4.5), request-header (section 5.3), response-header (section 6.2), and entity-header (section 7.1) fields, follow the same generic format as that given in Section 3.1 of RFC 822 [9]. Each header field consists of a name followed by a colon (":") and the field value. Field names are case-insensitive. The field value MAY be preceded by any amount of LWS, though a single SP is preferred.

I'm confused about the patch though:

I attached a patch to fix this issue. It basically makes all the header field names lowercase and fix the places in drupal core where it matters.

If we just established that header field names are case insensitive, then why are we changing the case of these field names, especially since the RFC uses capitalized field names itself (for example: If-Modified-Since)? Note: I'm not saying it's the wrong approach, I'm just not sure I fully understand the problem.

#10

Aron Novak - April 6, 2009 - 13:29

Well, you can do the strtolower() at every comparison, but this sucks. I think the right approach is to use it always lower-case in Drupal (except when we issue a request) and use strtolower() only when parsing the http requests.
I have to take a look why the patch failed.

#11

mr.baileys - April 6, 2009 - 14:18

I looked closer at your patch and the test and think I now understand the problem a bit better. I also agree that using strtolower() or strcasecmp() isn't the most elegant solution. I can't shake off the feeling that the proposed patch treats the symptoms rather than the actual problem though, but I understand your reasoning.

And now on to the actual patch:

  1.      if (isset($result->headers[$header]) && $header == 'Set-Cookie') {
           // RFC 2109: the Set-Cookie response header comprises the token Set-
           // Cookie:, followed by a comma-separated list of one or more cookies.
    -      $result->headers[$header] .= ',' . trim($value);
    +      $result->headers[strtolower($header)] .= ',' . trim($value);
         }

    I think this can become a bit messy: if I'm not mistaken, we can end up with two values, $result->headers['Set-Cookie'] and $result->headers['set-cookie'] which have different values?
  2. If we're forcing the result headers to lowercase, I feel we should at least document this, both at the PHPDoc for drupal_http_request:
    *   - headers
    *       An array containing the response headers as name/value pairs.

    as well as when the actual lowercase conversion happens.

#12

c960657 - May 8, 2009 - 21:01

I can't shake off the feeling that the proposed patch treats the symptoms rather than the actual problem though, but I understand your reasoning.

Well, I think the actual problem is that PHP doesn't support an array-like datatype with case-insensitive keys. The strtolower() approach is also used in SimpleTest in DrupalWebTestCase::drupalGetHeaders().

-    $headers['If-None-Match'] = $feed->etag;
+    $headers['if-none-match'] = $feed->etag;
This changes headers that are sent by drupal_http_request(). There is no need to lower-case them. It is only received headers that should be lower-cased.

#13

c960657 - July 22, 2009 - 19:25
Status:needs work» needs review

Updated patch.

AttachmentSizeStatusTest resultOperations
drupal_http_request-1.patch7.78 KBIdleFailed: 11814 passes, 30 fails, 32 exceptionsView details | Re-test

#14

System Message - July 22, 2009 - 19:36
Status:needs review» needs work

The last submitted patch failed testing.

#15

c960657 - July 22, 2009 - 19:56
Status:needs work» needs review

Ahem.

AttachmentSizeStatusTest resultOperations
drupal_http_request-2.patch7.78 KBIdleFailed: Failed to apply patch.View details | Re-test

#16

System Message - October 9, 2009 - 01:10
Status:needs review» needs work

The last submitted patch failed testing.

#17

c960657 - October 21, 2009 - 21:33
Status:needs work» needs review

It's been a while, but here is a reroll.

AttachmentSizeStatusTest resultOperations
drupal_http_request-3.patch8.13 KBIdlePassed: 14690 passes, 0 fails, 0 exceptionsView details | Re-test
 
 

Drupal is a registered trademark of Dries Buytaert.