summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2021-02-23 15:32:54 +0100
committerChristoph M. Becker <cmbecker69@gmx.de>2021-03-03 10:45:25 +0100
commit51e2015af3fc4757a666736aae7899a43f76ae6d (patch)
tree9f9d4e78749646c5db9a5939f933fdbc4becab73
parent71297a254b8f0d97c028f3324cbaf95adf8de33c (diff)
downloadphp-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--NEWS2
-rw-r--r--ext/standard/http_fopen_wrapper.c18
-rw-r--r--ext/standard/tests/http/bug78719.phpt26
3 files changed, 33 insertions, 13 deletions
diff --git a/NEWS b/NEWS
index f2bd80397e..afd2514519 100644
--- a/NEWS
+++ b/NEWS
@@ -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)