Bug #81487 [Opn->Dup]: feof() should return true after reading last chunk for HTTP requests
| From: | requinix@php.net | Date: | Wed, 29 Sep 2021 09:16:05 +0000 |
| Subject: | Bug #81487 [Opn->Dup]: feof() should return true after reading last chunk for HTTP requests | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-236910@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=81487&edit=1
ID: 81487
Updated by: requinix@php.net
Reported by: public+php dot net at bastelstu dot be
Summary: feof() should return true after reading last chunk
for HTTP requests
-Status: Open
+Status: Duplicate
Type: Bug
-Package: HTTP related
+Package: Streams related
Operating System: Ubuntu 20.04 + Docker
PHP Version: 8.0.11
Block user comment: N
Private report: N
New Comment:
Same problem as bug #80931
Previous Comments:
------------------------------------------------------------------------
[2021-09-29 08:36:23] public+php dot net at bastelstu dot be
Description:
------------
When performing HTTP requests using
fopen(), feof() will not return
true until the server closes the connection, even if the full body has already been
received.
According to RFC 7230#6.6 (https://httpwg.org/specs/rfc7230.html#persistent.tear-down):
> A client that sends a "close" connection option MUST NOT send further requests
> on that connection (after the one containing "close") and MUST close the
> connection after reading the final response message corresponding to this request.
PHP should detect that the full response message has been read and close the socket.
---------------------
In my real world use case, I am using Guzzles StreamHandler
(https://github.com/guzzle/guzzle/blob/master/src/Handler/StreamHandler.php) to perform HTTP
requests, reading Open Graph metadata.
In one case I was apparently hitting a NetScaler load balancer
(https://www.nextthing.org/archives/2005/08/07/fun-with-http-headers#comment-24970). These appear to
ignore any Connection: close headers within the request and keep the connection open
(for minutes). This is in violation of section RFC7230#6.6:
> A server that receives a "close" connection option MUST initiate a close of
> the connection (see below) after it sends the final response to the request
> that contained "close". The server SHOULD send a "close" connection option
> in its final response on that connection. The server MUST NOT process any
> further requests received on that connection.
*Nonetheless* PHP should also honor its side of RFC7230 and also actually close the connection after
receiving the response.
cURL on the command line and HTTPie both will close the connection on their own.
Test script:
---------------
<?php
// Reproducer server in C:
// https://gist.github.com/TimWolla/0a94abd5c3a9e4c75f317910ac56fa80
$fd = fopen("http://172.17.0.1:8080",
"r");
while (!feof($fd)) {
var_dump(fread($fd, 2));
}
Expected result:
----------------
I expected the while loop to terminate after reading the 9 within the
response, like cURL does:
$ curl -v 'localhost:8080'
* Trying 127.0.0.1:8080...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 Ok
< Connection: keep-alive
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact
0123456789
Actual result:
--------------
The loop / script did not terminate until I terminated the HTTP server, thus implicitly closing the
socket:
$ php test.php
string(2) "01"
string(2) "23"
string(2) "45"
string(2) "67"
string(2) "89"
*hangs at this point*
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=81487&edit=1