[wp-trac] [WordPress Trac] #32932: WP_Http::request hangs on badly behaving servers
WordPress Trac
noreply at wordpress.org
Thu Jul 9 00:52:58 UTC 2015
#32932: WP_Http::request hangs on badly behaving servers
------------------------------+----------------------------
Reporter: Lutz Donnerhacke | Owner:
Type: defect (bug) | Status: new
Priority: normal | Milestone: Future Release
Component: HTTP API | Version:
Severity: normal | Keywords:
Focuses: |
------------------------------+----------------------------
Some plugin includes a call to "fetch_feed( 'https://wpml.org/feed/' )"
which takes 300 seconds to complete. The whole backend hangs during this
rending of the dashboard widget.
Tracing the problem down reveals, that the function WP_Http::request has a
problem with the response from the server.
The server does answer the HTTP/1.0 request with an HTTP/1.1 response and
300 seconds timeout:
{{{
$ openssl s_client -connect wpml.org:443
SSL-Session:
Protocol : TLSv1
Cipher : DHE-RSA-AES128-SHA
Session-ID: 45...30
Session-ID-ctx:
Master-Key: 68...4F
Key-Arg : None
Start Time: 1436367230
Timeout : 300 (sec)
---
GET /feed/ HTTP/1.0
Host: wpml.org
HTTP/1.1 302 Found
...
[300 seconds to wait until the server closes the connection]
}}}
The WP_Http::request function does not handle this case correctly.
It located in this part of the code:
{{{
$header_length = 0;
while ( ! feof( $handle ) && $keep_reading ) {
$block = fread( $handle, $block_size );
$strResponse .= $block;
if ( ! $bodyStarted && strpos( $strResponse, ...
$header_length = strpos( $strResponse, ...
$bodyStarted = true;
}
$keep_reading = ( ! $bodyStarted || !...
}
}}}
fread() waits the default 10s timeout and returns nothing (after the
initial two reads). The repeats 30 times accumulating to 300 seconds.
{{{
Count Avg.Time Tot.Time Name (linenumbers differ from the
original)
1 301.201028 301.201028 wp-includes/class-http.php:889
1 0.595707 0.595707 -> 1065
1 0.000048 0.000048 -> 1067
1 0.000008 0.000008 -> 1075
1 0.000007 0.000007 -> 1084
1 0.000006 0.000006 -> 1131
32 0.000033 0.001070 -> 1134
32 9.386880 300.380167 -> 1136
1 0.000025 0.000025 -> 1145
1 0.000030 0.000030 -> 1148
1 0.000109 0.000109 -> 1153
}}}
The obvious solution is to stop reading if nothing is returned.
{{{
$header_length = 0;
while ( ! feof( $handle ) && $keep_reading ) {
$block = fread( $handle, $block_size );
$strResponse .= $block;
if ( ! $bodyStarted && strpos( $strResponse, ...
$header_length = strpos( $strResponse, ...
$bodyStarted = true;
}
$keep_reading = ( ! $bodyStarted || !...
+ if(strlen($block) === 0) break;
}
}}}
This solves the problem for the badly behaving servers (in this case the
one from the plugin).
(From #meta1104
--
Ticket URL: <https://core.trac.wordpress.org/ticket/32932>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list