Make WordPress Core

Changeset 54997


Ignore:
Timestamp:
12/15/2022 09:30:26 PM (4 years ago)
Author:
hellofromTonya
Message:

External Libraries: Update Requests library to version 2.0.0.

This is a major release and contains breaking changes.

Most important changes to be aware of for this release:

  • All code is now namespaced. Though there is a full backward compatibility layer available and the old class names are still supported, using them will generate a deprecation notice (which can be silenced by plugins if they'd need to support multiple WP versions). See the upgrade guide for more details.
  • A lot of classes have been marked final. This should generally not affect userland code as care has been taken to not apply the final keyword to classes which are known to be extended in userland code.
  • Extensive input validation has been added to Requests. When Requests is used as documented though, this will be unnoticable.
  • A new WpOrg\Requests\Requests::has_capabilities() method has been introduced which can be used to address #37708.
  • A new WpOrg\Requests\Response::decode_body() method has been introduced which may be usable to simplify some of the WP native wrapper code.
  • Remaining PHP 8.0 compatibility fixed (support for named parameters).
  • PHP 8.1 compatibility.

Release notes: https://github.com/WordPress/Requests/releases/tag/v2.0.0

For a full list of changes in this update, see the Requests GitHub:
https://github.com/WordPress/Requests/compare/v1.8.1...v2.0.0

This commit also resolves 2 blocking issues which previously caused the revert of [52244]:

  • New Requests files are loaded into wp-includes/Requests/src/, matching the location of the library. In doing so, filesystems that are case-insensitive are not impacted (see #54582).
  • Preload: During a Core update, the old Requests files are preloaded into memory before the update deletes the files. Preloading avoids fatal errors noted in #54562.

Follow-up to [50842], [51078], [52244], [52315], [52327], [52328].

Props jrf, schlessera, datagutten, wojsmol, dustinrue, soulseekah, szepeviktor. costdev, sergeybiryukov, peterwilsoncc, ironprogrammer, antonvlasenko, hellofromTonya, swissspidy, dd32, azaozz, TobiasBg, audrasjb.
Fixes #54504.
See #54582, #54562.

Location:
trunk
Files:
74 added
20 deleted
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/update-core.php

    r54891 r54997  
    867867
    868868/**
     869 * Stores Requests files to be preloaded and deleted.
     870 *
     871 * For classes/interfaces, use the class/interface name
     872 * as the array key.
     873 *
     874 * All other files/directories should not have a key.
     875 *
     876 * @since 6.2.0
     877 *
     878 * @global array $_old_requests_files
     879 * @var array
     880 * @name $_old_requests_files
     881 */
     882global $_old_requests_files;
     883
     884$_old_requests_files = array(
     885        // Interfaces.
     886        'Requests_Auth'                              => 'wp-includes/Requests/Auth.php',
     887        'Requests_Hooker'                            => 'wp-includes/Requests/Hooker.php',
     888        'Requests_Proxy'                             => 'wp-includes/Requests/Proxy.php',
     889        'Requests_Transport'                         => 'wp-includes/Requests/Transport.php',
     890
     891        // Classes.
     892        'Requests_Auth_Basic'                        => 'wp-includes/Requests/Auth/Basic.php',
     893        'Requests_Cookie_Jar'                        => 'wp-includes/Requests/Cookie/Jar.php',
     894        'Requests_Exception_HTTP'                    => 'wp-includes/Requests/Exception/HTTP.php',
     895        'Requests_Exception_Transport'               => 'wp-includes/Requests/Exception/Transport.php',
     896        'Requests_Exception_HTTP_304'                => 'wp-includes/Requests/Exception/HTTP/304.php',
     897        'Requests_Exception_HTTP_305'                => 'wp-includes/Requests/Exception/HTTP/305.php',
     898        'Requests_Exception_HTTP_306'                => 'wp-includes/Requests/Exception/HTTP/306.php',
     899        'Requests_Exception_HTTP_400'                => 'wp-includes/Requests/Exception/HTTP/400.php',
     900        'Requests_Exception_HTTP_401'                => 'wp-includes/Requests/Exception/HTTP/401.php',
     901        'Requests_Exception_HTTP_402'                => 'wp-includes/Requests/Exception/HTTP/402.php',
     902        'Requests_Exception_HTTP_403'                => 'wp-includes/Requests/Exception/HTTP/403.php',
     903        'Requests_Exception_HTTP_404'                => 'wp-includes/Requests/Exception/HTTP/404.php',
     904        'Requests_Exception_HTTP_405'                => 'wp-includes/Requests/Exception/HTTP/405.php',
     905        'Requests_Exception_HTTP_406'                => 'wp-includes/Requests/Exception/HTTP/406.php',
     906        'Requests_Exception_HTTP_407'                => 'wp-includes/Requests/Exception/HTTP/407.php',
     907        'Requests_Exception_HTTP_408'                => 'wp-includes/Requests/Exception/HTTP/408.php',
     908        'Requests_Exception_HTTP_409'                => 'wp-includes/Requests/Exception/HTTP/409.php',
     909        'Requests_Exception_HTTP_410'                => 'wp-includes/Requests/Exception/HTTP/410.php',
     910        'Requests_Exception_HTTP_411'                => 'wp-includes/Requests/Exception/HTTP/411.php',
     911        'Requests_Exception_HTTP_412'                => 'wp-includes/Requests/Exception/HTTP/412.php',
     912        'Requests_Exception_HTTP_413'                => 'wp-includes/Requests/Exception/HTTP/413.php',
     913        'Requests_Exception_HTTP_414'                => 'wp-includes/Requests/Exception/HTTP/414.php',
     914        'Requests_Exception_HTTP_415'                => 'wp-includes/Requests/Exception/HTTP/415.php',
     915        'Requests_Exception_HTTP_416'                => 'wp-includes/Requests/Exception/HTTP/416.php',
     916        'Requests_Exception_HTTP_417'                => 'wp-includes/Requests/Exception/HTTP/417.php',
     917        'Requests_Exception_HTTP_418'                => 'wp-includes/Requests/Exception/HTTP/418.php',
     918        'Requests_Exception_HTTP_428'                => 'wp-includes/Requests/Exception/HTTP/428.php',
     919        'Requests_Exception_HTTP_429'                => 'wp-includes/Requests/Exception/HTTP/429.php',
     920        'Requests_Exception_HTTP_431'                => 'wp-includes/Requests/Exception/HTTP/431.php',
     921        'Requests_Exception_HTTP_500'                => 'wp-includes/Requests/Exception/HTTP/500.php',
     922        'Requests_Exception_HTTP_501'                => 'wp-includes/Requests/Exception/HTTP/501.php',
     923        'Requests_Exception_HTTP_502'                => 'wp-includes/Requests/Exception/HTTP/502.php',
     924        'Requests_Exception_HTTP_503'                => 'wp-includes/Requests/Exception/HTTP/503.php',
     925        'Requests_Exception_HTTP_504'                => 'wp-includes/Requests/Exception/HTTP/504.php',
     926        'Requests_Exception_HTTP_505'                => 'wp-includes/Requests/Exception/HTTP/505.php',
     927        'Requests_Exception_HTTP_511'                => 'wp-includes/Requests/Exception/HTTP/511.php',
     928        'Requests_Exception_HTTP_Unknown'            => 'wp-includes/Requests/Exception/HTTP/Unknown.php',
     929        'Requests_Exception_Transport_cURL'          => 'wp-includes/Requests/Exception/Transport/cURL.php',
     930        'Requests_Proxy_HTTP'                        => 'wp-includes/Requests/Proxy/HTTP.php',
     931        'Requests_Response_Headers'                  => 'wp-includes/Requests/Response/Headers.php',
     932        'Requests_Transport_cURL'                    => 'wp-includes/Requests/Transport/cURL.php',
     933        'Requests_Transport_fsockopen'               => 'wp-includes/Requests/Transport/fsockopen.php',
     934        'Requests_Utility_CaseInsensitiveDictionary' => 'wp-includes/Requests/Utility/CaseInsensitiveDictionary.php',
     935        'Requests_Utility_FilteredIterator'          => 'wp-includes/Requests/Utility/FilteredIterator.php',
     936        'Requests_Cookie'                            => 'wp-includes/Requests/Cookie.php',
     937        'Requests_Exception'                         => 'wp-includes/Requests/Exception.php',
     938        'Requests_Hooks'                             => 'wp-includes/Requests/Hooks.php',
     939        'Requests_IDNAEncoder'                       => 'wp-includes/Requests/IDNAEncoder.php',
     940        'Requests_IPv6'                              => 'wp-includes/Requests/IPv6.php',
     941        'Requests_IRI'                               => 'wp-includes/Requests/IRI.php',
     942        'Requests_Response'                          => 'wp-includes/Requests/Response.php',
     943        'Requests_SSL'                               => 'wp-includes/Requests/SSL.php',
     944        'Requests_Session'                           => 'wp-includes/Requests/Session.php',
     945
     946        // Directories.
     947        'wp-includes/Requests/Auth/',
     948        'wp-includes/Requests/Cookie/',
     949        'wp-includes/Requests/Exception/HTTP/',
     950        'wp-includes/Requests/Exception/Transport/',
     951        'wp-includes/Requests/Exception/',
     952        'wp-includes/Requests/Proxy/',
     953        'wp-includes/Requests/Response/',
     954        'wp-includes/Requests/Transport/',
     955        'wp-includes/Requests/Utility/',
     956);
     957
     958/**
    869959 * Stores new files in wp-content to copy
    870960 *
     
    9501040 * @global WP_Filesystem_Base $wp_filesystem          WordPress filesystem subclass.
    9511041 * @global array              $_old_files
     1042 * @global array              $_old_requests_files
    9521043 * @global array              $_new_bundled_files
    9531044 * @global wpdb               $wpdb                   WordPress database abstraction object.
     
    9611052 */
    9621053function update_core( $from, $to ) {
    963         global $wp_filesystem, $_old_files, $_new_bundled_files, $wpdb;
     1054        global $wp_filesystem, $_old_files, $_old_requests_files, $_new_bundled_files, $wpdb;
    9641055
    9651056        set_time_limit( 300 );
     1057
     1058        /*
     1059         * Merge the old Requests files and directories into the `$_old_files`.
     1060         * Then preload these Requests files first, before the files are deleted
     1061         * and replaced to ensure the code is in memory if needed.
     1062         */
     1063        $_old_files = array_merge( $_old_files, array_values( $_old_requests_files ) );
     1064        _preload_old_requests_classes_and_interfaces( $to );
    9661065
    9671066        /**
     
    14801579
    14811580/**
     1581 * Preloads old Requests classes and interfaces.
     1582 *
     1583 * This function preloads the old Requests code into memory before the
     1584 * upgrade process deletes the files. Why? Requests code is loaded into
     1585 * memory via an autoloader, meaning when a class or interface is needed
     1586 * If a request is in process, Requests could attempt to access code. If
     1587 * the file is not there, a fatal error could occur. If the file was
     1588 * replaced, the new code is not compatible with the old, resulting in
     1589 * a fatal error. Preloading ensures the code is in memory before the
     1590 * code is updated.
     1591 *
     1592 * @since 6.2.0
     1593 *
     1594 * @global array              $_old_requests_files Requests files to be preloaded.
     1595 * @global WP_Filesystem_Base $wp_filesystem       WordPress filesystem subclass.
     1596 *
     1597 * @param string $to Path to old WordPress installation.
     1598 */
     1599function _preload_old_requests_classes_and_interfaces( $to ) {
     1600        global $_old_requests_files, $wp_filesystem;
     1601
     1602        foreach ( $_old_requests_files as $name => $file ) {
     1603                // Skip files that aren't interfaces or classes.
     1604                if ( is_int( $name ) ) {
     1605                        continue;
     1606                }
     1607
     1608                // Skip if it's already loaded.
     1609                if ( class_exists( $name ) || interface_exists( $name ) ) {
     1610                        continue;
     1611                }
     1612
     1613                // Skip if the file is missing.
     1614                if ( ! $wp_filesystem->is_file( $to . $file ) ) {
     1615                        continue;
     1616                }
     1617
     1618                require_once $to . $file;
     1619        }
     1620}
     1621
     1622/**
    14821623 * Redirect to the About WordPress page after a successful upgrade.
    14831624 *
  • trunk/src/wp-includes/class-requests.php

    r52328 r54997  
    88 *
    99 * @package Requests
     10 *
     11 * @deprecated 6.2.0
    1012 */
     13
     14/*
     15 * Integrators who cannot yet upgrade to the PSR-4 class names can silence deprecations
     16 * by defining a `REQUESTS_SILENCE_PSR0_DEPRECATIONS` constant and setting it to `true`.
     17 * The constant needs to be defined before this class is required.
     18 */
     19if (!defined('REQUESTS_SILENCE_PSR0_DEPRECATIONS') || REQUESTS_SILENCE_PSR0_DEPRECATIONS !== true) {
     20        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
     21        trigger_error(
     22                'The PSR-0 `Requests_...` class names in the Request library are deprecated.'
     23                . ' Switch to the PSR-4 `WpOrg\Requests\...` class names at your earliest convenience.',
     24                E_USER_DEPRECATED
     25        );
     26
     27        // Prevent the deprecation notice from being thrown twice.
     28        if (!defined('REQUESTS_SILENCE_PSR0_DEPRECATIONS')) {
     29                define('REQUESTS_SILENCE_PSR0_DEPRECATIONS', true);
     30        }
     31}
     32
     33require_once __DIR__ . '/Requests/src/Requests.php';
    1134
    1235/**
     
    1841 *
    1942 * @package Requests
     43 *
     44 * @deprecated 6.2.0 Use `WpOrg\Requests\Requests` instead for the actual functionality and
     45 *                   use `WpOrg\Requests\Autoload` for the autoloading.
    2046 */
    21 class Requests {
    22         /**
    23          * POST method
    24          *
    25          * @var string
    26          */
    27         const POST = 'POST';
     47class Requests extends WpOrg\Requests\Requests {
    2848
    2949        /**
    30          * PUT method
     50         * Deprecated autoloader for Requests.
    3151         *
    32          * @var string
    33          */
    34         const PUT = 'PUT';
    35 
    36         /**
    37          * GET method
    38          *
    39          * @var string
    40          */
    41         const GET = 'GET';
    42 
    43         /**
    44          * HEAD method
    45          *
    46          * @var string
    47          */
    48         const HEAD = 'HEAD';
    49 
    50         /**
    51          * DELETE method
    52          *
    53          * @var string
    54          */
    55         const DELETE = 'DELETE';
    56 
    57         /**
    58          * OPTIONS method
    59          *
    60          * @var string
    61          */
    62         const OPTIONS = 'OPTIONS';
    63 
    64         /**
    65          * TRACE method
    66          *
    67          * @var string
    68          */
    69         const TRACE = 'TRACE';
    70 
    71         /**
    72          * PATCH method
    73          *
    74          * @link https://tools.ietf.org/html/rfc5789
    75          * @var string
    76          */
    77         const PATCH = 'PATCH';
    78 
    79         /**
    80          * Default size of buffer size to read streams
    81          *
    82          * @var integer
    83          */
    84         const BUFFER_SIZE = 1160;
    85 
    86         /**
    87          * Current version of Requests
    88          *
    89          * @var string
    90          */
    91         const VERSION = '1.8.1';
    92 
    93         /**
    94          * Registered transport classes
    95          *
    96          * @var array
    97          */
    98         protected static $transports = array();
    99 
    100         /**
    101          * Selected transport name
    102          *
    103          * Use {@see get_transport()} instead
    104          *
    105          * @var array
    106          */
    107         public static $transport = array();
    108 
    109         /**
    110          * Default certificate path.
    111          *
    112          * @see Requests::get_certificate_path()
    113          * @see Requests::set_certificate_path()
    114          *
    115          * @var string
    116          */
    117         protected static $certificate_path;
    118 
    119         /**
    120          * This is a static class, do not instantiate it
    121          *
    122          * @codeCoverageIgnore
    123          */
    124         private function __construct() {}
    125 
    126         /**
    127          * Autoloader for Requests
    128          *
    129          * Register this with {@see register_autoloader()} if you'd like to avoid
    130          * having to create your own.
    131          *
    132          * (You can also use `spl_autoload_register` directly if you'd prefer.)
     52         * @deprecated 6.2.0 Use the `WpOrg\Requests\Autoload::load()` method instead.
    13353         *
    13454         * @codeCoverageIgnore
     
    13757         */
    13858        public static function autoloader($class) {
    139                 // Check that the class starts with "Requests"
    140                 if (strpos($class, 'Requests') !== 0) {
    141                         return;
     59                if (class_exists('WpOrg\Requests\Autoload') === false) {
     60                        require_once __DIR__ . '/Requests/src/Autoload.php';
    14261                }
    14362
    144                 $file = str_replace('_', '/', $class);
    145                 if (file_exists(dirname(__FILE__) . '/' . $file . '.php')) {
    146                         require_once dirname(__FILE__) . '/' . $file . '.php';
    147                 }
     63                return WpOrg\Requests\Autoload::load($class);
    14864        }
    14965
     
    15167         * Register the built-in autoloader
    15268         *
     69         * @deprecated 6.2.0 Include the `WpOrg\Requests\Autoload` class and
     70         *                   call `WpOrg\Requests\Autoload::register()` instead.
     71         *
    15372         * @codeCoverageIgnore
    15473         */
    15574        public static function register_autoloader() {
    156                 spl_autoload_register(array('Requests', 'autoloader'));
    157         }
    158 
    159         /**
    160          * Register a transport
    161          *
    162          * @param string $transport Transport class to add, must support the Requests_Transport interface
    163          */
    164         public static function add_transport($transport) {
    165                 if (empty(self::$transports)) {
    166                         self::$transports = array(
    167                                 'Requests_Transport_cURL',
    168                                 'Requests_Transport_fsockopen',
    169                         );
    170                 }
    171 
    172                 self::$transports = array_merge(self::$transports, array($transport));
    173         }
    174 
    175         /**
    176          * Get a working transport
    177          *
    178          * @throws Requests_Exception If no valid transport is found (`notransport`)
    179          * @return Requests_Transport
    180          */
    181         protected static function get_transport($capabilities = array()) {
    182                 // Caching code, don't bother testing coverage
    183                 // @codeCoverageIgnoreStart
    184                 // array of capabilities as a string to be used as an array key
    185                 ksort($capabilities);
    186                 $cap_string = serialize($capabilities);
    187 
    188                 // Don't search for a transport if it's already been done for these $capabilities
    189                 if (isset(self::$transport[$cap_string]) && self::$transport[$cap_string] !== null) {
    190                         $class = self::$transport[$cap_string];
    191                         return new $class();
    192                 }
    193                 // @codeCoverageIgnoreEnd
    194 
    195                 if (empty(self::$transports)) {
    196                         self::$transports = array(
    197                                 'Requests_Transport_cURL',
    198                                 'Requests_Transport_fsockopen',
    199                         );
    200                 }
    201 
    202                 // Find us a working transport
    203                 foreach (self::$transports as $class) {
    204                         if (!class_exists($class)) {
    205                                 continue;
    206                         }
    207 
    208                         $result = call_user_func(array($class, 'test'), $capabilities);
    209                         if ($result) {
    210                                 self::$transport[$cap_string] = $class;
    211                                 break;
    212                         }
    213                 }
    214                 if (self::$transport[$cap_string] === null) {
    215                         throw new Requests_Exception('No working transports found', 'notransport', self::$transports);
    216                 }
    217 
    218                 $class = self::$transport[$cap_string];
    219                 return new $class();
    220         }
    221 
    222         /**#@+
    223          * @see request()
    224          * @param string $url
    225          * @param array $headers
    226          * @param array $options
    227          * @return Requests_Response
    228          */
    229         /**
    230          * Send a GET request
    231          */
    232         public static function get($url, $headers = array(), $options = array()) {
    233                 return self::request($url, $headers, null, self::GET, $options);
    234         }
    235 
    236         /**
    237          * Send a HEAD request
    238          */
    239         public static function head($url, $headers = array(), $options = array()) {
    240                 return self::request($url, $headers, null, self::HEAD, $options);
    241         }
    242 
    243         /**
    244          * Send a DELETE request
    245          */
    246         public static function delete($url, $headers = array(), $options = array()) {
    247                 return self::request($url, $headers, null, self::DELETE, $options);
    248         }
    249 
    250         /**
    251          * Send a TRACE request
    252          */
    253         public static function trace($url, $headers = array(), $options = array()) {
    254                 return self::request($url, $headers, null, self::TRACE, $options);
    255         }
    256         /**#@-*/
    257 
    258         /**#@+
    259          * @see request()
    260          * @param string $url
    261          * @param array $headers
    262          * @param array $data
    263          * @param array $options
    264          * @return Requests_Response
    265          */
    266         /**
    267          * Send a POST request
    268          */
    269         public static function post($url, $headers = array(), $data = array(), $options = array()) {
    270                 return self::request($url, $headers, $data, self::POST, $options);
    271         }
    272         /**
    273          * Send a PUT request
    274          */
    275         public static function put($url, $headers = array(), $data = array(), $options = array()) {
    276                 return self::request($url, $headers, $data, self::PUT, $options);
    277         }
    278 
    279         /**
    280          * Send an OPTIONS request
    281          */
    282         public static function options($url, $headers = array(), $data = array(), $options = array()) {
    283                 return self::request($url, $headers, $data, self::OPTIONS, $options);
    284         }
    285 
    286         /**
    287          * Send a PATCH request
    288          *
    289          * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the
    290          * specification recommends that should send an ETag
    291          *
    292          * @link https://tools.ietf.org/html/rfc5789
    293          */
    294         public static function patch($url, $headers, $data = array(), $options = array()) {
    295                 return self::request($url, $headers, $data, self::PATCH, $options);
    296         }
    297         /**#@-*/
    298 
    299         /**
    300          * Main interface for HTTP requests
    301          *
    302          * This method initiates a request and sends it via a transport before
    303          * parsing.
    304          *
    305          * The `$options` parameter takes an associative array with the following
    306          * options:
    307          *
    308          * - `timeout`: How long should we wait for a response?
    309          *    Note: for cURL, a minimum of 1 second applies, as DNS resolution
    310          *    operates at second-resolution only.
    311          *    (float, seconds with a millisecond precision, default: 10, example: 0.01)
    312          * - `connect_timeout`: How long should we wait while trying to connect?
    313          *    (float, seconds with a millisecond precision, default: 10, example: 0.01)
    314          * - `useragent`: Useragent to send to the server
    315          *    (string, default: php-requests/$version)
    316          * - `follow_redirects`: Should we follow 3xx redirects?
    317          *    (boolean, default: true)
    318          * - `redirects`: How many times should we redirect before erroring?
    319          *    (integer, default: 10)
    320          * - `blocking`: Should we block processing on this request?
    321          *    (boolean, default: true)
    322          * - `filename`: File to stream the body to instead.
    323          *    (string|boolean, default: false)
    324          * - `auth`: Authentication handler or array of user/password details to use
    325          *    for Basic authentication
    326          *    (Requests_Auth|array|boolean, default: false)
    327          * - `proxy`: Proxy details to use for proxy by-passing and authentication
    328          *    (Requests_Proxy|array|string|boolean, default: false)
    329          * - `max_bytes`: Limit for the response body size.
    330          *    (integer|boolean, default: false)
    331          * - `idn`: Enable IDN parsing
    332          *    (boolean, default: true)
    333          * - `transport`: Custom transport. Either a class name, or a
    334          *    transport object. Defaults to the first working transport from
    335          *    {@see getTransport()}
    336          *    (string|Requests_Transport, default: {@see getTransport()})
    337          * - `hooks`: Hooks handler.
    338          *    (Requests_Hooker, default: new Requests_Hooks())
    339          * - `verify`: Should we verify SSL certificates? Allows passing in a custom
    340          *    certificate file as a string. (Using true uses the system-wide root
    341          *    certificate store instead, but this may have different behaviour
    342          *    across transports.)
    343          *    (string|boolean, default: library/Requests/Transport/cacert.pem)
    344          * - `verifyname`: Should we verify the common name in the SSL certificate?
    345          *    (boolean, default: true)
    346          * - `data_format`: How should we send the `$data` parameter?
    347          *    (string, one of 'query' or 'body', default: 'query' for
    348          *    HEAD/GET/DELETE, 'body' for POST/PUT/OPTIONS/PATCH)
    349          *
    350          * @throws Requests_Exception On invalid URLs (`nonhttp`)
    351          *
    352          * @param string $url URL to request
    353          * @param array $headers Extra headers to send with the request
    354          * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
    355          * @param string $type HTTP request type (use Requests constants)
    356          * @param array $options Options for the request (see description for more information)
    357          * @return Requests_Response
    358          */
    359         public static function request($url, $headers = array(), $data = array(), $type = self::GET, $options = array()) {
    360                 if (empty($options['type'])) {
    361                         $options['type'] = $type;
    362                 }
    363                 $options = array_merge(self::get_default_options(), $options);
    364 
    365                 self::set_defaults($url, $headers, $data, $type, $options);
    366 
    367                 $options['hooks']->dispatch('requests.before_request', array(&$url, &$headers, &$data, &$type, &$options));
    368 
    369                 if (!empty($options['transport'])) {
    370                         $transport = $options['transport'];
    371 
    372                         if (is_string($options['transport'])) {
    373                                 $transport = new $transport();
    374                         }
    375                 }
    376                 else {
    377                         $need_ssl     = (stripos($url, 'https://') === 0);
    378                         $capabilities = array('ssl' => $need_ssl);
    379                         $transport    = self::get_transport($capabilities);
    380                 }
    381                 $response = $transport->request($url, $headers, $data, $options);
    382 
    383                 $options['hooks']->dispatch('requests.before_parse', array(&$response, $url, $headers, $data, $type, $options));
    384 
    385                 return self::parse_response($response, $url, $headers, $data, $options);
    386         }
    387 
    388         /**
    389          * Send multiple HTTP requests simultaneously
    390          *
    391          * The `$requests` parameter takes an associative or indexed array of
    392          * request fields. The key of each request can be used to match up the
    393          * request with the returned data, or with the request passed into your
    394          * `multiple.request.complete` callback.
    395          *
    396          * The request fields value is an associative array with the following keys:
    397          *
    398          * - `url`: Request URL Same as the `$url` parameter to
    399          *    {@see Requests::request}
    400          *    (string, required)
    401          * - `headers`: Associative array of header fields. Same as the `$headers`
    402          *    parameter to {@see Requests::request}
    403          *    (array, default: `array()`)
    404          * - `data`: Associative array of data fields or a string. Same as the
    405          *    `$data` parameter to {@see Requests::request}
    406          *    (array|string, default: `array()`)
    407          * - `type`: HTTP request type (use Requests constants). Same as the `$type`
    408          *    parameter to {@see Requests::request}
    409          *    (string, default: `Requests::GET`)
    410          * - `cookies`: Associative array of cookie name to value, or cookie jar.
    411          *    (array|Requests_Cookie_Jar)
    412          *
    413          * If the `$options` parameter is specified, individual requests will
    414          * inherit options from it. This can be used to use a single hooking system,
    415          * or set all the types to `Requests::POST`, for example.
    416          *
    417          * In addition, the `$options` parameter takes the following global options:
    418          *
    419          * - `complete`: A callback for when a request is complete. Takes two
    420          *    parameters, a Requests_Response/Requests_Exception reference, and the
    421          *    ID from the request array (Note: this can also be overridden on a
    422          *    per-request basis, although that's a little silly)
    423          *    (callback)
    424          *
    425          * @param array $requests Requests data (see description for more information)
    426          * @param array $options Global and default options (see {@see Requests::request})
    427          * @return array Responses (either Requests_Response or a Requests_Exception object)
    428          */
    429         public static function request_multiple($requests, $options = array()) {
    430                 $options = array_merge(self::get_default_options(true), $options);
    431 
    432                 if (!empty($options['hooks'])) {
    433                         $options['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
    434                         if (!empty($options['complete'])) {
    435                                 $options['hooks']->register('multiple.request.complete', $options['complete']);
    436                         }
    437                 }
    438 
    439                 foreach ($requests as $id => &$request) {
    440                         if (!isset($request['headers'])) {
    441                                 $request['headers'] = array();
    442                         }
    443                         if (!isset($request['data'])) {
    444                                 $request['data'] = array();
    445                         }
    446                         if (!isset($request['type'])) {
    447                                 $request['type'] = self::GET;
    448                         }
    449                         if (!isset($request['options'])) {
    450                                 $request['options']         = $options;
    451                                 $request['options']['type'] = $request['type'];
    452                         }
    453                         else {
    454                                 if (empty($request['options']['type'])) {
    455                                         $request['options']['type'] = $request['type'];
    456                                 }
    457                                 $request['options'] = array_merge($options, $request['options']);
    458                         }
    459 
    460                         self::set_defaults($request['url'], $request['headers'], $request['data'], $request['type'], $request['options']);
    461 
    462                         // Ensure we only hook in once
    463                         if ($request['options']['hooks'] !== $options['hooks']) {
    464                                 $request['options']['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
    465                                 if (!empty($request['options']['complete'])) {
    466                                         $request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']);
    467                                 }
    468                         }
    469                 }
    470                 unset($request);
    471 
    472                 if (!empty($options['transport'])) {
    473                         $transport = $options['transport'];
    474 
    475                         if (is_string($options['transport'])) {
    476                                 $transport = new $transport();
    477                         }
    478                 }
    479                 else {
    480                         $transport = self::get_transport();
    481                 }
    482                 $responses = $transport->request_multiple($requests, $options);
    483 
    484                 foreach ($responses as $id => &$response) {
    485                         // If our hook got messed with somehow, ensure we end up with the
    486                         // correct response
    487                         if (is_string($response)) {
    488                                 $request = $requests[$id];
    489                                 self::parse_multiple($response, $request);
    490                                 $request['options']['hooks']->dispatch('multiple.request.complete', array(&$response, $id));
    491                         }
    492                 }
    493 
    494                 return $responses;
    495         }
    496 
    497         /**
    498          * Get the default options
    499          *
    500          * @see Requests::request() for values returned by this method
    501          * @param boolean $multirequest Is this a multirequest?
    502          * @return array Default option values
    503          */
    504         protected static function get_default_options($multirequest = false) {
    505                 $defaults = array(
    506                         'timeout'          => 10,
    507                         'connect_timeout'  => 10,
    508                         'useragent'        => 'php-requests/' . self::VERSION,
    509                         'protocol_version' => 1.1,
    510                         'redirected'       => 0,
    511                         'redirects'        => 10,
    512                         'follow_redirects' => true,
    513                         'blocking'         => true,
    514                         'type'             => self::GET,
    515                         'filename'         => false,
    516                         'auth'             => false,
    517                         'proxy'            => false,
    518                         'cookies'          => false,
    519                         'max_bytes'        => false,
    520                         'idn'              => true,
    521                         'hooks'            => null,
    522                         'transport'        => null,
    523                         'verify'           => self::get_certificate_path(),
    524                         'verifyname'       => true,
    525                 );
    526                 if ($multirequest !== false) {
    527                         $defaults['complete'] = null;
    528                 }
    529                 return $defaults;
    530         }
    531 
    532         /**
    533          * Get default certificate path.
    534          *
    535          * @return string Default certificate path.
    536          */
    537         public static function get_certificate_path() {
    538                 if (!empty(self::$certificate_path)) {
    539                         return self::$certificate_path;
    540                 }
    541 
    542                 return dirname(__FILE__) . '/Requests/Transport/cacert.pem';
    543         }
    544 
    545         /**
    546          * Set default certificate path.
    547          *
    548          * @param string $path Certificate path, pointing to a PEM file.
    549          */
    550         public static function set_certificate_path($path) {
    551                 self::$certificate_path = $path;
    552         }
    553 
    554         /**
    555          * Set the default values
    556          *
    557          * @param string $url URL to request
    558          * @param array $headers Extra headers to send with the request
    559          * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
    560          * @param string $type HTTP request type
    561          * @param array $options Options for the request
    562          * @return array $options
    563          */
    564         protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) {
    565                 if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) {
    566                         throw new Requests_Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url);
    567                 }
    568 
    569                 if (empty($options['hooks'])) {
    570                         $options['hooks'] = new Requests_Hooks();
    571                 }
    572 
    573                 if (is_array($options['auth'])) {
    574                         $options['auth'] = new Requests_Auth_Basic($options['auth']);
    575                 }
    576                 if ($options['auth'] !== false) {
    577                         $options['auth']->register($options['hooks']);
    578                 }
    579 
    580                 if (is_string($options['proxy']) || is_array($options['proxy'])) {
    581                         $options['proxy'] = new Requests_Proxy_HTTP($options['proxy']);
    582                 }
    583                 if ($options['proxy'] !== false) {
    584                         $options['proxy']->register($options['hooks']);
    585                 }
    586 
    587                 if (is_array($options['cookies'])) {
    588                         $options['cookies'] = new Requests_Cookie_Jar($options['cookies']);
    589                 }
    590                 elseif (empty($options['cookies'])) {
    591                         $options['cookies'] = new Requests_Cookie_Jar();
    592                 }
    593                 if ($options['cookies'] !== false) {
    594                         $options['cookies']->register($options['hooks']);
    595                 }
    596 
    597                 if ($options['idn'] !== false) {
    598                         $iri       = new Requests_IRI($url);
    599                         $iri->host = Requests_IDNAEncoder::encode($iri->ihost);
    600                         $url       = $iri->uri;
    601                 }
    602 
    603                 // Massage the type to ensure we support it.
    604                 $type = strtoupper($type);
    605 
    606                 if (!isset($options['data_format'])) {
    607                         if (in_array($type, array(self::HEAD, self::GET, self::DELETE), true)) {
    608                                 $options['data_format'] = 'query';
    609                         }
    610                         else {
    611                                 $options['data_format'] = 'body';
    612                         }
    613                 }
    614         }
    615 
    616         /**
    617          * HTTP response parser
    618          *
    619          * @throws Requests_Exception On missing head/body separator (`requests.no_crlf_separator`)
    620          * @throws Requests_Exception On missing head/body separator (`noversion`)
    621          * @throws Requests_Exception On missing head/body separator (`toomanyredirects`)
    622          *
    623          * @param string $headers Full response text including headers and body
    624          * @param string $url Original request URL
    625          * @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects
    626          * @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects
    627          * @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects
    628          * @return Requests_Response
    629          */
    630         protected static function parse_response($headers, $url, $req_headers, $req_data, $options) {
    631                 $return = new Requests_Response();
    632                 if (!$options['blocking']) {
    633                         return $return;
    634                 }
    635 
    636                 $return->raw  = $headers;
    637                 $return->url  = (string) $url;
    638                 $return->body = '';
    639 
    640                 if (!$options['filename']) {
    641                         $pos = strpos($headers, "\r\n\r\n");
    642                         if ($pos === false) {
    643                                 // Crap!
    644                                 throw new Requests_Exception('Missing header/body separator', 'requests.no_crlf_separator');
    645                         }
    646 
    647                         $headers = substr($return->raw, 0, $pos);
    648                         // Headers will always be separated from the body by two new lines - `\n\r\n\r`.
    649                         $body = substr($return->raw, $pos + 4);
    650                         if (!empty($body)) {
    651                                 $return->body = $body;
    652                         }
    653                 }
    654                 // Pretend CRLF = LF for compatibility (RFC 2616, section 19.3)
    655                 $headers = str_replace("\r\n", "\n", $headers);
    656                 // Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2)
    657                 $headers = preg_replace('/\n[ \t]/', ' ', $headers);
    658                 $headers = explode("\n", $headers);
    659                 preg_match('#^HTTP/(1\.\d)[ \t]+(\d+)#i', array_shift($headers), $matches);
    660                 if (empty($matches)) {
    661                         throw new Requests_Exception('Response could not be parsed', 'noversion', $headers);
    662                 }
    663                 $return->protocol_version = (float) $matches[1];
    664                 $return->status_code      = (int) $matches[2];
    665                 if ($return->status_code >= 200 && $return->status_code < 300) {
    666                         $return->success = true;
    667                 }
    668 
    669                 foreach ($headers as $header) {
    670                         list($key, $value) = explode(':', $header, 2);
    671                         $value             = trim($value);
    672                         preg_replace('#(\s+)#i', ' ', $value);
    673                         $return->headers[$key] = $value;
    674                 }
    675                 if (isset($return->headers['transfer-encoding'])) {
    676                         $return->body = self::decode_chunked($return->body);
    677                         unset($return->headers['transfer-encoding']);
    678                 }
    679                 if (isset($return->headers['content-encoding'])) {
    680                         $return->body = self::decompress($return->body);
    681                 }
    682 
    683                 //fsockopen and cURL compatibility
    684                 if (isset($return->headers['connection'])) {
    685                         unset($return->headers['connection']);
    686                 }
    687 
    688                 $options['hooks']->dispatch('requests.before_redirect_check', array(&$return, $req_headers, $req_data, $options));
    689 
    690                 if ($return->is_redirect() && $options['follow_redirects'] === true) {
    691                         if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) {
    692                                 if ($return->status_code === 303) {
    693                                         $options['type'] = self::GET;
    694                                 }
    695                                 $options['redirected']++;
    696                                 $location = $return->headers['location'];
    697                                 if (strpos($location, 'http://') !== 0 && strpos($location, 'https://') !== 0) {
    698                                         // relative redirect, for compatibility make it absolute
    699                                         $location = Requests_IRI::absolutize($url, $location);
    700                                         $location = $location->uri;
    701                                 }
    702 
    703                                 $hook_args = array(
    704                                         &$location,
    705                                         &$req_headers,
    706                                         &$req_data,
    707                                         &$options,
    708                                         $return,
    709                                 );
    710                                 $options['hooks']->dispatch('requests.before_redirect', $hook_args);
    711                                 $redirected            = self::request($location, $req_headers, $req_data, $options['type'], $options);
    712                                 $redirected->history[] = $return;
    713                                 return $redirected;
    714                         }
    715                         elseif ($options['redirected'] >= $options['redirects']) {
    716                                 throw new Requests_Exception('Too many redirects', 'toomanyredirects', $return);
    717                         }
    718                 }
    719 
    720                 $return->redirects = $options['redirected'];
    721 
    722                 $options['hooks']->dispatch('requests.after_request', array(&$return, $req_headers, $req_data, $options));
    723                 return $return;
    724         }
    725 
    726         /**
    727          * Callback for `transport.internal.parse_response`
    728          *
    729          * Internal use only. Converts a raw HTTP response to a Requests_Response
    730          * while still executing a multiple request.
    731          *
    732          * @param string $response Full response text including headers and body (will be overwritten with Response instance)
    733          * @param array $request Request data as passed into {@see Requests::request_multiple()}
    734          * @return null `$response` is either set to a Requests_Response instance, or a Requests_Exception object
    735          */
    736         public static function parse_multiple(&$response, $request) {
    737                 try {
    738                         $url      = $request['url'];
    739                         $headers  = $request['headers'];
    740                         $data     = $request['data'];
    741                         $options  = $request['options'];
    742                         $response = self::parse_response($response, $url, $headers, $data, $options);
    743                 }
    744                 catch (Requests_Exception $e) {
    745                         $response = $e;
    746                 }
    747         }
    748 
    749         /**
    750          * Decoded a chunked body as per RFC 2616
    751          *
    752          * @see https://tools.ietf.org/html/rfc2616#section-3.6.1
    753          * @param string $data Chunked body
    754          * @return string Decoded body
    755          */
    756         protected static function decode_chunked($data) {
    757                 if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) {
    758                         return $data;
    759                 }
    760 
    761                 $decoded = '';
    762                 $encoded = $data;
    763 
    764                 while (true) {
    765                         $is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches);
    766                         if (!$is_chunked) {
    767                                 // Looks like it's not chunked after all
    768                                 return $data;
    769                         }
    770 
    771                         $length = hexdec(trim($matches[1]));
    772                         if ($length === 0) {
    773                                 // Ignore trailer headers
    774                                 return $decoded;
    775                         }
    776 
    777                         $chunk_length = strlen($matches[0]);
    778                         $decoded     .= substr($encoded, $chunk_length, $length);
    779                         $encoded      = substr($encoded, $chunk_length + $length + 2);
    780 
    781                         if (trim($encoded) === '0' || empty($encoded)) {
    782                                 return $decoded;
    783                         }
    784                 }
    785 
    786                 // We'll never actually get down here
    787                 // @codeCoverageIgnoreStart
    788         }
    789         // @codeCoverageIgnoreEnd
    790 
    791         /**
    792          * Convert a key => value array to a 'key: value' array for headers
    793          *
    794          * @param array $array Dictionary of header values
    795          * @return array List of headers
    796          */
    797         public static function flatten($array) {
    798                 $return = array();
    799                 foreach ($array as $key => $value) {
    800                         $return[] = sprintf('%s: %s', $key, $value);
    801                 }
    802                 return $return;
    803         }
    804 
    805         /**
    806          * Convert a key => value array to a 'key: value' array for headers
    807          *
    808          * @codeCoverageIgnore
    809          * @deprecated Misspelling of {@see Requests::flatten}
    810          * @param array $array Dictionary of header values
    811          * @return array List of headers
    812          */
    813         public static function flattern($array) {
    814                 return self::flatten($array);
    815         }
    816 
    817         /**
    818          * Decompress an encoded body
    819          *
    820          * Implements gzip, compress and deflate. Guesses which it is by attempting
    821          * to decode.
    822          *
    823          * @param string $data Compressed data in one of the above formats
    824          * @return string Decompressed string
    825          */
    826         public static function decompress($data) {
    827                 if (substr($data, 0, 2) !== "\x1f\x8b" && substr($data, 0, 2) !== "\x78\x9c") {
    828                         // Not actually compressed. Probably cURL ruining this for us.
    829                         return $data;
    830                 }
    831 
    832                 if (function_exists('gzdecode')) {
    833                         // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.gzdecodeFound -- Wrapped in function_exists() for PHP 5.2.
    834                         $decoded = @gzdecode($data);
    835                         if ($decoded !== false) {
    836                                 return $decoded;
    837                         }
    838                 }
    839 
    840                 if (function_exists('gzinflate')) {
    841                         $decoded = @gzinflate($data);
    842                         if ($decoded !== false) {
    843                                 return $decoded;
    844                         }
    845                 }
    846 
    847                 $decoded = self::compatible_gzinflate($data);
    848                 if ($decoded !== false) {
    849                         return $decoded;
    850                 }
    851 
    852                 if (function_exists('gzuncompress')) {
    853                         $decoded = @gzuncompress($data);
    854                         if ($decoded !== false) {
    855                                 return $decoded;
    856                         }
    857                 }
    858 
    859                 return $data;
    860         }
    861 
    862         /**
    863          * Decompression of deflated string while staying compatible with the majority of servers.
    864          *
    865          * Certain Servers will return deflated data with headers which PHP's gzinflate()
    866          * function cannot handle out of the box. The following function has been created from
    867          * various snippets on the gzinflate() PHP documentation.
    868          *
    869          * Warning: Magic numbers within. Due to the potential different formats that the compressed
    870          * data may be returned in, some "magic offsets" are needed to ensure proper decompression
    871          * takes place. For a simple progmatic way to determine the magic offset in use, see:
    872          * https://core.trac.wordpress.org/ticket/18273
    873          *
    874          * @since 2.8.1
    875          * @link https://core.trac.wordpress.org/ticket/18273
    876          * @link https://secure.php.net/manual/en/function.gzinflate.php#70875
    877          * @link https://secure.php.net/manual/en/function.gzinflate.php#77336
    878          *
    879          * @param string $gz_data String to decompress.
    880          * @return string|bool False on failure.
    881          */
    882         public static function compatible_gzinflate($gz_data) {
    883                 // Compressed data might contain a full zlib header, if so strip it for
    884                 // gzinflate()
    885                 if (substr($gz_data, 0, 3) === "\x1f\x8b\x08") {
    886                         $i   = 10;
    887                         $flg = ord(substr($gz_data, 3, 1));
    888                         if ($flg > 0) {
    889                                 if ($flg & 4) {
    890                                         list($xlen) = unpack('v', substr($gz_data, $i, 2));
    891                                         $i         += 2 + $xlen;
    892                                 }
    893                                 if ($flg & 8) {
    894                                         $i = strpos($gz_data, "\0", $i) + 1;
    895                                 }
    896                                 if ($flg & 16) {
    897                                         $i = strpos($gz_data, "\0", $i) + 1;
    898                                 }
    899                                 if ($flg & 2) {
    900                                         $i += 2;
    901                                 }
    902                         }
    903                         $decompressed = self::compatible_gzinflate(substr($gz_data, $i));
    904                         if ($decompressed !== false) {
    905                                 return $decompressed;
    906                         }
    907                 }
    908 
    909                 // If the data is Huffman Encoded, we must first strip the leading 2
    910                 // byte Huffman marker for gzinflate()
    911                 // The response is Huffman coded by many compressors such as
    912                 // java.util.zip.Deflater, Ruby’s Zlib::Deflate, and .NET's
    913                 // System.IO.Compression.DeflateStream.
    914                 //
    915                 // See https://decompres.blogspot.com/ for a quick explanation of this
    916                 // data type
    917                 $huffman_encoded = false;
    918 
    919                 // low nibble of first byte should be 0x08
    920                 list(, $first_nibble) = unpack('h', $gz_data);
    921 
    922                 // First 2 bytes should be divisible by 0x1F
    923                 list(, $first_two_bytes) = unpack('n', $gz_data);
    924 
    925                 if ($first_nibble === 0x08 && ($first_two_bytes % 0x1F) === 0) {
    926                         $huffman_encoded = true;
    927                 }
    928 
    929                 if ($huffman_encoded) {
    930                         $decompressed = @gzinflate(substr($gz_data, 2));
    931                         if ($decompressed !== false) {
    932                                 return $decompressed;
    933                         }
    934                 }
    935 
    936                 if (substr($gz_data, 0, 4) === "\x50\x4b\x03\x04") {
    937                         // ZIP file format header
    938                         // Offset 6: 2 bytes, General-purpose field
    939                         // Offset 26: 2 bytes, filename length
    940                         // Offset 28: 2 bytes, optional field length
    941                         // Offset 30: Filename field, followed by optional field, followed
    942                         // immediately by data
    943                         list(, $general_purpose_flag) = unpack('v', substr($gz_data, 6, 2));
    944 
    945                         // If the file has been compressed on the fly, 0x08 bit is set of
    946                         // the general purpose field. We can use this to differentiate
    947                         // between a compressed document, and a ZIP file
    948                         $zip_compressed_on_the_fly = ((0x08 & $general_purpose_flag) === 0x08);
    949 
    950                         if (!$zip_compressed_on_the_fly) {
    951                                 // Don't attempt to decode a compressed zip file
    952                                 return $gz_data;
    953                         }
    954 
    955                         // Determine the first byte of data, based on the above ZIP header
    956                         // offsets:
    957                         $first_file_start = array_sum(unpack('v2', substr($gz_data, 26, 4)));
    958                         $decompressed     = @gzinflate(substr($gz_data, 30 + $first_file_start));
    959                         if ($decompressed !== false) {
    960                                 return $decompressed;
    961                         }
    962                         return false;
    963                 }
    964 
    965                 // Finally fall back to straight gzinflate
    966                 $decompressed = @gzinflate($gz_data);
    967                 if ($decompressed !== false) {
    968                         return $decompressed;
    969                 }
    970 
    971                 // Fallback for all above failing, not expected, but included for
    972                 // debugging and preventing regressions and to track stats
    973                 $decompressed = @gzinflate(substr($gz_data, 2));
    974                 if ($decompressed !== false) {
    975                         return $decompressed;
    976                 }
    977 
    978                 return false;
    979         }
    980 
    981         public static function match_domain($host, $reference) {
    982                 // Check for a direct match
    983                 if ($host === $reference) {
    984                         return true;
    985                 }
    986 
    987                 // Calculate the valid wildcard match if the host is not an IP address
    988                 // Also validates that the host has 3 parts or more, as per Firefox's
    989                 // ruleset.
    990                 $parts = explode('.', $host);
    991                 if (ip2long($host) === false && count($parts) >= 3) {
    992                         $parts[0] = '*';
    993                         $wildcard = implode('.', $parts);
    994                         if ($wildcard === $reference) {
    995                                 return true;
    996                         }
    997                 }
    998 
    999                 return false;
     75                require_once __DIR__ . '/Requests/src/Autoload.php';
     76                WpOrg\Requests\Autoload::register();
    100077        }
    100178}
  • trunk/src/wp-includes/class-wp-http-requests-hooks.php

    r54133 r54997  
    1313 * @since 4.7.0
    1414 *
    15  * @see Requests_Hooks
     15 * @see WpOrg\Requests\Hooks
    1616 */
    1717#[AllowDynamicProperties]
    18 class WP_HTTP_Requests_Hooks extends Requests_Hooks {
     18class WP_HTTP_Requests_Hooks extends WpOrg\Requests\Hooks {
    1919        /**
    2020         * Requested URL.
  • trunk/src/wp-includes/class-wp-http-requests-response.php

    r52328 r54997  
    99
    1010/**
    11  * Core wrapper object for a Requests_Response for standardisation.
     11 * Core wrapper object for a WpOrg\Requests\Response for standardisation.
    1212 *
    1313 * @since 4.6.0
     
    2020         *
    2121         * @since 4.6.0
    22          * @var Requests_Response
     22         * @var \WpOrg\Requests\Response
    2323         */
    2424        protected $response;
     
    3737         * @since 4.6.0
    3838         *
    39          * @param Requests_Response $response HTTP response.
    40          * @param string            $filename Optional. File name. Default empty.
     39         * @param \WpOrg\Requests\Response $response HTTP response.
     40         * @param string                   $filename Optional. File name. Default empty.
    4141         */
    42         public function __construct( Requests_Response $response, $filename = '' ) {
     42        public function __construct( WpOrg\Requests\Response $response, $filename = '' ) {
    4343                $this->response = $response;
    4444                $this->filename = $filename;
     
    5050         * @since 4.6.0
    5151         *
    52          * @return Requests_Response HTTP response.
     52         * @return WpOrg\Requests\Response HTTP response.
    5353         */
    5454        public function get_response_object() {
     
    6161         * @since 4.6.0
    6262         *
    63          * @return \Requests_Utility_CaseInsensitiveDictionary Map of header name to header value.
     63         * @return \WpOrg\Requests\Utility\CaseInsensitiveDictionary Map of header name to header value.
    6464         */
    6565        public function get_headers() {
    6666                // Ensure headers remain case-insensitive.
    67                 $converted = new Requests_Utility_CaseInsensitiveDictionary();
     67                $converted = new WpOrg\Requests\Utility\CaseInsensitiveDictionary();
    6868
    6969                foreach ( $this->response->headers->getAll() as $key => $value ) {
     
    8686         */
    8787        public function set_headers( $headers ) {
    88                 $this->response->headers = new Requests_Response_Headers( $headers );
     88                $this->response->headers = new WpOrg\Requests\Response\Headers( $headers );
    8989        }
    9090
  • trunk/src/wp-includes/class-wp-http.php

    r54891 r54997  
    88 */
    99
    10 if ( ! class_exists( 'Requests' ) ) {
    11         require ABSPATH . WPINC . '/class-requests.php';
    12 
    13         Requests::register_autoloader();
    14         Requests::set_certificate_path( ABSPATH . WPINC . '/certificates/ca-bundle.crt' );
     10if ( ! class_exists( 'WpOrg\Requests\Autoload' ) ) {
     11        require ABSPATH . WPINC . '/Requests/src/Autoload.php';
     12
     13        WpOrg\Requests\Autoload::register();
     14        WpOrg\Requests\Requests::set_certificate_path( ABSPATH . WPINC . '/certificates/ca-bundle.crt' );
    1515}
    1616
     
    276276                        $response = new WP_Error( 'http_request_failed', __( 'A valid URL was not provided.' ) );
    277277                        /** This action is documented in wp-includes/class-wp-http.php */
    278                         do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
     278                        do_action( 'http_api_debug', $response, 'response', 'WpOrg\Requests\Requests', $parsed_args, $url );
    279279                        return $response;
    280280                }
     
    283283                        $response = new WP_Error( 'http_request_not_executed', __( 'User has blocked requests through HTTP.' ) );
    284284                        /** This action is documented in wp-includes/class-wp-http.php */
    285                         do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
     285                        do_action( 'http_api_debug', $response, 'response', 'WpOrg\Requests\Requests', $parsed_args, $url );
    286286                        return $response;
    287287                }
     
    300300                                $response = new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) );
    301301                                /** This action is documented in wp-includes/class-wp-http.php */
    302                                 do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
     302                                do_action( 'http_api_debug', $response, 'response', 'WpOrg\Requests\Requests', $parsed_args, $url );
    303303                                return $response;
    304304                        }
     
    348348                }
    349349
    350                 // If we've got cookies, use and convert them to Requests_Cookie.
     350                // If we've got cookies, use and convert them to WpOrg\Requests\Cookie.
    351351                if ( ! empty( $parsed_args['cookies'] ) ) {
    352352                        $options['cookies'] = WP_Http::normalize_cookies( $parsed_args['cookies'] );
     
    380380                $proxy = new WP_HTTP_Proxy();
    381381                if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
    382                         $options['proxy'] = new Requests_Proxy_HTTP( $proxy->host() . ':' . $proxy->port() );
     382                        $options['proxy'] = new WpOrg\Requests\Proxy\HTTP( $proxy->host() . ':' . $proxy->port() );
    383383
    384384                        if ( $proxy->use_authentication() ) {
     
    393393
    394394                try {
    395                         $requests_response = Requests::request( $url, $headers, $data, $type, $options );
     395                        $requests_response = WpOrg\Requests\Requests::request( $url, $headers, $data, $type, $options );
    396396
    397397                        // Convert the response into an array.
     
    401401                        // Add the original object to the array.
    402402                        $response['http_response'] = $http_response;
    403                 } catch ( Requests_Exception $e ) {
     403                } catch ( WpOrg\Requests\Exception $e ) {
    404404                        $response = new WP_Error( 'http_request_failed', $e->getMessage() );
    405405                }
     
    418418                 * @param string         $url         The request URL.
    419419                 */
    420                 do_action( 'http_api_debug', $response, 'response', 'Requests', $parsed_args, $url );
     420                do_action( 'http_api_debug', $response, 'response', 'WpOrg\Requests\Requests', $parsed_args, $url );
    421421                if ( is_wp_error( $response ) ) {
    422422                        return $response;
     
    454454         *
    455455         * @param array $cookies Array of cookies to send with the request.
    456          * @return Requests_Cookie_Jar Cookie holder object.
     456         * @return WpOrg\Requests\Cookie\Jar Cookie holder object.
    457457         */
    458458        public static function normalize_cookies( $cookies ) {
    459                 $cookie_jar = new Requests_Cookie_Jar();
     459                $cookie_jar = new WpOrg\Requests\Cookie\Jar();
    460460
    461461                foreach ( $cookies as $name => $value ) {
     
    467467                                        }
    468468                                );
    469                                 $cookie_jar[ $value->name ] = new Requests_Cookie( $value->name, $value->value, $attributes, array( 'host-only' => $value->host_only ) );
     469                                $cookie_jar[ $value->name ] = new WpOrg\Requests\Cookie( $value->name, $value->value, $attributes, array( 'host-only' => $value->host_only ) );
    470470                        } elseif ( is_scalar( $value ) ) {
    471                                 $cookie_jar[ $name ] = new Requests_Cookie( $name, $value );
     471                                $cookie_jar[ $name ] = new WpOrg\Requests\Cookie( $name, (string) $value );
    472472                        }
    473473                }
     
    485485         * @since 4.6.0
    486486         *
    487          * @param string            $location URL to redirect to.
    488          * @param array             $headers  Headers for the redirect.
    489          * @param string|array      $data     Body to send with the request.
    490          * @param array             $options  Redirect request options.
    491          * @param Requests_Response $original Response object.
     487         * @param string                  $location URL to redirect to.
     488         * @param array                   $headers  Headers for the redirect.
     489         * @param string|array            $data     Body to send with the request.
     490         * @param array                   $options  Redirect request options.
     491         * @param WpOrg\Requests\Response $original Response object.
    492492         */
    493493        public static function browser_redirect_compatibility( $location, $headers, $data, &$options, $original ) {
    494494                // Browser compatibility.
    495495                if ( 302 === $original->status_code ) {
    496                         $options['type'] = Requests::GET;
     496                        $options['type'] = WpOrg\Requests\Requests::GET;
    497497                }
    498498        }
     
    503503         * @since 4.7.5
    504504         *
    505          * @throws Requests_Exception On unsuccessful URL validation.
     505         * @throws WpOrg\Requests\Exception On unsuccessful URL validation.
    506506         * @param string $location URL to redirect to.
    507507         */
    508508        public static function validate_redirects( $location ) {
    509509                if ( ! wp_http_validate_url( $location ) ) {
    510                         throw new Requests_Exception( __( 'A valid URL was not provided.' ), 'wp_http.redirect_failed_validation' );
     510                        throw new WpOrg\Requests\Exception( __( 'A valid URL was not provided.' ), 'wp_http.redirect_failed_validation' );
    511511                }
    512512        }
  • trunk/src/wp-includes/deprecated.php

    r54878 r54997  
    36553655 * @param int         $red       Optional. The number of Redirects followed, Upon 5 being hit,
    36563656 *                               returns false. Default 1.
    3657  * @return \Requests_Utility_CaseInsensitiveDictionary|false Headers on success, false on failure.
     3657 * @return \WpOrg\Requests\Utility\CaseInsensitiveDictionary|false Headers on success, false on failure.
    36583658 */
    36593659function wp_get_http( $url, $file_path = false, $red = 1 ) {
  • trunk/src/wp-includes/functions.php

    r54929 r54997  
    977977 * @param string $url        URL to retrieve HTTP headers from.
    978978 * @param bool   $deprecated Not Used.
    979  * @return \Requests_Utility_CaseInsensitiveDictionary|false Headers on success, false on failure.
     979 * @return \WpOrg\Requests\Utility\CaseInsensitiveDictionary|false Headers on success, false on failure.
    980980 */
    981981function wp_get_http_headers( $url, $deprecated = false ) {
  • trunk/src/wp-includes/http.php

    r54157 r54997  
    201201 *
    202202 * @since 2.7.0
    203  * @since 4.6.0 Return value changed from an array to an Requests_Utility_CaseInsensitiveDictionary instance.
    204  *
    205  * @see \Requests_Utility_CaseInsensitiveDictionary
     203 * @since 4.6.0 Return value changed from an array to an WpOrg\Requests\Utility\CaseInsensitiveDictionary instance.
     204 *
     205 * @see \WpOrg\Requests\Utility\CaseInsensitiveDictionary
    206206 *
    207207 * @param array|WP_Error $response HTTP response.
    208  * @return \Requests_Utility_CaseInsensitiveDictionary|array The headers of the response, or empty array
    209  *                                                           if incorrect parameter given.
     208 * @return \WpOrg\Requests\Utility\CaseInsensitiveDictionary|array The headers of the response, or empty array
     209 *                                                                 if incorrect parameter given.
    210210 */
    211211function wp_remote_retrieve_headers( $response ) {
  • trunk/src/wp-includes/rest-api.php

    r54964 r54997  
    14151415        $ipv4_pattern = '/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/';
    14161416
    1417         if ( ! preg_match( $ipv4_pattern, $ip ) && ! Requests_IPv6::check_ipv6( $ip ) ) {
     1417        if ( ! preg_match( $ipv4_pattern, $ip ) && ! WpOrg\Requests\Ipv6::check_ipv6( $ip ) ) {
    14181418                return false;
    14191419        }
  • trunk/tests/phpunit/tests/feed/wpSimplePieFile.php

    r54872 r54997  
    8686
    8787                return array(
    88                         'headers'  => new Requests_Utility_CaseInsensitiveDictionary( $single_value_headers ),
     88                        'headers'  => new WpOrg\Requests\Utility\CaseInsensitiveDictionary( $single_value_headers ),
    8989                        'body'     => file_get_contents( DIR_TESTDATA . '/feed/wordpress-org-news.xml' ),
    9090                        'response' => array(
     
    115115                );
    116116
    117                 $response['headers'] = new Requests_Utility_CaseInsensitiveDictionary( $multiple_value_headers );
     117                $response['headers'] = new WpOrg\Requests\Utility\CaseInsensitiveDictionary( $multiple_value_headers );
    118118
    119119                return $response;
  • trunk/tests/phpunit/tests/functions/maybeSerialize.php

    r53890 r54997  
    214214                $serialized = maybe_serialize( $value );
    215215
    216                 if ( get_class( $value ) === 'Requests_Utility_FilteredIterator' ) {
     216                if ( get_class( $value ) === 'WpOrg\Requests\Utility\FilteredIterator' ) {
    217217                        $new_value = unserialize( $serialized );
    218                         $property  = ( new ReflectionClass( 'Requests_Utility_FilteredIterator' ) )->getProperty( 'callback' );
     218                        $property  = ( new ReflectionClass( 'WpOrg\Requests\Utility\FilteredIterator' ) )->getProperty( 'callback' );
    219219                        $property->setAccessible( true );
    220220                        $callback_value = $property->getValue( $new_value );
     
    234234                return array(
    235235                        'filtered iterator using md5'  => array(
    236                                 new Requests_Utility_FilteredIterator( array( 1 ), 'md5' ),
     236                                new WpOrg\Requests\Utility\FilteredIterator( array( 1 ), 'md5' ),
    237237                        ),
    238238                        'filtered iterator using sha1' => array(
    239                                 new Requests_Utility_FilteredIterator( array( 1, 2 ), 'sha1' ),
     239                                new WpOrg\Requests\Utility\FilteredIterator( array( 1, 2 ), 'sha1' ),
    240240                        ),
    241241                        'array iterator'               => array(
  • trunk/tests/phpunit/tests/http/functions.php

    r53491 r54997  
    217217        public function test_get_cookie_host_only() {
    218218                // Emulate WP_Http::request() internals.
    219                 $requests_response = new Requests_Response();
    220 
    221                 $requests_response->cookies['test'] = Requests_Cookie::parse( 'test=foo; domain=.wordpress.org' );
     219                $requests_response = new WpOrg\Requests\Response();
     220
     221                $requests_response->cookies['test'] = WpOrg\Requests\Cookie::parse( 'test=foo; domain=.wordpress.org' );
    222222
    223223                $requests_response->cookies['test']->flags['host-only'] = false; // https://github.com/WordPress/Requests/issues/306
     
    232232                $this->assertFalse( $cookie->host_only, 'host-only flag not set' );
    233233
    234                 // Regurgitate (Requests_Cookie -> WP_Http_Cookie -> Requests_Cookie).
     234                // Regurgitate (WpOrg\Requests\Cookie -> WP_Http_Cookie -> WpOrg\Requests\Cookie).
    235235                $cookies = WP_Http::normalize_cookies( wp_remote_retrieve_cookies( $response ) );
    236236                $this->assertFalse( $cookies['test']->flags['host-only'], 'host-only flag data lost' );
  • trunk/tests/phpunit/tests/http/http.php

    r54968 r54997  
    310310                );
    311311
    312                 $this->assertInstanceOf( 'Requests_Cookie_Jar', $cookie_jar );
     312                $this->assertInstanceOf( 'WpOrg\Requests\Cookie\Jar', $cookie_jar );
    313313
    314314                foreach ( array_keys( $cookies ) as $cookie ) {
     
    316316                                $this->assertArrayNotHasKey( $cookie, $cookie_jar );
    317317                        } else {
    318                                 $this->assertInstanceOf( 'Requests_Cookie', $cookie_jar[ $cookie ] );
     318                                $this->assertInstanceOf( 'WpOrg\Requests\Cookie', $cookie_jar[ $cookie ] );
    319319                        }
    320320                }
  • trunk/tests/phpunit/tests/rest-api/rest-widgets-controller.php

    r54896 r54997  
    418418
    419419                return array(
    420                         'headers'  => new Requests_Utility_CaseInsensitiveDictionary( $single_value_headers ),
     420                        'headers'  => new WpOrg\Requests\Utility\CaseInsensitiveDictionary( $single_value_headers ),
    421421                        'body'     => file_get_contents( DIR_TESTDATA . '/feed/wordpress-org-news.xml' ),
    422422                        'response' => array(
  • trunk/tests/phpunit/tests/widgets/wpWidgetRss.php

    r52328 r54997  
    107107
    108108                return array(
    109                         'headers'  => new Requests_Utility_CaseInsensitiveDictionary( $single_value_headers ),
     109                        'headers'  => new WpOrg\Requests\Utility\CaseInsensitiveDictionary( $single_value_headers ),
    110110                        'body'     => file_get_contents( DIR_TESTDATA . '/feed/wordpress-org-news.xml' ),
    111111                        'response' => array(
Note: See TracChangeset for help on using the changeset viewer.