#1104 closed defect (bug) (invalid)
WP_Http::request hangs on badly behaving servers
Reported by: | Lutz Donnerhacke | Owned by: | |
---|---|---|---|
Milestone: | Priority: | normal | |
Component: | General | Keywords: | has-patch needs-testing |
Cc: |
Description
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).
Hello,
It seems you've filed a ticket here on the meta trac but meant to file it on core trac. This trac is for issues with WordPress.org and its related sites, not for issues with the WordPress core project. Please file your ticket on the core trac.