]> granicus.if.org Git - php/commitdiff
Fix #78719: http wrapper silently ignores long Location headers
authorChristoph M. Becker <cmbecker69@gmx.de>
Tue, 23 Feb 2021 14:32:54 +0000 (15:32 +0100)
committerChristoph M. Becker <cmbecker69@gmx.de>
Wed, 3 Mar 2021 09:45:25 +0000 (10:45 +0100)
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.

NEWS
ext/standard/http_fopen_wrapper.c
ext/standard/tests/http/bug78719.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index f2bd80397e05c4da19895229478cda65acae1842..afd2514519d9c975fd23fbf501304cab74fb7536 100644 (file)
--- 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
 
index bf0363fd3cca44cb92cc817e506d6d6da61ee658..4f702bf75f38b5034567fdfe0debdca8d1120784 100644 (file)
@@ -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 (file)
index 0000000..b12bd39
--- /dev/null
@@ -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)