php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #62524 fopen follows redirects for non-3xx statuses
Submitted: 2012-07-10 16:00 UTC Modified: -
Votes:2
Avg. Score:3.5 ± 0.5
Reproduced:2 of 2 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: mike dot hall at twistdigital dot co dot uk Assigned:
Status: Closed Package: Streams related
PHP Version: 5.4.4 OS: Ubuntu 12.04
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: mike dot hall at twistdigital dot co dot uk
New email:
PHP Version: OS:

 

 [2012-07-10 16:00 UTC] mike dot hall at twistdigital dot co dot uk
Description:
------------
The HTTP location header can either be used to direct the user to another 
resource (when accompanied by a 3xx status code) or to inform the user of the 
location of the document they just created (with a 2xx) status code.

It doesn't make sense to treat the location header as a redirect in the second 
context - the location header indicates a redirect only when accompanied by a 3xx 
status code.

Currently, PHP follows Location headers as if they are redirects regardless of 
the returned status code.

Test script:
---------------
$context = stream_context_create([
    "http" => [
        "method"  => "POST"
        "header"  => "Content-Length: 13"
        "content" => "{\"foo\":\"bar\"}",
    ],
]);

// Returns HTTP/1.1 201 Created
// Location: http://example.com/mydb/documentid
//
// {"status":"ok"}
$fp = fopen('http://example.com/mydb', 'r', null, $context);
$data = stream_get_contents($fp);

list($headers, $body) = explode("\r\n\r\n", $data, 2);
echo $body;

Expected result:
----------------
{"status":"ok"}

Actual result:
--------------
{"foo":"bar"}

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-07-12 14:34 UTC] Sjon at hortensius dot net
A more complete example confirms this behavior:

I also fixed some syntax errors

<?php

header('Location: http://php.net', true, 201);

if (isset($_GET['waa']))
    return;

$context = stream_context_create(array(
    "http" => array(
        "method"  => "POST",
        "header"  => "Content-Length: 13",
        "content" => "{\"foo\":\"bar\"}",
    ),
));

$fp = fopen('http://'.$_SERVER['SERVER_NAME']. $_SERVER['PHP_SELF'] .'?waa=1', 
'r', null, $context);
print(stream_get_contents($fp));
 [2012-11-25 02:15 UTC] wes at serverdensity dot com
I've submitted a patch for this via Github pull request: 
https://github.com/php/php-src/pull/236
 [2013-01-29 08:29 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=5382e156f925603ef0f65b9cc4fed29cbe2dce9b
Log: Fix bug #62524, only follow redirects in file streams for 3xx HTTP statuses
 [2013-01-29 08:29 UTC] stas@php.net
-Status: Open +Status: Closed
 [2013-03-05 07:27 UTC] stormbyte at gmail dot com
I saw git diff, and 308 permanent redirect is missing in the code:
/* we only care about Location for 300, 301, 302, 303 and 307 */

Since 308 is Permanent Redirect in http 1.1, it should be included also to be followed and not ignored, otherwise, this bug might happen again on some servers.
 [2013-03-05 07:38 UTC] stormbyte at gmail dot com
I attach a git diff with proposed changes:

diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
index 870f904..a3f193b 100644
--- a/ext/standard/http_fopen_wrapper.c
+++ b/ext/standard/http_fopen_wrapper.c
@@ -731,9 +731,9 @@ finish:
                        http_header_line[http_header_line_length] = '\0';
 
                        if (!strncasecmp(http_header_line, "Location: ", 10)) {
-                               /* we only care about Location for 300, 301, 302, 303 and 307 */
+                               /* we only care about Location for 300, 301, 302, 303, 307 and 308 */
                                /* see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1 */
-                               if ((response_code >= 300 && response_code < 304 || 307 == response_code) && context && php_stream_context_get_option(context, "http", "follow_location", &tmpzval) == SUCCESS) {
+                               if ((response_code >= 300 && response_code < 304 || 307 == response_code || 308 == response_code) && context && php_stream_context_get_option(context, "http", "follow_location", &tmpzval) == SUCCESS) {
                                        SEPARATE_ZVAL(tmpzval);
                                        convert_to_long_ex(tmpzval);
                                        follow_location = Z_LVAL_PP(tmpzval);
 [2014-10-07 23:20 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src-security.git;a=commit;h=5382e156f925603ef0f65b9cc4fed29cbe2dce9b
Log: Fix bug #62524, only follow redirects in file streams for 3xx HTTP statuses
 [2014-10-07 23:31 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src-security.git;a=commit;h=5382e156f925603ef0f65b9cc4fed29cbe2dce9b
Log: Fix bug #62524, only follow redirects in file streams for 3xx HTTP statuses
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Oct 27 16:01:27 2024 UTC