id,summary,reporter,owner,description,type,status,priority,milestone,component,version,severity,resolution,keywords,cc,focuses 32932,WP_Http::request hangs on badly behaving servers,Lutz Donnerhacke,,"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",defect (bug),new,normal,,HTTP API,,normal,,,,