Make WordPress Core

Changeset 17550


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