Edit report at https://bugs.php.net/bug.php?id=80931&edit=1
ID: 80931
Comment by: kelunik@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
Block user comment: N
Private report: N
New Comment:
https://gist.github.com/kelunik/c82ce751c1c203806b10ef7326f3e56a
fixes it for chunked encoding, but still fails with a content-length or if auto_decode = false.
Previous Comments:
------------------------------------------------------------------------
[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
------------------------------------------------------------------------
[2021-04-08 13:43:25] rowan dot collins at gmail dot com
Note that the PHP client code always sends a "Connection: Close" header in the request,
for both HTTP/1.0 and HTTP/1.1 requests: https://heap.space/xref/php-src/ext/standard/http_fopen_wrapper.c?r=5787f91c#570
For some reason, the server appears to only be honouring that for HTTP/1.0 requests, which makes no
sense, because it's an HTTP/1.1 feature.
------------------------------------------------------------------------
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