Bug #78719 [Com]: fopen() http wrapper silently ignores long Location headers
| From: | henry dot paradiz at gmail dot com | Date: | Wed, 13 Nov 2019 19:32:57 +0000 |
| Subject: | Bug #78719 [Com]: fopen() http wrapper silently ignores long Location headers | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-223704@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78719&edit=1
ID: 78719
Comment by: henry dot paradiz at gmail dot com
Reported by: riikka dot kalliomaki at gmail dot com
Summary: fopen() http wrapper silently ignores long Location
headers
Status: Open
Type: Bug
Package: HTTP related
PHP Version: 7.3.10
Block user comment: N
Private report: N
New Comment:
1024 + 4068 = 5092
41 + 23 = 64
-----------------------------------------------------------------------------
$num = 5092;
$num2 = 64;
$result = $num + $num2 / 6;
echo $result;
Previous Comments:
------------------------------------------------------------------------
[2019-10-22 13:36:52] riikka dot kalliomaki at gmail dot com
Description:
------------
It seems that when a long enough URL is passed in the "Location" for redirection, PHP
simply ignores the header.
Looking further into the source code, it seems that internally in the HTTP wrapper for fopen()
"php_stream_url_wrap_http_ex" reads the headers from requests into a buffer that is
allocated 1024 bytes (HTTP_HEADER_BLOCK_SIZE). Any header that is longer than that seems to be
silently ignored.
This limit of 1024 characters is particularly limiting when it comes to URLs. While there isn't
really any specific maximum length of URLs, when googling "maximum url length", the most
common recommended answer is "2,048 characters".
What makes this worse is that the header is simply silently ignored. No notices, warnings or
anything. This can stop a simple redirection chain simply because the url was a bit long and give no
details about what went wrong. Looking at the stream with stream_get_meta_data() will not even
display the long header, so it looks to the user like the header was never received.
IMO, the HTTP wrapper should at least be able to handle location headers with URLs that are 2048
characters long. Additionally, it may be prudent to trigger a notice or warning if a header is
ignored and it may have affected the result instead of just silently ignoring it.
Test script:
---------------
Set up a remote test script like:
<?php
if (isset($_GET['r'])) {
echo 'Redirect Succesful' . PHP_EOL;
} elseif (isset($_GET['length'])) {
$header = 'Location: https://etc.riimu.net/redirect_test.php?r=';
$length = strlen($header) + 2; // Account for \r\n
$requested = max(0, (int)$_GET['length']);
if ($requested < $length) {
http_response_code(400);
printf('Cannot create header shorter than %d due to prefix "%s"' . PHP_EOL,
$length, $header);
} else {
header($header . str_repeat('a', $requested - $length), true, 302);
echo "Redirect Failed" . PHP_EOL;
}
} else {
echo "Usage: Set 'length' GET parameter to desired Location header line
length" . PHP_EOL;
}
And then run on your local machine like:
<?php
echo file_get_contents('https://etc.riimu.net/redirect_test.php?length=1023');
echo file_get_contents('https://etc.riimu.net/redirect_test.php?length=1024');
Expected result:
----------------
Redirect Succesful
Redirect Succesful
Actual result:
--------------
Redirect Succesful
Redirect Failed
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=78719&edit=1