Bug #80931 [Com]: file_get_contents() hangs with HTTP/1.1 if server doesn't close connection

From: Date: Fri, 09 Apr 2021 14:25:24 +0000
Subject: Bug #80931 [Com]: file_get_contents() hangs with HTTP/1.1 if server doesn't close connection
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-233345@lists.php.net to get a copy of this message
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


Thread (35 messages)

« previous php.bugs (#233345) next »