WordPress.org

Make WordPress Core

Ticket #8622: 8622.4.diff

File 8622.4.diff, 11.1 KB (added by dd32, 11 years ago)

Heavy handed approach, Assumes fopen is gone(#13915) therefor Get/Post can be combined

  • wp-includes/class-http.php

     
    3838class WP_Http {
    3939
    4040        /**
    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, Fopen, 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_Fopen::test($args) ) {
    102                                 $working_transport['fopen'] = new WP_Http_Fopen();
    103                                 $blocking_transport[] = &$working_transport['fopen'];
    104                         } else if ( true === WP_Http_Fsockopen::test($args) ) {
    105                                 $working_transport['fsockopen'] = new WP_Http_Fsockopen();
    106                                 $blocking_transport[] = &$working_transport['fsockopen'];
    107                         }
    108 
    109                         foreach ( array('curl', 'streams', 'fopen', 'fsockopen', 'exthttp') as $transport ) {
    110                                 if ( isset($working_transport[$transport]) )
    111                                         $nonblocking_transport[] = &$working_transport[$transport];
    112                         }
    113                 }
    114 
    115                 do_action( 'http_transport_get_debug', $working_transport, $blocking_transport, $nonblocking_transport );
    116 
    117                 if ( isset($args['blocking']) && !$args['blocking'] )
    118                         return $nonblocking_transport;
    119                 else
    120                         return $blocking_transport;
    121         }
    122 
    123         /**
    124          * Tests the WordPress HTTP objects for an object to use and returns it.
    125          *
    126          * Tests all of the objects and returns the object that passes. Also caches
    127          * that object to be used later. This is for posting content to a URL and
    128          * is used when there is a body. The plain Fopen Transport can not be used
    129          * to send content, but the streams transport can. This is a limitation that
    130          * is addressed here, by just not including that transport.
    131          *
    132          * @since 2.7.0
    133          * @access private
    134          *
    135          * @param array $args Request args, default us an empty array
    136          * @return object|null Null if no transports are available, HTTP transport object.
    137          */
    138         function &_postTransport( $args = array() ) {
    139                 static $working_transport, $blocking_transport, $nonblocking_transport;
    140 
    141                 if ( is_null($working_transport) ) {
    142                         if ( true === WP_Http_ExtHttp::test($args) ) {
    143                                 $working_transport['exthttp'] = new WP_Http_ExtHttp();
    144                                 $blocking_transport[] = &$working_transport['exthttp'];
    145                         } else if ( true === WP_Http_Curl::test($args) ) {
    146                                 $working_transport['curl'] = new WP_Http_Curl();
    147                                 $blocking_transport[] = &$working_transport['curl'];
    148                         } else if ( true === WP_Http_Streams::test($args) ) {
    149                                 $working_transport['streams'] = new WP_Http_Streams();
    150                                 $blocking_transport[] = &$working_transport['streams'];
    151                         } else if ( true === WP_Http_Fsockopen::test($args) ) {
    152                                 $working_transport['fsockopen'] = new WP_Http_Fsockopen();
    153                                 $blocking_transport[] = &$working_transport['fsockopen'];
    154                         }
    155 
    156                         foreach ( array('curl', 'streams', 'fsockopen', 'exthttp') as $transport ) {
    157                                 if ( isset($working_transport[$transport]) )
    158                                         $nonblocking_transport[] = &$working_transport[$transport];
    159                         }
    160                 }
    161 
    162                 do_action( 'http_transport_post_debug', $working_transport, $blocking_transport, $nonblocking_transport );
    163 
    164                 if ( isset($args['blocking']) && !$args['blocking'] )
    165                         return $nonblocking_transport;
    166                 else
    167                         return $blocking_transport;
    168         }
    169 
    170         /**
    17141         * Send a HTTP request to a URI.
    17242         *
    17343         * The body and headers are part of the arguments. The 'body' argument is for the body and will
     
    286156                        // header isn't already set.
    287157                        if ( ($r['method'] == 'POST' || $r['method'] == 'PUT') && ! isset( $r['headers']['Content-Length'] ) )
    288158                                $r['headers']['Content-Length'] = 0;
    289 
    290                         // The method is ambiguous, because we aren't talking about HTTP methods, the "get" in
    291                         // this case is simply that we aren't sending any bodies and to get the transports that
    292                         // don't support sending bodies along with those which do.
    293                         $transports = WP_Http::_getTransport( $r );
    294159                } else {
    295160                        if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) {
    296161                                if ( ! version_compare(phpversion(), '5.1.2', '>=') )
     
    303168
    304169                        if ( ! isset( $r['headers']['Content-Length'] ) && ! isset( $r['headers']['content-length'] ) )
    305170                                $r['headers']['Content-Length'] = strlen( $r['body'] );
    306 
    307                         // The method is ambiguous, because we aren't talking about HTTP methods, the "post" in
    308                         // this case is simply that we are sending HTTP body and to get the transports that do
    309                         // support sending the body. Not all do, depending on the limitations of the PHP core
    310                         // limitations.
    311                         $transports = WP_Http::_postTransport( $r );
    312171                }
    313172
    314                 do_action( 'http_api_debug', $transports, 'transports_list' );
     173                return $this->_dispatch_request($url, $r);
     174        }
    315175
    316                 $response = array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
    317                 foreach ( (array) $transports as $transport ) {
    318                         $response = $transport->request( $url, $r );
     176        // Need to check the pass-by-reference stuff here to reduce the number of variable copies vs. references
     177        // @TODO: Also, Docs.
     178        function _dispatch_request($url, $r) {
     179                static $transports;
    319180
    320                         do_action( 'http_api_debug', $response, 'response', get_class( $transport ) );
     181                $request_order = isset($r['blocking']) && !$r['blocking'] ?
     182                                                        array('curl', 'streams', 'fsockopen', 'exthttp') : // non-blocking order
     183                                                        array('exthttp', 'curl', 'streams', 'fsockopen'); // blocking order
    321184
    322                         if ( ! is_wp_error( $response ) )
    323                                 return apply_filters( 'http_response', $response, $r, $url );
    324                 }
     185                // This loops over each transport on each HTTP request looking for one which will serve it's needs
     186                foreach ( $request_order as $transport ) {
     187                        $class = 'WP_HTTP_' . $transport;
    325188
    326                 return $response;
     189                        // Check to see if this transport is a possibility
     190                        if ( ! $class::test($r, $url) ) //Note: ::test() does not use $url
     191                                continue;
     192
     193                        // Class claims to support request, Instantate it and give it a whirl.
     194                        if ( empty($transports[$transport]) )
     195                                $transports[$transport] = new $class;
     196
     197                        // Make the request already!
     198                        $response = $transports[$transport]->request( $url, $r );
     199
     200                        do_action( 'http_api_debug', $response, 'response', $class );
     201
     202                        // Remove this If block to have pre-3.2 style responses, ie. Only try *one* transport then give up,
     203                        // Putting this here as a possibility for enabling requests to attmept another transport if it fails
     204                        //  or as a means to do staged-backoff's in times where requests consistently fail with a transport
     205                        //  as happens with cURL on some errors on certain hosts.
     206                        if ( is_wp_error( $response ) ) {
     207                                // Set an increasing count of transport failures? Ie. If cURL fails 3 times, just discard it?
     208                                //get_transient(); set_transient();
     209
     210                                // If the arg 'try-other-transports' is set, and this request failed, Try the next transport instead of failure.
     211                                if ( !empty($r['try-other-transports']) )
     212                                        continue;
     213                        }
     214
     215                        return apply_filters( 'http_response', $response, $r, $url );
     216                }
     217                // Pre-3.2 this would've been returned in the event that nothing could handle it:
     218                // array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
     219                return new WP_Error('http_failure', __('HTTP Failure - There are no transports available which can serve your request.')); //@TODO: String change
    327220        }
    328221
    329222        /**
     
    789682         * @static
    790683         * @return boolean False means this class can not be used, true means it can.
    791684         */
    792         function test( $args = array() ) {
     685        function test( $args = array() ) { //fsockopen
    793686                if ( false !== ($option = get_option( 'disable_fsockopen' )) && time()-$option < 43200 ) // 12 hours
    794687                        return false;
    795688
     
    928821         * @static
    929822         * @return boolean False means this class can not be used, true means it can.
    930823         */
    931         function test($args = array()) {
     824        function test($args = array()) { //fopen
    932825                if ( ! function_exists('fopen') || (function_exists('ini_get') && true != ini_get('allow_url_fopen')) )
    933826                        return false;
    934827
     
    1104997         *
    1105998         * @return boolean False means this class can not be used, true means it can.
    1106999         */
    1107         function test($args = array()) {
     1000        function test($args = array()) { //streams
    11081001                if ( ! function_exists('fopen') || (function_exists('ini_get') && true != ini_get('allow_url_fopen')) )
    11091002                        return false;
    11101003
     
    12751168         *
    12761169         * @return boolean False means this class can not be used, true means it can.
    12771170         */
    1278         function test($args = array()) {
     1171        function test($args = array()) { //ext
    12791172                return apply_filters('use_http_extension_transport', function_exists('http_request'), $args );
    12801173        }
    12811174}
     
    14701363         *
    14711364         * @return boolean False means this class can not be used, true means it can.
    14721365         */
    1473         function test($args = array()) {
     1366        function test($args = array()) { //curl
    14741367                if ( function_exists('curl_init') && function_exists('curl_exec') )
    14751368                        return apply_filters('use_curl_transport', true, $args);
    14761369