[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