There is currently no way to see if the correct response headers have been received.
| Comment | File | Size | Author |
|---|---|---|---|
| #52 | drupal_web_test_case.php-330582-52_D6.patch | 7.52 KB | darren oh |
| #52 | drupal_web_test_case.php-330582-52.patch | 10.7 KB | darren oh |
| #49 | drupal_web_test_case.php-330582-49_D6.patch | 7.52 KB | darren oh |
| #49 | drupal_web_test_case.php-330582-49.patch | 10.71 KB | darren oh |
| #48 | drupal_web_test_case.php-330582-48.patch | 10.77 KB | darren oh |
Comments
Comment #1
darren ohComment #2
darren ohForgot to account for cases where a header can be sent multiple times.
Comment #3
boombatower commentedThis should be discussed and committed to core before being backported to SimpleTest 6.x-2.x.
Comment #4
darren ohComment #5
c960657 commentedI really miss this feature.
It would be useful if headers were returned in a name => value array, e.g.
array('Expires' => 'Sun, 19 Nov 1978 05:00:00 GMT', 'Last-Modified' => 'Fri, 07 Nov 2008 16:59:08 GMT', …), like $result->headers from drupal_http_request(), and/or if there was function to get a header with a specific name, e.g.drupalGetHeader($name).Comment #6
darren ohHow would you check for two headers of the same type?
Comment #7
c960657 commentedAccording to RFC 2616, section 4.2 (last paragraph), two headers with the same name may be combined in one by concatenating the values separated by comma. The following two header blocks are equivalent:
So in the name => value array I'd combine identical headers using comma.
Comment #8
darren ohCurl may perform a dialog when HTTP authentication is being used, resulting in multiple requests. How would you keep the headers from different requests separate?
Comment #9
c960657 commentedI would only keep the headers from the last request like drupalGetContent() and assertResponse() do. If a test wishes to inspect the "intermediate" request, I suggest it call curlExec() with an option to do only one request (i.e. CURLOPT_FOLLOWLOCATION = FALSE etc). Not sure whether this is possible with the current version of drupal_web_test_case, though.
Comment #11
lilou commentedSee: #335122: Test clean HEAD after every commit and http://pastebin.ca/1258476
Comment #12
c960657 commentedThis patch adds the ability to get response headers and add request headers. It adds a test to ensure the behaviour described in #9.
The patch also updates drupal_http_request() to use the $name/$value wording as discussed in #327269: drupal_page_cache_header() should compare timestamp where the patch was originally posted.
Comment #13
c960657 commented... the patch:
Comment #14
darren ohI'm using headers to test an HTTP authorization exchange, in which three sets of headers may be received before the message body is transmitted.
Comment #15
c960657 commentedThis patch adds access to the response headers from intermediate requests (see the unit test for an example). Will that work?
Comment #16
darren ohThanks, that would work. Another solution would be to store the headers from each response as an arrays within a larger array. When $this->drupalGetHeaders() is invoked without arguments, the headers from the last response would be popped off the end of the array. Given the argument "all", the entire array could be returned.
I'll do a patch tomorrow.
Comment #17
darren ohComment #18
damien tournoud commentedIt is easy enough to override curlHeaderCallback() in your own test class to get the headers and do whatever you need to do with them. There is no need for this feature, given that it will waste memory while only being useful in a small number of test cases. I suggest we won't fix this, there is enough clutter in DWTC already.
Comment #19
c960657 commentedThis feature would be useful in several other issues: #327269: drupal_page_cache_header() should compare timestamp, #201122: Drupal should support disabling anonymous sessions, #43462: cache_set and cache_get base_url brokenosity. I hope you will reconsider your decision.
Is the increased memory usage more than 1-2 KB total? We don't save the headers from old requests when drupalGet() is called again, and the old headers are garbage collected, so the 1-2 KB don't add up.
Comment #20
darren ohChecking headers is not a specialized task. Many modules set headers. If they have to reimplement curlHeaderCallback(), there is a serious chance that things could break when drupal_web_test_case.php is updated.
Comment #21
damien tournoud commentedHere is what pwolanin is doing in #280934: Use httponly cookie support when available:
Would that kill you?
Simpletest is already slow and already requires a lot of memory. No need to add clutter to the clutter.
Comment #22
darren ohThe memory required for page headers is insignificant compared to that required for page content. If you can show a significant performance problem from retrieving headers, we can address that. As I said, reimplementing curlHeaderCallback() easily breaks things. pwolanin broke SimpleTest error headers. Keeping SimpleTest uncluttered is the reason I produced the latest patch. My patch keeps things simple and ensures that future updates to SimpleTest core will not be rendered ineffective by people reimplementing curlHeaderCallback().
Comment #23
dries commentedOne possible way to address the performance concerns, is to do the heavy lifting in drupalGetHeaders(). Is there a reason the header parsing could not be postponed until drupalGetHeaders() is called?
Comment #24
damien tournoud commented@Darren Oh: pwolanin has not broken anything. Why would you think that the SimpleTest error headers are "broken"?
Comment #25
c960657 commentedWith this patch, the headers are parsed on demand in drupalGetHeaders().
Comment #26
darren ohSimpler patch.
Comment #27
c960657 commentedTo sum up: The patches in #25 and #26 both implement drupalGetHeaders() in largely the same way. In addition, the one in #25 includes a test, adds drupalGetHeader($name) for getting only one header, updates the terminology for header names and values in common.inc to be consistent with than in drupal_web_test_case, and adds the ability to add request headers. Some of this is outside the scope of this bug but was included due to discussion in #327269: drupal_page_cache_header() should compare timestamp where earlier versions of the patch was posted.
Comment #28
dries commentedThanks for implementing my suggestion. The patch in #25/#26 gives us the best of both worlds: no performance impact and a clean API to access the headers. Should pwolanin's test referenced in the discussion above be updated
Personally, I think drupalGetHeader($name) is a LOT more useful than drupalGetHeaders().
Comment #29
darren ohSimpler version of c960657's patch, limited to the current issue.
Comment #30
dries commentedI'm not sure I understand why $all_requests is useful. The PHPdoc is not really helping me understand the purpose of $all_requests.
Comment #31
darren ohIf a page is redirected, it would not be sufficient to examine only the last set of headers received. The same applies when using HTTP authentication. $all_requests may be a misleading name for this variable.
Comment #32
dries commentedIt would be good if we could improve the variable name and its explanation. Darren's comment in #31 is already a better explanation than what we have right now.
Second, it looks like we need to grep the existing tests for header parsing and see if we can reuse our new API. Damien referenced some code from pwolanin that might be a candidate for clean-up.
It looks like we should be able to drive this patch home reasonably easily.
Comment #33
c960657 commentedInstead of
Status-LineI suggest using a key that doesn't give the impression that this is an actual header, e.g.:status. This is not a valid HTTP header name (see the token production in RFC 2616, section 2.2).+ list($name, $value) = array('Status-Line' => $header);This is an unusual way of assigning two variables. It took me a few moments to figure out what was going on.
+ $headers[$request][$name] .= ','. trim($value);Small coding style glitch (misses a space before the period).
I don't think the comment adds anything that isn't already obvious.
Now that the headers are accessible through drupalGetHeaders(), I don't think that drupalHead() should put them in drupalGetContent() too.
Comment #34
darren ohSuggestions implemented.
Comment #36
c960657 commentedSome additional comments:
+ * Gets the value of an HTTP header return by the last request.I assume this should have been "returned".
I suggest the wording "HTTP response header" to emphasize that we are not referring to request headers (not that this is particularly unclear, but it doesn't hurt).
If you are removing CURLOPT_HEADER from drupalHead(), you may want to remove it from the rest of the file as well (originally suggested by mfb).
The
:statuspseudo-header should be described in the Doxygen comment.The patch in #25 contains a test that might be relevant.
Comment #37
darren ohImplemented more suggestions. This patch will cause the current cache test to fail.
Comment #39
darren ohThe test that failed was the page cache test, as expected. The test should succeed after this patch is committed.
Comment #40
c960657 commentedAFAICT the test is failing due to this line:
+ list($name, $value) = array(':status' => $header);There are no keys 0 and 1 in that array, so it triggers two notices. Replacing this with
$name = ':status'; $value = $header;fixes the problem.Comment #41
darren ohFixed.
Comment #42
c960657 commented+ list($name, $value) = array(':status', $header);I still think this is a peculiar way of assigning two variables. The bug mentioned in #40 is a good example of how unusual coding patterns are more likely to hide bugs, because it is harder to see what is going on. But I think it works now. Apart from that the code looks good.
The comments are now much better. Perhaps the handling of duplicate header names using comma deserves mention?
Don't you think a test would be relevant?
Comment #43
darren ohSuggestions implemented. There is no test for drupalGetContent(), so I don't think we need one for drupalGetHeader() or drupalGetHeaders() either.
Comment #45
c960657 commentedApart from the conflict with the #338403: Use {@inheritdoc} on all class methods (including tests) that prevents the patch for applying, it looks like this wont work, because the cookie is set in an intermediate request:
drupalGetHeaders() is considerably more complex than drupalGetContent(). Also, the construction of a complete test suite for Drupal is still work in progress, so some functions may not have tests even though they should have (specifically drupalGetContent() is used by almost every other unit test, so testing it directly as well probably isn't that relevant).
Comment #46
darren ohPlease be specific about what you would test.
Comment #47
c960657 commentedsimpletest-headers-3.patch contains an example that covers the case where drupalGetHeaders(TRUE) returns headers for several requests. You could also test whether the two Cache-Control headers in drupal_page_header() are properly concatenated using comma. Then all code paths of the new functions would be covered.
The tests may not only prevent future bugs in Drupal itself but also help discover if cURL behaves differently on different platforms (it doesn't seem unlikely that e.g. the header callback has subtle differences in different versions of cURL and/or PHP). The test suite has helped me report several bugs that occur with PHP 5.2.0 but not with newer versions (e.g #310904: Use early fetch and document why).
Comment #48
darren ohAdded tests and the ability to check all requests for a header. Also made header names case-insensitive.
Comment #49
darren ohLeft an unused variable in the last patch.
Comment #50
c960657 commentedThis looks good. Nice that you did the lowercasing of header names.
Just two nits:
trueshould beTRUE.You missed a
).Comment #51
chx commentedthis is PHP5, if you are using, there is hardly any need for protected $_headers; the underscore where the underscore is the pseudo-visibility marker that Drupal uses. Just protected $headers will do.
Comment #52
darren ohSuggestions implemented.
Comment #53
dries commentedI reviewed this patch and it looks ready. I committed it to CVS HEAD. Thanks all.
Comment #54
darren ohReady to be committed to SimpleTest (see #3).
Comment #55
boombatower commentedGot all passes.
Committed.