WordPress.org

Make WordPress Core

Changeset 17550


Ignore:
Timestamp:
03/24/11 02:16:13 (3 years ago)
Author:
dd32
Message:

Fix WP_HTTP to only make a request upon a working transport, as well as to allow Unit Testing. Removes the getTransport() & postTransport() methods as they're no longer needed, replaces them with a single _dispatch_request() method. Fixes #11613

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/class-http.php

    r17535 r17550  
    3737 */ 
    3838class WP_Http { 
    39  
    40     /** 
    41      * PHP4 style Constructor - Calls PHP5 Style Constructor 
    42      * 
    43      * @since 2.7.0 
    44      * @return WP_Http 
    45      */ 
    46     function WP_Http() { 
    47         $this->__construct(); 
    48     } 
    49  
    50     /** 
    51      * PHP5 style Constructor - Set up available transport if not available. 
    52      * 
    53      * PHP4 does not have the 'self' keyword and since WordPress supports PHP4, the class needs to 
    54      * be used for the static call. The transport are set up to save time and will only be created 
    55      * once. This class can be created many times without having to go through the step of finding 
    56      * which transports are available. 
    57      * 
    58      * @since 2.7.0 
    59      * @return WP_Http 
    60      */ 
    61     function __construct() { 
    62         WP_Http::_getTransport(); 
    63         WP_Http::_postTransport(); 
    64     } 
    65  
    66     /** 
    67      * Tests the WordPress HTTP objects for an object to use and returns it. 
    68      * 
    69      * Tests all of the objects and returns the object that passes. Also caches that object to be 
    70      * used later. 
    71      * 
    72      * The order for the GET/HEAD requests are HTTP Extension, cURL, Streams, and finally 
    73      * Fsockopen. fsockopen() is used last, because it has the most overhead in its implementation. 
    74      * There isn't any real way around it, since redirects have to be supported, much the same way 
    75      * the other transports also handle redirects. 
    76      * 
    77      * There are currently issues with "localhost" not resolving correctly with DNS. This may cause 
    78      * an error "failed to open stream: A connection attempt failed because the connected party did 
    79      * not properly respond after a period of time, or established connection failed because [the] 
    80      * connected host has failed to respond." 
    81      * 
    82      * @since 2.7.0 
    83      * @access private 
    84      * 
    85      * @param array $args Request args, default us an empty array 
    86      * @return object|null Null if no transports are available, HTTP transport object. 
    87      */ 
    88     function &_getTransport( $args = array() ) { 
    89         static $working_transport, $blocking_transport, $nonblocking_transport; 
    90  
    91         if ( is_null($working_transport) ) { 
    92             if ( true === WP_Http_ExtHttp::test($args) ) { 
    93                 $working_transport['exthttp'] = new WP_Http_ExtHttp(); 
    94                 $blocking_transport[] = &$working_transport['exthttp']; 
    95             } else if ( true === WP_Http_Curl::test($args) ) { 
    96                 $working_transport['curl'] = new WP_Http_Curl(); 
    97                 $blocking_transport[] = &$working_transport['curl']; 
    98             } else if ( true === WP_Http_Streams::test($args) ) { 
    99                 $working_transport['streams'] = new WP_Http_Streams(); 
    100                 $blocking_transport[] = &$working_transport['streams']; 
    101             } else if ( true === WP_Http_Fsockopen::test($args) ) { 
    102                 $working_transport['fsockopen'] = new WP_Http_Fsockopen(); 
    103                 $blocking_transport[] = &$working_transport['fsockopen']; 
    104             } 
    105  
    106             foreach ( array('curl', 'streams', 'fsockopen', 'exthttp') as $transport ) { 
    107                 if ( isset($working_transport[$transport]) ) 
    108                     $nonblocking_transport[] = &$working_transport[$transport]; 
    109             } 
    110         } 
    111  
    112         do_action( 'http_transport_get_debug', $working_transport, $blocking_transport, $nonblocking_transport ); 
    113  
    114         if ( isset($args['blocking']) && !$args['blocking'] ) 
    115             return $nonblocking_transport; 
    116         else 
    117             return $blocking_transport; 
    118     } 
    119  
    120     /** 
    121      * Tests the WordPress HTTP objects for an object to use and returns it. 
    122      * 
    123      * Tests all of the objects and returns the object that passes. Also caches 
    124      * that object to be used later. This is for posting content to a URL and 
    125      * is used when there is a body. 
    126      * 
    127      * @since 2.7.0 
    128      * @access private 
    129      * 
    130      * @param array $args Request args, default us an empty array 
    131      * @return object|null Null if no transports are available, HTTP transport object. 
    132      */ 
    133     function &_postTransport( $args = array() ) { 
    134         static $working_transport, $blocking_transport, $nonblocking_transport; 
    135  
    136         if ( is_null($working_transport) ) { 
    137             if ( true === WP_Http_ExtHttp::test($args) ) { 
    138                 $working_transport['exthttp'] = new WP_Http_ExtHttp(); 
    139                 $blocking_transport[] = &$working_transport['exthttp']; 
    140             } else if ( true === WP_Http_Curl::test($args) ) { 
    141                 $working_transport['curl'] = new WP_Http_Curl(); 
    142                 $blocking_transport[] = &$working_transport['curl']; 
    143             } else if ( true === WP_Http_Streams::test($args) ) { 
    144                 $working_transport['streams'] = new WP_Http_Streams(); 
    145                 $blocking_transport[] = &$working_transport['streams']; 
    146             } else if ( true === WP_Http_Fsockopen::test($args) ) { 
    147                 $working_transport['fsockopen'] = new WP_Http_Fsockopen(); 
    148                 $blocking_transport[] = &$working_transport['fsockopen']; 
    149             } 
    150  
    151             foreach ( array('curl', 'streams', 'fsockopen', 'exthttp') as $transport ) { 
    152                 if ( isset($working_transport[$transport]) ) 
    153                     $nonblocking_transport[] = &$working_transport[$transport]; 
    154             } 
    155         } 
    156  
    157         do_action( 'http_transport_post_debug', $working_transport, $blocking_transport, $nonblocking_transport ); 
    158  
    159         if ( isset($args['blocking']) && !$args['blocking'] ) 
    160             return $nonblocking_transport; 
    161         else 
    162             return $blocking_transport; 
    163     } 
    16439 
    16540    /** 
     
    20681     * @param string $url URI resource. 
    20782     * @param str|array $args Optional. Override the defaults. 
    208      * @return array containing 'headers', 'body', 'response', 'cookies' 
     83     * @return array|object Array containing 'headers', 'body', 'response', 'cookies'. A WP_Error instance upon error 
    20984     */ 
    21085    function request( $url, $args = array() ) { 
     
    282157            if ( ($r['method'] == 'POST' || $r['method'] == 'PUT') && ! isset( $r['headers']['Content-Length'] ) ) 
    283158                $r['headers']['Content-Length'] = 0; 
    284  
    285             // The method is ambiguous, because we aren't talking about HTTP methods, the "get" in 
    286             // this case is simply that we aren't sending any bodies and to get the transports that 
    287             // don't support sending bodies along with those which do. 
    288             $transports = WP_Http::_getTransport( $r ); 
    289159        } else { 
    290160            if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) { 
     
    296166            if ( ! isset( $r['headers']['Content-Length'] ) && ! isset( $r['headers']['content-length'] ) ) 
    297167                $r['headers']['Content-Length'] = strlen( $r['body'] ); 
    298  
    299             // The method is ambiguous, because we aren't talking about HTTP methods, the "post" in 
    300             // this case is simply that we are sending HTTP body and to get the transports that do 
    301             // support sending the body. Not all do, depending on the limitations of the PHP core 
    302             // limitations. 
    303             $transports = WP_Http::_postTransport( $r ); 
    304         } 
    305  
    306         do_action( 'http_api_debug', $transports, 'transports_list' ); 
    307  
    308         $response = array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() ); 
    309         foreach ( (array) $transports as $transport ) { 
    310             $response = $transport->request( $url, $r ); 
    311  
    312             do_action( 'http_api_debug', $response, 'response', get_class( $transport ) ); 
    313  
    314             if ( ! is_wp_error( $response ) ) 
    315                 return apply_filters( 'http_response', $response, $r, $url ); 
    316         } 
    317  
    318         return $response; 
     168        } 
     169 
     170        return $this->_dispatch_request($url, $r); 
     171    } 
     172 
     173    /** 
     174     * Dispatches a HTTP request to a supporting transport. 
     175     * 
     176     * Tests each transport in order to find a transport which matches the request arguements. 
     177     * Also caches the transport instance to be used later. 
     178     * 
     179     * The order for blocking requests is HTTP Extension, cURL, Streams, and finally Fsockopen. 
     180     * The order for non-blocking requests is cURL, Streams, Fsockopen() and finally, HTTP Extension. 
     181     * The HTTP Extension does not support non-blocking requests, but is included as a final resort. 
     182     * 
     183     * There are currently issues with "localhost" not resolving correctly with DNS. This may cause 
     184     * an error "failed to open stream: A connection attempt failed because the connected party did 
     185     * not properly respond after a period of time, or established connection failed because [the] 
     186     * connected host has failed to respond." 
     187     * 
     188     * @since 3.2.0 
     189     * @access private 
     190     * 
     191     * @param string $url URL to Request 
     192     * @param array $args Request arguments 
     193     * @return array|object Array containing 'headers', 'body', 'response', 'cookies'. A WP_Error instance upon error 
     194     */ 
     195    private function _dispatch_request($url, $args) { 
     196        static $transports = null; 
     197        if ( is_null($transports) ) 
     198            $transports = array(); 
     199 
     200        $request_order = isset($r['blocking']) && !$r['blocking'] ? 
     201                            array('curl', 'streams', 'fsockopen', 'exthttp') : // non-blocking order 
     202                            array('exthttp', 'curl', 'streams', 'fsockopen'); // blocking order 
     203 
     204        // Loop over each transport on each HTTP request looking for one which will serve this requests needs 
     205        foreach ( $request_order as $transport ) { 
     206            $class = 'WP_HTTP_' . $transport; 
     207 
     208            // Check to see if this transport is a possibility, calls the transport statically 
     209            if ( ! call_user_func( array($class, 'test'), $args, $url) ) 
     210                continue; 
     211 
     212            // Transport claims to support request, Instantate it and give it a whirl. 
     213            if ( empty( $transports[ $transport ] ) ) 
     214                $transports[ $transport ] = new $class; 
     215 
     216            $response = $transports[ $transport ]->request( $url, $args ); 
     217 
     218            do_action( 'http_api_debug', $response, 'response', $class ); 
     219 
     220            if ( is_wp_error( $response ) ) 
     221                return $response; 
     222 
     223            return apply_filters( 'http_response', $response, $args, $url ); 
     224        } 
     225 
     226        return new WP_Error('http_failure', __('There are no HTTP transports available which can complete the requested request.') ); 
    319227    } 
    320228 
     
    329237     * @param string $url URI resource. 
    330238     * @param str|array $args Optional. Override the defaults. 
    331      * @return boolean 
     239     * @return array|object Array containing 'headers', 'body', 'response', 'cookies'. A WP_Error instance upon error 
    332240     */ 
    333241    function post($url, $args = array()) { 
     
    347255     * @param string $url URI resource. 
    348256     * @param str|array $args Optional. Override the defaults. 
    349      * @return boolean 
     257     * @return array|object Array containing 'headers', 'body', 'response', 'cookies'. A WP_Error instance upon error 
    350258     */ 
    351259    function get($url, $args = array()) { 
     
    365273     * @param string $url URI resource. 
    366274     * @param str|array $args Optional. Override the defaults. 
    367      * @return boolean 
     275     * @return array|object Array containing 'headers', 'body', 'response', 'cookies'. A WP_Error instance upon error 
    368276     */ 
    369277    function head($url, $args = array()) { 
Note: See TracChangeset for help on using the changeset viewer.