WordPress.org

Make WordPress Core

Changeset 17550


Ignore:
Timestamp:
03/24/2011 02:16:13 AM (7 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.