From 12c4ff9b878d9af4b4a4053c21acd5003ebf7c20 Mon Sep 17 00:00:00 2001 From: Rowan Collins Date: Tue, 11 Oct 2016 21:12:18 +0000 Subject: [PATCH 1/6] Add failing test for bug#73297 --- ext/standard/tests/http/bug73297.phpt | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 ext/standard/tests/http/bug73297.phpt diff --git a/ext/standard/tests/http/bug73297.phpt b/ext/standard/tests/http/bug73297.phpt new file mode 100644 index 00000000000..3575ccbcaa7 --- /dev/null +++ b/ext/standard/tests/http/bug73297.phpt @@ -0,0 +1,41 @@ +--TEST-- +Bug #73297 (Ignore 100 Continue returned by HTTP/1.1 servers) +--INI-- +allow_url_fopen=1 +--SKIPIF-- + +--FILE-- + [ + 'protocol_version' => '1.1', + 'header' => 'Connection: Close' + ], + ]; + + $ctx = stream_context_create($options); + + $responses = [ + "data://text/plain,HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\n\r\n" + . "Hello" + ]; + $pid = http_server('tcp://127.0.0.1:12342', $responses); + + echo file_get_contents('http://127.0.0.1:12342/', false, $ctx); + echo "\n"; + + http_server_kill($pid); +} + +do_test(); +echo "\n"; + +?> +--EXPECT-- +Hello + From 417162a9ba3e0cbfc87740d3c63da595b2ef8476 Mon Sep 17 00:00:00 2001 From: Rowan Collins Date: Sun, 23 Oct 2016 18:24:58 +0000 Subject: [PATCH 2/6] http_fopen_wrapper.c - bug#73297 Skip past "100 Continue" responses --- ext/standard/http_fopen_wrapper.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 9c10c4907ba..b751488fc98 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -699,6 +699,24 @@ finish: if ((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) { reqok = 1; } + + /* status codes of 1xx are "informational", and will be followed by a real response + * e.g "100 Continue". RFC 7231 states that unexpected 1xx status MUST be parsed, + * and MAY be ignored. As such, we need to skip ahead to the "real" status*/ + if (response_code >= 100 && response_code < 200) { + /* consume lines until we find a line starting 'HTTP/1' */ + while ( + !php_stream_eof(stream) + && php_stream_get_line(stream, tmp_line, sizeof(tmp_line) - 1, &tmp_line_len) != NULL + && ( tmp_line_len < 6 || strncasecmp(tmp_line, "HTTP/1", 6) ) + ); + + if (tmp_line_len > 9) { + response_code = atoi(tmp_line + 9); + } else { + response_code = 0; + } + } /* all status codes in the 2xx range are defined by the specification as successful; * all status codes in the 3xx range are for redirection, and so also should never * fail */ From 773bc082ca567368f29a9df826311d20e80c7047 Mon Sep 17 00:00:00 2001 From: Rowan Collins Date: Mon, 24 Oct 2016 18:01:17 +0000 Subject: [PATCH 3/6] Simplify ext/standard/tests/http/bug73297.phpt --- ext/standard/tests/http/bug73297.phpt | 38 +++++++++++---------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/ext/standard/tests/http/bug73297.phpt b/ext/standard/tests/http/bug73297.phpt index 3575ccbcaa7..0b0e02f3fd0 100644 --- a/ext/standard/tests/http/bug73297.phpt +++ b/ext/standard/tests/http/bug73297.phpt @@ -8,34 +8,26 @@ allow_url_fopen=1 [ + 'protocol_version' => '1.1', + 'header' => 'Connection: Close' + ], +]; -function do_test() { - $options = [ - 'http' => [ - 'protocol_version' => '1.1', - 'header' => 'Connection: Close' - ], - ]; +$ctx = stream_context_create($options); - $ctx = stream_context_create($options); +$responses = [ + "data://text/plain,HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\n\r\n" + . "Hello" +]; +$pid = http_server('tcp://127.0.0.1:12342', $responses); - $responses = [ - "data://text/plain,HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\n\r\n" - . "Hello" - ]; - $pid = http_server('tcp://127.0.0.1:12342', $responses); - - echo file_get_contents('http://127.0.0.1:12342/', false, $ctx); - echo "\n"; - - http_server_kill($pid); -} - -do_test(); +echo file_get_contents('http://127.0.0.1:12342/', false, $ctx); echo "\n"; +http_server_kill($pid); + ?> --EXPECT-- Hello - From 0f9225f89311489e46d7d9c60f84536a122c523b Mon Sep 17 00:00:00 2001 From: Julien Pauli Date: Thu, 17 Nov 2016 11:33:36 +0100 Subject: [PATCH 4/6] Improvement for bug73297 --- ext/standard/http_fopen_wrapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index b751488fc98..b9ca25687e4 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -708,7 +708,7 @@ finish: while ( !php_stream_eof(stream) && php_stream_get_line(stream, tmp_line, sizeof(tmp_line) - 1, &tmp_line_len) != NULL - && ( tmp_line_len < 6 || strncasecmp(tmp_line, "HTTP/1", 6) ) + && ( tmp_line_len < sizeof("HTTP/1") - 1 || strncasecmp(tmp_line, "HTTP/1", sizeof("HTTP/1") - 1) ) ); if (tmp_line_len > 9) { From 344bc66b07d9336081d512a85db71207be9b55e0 Mon Sep 17 00:00:00 2001 From: Julien Pauli Date: Thu, 17 Nov 2016 11:49:31 +0100 Subject: [PATCH 5/6] Updated NEWS --- NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 548aeae4608..94826541fd7 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,10 @@ PHP NEWS . Update to SQLite 3.15.1. (cmb) . Fixed bug #73530 (Unsetting result set may reset other result set). (cmb) +- Standard: + . Fixed bug #73297 (HTTP stream wrapper should ignore HTTP 100 Continue). + (rowan dot collins at gmail dot com) + - XML: . Fixed bug #72135 (malformed XML causes fault) (edgarsandi) From 226b82b127125ab20c957e1bc07c6aef7b4bf226 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 17 Nov 2016 01:07:18 +0100 Subject: [PATCH 6/6] RC inference fixes --- ext/opcache/Optimizer/zend_func_info.c | 4 ++-- ext/opcache/Optimizer/zend_inference.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c index c00964d9bd1..60954e0c19d 100644 --- a/ext/opcache/Optimizer/zend_func_info.c +++ b/ext/opcache/Optimizer/zend_func_info.c @@ -824,7 +824,7 @@ static const func_info_t func_infos[] = { F1("array_flip", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING), F1("array_change_key_case", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), F1("array_rand", UNKNOWN_INFO), - F1("array_unique", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), + FN("array_unique", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), F1("array_intersect", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), F1("array_intersect_key", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), F1("array_intersect_ukey", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), @@ -833,7 +833,7 @@ static const func_info_t func_infos[] = { F1("array_uintersect_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), F1("array_intersect_uassoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), F1("array_uintersect_uassoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), - F1("array_diff", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), + FN("array_diff", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), F1("array_diff_key", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), F1("array_diff_ukey", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), F1("array_udiff", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY), diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 4c41e2196b1..d0e5d84e895 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2524,10 +2524,10 @@ static void zend_update_type_info(const zend_op_array *op_array, tmp |= (t1 & MAY_BE_RC1) | MAY_BE_RCN; } else if ((opline->extended_value == IS_ARRAY || opline->extended_value == IS_OBJECT) && - (tmp & (MAY_BE_ARRAY|MAY_BE_OBJECT))) { + (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT))) { tmp |= MAY_BE_RC1 | MAY_BE_RCN; } else if (opline->extended_value == IS_STRING && - (t1 & MAY_BE_STRING)) { + (t1 & (MAY_BE_STRING|MAY_BE_OBJECT))) { tmp |= MAY_BE_RC1 | MAY_BE_RCN; } else { tmp |= MAY_BE_RC1;