diff options
author | Christoph M. Becker <cmbecker69@gmx.de> | 2021-02-23 15:32:54 +0100 |
---|---|---|
committer | Christoph M. Becker <cmbecker69@gmx.de> | 2021-03-03 10:45:25 +0100 |
commit | 51e2015af3fc4757a666736aae7899a43f76ae6d (patch) | |
tree | 9f9d4e78749646c5db9a5939f933fdbc4becab73 | |
parent | 71297a254b8f0d97c028f3324cbaf95adf8de33c (diff) | |
download | php-git-51e2015af3fc4757a666736aae7899a43f76ae6d.tar.gz |
Fix #78719: http wrapper silently ignores long Location headers
When opening HTTP streams, and reading the headers, we currently
discard header lines longer than `HTTP_HEADER_BLOCK_SIZE` (1024 bytes).
While this is not generally forbidden by RFC 7230, section 3.2.5, it
is not generally allowed either, since that may change the "message
framing or response semantics".
We thus fix this by allowing arbitrarily long header lines.
Closes GH-6720.
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | ext/standard/http_fopen_wrapper.c | 18 | ||||
-rw-r--r-- | ext/standard/tests/http/bug78719.phpt | 26 |
3 files changed, 33 insertions, 13 deletions
@@ -26,6 +26,8 @@ PHP NEWS - Standard: . Fixed bug #80771 (phpinfo(INFO_CREDITS) displays nothing in CLI). (cmb) + . Fixed bug #78719 (http wrapper silently ignores long Location headers). + (cmb) 04 Mar 2021, php 7.4.16 diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index bf0363fd3c..4f702bf75f 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -732,24 +732,16 @@ finish: /* read past HTTP headers */ - http_header_line = emalloc(HTTP_HEADER_BLOCK_SIZE); - while (!php_stream_eof(stream)) { size_t http_header_line_length; - if (php_stream_get_line(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE, &http_header_line_length) && *http_header_line != '\n' && *http_header_line != '\r') { + if (http_header_line != NULL) { + efree(http_header_line); + } + if ((http_header_line = php_stream_get_line(stream, NULL, 0, &http_header_line_length)) && *http_header_line != '\n' && *http_header_line != '\r') { char *e = http_header_line + http_header_line_length - 1; char *http_header_value; - if (*e != '\n') { - do { /* partial header */ - if (php_stream_get_line(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE, &http_header_line_length) == NULL) { - php_stream_wrapper_log_error(wrapper, options, "Failed to read HTTP headers"); - goto out; - } - e = http_header_line + http_header_line_length - 1; - } while (*e != '\n'); - continue; - } + while (e >= http_header_line && (*e == '\n' || *e == '\r')) { e--; } diff --git a/ext/standard/tests/http/bug78719.phpt b/ext/standard/tests/http/bug78719.phpt new file mode 100644 index 0000000000..b12bd3951e --- /dev/null +++ b/ext/standard/tests/http/bug78719.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug #78719 (http wrapper silently ignores long Location headers) +--SKIPIF-- +<?php require 'server.inc'; http_server_skipif('tcp://127.0.0.1:12342'); ?> +--INI-- +allow_url_fopen=1 +--FILE-- +<?php +require 'server.inc'; + +$url = str_repeat('*', 2000); +$responses = array( + "data://text/plain,HTTP/1.0 302 Ok\r\nLocation: $url\r\n\r\nBody", +); +$pid = http_server("tcp://127.0.0.1:12342", $responses, $output); + +$context = stream_context_create(['http' => ['follow_location' => 0]]); +$stream = fopen('http://127.0.0.1:12342/', 'r', false, $context); +var_dump(stream_get_contents($stream)); +var_dump(stream_get_meta_data($stream)['wrapper_data'][1] === "Location: $url"); + +http_server_kill($pid); +?> +--EXPECTF-- +string(4) "Body" +bool(true) |