Edit report at https://bugs.php.net/bug.php?id=80931&edit=1
ID: 80931
Updated by: twosee@php.net
Reported by: gilperon at gmail dot com
Summary: file_get_contents() hangs with HTTP/1.1 if server
doesn't close connection
Status: Verified
Type: Bug
Package: Streams related
Operating System: any
PHP Version: 7.4
Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
In my opinion, this is a PHP design problem for all versions.
file_get_content("http://*") (php http stream
wrapper) always depends on the behavior of the server. It always expects recv to return 0 and uses
this to detect the end of the response.
But, if the peer does not close the connection, it will wait for data forever.
In this case, even if we set "Connection: close" when the protocol version is 1.1, the
server still treats it as a persistent connection, although the server also has implementation
problems, it did expose the problem of PHP.
So we can reproduce this problem on almost all websites:
<?php
$context = stream_context_create(['http' => ['protocol_version' => 1.1,
'header' => ['Connection: keep-alive']]]);
echo file_get_contents("http://www.baidu.com",
0, $context); // largest search engine in China
// hang...
Previous Comments:
------------------------------------------------------------------------
[2021-04-09 14:25:24] kelunik@php.net
https://gist.github.com/kelunik/c82ce751c1c203806b10ef7326f3e56a
fixes it for chunked encoding, but still fails with a content-length or if auto_decode = false.
------------------------------------------------------------------------
[2021-04-09 13:11:04] kelunik@php.net
Simple reproduce script:
php -r '$server = stream_socket_server("tcp://127.0.0.1:8080"); while ($client =
stream_socket_accept($server)) { fwrite($client, "HTTP/1.1 200 OK\r\ncontent-length:
0\r\n\r\n"); }'
php -r 'file_get_contents("http://127.0.0.1:8080/");'
------------------------------------------------------------------------
[2021-04-08 18:34:07] gilperon at gmail dot com
I think you guys could check how CURL does it, because it handles this "buggy coreios
server" well; it does not hang.
Also, could you please take a look at https://stackoverflow.com/questions/34864179/prevent-php-http-wrapper-from-waiting-for-close-of-persistent-connection
? This looks a similar problem from 5 years ago that I just found out talking with people on discord
server.
------------------------------------------------------------------------
[2021-04-08 18:20:30] rowan dot collins at gmail dot com
To confirm the below is enough to make this particular server respond in a way that PHP handles OK:
diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
index da822d9160..7fdfa9448c 100644
--- a/ext/standard/http_fopen_wrapper.c
+++ b/ext/standard/http_fopen_wrapper.c
@@ -574,7 +574,7 @@ finish:
* HTTP/1.0 to avoid issues when the server respond with a HTTP/1.1
* keep-alive response, which is the preferred response type. */
if ((have_header & HTTP_HEADER_CONNECTION) == 0) {
- smart_str_appends(&req_buf, "Connection: close\r\n");
+ smart_str_appends(&req_buf, "Connection: Close\r\n");
}
if (context &&
However, the correct solution is probably to make the PHP implementation forcefully close
connections when the server defaults to Keep-Alive behaviour.
------------------------------------------------------------------------
[2021-04-08 18:00:41] rowan dot collins at gmail dot com
OK, I think I have figured out what's happening here:
* If you send the server an HTTP/1.1 request with the header "Connection: Close", it
acknowledges with "connection: close"; if you send "Connection: close" (as PHP
does), it does not acknowledge it, and presumably defaults to Connection: Keep-Alive
* RFC 7230 clearly states that "Connection options are case-insensitive." so this is
definitely a bug in the server. https://tools.ietf.org/html/rfc7230#section-6.1
* A local and up to date IIS server does not exhibit the bug.
* The server at ws.correios.com.br is probably running an old version of IIS. The headers include
"x-aspnet-version: 4.0.30319" which was released sometime between 2010 and 2012
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=80931
--
Edit this bug report at https://bugs.php.net/bug.php?id=80931&edit=1