WordPress.org

Make WordPress Core

Changeset 52244


Ignore:
Timestamp:
11/25/2021 01:10:30 AM (2 weeks ago)
Author:
SergeyBiryukov
Message:

External Libraries: Update the 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

Follow-up to [50842], [51078].

Props jrf, schlessera, datagutten, wojsmol, dd32, dustinrue, soulseekah, costdev, szepeviktor.
Fixes #54504.

Location:
trunk
Files:
7 added
33 deleted
26 edited
34 copied
11 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/Requests/Auth.php

    r50842 r52244  
    33 * Authentication provider interface
    44 *
    5  * @package Requests
    6  * @subpackage Authentication
     5 * @package Requests\Authentication
    76 */
     7
     8namespace WpOrg\Requests;
     9
     10use WpOrg\Requests\Hooks;
    811
    912/**
     
    1518 * makes it much easier for users to use your provider.
    1619 *
    17  * @see Requests_Hooks
    18  * @package Requests
    19  * @subpackage Authentication
     20 * @see \WpOrg\Requests\Hooks
     21 *
     22 * @package Requests\Authentication
    2023 */
    21 interface Requests_Auth {
     24interface Auth {
    2225    /**
    2326     * Register hooks as needed
    2427     *
    25      * This method is called in {@see Requests::request} when the user has set
    26      * an instance as the 'auth' option. Use this callback to register all the
     28     * This method is called in {@see \WpOrg\Requests\Requests::request()} when the user
     29     * has set an instance as the 'auth' option. Use this callback to register all the
    2730     * hooks you'll need.
    2831     *
    29      * @see Requests_Hooks::register
    30      * @param Requests_Hooks $hooks Hook system
     32     * @see \WpOrg\Requests\Hooks::register()
     33     * @param \WpOrg\Requests\Hooks $hooks Hook system
    3134     */
    32     public function register(Requests_Hooks $hooks);
     35    public function register(Hooks $hooks);
    3336}
  • trunk/src/wp-includes/Requests/Auth/Basic.php

    r50842 r52244  
    33 * Basic Authentication provider
    44 *
    5  * @package Requests
    6  * @subpackage Authentication
     5 * @package Requests\Authentication
    76 */
     7
     8namespace WpOrg\Requests\Auth;
     9
     10use WpOrg\Requests\Auth;
     11use WpOrg\Requests\Exception\ArgumentCount;
     12use WpOrg\Requests\Exception\InvalidArgument;
     13use WpOrg\Requests\Hooks;
    814
    915/**
     
    1319 * header.
    1420 *
    15  * @package Requests
    16  * @subpackage Authentication
     21 * @package Requests\Authentication
    1722 */
    18 class Requests_Auth_Basic implements Requests_Auth {
     23class Basic implements Auth {
    1924    /**
    2025     * Username
     
    3439     * Constructor
    3540     *
    36      * @throws Requests_Exception On incorrect number of arguments (`authbasicbadargs`)
     41     * @since 2.0 Throws an `InvalidArgument` exception.
     42     * @since 2.0 Throws an `ArgumentCount` exception instead of the Requests base `Exception.
     43     *
    3744     * @param array|null $args Array of user and password. Must have exactly two elements
     45     *
     46     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not an array or null.
     47     * @throws \WpOrg\Requests\Exception\ArgumentCount   On incorrect number of array elements (`authbasicbadargs`).
    3848     */
    3949    public function __construct($args = null) {
    4050        if (is_array($args)) {
    4151            if (count($args) !== 2) {
    42                 throw new Requests_Exception('Invalid number of arguments', 'authbasicbadargs');
     52                throw ArgumentCount::create('an array with exactly two elements', count($args), 'authbasicbadargs');
    4353            }
    4454
    4555            list($this->user, $this->pass) = $args;
     56            return;
     57        }
     58
     59        if ($args !== null) {
     60            throw InvalidArgument::create(1, '$args', 'array|null', gettype($args));
    4661        }
    4762    }
     
    5065     * Register the necessary callbacks
    5166     *
    52      * @see curl_before_send
    53      * @see fsockopen_header
    54      * @param Requests_Hooks $hooks Hook system
     67     * @see \WpOrg\Requests\Auth\Basic::curl_before_send()
     68     * @see \WpOrg\Requests\Auth\Basic::fsockopen_header()
     69     * @param \WpOrg\Requests\Hooks $hooks Hook system
    5570     */
    56     public function register(Requests_Hooks $hooks) {
    57         $hooks->register('curl.before_send', array($this, 'curl_before_send'));
    58         $hooks->register('fsockopen.after_headers', array($this, 'fsockopen_header'));
     71    public function register(Hooks $hooks) {
     72        $hooks->register('curl.before_send', [$this, 'curl_before_send']);
     73        $hooks->register('fsockopen.after_headers', [$this, 'fsockopen_header']);
    5974    }
    6075
     
    6277     * Set cURL parameters before the data is sent
    6378     *
    64      * @param resource $handle cURL resource
     79     * @param resource|\CurlHandle $handle cURL handle
    6580     */
    6681    public function curl_before_send(&$handle) {
  • trunk/src/wp-includes/Requests/Cookie.php

    r50842 r52244  
    33 * Cookie storage object
    44 *
    5  * @package Requests
    6  * @subpackage Cookies
     5 * @package Requests\Cookies
    76 */
     7
     8namespace WpOrg\Requests;
     9
     10use WpOrg\Requests\Exception\InvalidArgument;
     11use WpOrg\Requests\Iri;
     12use WpOrg\Requests\Response\Headers;
     13use WpOrg\Requests\Utility\CaseInsensitiveDictionary;
     14use WpOrg\Requests\Utility\InputValidator;
    815
    916/**
    1017 * Cookie storage object
    1118 *
    12  * @package Requests
    13  * @subpackage Cookies
     19 * @package Requests\Cookies
    1420 */
    15 class Requests_Cookie {
     21class Cookie {
    1622    /**
    1723     * Cookie name.
     
    3440     * httponly.
    3541     *
    36      * @var Requests_Utility_CaseInsensitiveDictionary|array Array-like object
    37      */
    38     public $attributes = array();
     42     * @var \WpOrg\Requests\Utility\CaseInsensitiveDictionary|array Array-like object
     43     */
     44    public $attributes = [];
    3945
    4046    /**
     
    4652     * @var array
    4753     */
    48     public $flags = array();
     54    public $flags = [];
    4955
    5056    /**
     
    6369     * @param string $name
    6470     * @param string $value
    65      * @param array|Requests_Utility_CaseInsensitiveDictionary $attributes Associative array of attribute data
    66      */
    67     public function __construct($name, $value, $attributes = array(), $flags = array(), $reference_time = null) {
     71     * @param array|\WpOrg\Requests\Utility\CaseInsensitiveDictionary $attributes Associative array of attribute data
     72     * @param array $flags
     73     * @param int|null $reference_time
     74     *
     75     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $name argument is not a string.
     76     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $value argument is not a string.
     77     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $attributes argument is not an array or iterable object with array access.
     78     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $flags argument is not an array.
     79     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $reference_time argument is not an integer or null.
     80     */
     81    public function __construct($name, $value, $attributes = [], $flags = [], $reference_time = null) {
     82        if (is_string($name) === false) {
     83            throw InvalidArgument::create(1, '$name', 'string', gettype($name));
     84        }
     85
     86        if (is_string($value) === false) {
     87            throw InvalidArgument::create(2, '$value', 'string', gettype($value));
     88        }
     89
     90        if (InputValidator::has_array_access($attributes) === false || InputValidator::is_iterable($attributes) === false) {
     91            throw InvalidArgument::create(3, '$attributes', 'array|ArrayAccess&Traversable', gettype($attributes));
     92        }
     93
     94        if (is_array($flags) === false) {
     95            throw InvalidArgument::create(4, '$flags', 'array', gettype($flags));
     96        }
     97
     98        if ($reference_time !== null && is_int($reference_time) === false) {
     99            throw InvalidArgument::create(5, '$reference_time', 'integer|null', gettype($reference_time));
     100        }
     101
    68102        $this->name       = $name;
    69103        $this->value      = $value;
    70104        $this->attributes = $attributes;
    71         $default_flags    = array(
     105        $default_flags    = [
    72106            'creation'    => time(),
    73107            'last-access' => time(),
    74108            'persistent'  => false,
    75109            'host-only'   => true,
    76         );
     110        ];
    77111        $this->flags      = array_merge($default_flags, $flags);
    78112
     
    83117
    84118        $this->normalize();
     119    }
     120
     121    /**
     122     * Get the cookie value
     123     *
     124     * Attributes and other data can be accessed via methods.
     125     */
     126    public function __toString() {
     127        return $this->value;
    85128    }
    86129
     
    114157     * Check if a cookie is valid for a given URI
    115158     *
    116      * @param Requests_IRI $uri URI to check
     159     * @param \WpOrg\Requests\Iri $uri URI to check
    117160     * @return boolean Whether the cookie is valid for the given URI
    118161     */
    119     public function uri_matches(Requests_IRI $uri) {
     162    public function uri_matches(Iri $uri) {
    120163        if (!$this->domain_matches($uri->host)) {
    121164            return false;
     
    132175     * Check if a cookie is valid for a given domain
    133176     *
    134      * @param string $string Domain to check
     177     * @param string $domain Domain to check
    135178     * @return boolean Whether the cookie is valid for the given domain
    136179     */
    137     public function domain_matches($string) {
     180    public function domain_matches($domain) {
     181        if (is_string($domain) === false) {
     182            return false;
     183        }
     184
    138185        if (!isset($this->attributes['domain'])) {
    139186            // Cookies created manually; cookies created by Requests will set
     
    142189        }
    143190
    144         $domain_string = $this->attributes['domain'];
    145         if ($domain_string === $string) {
    146             // The domain string and the string are identical.
     191        $cookie_domain = $this->attributes['domain'];
     192        if ($cookie_domain === $domain) {
     193            // The cookie domain and the passed domain are identical.
    147194            return true;
    148195        }
     
    154201        }
    155202
    156         if (strlen($string) <= strlen($domain_string)) {
    157             // For obvious reasons, the string cannot be a suffix if the domain
    158             // is shorter than the domain string
    159             return false;
    160         }
    161 
    162         if (substr($string, -1 * strlen($domain_string)) !== $domain_string) {
    163             // The domain string should be a suffix of the string.
    164             return false;
    165         }
    166 
    167         $prefix = substr($string, 0, strlen($string) - strlen($domain_string));
     203        if (strlen($domain) <= strlen($cookie_domain)) {
     204            // For obvious reasons, the cookie domain cannot be a suffix if the passed domain
     205            // is shorter than the cookie domain
     206            return false;
     207        }
     208
     209        if (substr($domain, -1 * strlen($cookie_domain)) !== $cookie_domain) {
     210            // The cookie domain should be a suffix of the passed domain.
     211            return false;
     212        }
     213
     214        $prefix = substr($domain, 0, strlen($domain) - strlen($cookie_domain));
    168215        if (substr($prefix, -1) !== '.') {
    169             // The last character of the string that is not included in the
     216            // The last character of the passed domain that is not included in the
    170217            // domain string should be a %x2E (".") character.
    171218            return false;
    172219        }
    173220
    174         // The string should be a host name (i.e., not an IP address).
    175         return !preg_match('#^(.+\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $string);
     221        // The passed domain should be a host name (i.e., not an IP address).
     222        return !preg_match('#^(.+\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $domain);
    176223    }
    177224
     
    194241            // the path to the requested path
    195242            return true;
     243        }
     244
     245        if (is_scalar($request_path) === false) {
     246            return false;
    196247        }
    197248
     
    318369
    319370    /**
    320      * Format a cookie for a Cookie header
    321      *
    322      * @codeCoverageIgnore
    323      * @deprecated Use {@see Requests_Cookie::format_for_header}
    324      * @return string
    325      */
    326     public function formatForHeader() {
    327         return $this->format_for_header();
    328     }
    329 
    330     /**
    331371     * Format a cookie for a Set-Cookie header
    332372     *
     
    339379        $header_value = $this->format_for_header();
    340380        if (!empty($this->attributes)) {
    341             $parts = array();
     381            $parts = [];
    342382            foreach ($this->attributes as $key => $value) {
    343383                // Ignore non-associative attributes
     
    356396
    357397    /**
    358      * Format a cookie for a Set-Cookie header
    359      *
    360      * @codeCoverageIgnore
    361      * @deprecated Use {@see Requests_Cookie::format_for_set_cookie}
    362      * @return string
    363      */
    364     public function formatForSetCookie() {
    365         return $this->format_for_set_cookie();
    366     }
    367 
    368     /**
    369      * Get the cookie value
    370      *
    371      * Attributes and other data can be accessed via methods.
    372      */
    373     public function __toString() {
    374         return $this->value;
    375     }
    376 
    377     /**
    378398     * Parse a cookie string into a cookie object
    379399     *
     
    382402     * specifies some of this handling, but not in a thorough manner.
    383403     *
    384      * @param string Cookie header value (from a Set-Cookie header)
    385      * @return Requests_Cookie Parsed cookie object
    386      */
    387     public static function parse($string, $name = '', $reference_time = null) {
    388         $parts   = explode(';', $string);
     404     * @param string $cookie_header Cookie header value (from a Set-Cookie header)
     405     * @param string $name
     406     * @param int|null $reference_time
     407     * @return \WpOrg\Requests\Cookie Parsed cookie object
     408     *
     409     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $cookie_header argument is not a string.
     410     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $name argument is not a string.
     411     */
     412    public static function parse($cookie_header, $name = '', $reference_time = null) {
     413        if (is_string($cookie_header) === false) {
     414            throw InvalidArgument::create(1, '$cookie_header', 'string', gettype($cookie_header));
     415        }
     416
     417        if (is_string($name) === false) {
     418            throw InvalidArgument::create(2, '$name', 'string', gettype($name));
     419        }
     420
     421        $parts   = explode(';', $cookie_header);
    389422        $kvparts = array_shift($parts);
    390423
    391424        if (!empty($name)) {
    392             $value = $string;
     425            $value = $cookie_header;
    393426        }
    394427        elseif (strpos($kvparts, '=') === false) {
     
    407440        $value = trim($value);
    408441
    409         // Attribute key are handled case-insensitively
    410         $attributes = new Requests_Utility_CaseInsensitiveDictionary();
     442        // Attribute keys are handled case-insensitively
     443        $attributes = new CaseInsensitiveDictionary();
    411444
    412445        if (!empty($parts)) {
     
    426459        }
    427460
    428         return new Requests_Cookie($name, $value, $attributes, array(), $reference_time);
     461        return new static($name, $value, $attributes, [], $reference_time);
    429462    }
    430463
     
    432465     * Parse all Set-Cookie headers from request headers
    433466     *
    434      * @param Requests_Response_Headers $headers Headers to parse from
    435      * @param Requests_IRI|null $origin URI for comparing cookie origins
     467     * @param \WpOrg\Requests\Response\Headers $headers Headers to parse from
     468     * @param \WpOrg\Requests\Iri|null $origin URI for comparing cookie origins
    436469     * @param int|null $time Reference time for expiration calculation
    437470     * @return array
    438471     */
    439     public static function parse_from_headers(Requests_Response_Headers $headers, Requests_IRI $origin = null, $time = null) {
     472    public static function parse_from_headers(Headers $headers, Iri $origin = null, $time = null) {
    440473        $cookie_headers = $headers->getValues('Set-Cookie');
    441474        if (empty($cookie_headers)) {
    442             return array();
    443         }
    444 
    445         $cookies = array();
     475            return [];
     476        }
     477
     478        $cookies = [];
    446479        foreach ($cookie_headers as $header) {
    447480            $parsed = self::parse($header, '', $time);
     
    492525        return $cookies;
    493526    }
    494 
    495     /**
    496      * Parse all Set-Cookie headers from request headers
    497      *
    498      * @codeCoverageIgnore
    499      * @deprecated Use {@see Requests_Cookie::parse_from_headers}
    500      * @return array
    501      */
    502     public static function parseFromHeaders(Requests_Response_Headers $headers) {
    503         return self::parse_from_headers($headers);
    504     }
    505527}
  • trunk/src/wp-includes/Requests/Cookie/Jar.php

    r50842 r52244  
    33 * Cookie holder object
    44 *
    5  * @package Requests
    6  * @subpackage Cookies
     5 * @package Requests\Cookies
    76 */
     7
     8namespace WpOrg\Requests\Cookie;
     9
     10use ArrayAccess;
     11use ArrayIterator;
     12use IteratorAggregate;
     13use ReturnTypeWillChange;
     14use WpOrg\Requests\Cookie;
     15use WpOrg\Requests\Exception;
     16use WpOrg\Requests\Exception\InvalidArgument;
     17use WpOrg\Requests\HookManager;
     18use WpOrg\Requests\Iri;
     19use WpOrg\Requests\Response;
    820
    921/**
    1022 * Cookie holder object
    1123 *
    12  * @package Requests
    13  * @subpackage Cookies
     24 * @package Requests\Cookies
    1425 */
    15 class Requests_Cookie_Jar implements ArrayAccess, IteratorAggregate {
     26class Jar implements ArrayAccess, IteratorAggregate {
    1627    /**
    1728     * Actual item data
     
    1930     * @var array
    2031     */
    21     protected $cookies = array();
     32    protected $cookies = [];
    2233
    2334    /**
     
    2536     *
    2637     * @param array $cookies Existing cookie values
     38     *
     39     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not an array.
    2740     */
    28     public function __construct($cookies = array()) {
     41    public function __construct($cookies = []) {
     42        if (is_array($cookies) === false) {
     43            throw InvalidArgument::create(1, '$cookies', 'array', gettype($cookies));
     44        }
     45
    2946        $this->cookies = $cookies;
    3047    }
    3148
    3249    /**
    33      * Normalise cookie data into a Requests_Cookie
     50     * Normalise cookie data into a \WpOrg\Requests\Cookie
    3451     *
    35      * @param string|Requests_Cookie $cookie
    36      * @return Requests_Cookie
     52     * @param string|\WpOrg\Requests\Cookie $cookie
     53     * @return \WpOrg\Requests\Cookie
    3754     */
    38     public function normalize_cookie($cookie, $key = null) {
    39         if ($cookie instanceof Requests_Cookie) {
     55    public function normalize_cookie($cookie, $key = '') {
     56        if ($cookie instanceof Cookie) {
    4057            return $cookie;
    4158        }
    4259
    43         return Requests_Cookie::parse($cookie, $key);
    44     }
    45 
    46     /**
    47      * Normalise cookie data into a Requests_Cookie
    48      *
    49      * @codeCoverageIgnore
    50      * @deprecated Use {@see Requests_Cookie_Jar::normalize_cookie}
    51      * @return Requests_Cookie
    52      */
    53     public function normalizeCookie($cookie, $key = null) {
    54         return $this->normalize_cookie($cookie, $key);
     60        return Cookie::parse($cookie, $key);
    5561    }
    5662
     
    5864     * Check if the given item exists
    5965     *
    60      * @param string $key Item key
     66     * @param string $offset Item key
    6167     * @return boolean Does the item exist?
    6268     */
    63     public function offsetExists($key) {
    64         return isset($this->cookies[$key]);
     69    #[ReturnTypeWillChange]
     70    public function offsetExists($offset) {
     71        return isset($this->cookies[$offset]);
    6572    }
    6673
     
    6875     * Get the value for the item
    6976     *
    70      * @param string $key Item key
     77     * @param string $offset Item key
    7178     * @return string|null Item value (null if offsetExists is false)
    7279     */
    73     public function offsetGet($key) {
    74         if (!isset($this->cookies[$key])) {
     80    #[ReturnTypeWillChange]
     81    public function offsetGet($offset) {
     82        if (!isset($this->cookies[$offset])) {
    7583            return null;
    7684        }
    7785
    78         return $this->cookies[$key];
     86        return $this->cookies[$offset];
    7987    }
    8088
     
    8290     * Set the given item
    8391     *
    84      * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
     92     * @param string $offset Item name
     93     * @param string $value Item value
    8594     *
    86      * @param string $key Item name
    87      * @param string $value Item value
     95     * @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`)
    8896     */
    89     public function offsetSet($key, $value) {
    90         if ($key === null) {
    91             throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
     97    #[ReturnTypeWillChange]
     98    public function offsetSet($offset, $value) {
     99        if ($offset === null) {
     100            throw new Exception('Object is a dictionary, not a list', 'invalidset');
    92101        }
    93102
    94         $this->cookies[$key] = $value;
     103        $this->cookies[$offset] = $value;
    95104    }
    96105
     
    98107     * Unset the given header
    99108     *
    100      * @param string $key
     109     * @param string $offset
    101110     */
    102     public function offsetUnset($key) {
    103         unset($this->cookies[$key]);
     111    #[ReturnTypeWillChange]
     112    public function offsetUnset($offset) {
     113        unset($this->cookies[$offset]);
    104114    }
    105115
     
    107117     * Get an iterator for the data
    108118     *
    109      * @return ArrayIterator
     119     * @return \ArrayIterator
    110120     */
     121    #[ReturnTypeWillChange]
    111122    public function getIterator() {
    112123        return new ArrayIterator($this->cookies);
     
    116127     * Register the cookie handler with the request's hooking system
    117128     *
    118      * @param Requests_Hooker $hooks Hooking system
     129     * @param \WpOrg\Requests\HookManager $hooks Hooking system
    119130     */
    120     public function register(Requests_Hooker $hooks) {
    121         $hooks->register('requests.before_request', array($this, 'before_request'));
    122         $hooks->register('requests.before_redirect_check', array($this, 'before_redirect_check'));
     131    public function register(HookManager $hooks) {
     132        $hooks->register('requests.before_request', [$this, 'before_request']);
     133        $hooks->register('requests.before_redirect_check', [$this, 'before_redirect_check']);
    123134    }
    124135
     
    135146     */
    136147    public function before_request($url, &$headers, &$data, &$type, &$options) {
    137         if (!$url instanceof Requests_IRI) {
    138             $url = new Requests_IRI($url);
     148        if (!$url instanceof Iri) {
     149            $url = new Iri($url);
    139150        }
    140151
    141152        if (!empty($this->cookies)) {
    142             $cookies = array();
     153            $cookies = [];
    143154            foreach ($this->cookies as $key => $cookie) {
    144155                $cookie = $this->normalize_cookie($cookie, $key);
     
    161172     * Parse all cookies from a response and attach them to the response
    162173     *
    163      * @var Requests_Response $response
     174     * @param \WpOrg\Requests\Response $response
    164175     */
    165     public function before_redirect_check(Requests_Response $return) {
    166         $url = $return->url;
    167         if (!$url instanceof Requests_IRI) {
    168             $url = new Requests_IRI($url);
     176    public function before_redirect_check(Response $response) {
     177        $url = $response->url;
     178        if (!$url instanceof Iri) {
     179            $url = new Iri($url);
    169180        }
    170181
    171         $cookies         = Requests_Cookie::parse_from_headers($return->headers, $url);
    172         $this->cookies   = array_merge($this->cookies, $cookies);
    173         $return->cookies = $this;
     182        $cookies           = Cookie::parse_from_headers($response->headers, $url);
     183        $this->cookies     = array_merge($this->cookies, $cookies);
     184        $response->cookies = $this;
    174185    }
    175186}
  • trunk/src/wp-includes/Requests/Exception.php

    r50842 r52244  
    33 * Exception for HTTP requests
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests;
     9
     10use Exception as PHPException;
    711
    812/**
    913 * Exception for HTTP requests
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception extends Exception {
     17class Exception extends PHPException {
    1418    /**
    1519     * Type of exception
     
    4246
    4347    /**
    44      * Like {@see getCode()}, but a string code.
     48     * Like {@see \Exception::getCode()}, but a string code.
    4549     *
    4650     * @codeCoverageIgnore
  • trunk/src/wp-includes/Requests/Exception/Http.php

    r52243 r52244  
    33 * Exception based on HTTP response
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception;
     9
     10use WpOrg\Requests\Exception;
     11use WpOrg\Requests\Exception\Http\StatusUnknown;
    712
    813/**
    914 * Exception based on HTTP response
    1015 *
    11  * @package Requests
     16 * @package Requests\Exceptions
    1217 */
    13 class Requests_Exception_HTTP extends Requests_Exception {
     18class Http extends Exception {
    1419    /**
    1520     * HTTP status code
     
    4550
    4651    /**
    47      * Get the status message
     52     * Get the status message.
     53     *
     54     * @return string
    4855     */
    4956    public function getReason() {
     
    5966    public static function get_class($code) {
    6067        if (!$code) {
    61             return 'Requests_Exception_HTTP_Unknown';
     68            return StatusUnknown::class;
    6269        }
    6370
    64         $class = sprintf('Requests_Exception_HTTP_%d', $code);
     71        $class = sprintf('\WpOrg\Requests\Exception\Http\Status%d', $code);
    6572        if (class_exists($class)) {
    6673            return $class;
    6774        }
    6875
    69         return 'Requests_Exception_HTTP_Unknown';
     76        return StatusUnknown::class;
    7077    }
    7178}
  • trunk/src/wp-includes/Requests/Exception/Http/Status304.php

    r52243 r52244  
    33 * Exception for 304 Not Modified responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 304 Not Modified responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_304 extends Requests_Exception_HTTP {
     17final class Status304 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status305.php

    r52243 r52244  
    33 * Exception for 305 Use Proxy responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 305 Use Proxy responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_305 extends Requests_Exception_HTTP {
     17final class Status305 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status306.php

    r52243 r52244  
    33 * Exception for 306 Switch Proxy responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 306 Switch Proxy responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_306 extends Requests_Exception_HTTP {
     17final class Status306 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status400.php

    r52243 r52244  
    33 * Exception for 400 Bad Request responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 400 Bad Request responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_400 extends Requests_Exception_HTTP {
     17final class Status400 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status401.php

    r52243 r52244  
    33 * Exception for 401 Unauthorized responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 401 Unauthorized responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_401 extends Requests_Exception_HTTP {
     17final class Status401 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status402.php

    r52243 r52244  
    33 * Exception for 402 Payment Required responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 402 Payment Required responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_402 extends Requests_Exception_HTTP {
     17final class Status402 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status403.php

    r52243 r52244  
    33 * Exception for 403 Forbidden responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 403 Forbidden responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_403 extends Requests_Exception_HTTP {
     17final class Status403 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status404.php

    r52243 r52244  
    33 * Exception for 404 Not Found responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 404 Not Found responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_404 extends Requests_Exception_HTTP {
     17final class Status404 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status405.php

    r52243 r52244  
    33 * Exception for 405 Method Not Allowed responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 405 Method Not Allowed responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_405 extends Requests_Exception_HTTP {
     17final class Status405 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status406.php

    r52243 r52244  
    33 * Exception for 406 Not Acceptable responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 406 Not Acceptable responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_406 extends Requests_Exception_HTTP {
     17final class Status406 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status407.php

    r52243 r52244  
    33 * Exception for 407 Proxy Authentication Required responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 407 Proxy Authentication Required responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_407 extends Requests_Exception_HTTP {
     17final class Status407 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status408.php

    r52243 r52244  
    33 * Exception for 408 Request Timeout responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 408 Request Timeout responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_408 extends Requests_Exception_HTTP {
     17final class Status408 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status409.php

    r52243 r52244  
    33 * Exception for 409 Conflict responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 409 Conflict responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_409 extends Requests_Exception_HTTP {
     17final class Status409 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status410.php

    r52243 r52244  
    33 * Exception for 410 Gone responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 410 Gone responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_410 extends Requests_Exception_HTTP {
     17final class Status410 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status411.php

    r52243 r52244  
    33 * Exception for 411 Length Required responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 411 Length Required responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_411 extends Requests_Exception_HTTP {
     17final class Status411 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status412.php

    r52243 r52244  
    33 * Exception for 412 Precondition Failed responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 412 Precondition Failed responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_412 extends Requests_Exception_HTTP {
     17final class Status412 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status413.php

    r52243 r52244  
    33 * Exception for 413 Request Entity Too Large responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 413 Request Entity Too Large responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_413 extends Requests_Exception_HTTP {
     17final class Status413 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status414.php

    r52243 r52244  
    33 * Exception for 414 Request-URI Too Large responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 414 Request-URI Too Large responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_414 extends Requests_Exception_HTTP {
     17final class Status414 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status415.php

    r52243 r52244  
    33 * Exception for 415 Unsupported Media Type responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 415 Unsupported Media Type responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_415 extends Requests_Exception_HTTP {
     17final class Status415 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status416.php

    r52243 r52244  
    33 * Exception for 416 Requested Range Not Satisfiable responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 416 Requested Range Not Satisfiable responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_416 extends Requests_Exception_HTTP {
     17final class Status416 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status417.php

    r52243 r52244  
    33 * Exception for 417 Expectation Failed responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 417 Expectation Failed responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_417 extends Requests_Exception_HTTP {
     17final class Status417 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status418.php

    r52243 r52244  
    33 * Exception for 418 I'm A Teapot responses
    44 *
    5  * @see https://tools.ietf.org/html/rfc2324
    6  * @package Requests
     5 * @link https://tools.ietf.org/html/rfc2324
     6 *
     7 * @package Requests\Exceptions
    78 */
     9
     10namespace WpOrg\Requests\Exception\Http;
     11
     12use WpOrg\Requests\Exception\Http;
    813
    914/**
    1015 * Exception for 418 I'm A Teapot responses
    1116 *
    12  * @see https://tools.ietf.org/html/rfc2324
    13  * @package Requests
     17 * @link https://tools.ietf.org/html/rfc2324
     18 *
     19 * @package Requests\Exceptions
    1420 */
    15 class Requests_Exception_HTTP_418 extends Requests_Exception_HTTP {
     21final class Status418 extends Http {
    1622    /**
    1723     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status428.php

    r52243 r52244  
    33 * Exception for 428 Precondition Required responses
    44 *
    5  * @see https://tools.ietf.org/html/rfc6585
    6  * @package Requests
     5 * @link https://tools.ietf.org/html/rfc6585
     6 *
     7 * @package Requests\Exceptions
    78 */
     9
     10namespace WpOrg\Requests\Exception\Http;
     11
     12use WpOrg\Requests\Exception\Http;
    813
    914/**
    1015 * Exception for 428 Precondition Required responses
    1116 *
    12  * @see https://tools.ietf.org/html/rfc6585
    13  * @package Requests
     17 * @link https://tools.ietf.org/html/rfc6585
     18 *
     19 * @package Requests\Exceptions
    1420 */
    15 class Requests_Exception_HTTP_428 extends Requests_Exception_HTTP {
     21final class Status428 extends Http {
    1622    /**
    1723     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status429.php

    r52243 r52244  
    33 * Exception for 429 Too Many Requests responses
    44 *
    5  * @see https://tools.ietf.org/html/draft-nottingham-http-new-status-04
    6  * @package Requests
     5 * @link https://tools.ietf.org/html/draft-nottingham-http-new-status-04
     6 *
     7 * @package Requests\Exceptions
    78 */
     9
     10namespace WpOrg\Requests\Exception\Http;
     11
     12use WpOrg\Requests\Exception\Http;
    813
    914/**
    1015 * Exception for 429 Too Many Requests responses
    1116 *
    12  * @see https://tools.ietf.org/html/draft-nottingham-http-new-status-04
    13  * @package Requests
     17 * @link https://tools.ietf.org/html/draft-nottingham-http-new-status-04
     18 *
     19 * @package Requests\Exceptions
    1420 */
    15 class Requests_Exception_HTTP_429 extends Requests_Exception_HTTP {
     21final class Status429 extends Http {
    1622    /**
    1723     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status431.php

    r52243 r52244  
    33 * Exception for 431 Request Header Fields Too Large responses
    44 *
    5  * @see https://tools.ietf.org/html/rfc6585
    6  * @package Requests
     5 * @link https://tools.ietf.org/html/rfc6585
     6 *
     7 * @package Requests\Exceptions
    78 */
     9
     10namespace WpOrg\Requests\Exception\Http;
     11
     12use WpOrg\Requests\Exception\Http;
    813
    914/**
    1015 * Exception for 431 Request Header Fields Too Large responses
    1116 *
    12  * @see https://tools.ietf.org/html/rfc6585
    13  * @package Requests
     17 * @link https://tools.ietf.org/html/rfc6585
     18 *
     19 * @package Requests\Exceptions
    1420 */
    15 class Requests_Exception_HTTP_431 extends Requests_Exception_HTTP {
     21final class Status431 extends Http {
    1622    /**
    1723     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status500.php

    r52243 r52244  
    33 * Exception for 500 Internal Server Error responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 500 Internal Server Error responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_500 extends Requests_Exception_HTTP {
     17final class Status500 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status501.php

    r52243 r52244  
    33 * Exception for 501 Not Implemented responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 501 Not Implemented responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_501 extends Requests_Exception_HTTP {
     17final class Status501 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status502.php

    r52243 r52244  
    33 * Exception for 502 Bad Gateway responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 502 Bad Gateway responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_502 extends Requests_Exception_HTTP {
     17final class Status502 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status503.php

    r52243 r52244  
    33 * Exception for 503 Service Unavailable responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 503 Service Unavailable responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_503 extends Requests_Exception_HTTP {
     17final class Status503 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status504.php

    r52243 r52244  
    33 * Exception for 504 Gateway Timeout responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 504 Gateway Timeout responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_504 extends Requests_Exception_HTTP {
     17final class Status504 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status505.php

    r52243 r52244  
    33 * Exception for 505 HTTP Version Not Supported responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
    711
    812/**
    913 * Exception for 505 HTTP Version Not Supported responses
    1014 *
    11  * @package Requests
     15 * @package Requests\Exceptions
    1216 */
    13 class Requests_Exception_HTTP_505 extends Requests_Exception_HTTP {
     17final class Status505 extends Http {
    1418    /**
    1519     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/Status511.php

    r52243 r52244  
    33 * Exception for 511 Network Authentication Required responses
    44 *
    5  * @see https://tools.ietf.org/html/rfc6585
    6  * @package Requests
     5 * @link https://tools.ietf.org/html/rfc6585
     6 *
     7 * @package Requests\Exceptions
    78 */
     9
     10namespace WpOrg\Requests\Exception\Http;
     11
     12use WpOrg\Requests\Exception\Http;
    813
    914/**
    1015 * Exception for 511 Network Authentication Required responses
    1116 *
    12  * @see https://tools.ietf.org/html/rfc6585
    13  * @package Requests
     17 * @link https://tools.ietf.org/html/rfc6585
     18 *
     19 * @package Requests\Exceptions
    1420 */
    15 class Requests_Exception_HTTP_511 extends Requests_Exception_HTTP {
     21final class Status511 extends Http {
    1622    /**
    1723     * HTTP status code
  • trunk/src/wp-includes/Requests/Exception/Http/StatusUnknown.php

    r52243 r52244  
    33 * Exception for unknown status responses
    44 *
    5  * @package Requests
     5 * @package Requests\Exceptions
    66 */
     7
     8namespace WpOrg\Requests\Exception\Http;
     9
     10use WpOrg\Requests\Exception\Http;
     11use WpOrg\Requests\Response;
    712
    813/**
    914 * Exception for unknown status responses
    1015 *
    11  * @package Requests
     16 * @package Requests\Exceptions
    1217 */
    13 class Requests_Exception_HTTP_Unknown extends Requests_Exception_HTTP {
     18final class StatusUnknown extends Http {
    1419    /**
    1520     * HTTP status code
     
    2934     * Create a new exception
    3035     *
    31      * If `$data` is an instance of {@see Requests_Response}, uses the status
     36     * If `$data` is an instance of {@see \WpOrg\Requests\Response}, uses the status
    3237     * code from it. Otherwise, sets as 0
    3338     *
     
    3641     */
    3742    public function __construct($reason = null, $data = null) {
    38         if ($data instanceof Requests_Response) {
    39             $this->code = $data->status_code;
     43        if ($data instanceof Response) {
     44            $this->code = (int) $data->status_code;
    4045        }
    4146
  • trunk/src/wp-includes/Requests/Exception/Transport.php

    r46586 r52244  
    11<?php
     2/**
     3 * Transport Exception
     4 *
     5 * @package Requests\Exceptions
     6 */
    27
    3 class Requests_Exception_Transport extends Requests_Exception {
     8namespace WpOrg\Requests\Exception;
    49
    5 }
     10use WpOrg\Requests\Exception;
     11
     12/**
     13 * Transport Exception
     14 *
     15 * @package Requests\Exceptions
     16 */
     17class Transport extends Exception {}
  • trunk/src/wp-includes/Requests/Exception/Transport/Curl.php

    r52243 r52244  
    11<?php
     2/**
     3 * CURL Transport Exception.
     4 *
     5 * @package Requests\Exceptions
     6 */
    27
    3 class Requests_Exception_Transport_cURL extends Requests_Exception_Transport {
     8namespace WpOrg\Requests\Exception\Transport;
     9
     10use WpOrg\Requests\Exception\Transport;
     11
     12/**
     13 * CURL Transport Exception.
     14 *
     15 * @package Requests\Exceptions
     16 */
     17final class Curl extends Transport {
    418
    519    const EASY  = 'cURLEasy';
     
    3044    protected $reason = 'Unknown';
    3145
     46    /**
     47     * Create a new exception.
     48     *
     49     * @param string $message Exception message.
     50     * @param string $type    Exception type.
     51     * @param mixed  $data    Associated data, if applicable.
     52     * @param int    $code    Exception numerical code, if applicable.
     53     */
    3254    public function __construct($message, $type, $data = null, $code = 0) {
    3355        if ($type !== null) {
     
    3658
    3759        if ($code !== null) {
    38             $this->code = $code;
     60            $this->code = (int) $code;
    3961        }
    4062
     
    4870
    4971    /**
    50      * Get the error message
     72     * Get the error message.
     73     *
     74     * @return string
    5175     */
    5276    public function getReason() {
  • trunk/src/wp-includes/Requests/HookManager.php

    r52243 r52244  
    33 * Event dispatcher
    44 *
    5  * @package Requests
    6  * @subpackage Utilities
     5 * @package Requests\EventDispatcher
    76 */
     7
     8namespace WpOrg\Requests;
    89
    910/**
    1011 * Event dispatcher
    1112 *
    12  * @package Requests
    13  * @subpackage Utilities
     13 * @package Requests\EventDispatcher
    1414 */
    15 interface Requests_Hooker {
     15interface HookManager {
    1616    /**
    1717     * Register a callback for a hook
    1818     *
    1919     * @param string $hook Hook name
    20      * @param callback $callback Function/method to call on event
     20     * @param callable $callback Function/method to call on event
    2121     * @param int $priority Priority number. <0 is executed earlier, >0 is executed later
    2222     */
     
    3030     * @return boolean Successfulness
    3131     */
    32     public function dispatch($hook, $parameters = array());
     32    public function dispatch($hook, $parameters = []);
    3333}
  • trunk/src/wp-includes/Requests/Hooks.php

    r50842 r52244  
    33 * Handles adding and dispatching events
    44 *
    5  * @package Requests
    6  * @subpackage Utilities
     5 * @package Requests\EventDispatcher
    76 */
     7
     8namespace WpOrg\Requests;
     9
     10use WpOrg\Requests\Exception\InvalidArgument;
     11use WpOrg\Requests\HookManager;
     12use WpOrg\Requests\Utility\InputValidator;
    813
    914/**
    1015 * Handles adding and dispatching events
    1116 *
    12  * @package Requests
    13  * @subpackage Utilities
     17 * @package Requests\EventDispatcher
    1418 */
    15 class Requests_Hooks implements Requests_Hooker {
     19class Hooks implements HookManager {
    1620    /**
    1721     * Registered callbacks for each hook
     
    1923     * @var array
    2024     */
    21     protected $hooks = array();
    22 
    23     /**
    24      * Constructor
    25      */
    26     public function __construct() {
    27         // pass
    28     }
     25    protected $hooks = [];
    2926
    3027    /**
     
    3229     *
    3330     * @param string $hook Hook name
    34      * @param callback $callback Function/method to call on event
     31     * @param callable $callback Function/method to call on event
    3532     * @param int $priority Priority number. <0 is executed earlier, >0 is executed later
     33     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $hook argument is not a string.
     34     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $callback argument is not callable.
     35     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $priority argument is not an integer.
    3636     */
    3737    public function register($hook, $callback, $priority = 0) {
     38        if (is_string($hook) === false) {
     39            throw InvalidArgument::create(1, '$hook', 'string', gettype($hook));
     40        }
     41
     42        if (is_callable($callback) === false) {
     43            throw InvalidArgument::create(2, '$callback', 'callable', gettype($callback));
     44        }
     45
     46        if (InputValidator::is_numeric_array_key($priority) === false) {
     47            throw InvalidArgument::create(3, '$priority', 'integer', gettype($priority));
     48        }
     49
    3850        if (!isset($this->hooks[$hook])) {
    39             $this->hooks[$hook] = array();
    40         }
    41         if (!isset($this->hooks[$hook][$priority])) {
    42             $this->hooks[$hook][$priority] = array();
     51            $this->hooks[$hook] = [
     52                $priority => [],
     53            ];
     54        } elseif (!isset($this->hooks[$hook][$priority])) {
     55            $this->hooks[$hook][$priority] = [];
    4356        }
    4457
     
    5265     * @param array $parameters Parameters to pass to callbacks
    5366     * @return boolean Successfulness
     67     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $hook argument is not a string.
     68     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $parameters argument is not an array.
    5469     */
    55     public function dispatch($hook, $parameters = array()) {
     70    public function dispatch($hook, $parameters = []) {
     71        if (is_string($hook) === false) {
     72            throw InvalidArgument::create(1, '$hook', 'string', gettype($hook));
     73        }
     74
     75        // Check strictly against array, as Array* objects don't work in combination with `call_user_func_array()`.
     76        if (is_array($parameters) === false) {
     77            throw InvalidArgument::create(2, '$parameters', 'array', gettype($parameters));
     78        }
     79
    5680        if (empty($this->hooks[$hook])) {
    5781            return false;
    5882        }
    5983
     84        if (!empty($parameters)) {
     85            // Strip potential keys from the array to prevent them being interpreted as parameter names in PHP 8.0.
     86            $parameters = array_values($parameters);
     87        }
     88
    6089        foreach ($this->hooks[$hook] as $priority => $hooked) {
    6190            foreach ($hooked as $callback) {
    62                 call_user_func_array($callback, $parameters);
     91                $callback(...$parameters);
    6392            }
    6493        }
  • trunk/src/wp-includes/Requests/IdnaEncoder.php

    r52243 r52244  
    11<?php
     2
     3namespace WpOrg\Requests;
     4
     5use WpOrg\Requests\Exception;
     6use WpOrg\Requests\Exception\InvalidArgument;
     7use WpOrg\Requests\Utility\InputValidator;
    28
    39/**
     
    612 * Note: Not fully compliant, as nameprep does nothing yet.
    713 *
    8  * @package Requests
    9  * @subpackage Utilities
    10  * @see https://tools.ietf.org/html/rfc3490 IDNA specification
    11  * @see https://tools.ietf.org/html/rfc3492 Punycode/Bootstrap specification
     14 * @package Requests\Utilities
     15 *
     16 * @link https://tools.ietf.org/html/rfc3490 IDNA specification
     17 * @link https://tools.ietf.org/html/rfc3492 Punycode/Bootstrap specification
    1218 */
    13 class Requests_IDNAEncoder {
     19class IdnaEncoder {
    1420    /**
    1521     * ACE prefix used for IDNA
    1622     *
    17      * @see https://tools.ietf.org/html/rfc3490#section-5
     23     * @link https://tools.ietf.org/html/rfc3490#section-5
    1824     * @var string
    1925     */
    2026    const ACE_PREFIX = 'xn--';
     27
     28    /**
     29     * Maximum length of a IDNA URL in ASCII.
     30     *
     31     * @see \WpOrg\Requests\IdnaEncoder::to_ascii()
     32     *
     33     * @since 2.0.0
     34     *
     35     * @var int
     36     */
     37    const MAX_LENGTH = 64;
    2138
    2239    /**#@+
    2340     * Bootstrap constant for Punycode
    2441     *
    25      * @see https://tools.ietf.org/html/rfc3492#section-5
     42     * @link https://tools.ietf.org/html/rfc3492#section-5
    2643     * @var int
    2744     */
     
    3855     * Encode a hostname using Punycode
    3956     *
    40      * @param string $string Hostname
     57     * @param string|Stringable $hostname Hostname
    4158     * @return string Punycode-encoded hostname
    42      */
    43     public static function encode($string) {
    44         $parts = explode('.', $string);
     59     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object.
     60     */
     61    public static function encode($hostname) {
     62        if (InputValidator::is_string_or_stringable($hostname) === false) {
     63            throw InvalidArgument::create(1, '$hostname', 'string|Stringable', gettype($hostname));
     64        }
     65
     66        $parts = explode('.', $hostname);
    4567        foreach ($parts as &$part) {
    4668            $part = self::to_ascii($part);
     
    5072
    5173    /**
    52      * Convert a UTF-8 string to an ASCII string using Punycode
    53      *
    54      * @throws Requests_Exception Provided string longer than 64 ASCII characters (`idna.provided_too_long`)
    55      * @throws Requests_Exception Prepared string longer than 64 ASCII characters (`idna.prepared_too_long`)
    56      * @throws Requests_Exception Provided string already begins with xn-- (`idna.provided_is_prefixed`)
    57      * @throws Requests_Exception Encoded string longer than 64 ASCII characters (`idna.encoded_too_long`)
    58      *
    59      * @param string $string ASCII or UTF-8 string (max length 64 characters)
     74     * Convert a UTF-8 text string to an ASCII string using Punycode
     75     *
     76     * @param string $text ASCII or UTF-8 string (max length 64 characters)
    6077     * @return string ASCII string
    61      */
    62     public static function to_ascii($string) {
    63         // Step 1: Check if the string is already ASCII
    64         if (self::is_ascii($string)) {
     78     *
     79     * @throws \WpOrg\Requests\Exception Provided string longer than 64 ASCII characters (`idna.provided_too_long`)
     80     * @throws \WpOrg\Requests\Exception Prepared string longer than 64 ASCII characters (`idna.prepared_too_long`)
     81     * @throws \WpOrg\Requests\Exception Provided string already begins with xn-- (`idna.provided_is_prefixed`)
     82     * @throws \WpOrg\Requests\Exception Encoded string longer than 64 ASCII characters (`idna.encoded_too_long`)
     83     */
     84    public static function to_ascii($text) {
     85        // Step 1: Check if the text is already ASCII
     86        if (self::is_ascii($text)) {
    6587            // Skip to step 7
    66             if (strlen($string) < 64) {
    67                 return $string;
    68             }
    69 
    70             throw new Requests_Exception('Provided string is too long', 'idna.provided_too_long', $string);
     88            if (strlen($text) < self::MAX_LENGTH) {
     89                return $text;
     90            }
     91
     92            throw new Exception('Provided string is too long', 'idna.provided_too_long', $text);
    7193        }
    7294
    7395        // Step 2: nameprep
    74         $string = self::nameprep($string);
     96        $text = self::nameprep($text);
    7597
    7698        // Step 3: UseSTD3ASCIIRules is false, continue
    7799        // Step 4: Check if it's ASCII now
    78         if (self::is_ascii($string)) {
     100        if (self::is_ascii($text)) {
    79101            // Skip to step 7
    80             if (strlen($string) < 64) {
    81                 return $string;
    82             }
    83 
    84             throw new Requests_Exception('Prepared string is too long', 'idna.prepared_too_long', $string);
     102            /*
     103             * As the `nameprep()` method returns the original string, this code will never be reached until
     104             * that method is properly implemented.
     105             */
     106            // @codeCoverageIgnoreStart
     107            if (strlen($text) < self::MAX_LENGTH) {
     108                return $text;
     109            }
     110
     111            throw new Exception('Prepared string is too long', 'idna.prepared_too_long', $text);
     112            // @codeCoverageIgnoreEnd
    85113        }
    86114
    87115        // Step 5: Check ACE prefix
    88         if (strpos($string, self::ACE_PREFIX) === 0) {
    89             throw new Requests_Exception('Provided string begins with ACE prefix', 'idna.provided_is_prefixed', $string);
     116        if (strpos($text, self::ACE_PREFIX) === 0) {
     117            throw new Exception('Provided string begins with ACE prefix', 'idna.provided_is_prefixed', $text);
    90118        }
    91119
    92120        // Step 6: Encode with Punycode
    93         $string = self::punycode_encode($string);
     121        $text = self::punycode_encode($text);
    94122
    95123        // Step 7: Prepend ACE prefix
    96         $string = self::ACE_PREFIX . $string;
     124        $text = self::ACE_PREFIX . $text;
    97125
    98126        // Step 8: Check size
    99         if (strlen($string) < 64) {
    100             return $string;
    101         }
    102 
    103         throw new Requests_Exception('Encoded string is too long', 'idna.encoded_too_long', $string);
    104     }
    105 
    106     /**
    107      * Check whether a given string contains only ASCII characters
     127        if (strlen($text) < self::MAX_LENGTH) {
     128            return $text;
     129        }
     130
     131        throw new Exception('Encoded string is too long', 'idna.encoded_too_long', $text);
     132    }
     133
     134    /**
     135     * Check whether a given text string contains only ASCII characters
    108136     *
    109137     * @internal (Testing found regex was the fastest implementation)
    110138     *
    111      * @param string $string
    112      * @return bool Is the string ASCII-only?
    113      */
    114     protected static function is_ascii($string) {
    115         return (preg_match('/(?:[^\x00-\x7F])/', $string) !== 1);
    116     }
    117 
    118     /**
    119      * Prepare a string for use as an IDNA name
     139     * @param string $text
     140     * @return bool Is the text string ASCII-only?
     141     */
     142    protected static function is_ascii($text) {
     143        return (preg_match('/(?:[^\x00-\x7F])/', $text) !== 1);
     144    }
     145
     146    /**
     147     * Prepare a text string for use as an IDNA name
    120148     *
    121149     * @todo Implement this based on RFC 3491 and the newer 5891
    122      * @param string $string
     150     * @param string $text
    123151     * @return string Prepared string
    124152     */
    125     protected static function nameprep($string) {
    126         return $string;
     153    protected static function nameprep($text) {
     154        return $text;
    127155    }
    128156
     
    130158     * Convert a UTF-8 string to a UCS-4 codepoint array
    131159     *
    132      * Based on Requests_IRI::replace_invalid_with_pct_encoding()
    133      *
    134      * @throws Requests_Exception Invalid UTF-8 codepoint (`idna.invalidcodepoint`)
     160     * Based on \WpOrg\Requests\Iri::replace_invalid_with_pct_encoding()
     161     *
    135162     * @param string $input
    136163     * @return array Unicode code points
     164     *
     165     * @throws \WpOrg\Requests\Exception Invalid UTF-8 codepoint (`idna.invalidcodepoint`)
    137166     */
    138167    protected static function utf8_to_codepoints($input) {
    139         $codepoints = array();
     168        $codepoints = [];
    140169
    141170        // Get number of bytes
     
    172201            // Invalid byte:
    173202            else {
    174                 throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $value);
     203                throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $value);
    175204            }
    176205
    177206            if ($remaining > 0) {
    178207                if ($position + $length > $strlen) {
    179                     throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
     208                    throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
    180209                }
    181210                for ($position++; $remaining > 0; $position++) {
     
    184213                    // If it is invalid, count the sequence as invalid and reprocess the current byte:
    185214                    if (($value & 0xC0) !== 0x80) {
    186                         throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
     215                        throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
    187216                    }
    188217
     
    209238                )
    210239            ) {
    211                 throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
     240                throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
    212241            }
    213242
     
    222251     *
    223252     * @internal Pseudo-code from Section 6.3 is commented with "#" next to relevant code
    224      * @throws Requests_Exception On character outside of the domain (never happens with Punycode) (`idna.character_outside_domain`)
    225253     *
    226254     * @param string $input UTF-8 encoded string to encode
    227255     * @return string Punycode-encoded string
     256     *
     257     * @throws \WpOrg\Requests\Exception On character outside of the domain (never happens with Punycode) (`idna.character_outside_domain`)
    228258     */
    229259    public static function punycode_encode($input) {
     
    240270        // copy them to the output in order
    241271        $codepoints = self::utf8_to_codepoints($input);
    242         $extended   = array();
     272        $extended   = [];
    243273
    244274        foreach ($codepoints as $char) {
     
    253283            // @codeCoverageIgnoreStart
    254284            elseif ($char < $n) {
    255                 throw new Requests_Exception('Invalid character', 'idna.character_outside_domain', $char);
     285                throw new Exception('Invalid character', 'idna.character_outside_domain', $char);
    256286            }
    257287            // @codeCoverageIgnoreEnd
     
    333363     * Convert a digit to its respective character
    334364     *
    335      * @see https://tools.ietf.org/html/rfc3492#section-5
    336      * @throws Requests_Exception On invalid digit (`idna.invalid_digit`)
     365     * @link https://tools.ietf.org/html/rfc3492#section-5
    337366     *
    338367     * @param int $digit Digit in the range 0-35
    339368     * @return string Single character corresponding to digit
     369     *
     370     * @throws \WpOrg\Requests\Exception On invalid digit (`idna.invalid_digit`)
    340371     */
    341372    protected static function digit_to_char($digit) {
     
    343374        // As far as I know, this never happens, but still good to be sure.
    344375        if ($digit < 0 || $digit > 35) {
    345             throw new Requests_Exception(sprintf('Invalid digit %d', $digit), 'idna.invalid_digit', $digit);
     376            throw new Exception(sprintf('Invalid digit %d', $digit), 'idna.invalid_digit', $digit);
    346377        }
    347378        // @codeCoverageIgnoreEnd
     
    353384     * Adapt the bias
    354385     *
    355      * @see https://tools.ietf.org/html/rfc3492#section-6.1
     386     * @link https://tools.ietf.org/html/rfc3492#section-6.1
    356387     * @param int $delta
    357388     * @param int $numpoints
  • trunk/src/wp-includes/Requests/Ipv6.php

    r52243 r52244  
    33 * Class to validate and to work with IPv6 addresses
    44 *
    5  * @package Requests
    6  * @subpackage Utilities
     5 * @package Requests\Utilities
    76 */
     7
     8namespace WpOrg\Requests;
     9
     10use WpOrg\Requests\Exception\InvalidArgument;
     11use WpOrg\Requests\Utility\InputValidator;
    812
    913/**
     
    1317 * entirely rewritten.
    1418 *
    15  * @package Requests
    16  * @subpackage Utilities
     19 * @package Requests\Utilities
    1720 */
    18 class Requests_IPv6 {
     21final class Ipv6 {
    1922    /**
    2023     * Uncompresses an IPv6 address
     
    3134     * @author Josh Peck <jmp at joshpeck dot org>
    3235     * @copyright 2003-2005 The PHP Group
    33      * @license http://www.opensource.org/licenses/bsd-license.php
    34      * @param string $ip An IPv6 address
     36     * @license https://opensource.org/licenses/bsd-license.php
     37     *
     38     * @param string|Stringable $ip An IPv6 address
    3539     * @return string The uncompressed IPv6 address
     40     *
     41     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object.
    3642     */
    3743    public static function uncompress($ip) {
     44        if (InputValidator::is_string_or_stringable($ip) === false) {
     45            throw InvalidArgument::create(1, '$ip', 'string|Stringable', gettype($ip));
     46        }
     47
     48        $ip = (string) $ip;
     49
    3850        if (substr_count($ip, '::') !== 1) {
    3951            return $ip;
     
    7991     *           0:0:0:0:0:0:0:1        ->  ::1
    8092     *
    81      * @see uncompress()
     93     * @see \WpOrg\Requests\IPv6::uncompress()
     94     *
    8295     * @param string $ip An IPv6 address
    8396     * @return string The compressed IPv6 address
    8497     */
    8598    public static function compress($ip) {
    86         // Prepare the IP to be compressed
     99        // Prepare the IP to be compressed.
     100        // Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method.
    87101        $ip       = self::uncompress($ip);
    88102        $ip_parts = self::split_v6_v4($ip);
     
    125139     * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part
    126140     */
    127     protected static function split_v6_v4($ip) {
     141    private static function split_v6_v4($ip) {
    128142        if (strpos($ip, '.') !== false) {
    129143            $pos       = strrpos($ip, ':');
    130144            $ipv6_part = substr($ip, 0, $pos);
    131145            $ipv4_part = substr($ip, $pos + 1);
    132             return array($ipv6_part, $ipv4_part);
    133         }
    134         else {
    135             return array($ip, '');
     146            return [$ipv6_part, $ipv4_part];
     147        }
     148        else {
     149            return [$ip, ''];
    136150        }
    137151    }
     
    146160     */
    147161    public static function check_ipv6($ip) {
     162        // Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method.
    148163        $ip                = self::uncompress($ip);
    149164        list($ipv6, $ipv4) = self::split_v6_v4($ip);
  • trunk/src/wp-includes/Requests/Iri.php

    r52243 r52244  
    33 * IRI parser/serialiser/normaliser
    44 *
    5  * @package Requests
    6  * @subpackage Utilities
     5 * @package Requests\Utilities
    76 */
     7
     8namespace WpOrg\Requests;
     9
     10use WpOrg\Requests\Exception;
     11use WpOrg\Requests\Exception\InvalidArgument;
     12use WpOrg\Requests\Ipv6;
     13use WpOrg\Requests\Port;
     14use WpOrg\Requests\Utility\InputValidator;
    815
    916/**
     
    3946 * POSSIBILITY OF SUCH DAMAGE.
    4047 *
    41  * @package Requests
    42  * @subpackage Utilities
     48 * @package Requests\Utilities
    4349 * @author Geoffrey Sneddon
    4450 * @author Steve Minutillo
    4551 * @copyright 2007-2009 Geoffrey Sneddon and Steve Minutillo
    46  * @license http://www.opensource.org/licenses/bsd-license.php
     52 * @license https://opensource.org/licenses/bsd-license.php
    4753 * @link http://hg.gsnedders.com/iri/
    4854 *
    4955 * @property string $iri IRI we're working with
    50  * @property-read string $uri IRI in URI form, {@see to_uri}
     56 * @property-read string $uri IRI in URI form, {@see \WpOrg\Requests\IRI::to_uri()}
    5157 * @property string $scheme Scheme part of the IRI
    5258 * @property string $authority Authority part, formatted for a URI (userinfo + host + port)
     
    6470 * @property string $ifragment Fragment part of the IRI (after '#')
    6571 */
    66 class Requests_IRI {
     72class Iri {
    6773    /**
    6874     * Scheme
     
    124130    protected $normalization = array(
    125131        'acap' => array(
    126             'port' => 674
     132            'port' => Port::ACAP,
    127133        ),
    128134        'dict' => array(
    129             'port' => 2628
     135            'port' => Port::DICT,
    130136        ),
    131137        'file' => array(
    132             'ihost' => 'localhost'
     138            'ihost' => 'localhost',
    133139        ),
    134140        'http' => array(
    135             'port' => 80,
     141            'port' => Port::HTTP,
    136142        ),
    137143        'https' => array(
    138             'port' => 443,
     144            'port' => Port::HTTPS,
    139145        ),
    140146    );
     
    241247     * Create a new IRI object, from a specified string
    242248     *
    243      * @param string|null $iri
     249     * @param string|Stringable|null $iri
     250     *
     251     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $iri argument is not a string, Stringable or null.
    244252     */
    245253    public function __construct($iri = null) {
     254        if ($iri !== null && InputValidator::is_string_or_stringable($iri) === false) {
     255            throw InvalidArgument::create(1, '$iri', 'string|Stringable|null', gettype($iri));
     256        }
     257
    246258        $this->set_iri($iri);
    247259    }
     
    252264     * Returns false if $base is not absolute, otherwise an IRI.
    253265     *
    254      * @param Requests_IRI|string $base (Absolute) Base IRI
    255      * @param Requests_IRI|string $relative Relative IRI
    256      * @return Requests_IRI|false
     266     * @param \WpOrg\Requests\Iri|string $base (Absolute) Base IRI
     267     * @param \WpOrg\Requests\Iri|string $relative Relative IRI
     268     * @return \WpOrg\Requests\Iri|false
    257269     */
    258270    public static function absolutize($base, $relative) {
    259         if (!($relative instanceof Requests_IRI)) {
    260             $relative = new Requests_IRI($relative);
     271        if (!($relative instanceof self)) {
     272            $relative = new self($relative);
    261273        }
    262274        if (!$relative->is_valid()) {
     
    267279        }
    268280
    269         if (!($base instanceof Requests_IRI)) {
    270             $base = new Requests_IRI($base);
     281        if (!($base instanceof self)) {
     282            $base = new self($base);
    271283        }
    272284        if ($base->scheme === null || !$base->is_valid()) {
     
    280292            }
    281293            else {
    282                 $target = new Requests_IRI;
     294                $target = new self;
    283295                $target->scheme = $base->scheme;
    284296                $target->iuserinfo = $base->iuserinfo;
     
    331343        $has_match = preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match);
    332344        if (!$has_match) {
    333             throw new Requests_Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri);
     345            throw new Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri);
    334346        }
    335347
     
    414426     * Replace invalid character with percent encoding
    415427     *
    416      * @param string $string Input string
     428     * @param string $text Input string
    417429     * @param string $extra_chars Valid characters not in iunreserved or
    418430     *                            iprivate (this is ASCII-only)
     
    420432     * @return string
    421433     */
    422     protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) {
     434    protected function replace_invalid_with_pct_encoding($text, $extra_chars, $iprivate = false) {
    423435        // Normalize as many pct-encoded sections as possible
    424         $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
     436        $text = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $text);
    425437
    426438        // Replace invalid percent characters
    427         $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
     439        $text = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $text);
    428440
    429441        // Add unreserved and % to $extra_chars (the latter is safe because all
     
    433445        // Now replace any bytes that aren't allowed with their pct-encoded versions
    434446        $position = 0;
    435         $strlen = strlen($string);
    436         while (($position += strspn($string, $extra_chars, $position)) < $strlen) {
    437             $value = ord($string[$position]);
     447        $strlen = strlen($text);
     448        while (($position += strspn($text, $extra_chars, $position)) < $strlen) {
     449            $value = ord($text[$position]);
    438450
    439451            // Start position
     
    472484                if ($position + $length <= $strlen) {
    473485                    for ($position++; $remaining; $position++) {
    474                         $value = ord($string[$position]);
     486                        $value = ord($text[$position]);
    475487
    476488                        // Check that the byte is valid, then add it to the character:
     
    523535
    524536                for ($j = $start; $j <= $position; $j++) {
    525                     $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
     537                    $text = substr_replace($text, sprintf('%%%02X', ord($text[$j])), $j, 1);
    526538                    $j += 2;
    527539                    $position += 2;
     
    531543        }
    532544
    533         return $string;
     545        return $text;
    534546    }
    535547
     
    540552     * encoded characters in iunreserved
    541553     *
    542      * @param array $match PCRE match
     554     * @param array $regex_match PCRE match
    543555     * @return string Replacement
    544556     */
    545     protected function remove_iunreserved_percent_encoded($match) {
     557    protected function remove_iunreserved_percent_encoded($regex_match) {
    546558        // As we just have valid percent encoded sequences we can just explode
    547559        // and ignore the first member of the returned array (an empty string).
    548         $bytes = explode('%', $match[0]);
     560        $bytes = explode('%', $regex_match[0]);
    549561
    550562        // Initialize the new string (this is what will be returned) and that
     
    722734            return true;
    723735        }
     736
     737        $iri = (string) $iri;
     738
    724739        if (isset($cache[$iri])) {
    725740            list($this->scheme,
     
    734749        }
    735750
    736         $parsed = $this->parse_iri((string) $iri);
     751        $parsed = $this->parse_iri($iri);
    737752
    738753        $return = $this->set_scheme($parsed['scheme'])
     
    864879        }
    865880        if (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') {
    866             if (Requests_IPv6::check_ipv6(substr($ihost, 1, -1))) {
    867                 $this->ihost = '[' . Requests_IPv6::compress(substr($ihost, 1, -1)) . ']';
     881            if (Ipv6::check_ipv6(substr($ihost, 1, -1))) {
     882                $this->ihost = '[' . Ipv6::compress(substr($ihost, 1, -1)) . ']';
    868883            }
    869884            else {
     
    9861001     * Convert an IRI to a URI (or parts thereof)
    9871002     *
    988      * @param string|bool IRI to convert (or false from {@see get_iri})
     1003     * @param string|bool $iri IRI to convert (or false from {@see \WpOrg\Requests\IRI::get_iri()})
    9891004     * @return string|false URI if IRI is valid, false otherwise.
    9901005     */
    991     protected function to_uri($string) {
    992         if (!is_string($string)) {
     1006    protected function to_uri($iri) {
     1007        if (!is_string($iri)) {
    9931008            return false;
    9941009        }
     
    10001015
    10011016        $position = 0;
    1002         $strlen = strlen($string);
    1003         while (($position += strcspn($string, $non_ascii, $position)) < $strlen) {
    1004             $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
     1017        $strlen = strlen($iri);
     1018        while (($position += strcspn($iri, $non_ascii, $position)) < $strlen) {
     1019            $iri = substr_replace($iri, sprintf('%%%02X', ord($iri[$position])), $position, 1);
    10051020            $position += 3;
    10061021            $strlen += 2;
    10071022        }
    10081023
    1009         return $string;
     1024        return $iri;
    10101025    }
    10111026
  • trunk/src/wp-includes/Requests/Proxy.php

    r50842 r52244  
    33 * Proxy connection interface
    44 *
    5  * @package Requests
    6  * @subpackage Proxy
    7  * @since 1.6
     5 * @package Requests\Proxy
     6 * @since   1.6
    87 */
     8
     9namespace WpOrg\Requests;
     10
     11use WpOrg\Requests\Hooks;
    912
    1013/**
     
    1619 * makes it much easier for users to use your provider.
    1720 *
    18  * @see Requests_Hooks
    19  * @package Requests
    20  * @subpackage Proxy
    21  * @since 1.6
     21 * @see \WpOrg\Requests\Hooks
     22 *
     23 * @package Requests\Proxy
     24 * @since   1.6
    2225 */
    23 interface Requests_Proxy {
     26interface Proxy {
    2427    /**
    2528     * Register hooks as needed
    2629     *
    27      * This method is called in {@see Requests::request} when the user has set
    28      * an instance as the 'auth' option. Use this callback to register all the
     30     * This method is called in {@see \WpOrg\Requests\Requests::request()} when the user
     31     * has set an instance as the 'auth' option. Use this callback to register all the
    2932     * hooks you'll need.
    3033     *
    31      * @see Requests_Hooks::register
    32      * @param Requests_Hooks $hooks Hook system
     34     * @see \WpOrg\Requests\Hooks::register()
     35     * @param \WpOrg\Requests\Hooks $hooks Hook system
    3336     */
    34     public function register(Requests_Hooks $hooks);
     37    public function register(Hooks $hooks);
    3538}
  • trunk/src/wp-includes/Requests/Proxy/Http.php

    r52243 r52244  
    33 * HTTP Proxy connection interface
    44 *
    5  * @package Requests
    6  * @subpackage Proxy
    7  * @since 1.6
     5 * @package Requests\Proxy
     6 * @since   1.6
    87 */
     8
     9namespace WpOrg\Requests\Proxy;
     10
     11use WpOrg\Requests\Exception\ArgumentCount;
     12use WpOrg\Requests\Exception\InvalidArgument;
     13use WpOrg\Requests\Hooks;
     14use WpOrg\Requests\Proxy;
    915
    1016/**
     
    1319 * Provides a handler for connection via an HTTP proxy
    1420 *
    15  * @package Requests
    16  * @subpackage Proxy
    17  * @since 1.6
     21 * @package Requests\Proxy
     22 * @since   1.6
    1823 */
    19 class Requests_Proxy_HTTP implements Requests_Proxy {
     24final class Http implements Proxy {
    2025    /**
    2126     * Proxy host and port
     
    5257     *
    5358     * @since 1.6
    54      * @throws Requests_Exception On incorrect number of arguments (`authbasicbadargs`)
    55      * @param array|null $args Array of user and password. Must have exactly two elements
     59     *
     60     * @param array|string|null $args Proxy as a string or an array of proxy, user and password.
     61     *                                When passed as an array, must have exactly one (proxy)
     62     *                                or three elements (proxy, user, password).
     63     *
     64     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not an array, a string or null.
     65     * @throws \WpOrg\Requests\Exception\ArgumentCount On incorrect number of arguments (`proxyhttpbadargs`)
    5666     */
    5767    public function __construct($args = null) {
     
    6878            }
    6979            else {
    70                 throw new Requests_Exception('Invalid number of arguments', 'proxyhttpbadargs');
     80                throw ArgumentCount::create(
     81                    'an array with exactly one element or exactly three elements',
     82                    count($args),
     83                    'proxyhttpbadargs'
     84                );
    7185            }
     86        } elseif ($args !== null) {
     87            throw InvalidArgument::create(1, '$args', 'array|string|null', gettype($args));
    7288        }
    7389    }
     
    7793     *
    7894     * @since 1.6
    79      * @see curl_before_send
    80      * @see fsockopen_remote_socket
    81      * @see fsockopen_remote_host_path
    82      * @see fsockopen_header
    83      * @param Requests_Hooks $hooks Hook system
     95     * @see \WpOrg\Requests\Proxy\HTTP::curl_before_send()
     96     * @see \WpOrg\Requests\Proxy\HTTP::fsockopen_remote_socket()
     97     * @see \WpOrg\Requests\Proxy\HTTP::fsockopen_remote_host_path()
     98     * @see \WpOrg\Requests\Proxy\HTTP::fsockopen_header()
     99     * @param \WpOrg\Requests\Hooks $hooks Hook system
    84100     */
    85     public function register(Requests_Hooks $hooks) {
    86         $hooks->register('curl.before_send', array($this, 'curl_before_send'));
     101    public function register(Hooks $hooks) {
     102        $hooks->register('curl.before_send', [$this, 'curl_before_send']);
    87103
    88         $hooks->register('fsockopen.remote_socket', array($this, 'fsockopen_remote_socket'));
    89         $hooks->register('fsockopen.remote_host_path', array($this, 'fsockopen_remote_host_path'));
     104        $hooks->register('fsockopen.remote_socket', [$this, 'fsockopen_remote_socket']);
     105        $hooks->register('fsockopen.remote_host_path', [$this, 'fsockopen_remote_host_path']);
    90106        if ($this->use_authentication) {
    91             $hooks->register('fsockopen.after_headers', array($this, 'fsockopen_header'));
     107            $hooks->register('fsockopen.after_headers', [$this, 'fsockopen_header']);
    92108        }
    93109    }
     
    97113     *
    98114     * @since 1.6
    99      * @param resource $handle cURL resource
     115     * @param resource|\CurlHandle $handle cURL handle
    100116     */
    101117    public function curl_before_send(&$handle) {
  • trunk/src/wp-includes/Requests/Requests.php

    r52243 r52244  
    1010 */
    1111
     12namespace WpOrg\Requests;
     13
     14use WpOrg\Requests\Auth\Basic;
     15use WpOrg\Requests\Capability;
     16use WpOrg\Requests\Cookie\Jar;
     17use WpOrg\Requests\Exception;
     18use WpOrg\Requests\Exception\InvalidArgument;
     19use WpOrg\Requests\Hooks;
     20use WpOrg\Requests\IdnaEncoder;
     21use WpOrg\Requests\Iri;
     22use WpOrg\Requests\Proxy\Http;
     23use WpOrg\Requests\Response;
     24use WpOrg\Requests\Transport\Curl;
     25use WpOrg\Requests\Transport\Fsockopen;
     26use WpOrg\Requests\Utility\InputValidator;
     27
    1228/**
    1329 * Requests for PHP
     
    85101
    86102    /**
     103     * Option defaults.
     104     *
     105     * @see \WpOrg\Requests\Requests::get_default_options()
     106     * @see \WpOrg\Requests\Requests::request() for values returned by this method
     107     *
     108     * @since 2.0.0
     109     *
     110     * @var array
     111     */
     112    const OPTION_DEFAULTS = [
     113        'timeout'          => 10,
     114        'connect_timeout'  => 10,
     115        'useragent'        => 'php-requests/' . self::VERSION,
     116        'protocol_version' => 1.1,
     117        'redirected'       => 0,
     118        'redirects'        => 10,
     119        'follow_redirects' => true,
     120        'blocking'         => true,
     121        'type'             => self::GET,
     122        'filename'         => false,
     123        'auth'             => false,
     124        'proxy'            => false,
     125        'cookies'          => false,
     126        'max_bytes'        => false,
     127        'idn'              => true,
     128        'hooks'            => null,
     129        'transport'        => null,
     130        'verify'           => null,
     131        'verifyname'       => true,
     132    ];
     133
     134    /**
     135     * Default supported Transport classes.
     136     *
     137     * @since 2.0.0
     138     *
     139     * @var array
     140     */
     141    const DEFAULT_TRANSPORTS = [
     142        Curl::class      => Curl::class,
     143        Fsockopen::class => Fsockopen::class,
     144    ];
     145
     146    /**
    87147     * Current version of Requests
    88148     *
    89149     * @var string
    90150     */
    91     const VERSION = '1.8.1';
     151    const VERSION = '2.0.0';
     152
     153    /**
     154     * Selected transport name
     155     *
     156     * Use {@see \WpOrg\Requests\Requests::get_transport()} instead
     157     *
     158     * @var array
     159     */
     160    public static $transport = [];
    92161
    93162    /**
     
    96165     * @var array
    97166     */
    98     protected static $transports = array();
    99 
    100     /**
    101      * Selected transport name
    102      *
    103      * Use {@see get_transport()} instead
     167    protected static $transports = [];
     168
     169    /**
     170     * Default certificate path.
     171     *
     172     * @see \WpOrg\Requests\Requests::get_certificate_path()
     173     * @see \WpOrg\Requests\Requests::set_certificate_path()
     174     *
     175     * @var string
     176     */
     177    protected static $certificate_path = __DIR__ . '/../certificates/cacert.pem';
     178
     179    /**
     180     * All (known) valid deflate, gzip header magic markers.
     181     *
     182     * These markers relate to different compression levels.
     183     *
     184     * @link https://stackoverflow.com/a/43170354/482864 Marker source.
     185     *
     186     * @since 2.0.0
    104187     *
    105188     * @var array
    106189     */
    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;
     190    private static $magic_compression_headers = [
     191        "\x1f\x8b" => true, // Gzip marker.
     192        "\x78\x01" => true, // Zlib marker - level 1.
     193        "\x78\x5e" => true, // Zlib marker - level 2 to 5.
     194        "\x78\x9c" => true, // Zlib marker - level 6.
     195        "\x78\xda" => true, // Zlib marker - level 7 to 9.
     196    ];
    118197
    119198    /**
     
    125204
    126205    /**
    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.)
    133      *
    134      * @codeCoverageIgnore
    135      *
    136      * @param string $class Class name to load
    137      */
    138     public static function autoloader($class) {
    139         // Check that the class starts with "Requests"
    140         if (strpos($class, 'Requests') !== 0) {
    141             return;
    142         }
    143 
    144         $file = str_replace('_', '/', $class);
    145         if (file_exists(dirname(__FILE__) . '/' . $file . '.php')) {
    146             require_once dirname(__FILE__) . '/' . $file . '.php';
    147         }
    148     }
    149 
    150     /**
    151      * Register the built-in autoloader
    152      *
    153      * @codeCoverageIgnore
    154      */
    155     public static function register_autoloader() {
    156         spl_autoload_register(array('Requests', 'autoloader'));
    157     }
    158 
    159     /**
    160206     * Register a transport
    161207     *
    162      * @param string $transport Transport class to add, must support the Requests_Transport interface
     208     * @param string $transport Transport class to add, must support the \WpOrg\Requests\Transport interface
    163209     */
    164210    public static function add_transport($transport) {
    165211        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
     212            self::$transports = self::DEFAULT_TRANSPORTS;
     213        }
     214
     215        self::$transports[$transport] = $transport;
     216    }
     217
     218    /**
     219     * Get the fully qualified class name (FQCN) for a working transport.
     220     *
     221     * @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
     222     * @return string FQCN of the transport to use, or an empty string if no transport was
     223     *                found which provided the requested capabilities.
     224     */
     225    protected static function get_transport_class(array $capabilities = []) {
     226        // Caching code, don't bother testing coverage.
    183227        // @codeCoverageIgnoreStart
    184         // array of capabilities as a string to be used as an array key
     228        // Array of capabilities as a string to be used as an array key.
    185229        ksort($capabilities);
    186230        $cap_string = serialize($capabilities);
    187231
    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         }
     232        // Don't search for a transport if it's already been done for these $capabilities.
     233        if (isset(self::$transport[$cap_string])) {
     234            return self::$transport[$cap_string];
     235        }
     236
     237        // Ensure we will not run this same check again later on.
     238        self::$transport[$cap_string] = '';
    193239        // @codeCoverageIgnoreEnd
    194240
    195241        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
     242            self::$transports = self::DEFAULT_TRANSPORTS;
     243        }
     244
     245        // Find us a working transport.
    203246        foreach (self::$transports as $class) {
    204247            if (!class_exists($class)) {
     
    206249            }
    207250
    208             $result = call_user_func(array($class, 'test'), $capabilities);
    209             if ($result) {
     251            $result = $class::test($capabilities);
     252            if ($result === true) {
    210253                self::$transport[$cap_string] = $class;
    211254                break;
    212255            }
    213256        }
    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];
     257
     258        return self::$transport[$cap_string];
     259    }
     260
     261    /**
     262     * Get a working transport.
     263     *
     264     * @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
     265     * @return \WpOrg\Requests\Transport
     266     * @throws \WpOrg\Requests\Exception If no valid transport is found (`notransport`).
     267     */
     268    protected static function get_transport(array $capabilities = []) {
     269        $class = self::get_transport_class($capabilities);
     270
     271        if ($class === '') {
     272            throw new Exception('No working transports found', 'notransport', self::$transports);
     273        }
     274
    219275        return new $class();
    220276    }
    221277
     278    /**
     279     * Checks to see if we have a transport for the capabilities requested.
     280     *
     281     * Supported capabilities can be found in the {@see \WpOrg\Requests\Capability}
     282     * interface as constants.
     283     *
     284     * Example usage:
     285     * `Requests::has_capabilities([Capability::SSL => true])`.
     286     *
     287     * @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
     288     * @return bool Whether the transport has the requested capabilities.
     289     */
     290    public static function has_capabilities(array $capabilities = []) {
     291        return self::get_transport_class($capabilities) !== '';
     292    }
     293
    222294    /**#@+
    223      * @see request()
     295     * @see \WpOrg\Requests\Requests::request()
    224296     * @param string $url
    225297     * @param array $headers
    226298     * @param array $options
    227      * @return Requests_Response
     299     * @return \WpOrg\Requests\Response
    228300     */
    229301    /**
    230302     * Send a GET request
    231303     */
    232     public static function get($url, $headers = array(), $options = array()) {
     304    public static function get($url, $headers = [], $options = []) {
    233305        return self::request($url, $headers, null, self::GET, $options);
    234306    }
     
    237309     * Send a HEAD request
    238310     */
    239     public static function head($url, $headers = array(), $options = array()) {
     311    public static function head($url, $headers = [], $options = []) {
    240312        return self::request($url, $headers, null, self::HEAD, $options);
    241313    }
     
    244316     * Send a DELETE request
    245317     */
    246     public static function delete($url, $headers = array(), $options = array()) {
     318    public static function delete($url, $headers = [], $options = []) {
    247319        return self::request($url, $headers, null, self::DELETE, $options);
    248320    }
     
    251323     * Send a TRACE request
    252324     */
    253     public static function trace($url, $headers = array(), $options = array()) {
     325    public static function trace($url, $headers = [], $options = []) {
    254326        return self::request($url, $headers, null, self::TRACE, $options);
    255327    }
     
    257329
    258330    /**#@+
    259      * @see request()
     331     * @see \WpOrg\Requests\Requests::request()
    260332     * @param string $url
    261333     * @param array $headers
    262334     * @param array $data
    263335     * @param array $options
    264      * @return Requests_Response
     336     * @return \WpOrg\Requests\Response
    265337     */
    266338    /**
    267339     * Send a POST request
    268340     */
    269     public static function post($url, $headers = array(), $data = array(), $options = array()) {
     341    public static function post($url, $headers = [], $data = [], $options = []) {
    270342        return self::request($url, $headers, $data, self::POST, $options);
    271343    }
     
    273345     * Send a PUT request
    274346     */
    275     public static function put($url, $headers = array(), $data = array(), $options = array()) {
     347    public static function put($url, $headers = [], $data = [], $options = []) {
    276348        return self::request($url, $headers, $data, self::PUT, $options);
    277349    }
     
    280352     * Send an OPTIONS request
    281353     */
    282     public static function options($url, $headers = array(), $data = array(), $options = array()) {
     354    public static function options($url, $headers = [], $data = [], $options = []) {
    283355        return self::request($url, $headers, $data, self::OPTIONS, $options);
    284356    }
     
    287359     * Send a PATCH request
    288360     *
    289      * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the
    290      * specification recommends that should send an ETag
     361     * Note: Unlike {@see \WpOrg\Requests\Requests::post()} and {@see \WpOrg\Requests\Requests::put()},
     362     * `$headers` is required, as the specification recommends that should send an ETag
    291363     *
    292364     * @link https://tools.ietf.org/html/rfc5789
    293365     */
    294     public static function patch($url, $headers, $data = array(), $options = array()) {
     366    public static function patch($url, $headers, $data = [], $options = []) {
    295367        return self::request($url, $headers, $data, self::PATCH, $options);
    296368    }
     
    324396     * - `auth`: Authentication handler or array of user/password details to use
    325397     *    for Basic authentication
    326      *    (Requests_Auth|array|boolean, default: false)
     398     *    (\WpOrg\Requests\Auth|array|boolean, default: false)
    327399     * - `proxy`: Proxy details to use for proxy by-passing and authentication
    328      *    (Requests_Proxy|array|string|boolean, default: false)
     400     *    (\WpOrg\Requests\Proxy|array|string|boolean, default: false)
    329401     * - `max_bytes`: Limit for the response body size.
    330402     *    (integer|boolean, default: false)
     
    333405     * - `transport`: Custom transport. Either a class name, or a
    334406     *    transport object. Defaults to the first working transport from
    335      *    {@see getTransport()}
    336      *    (string|Requests_Transport, default: {@see getTransport()})
     407     *    {@see \WpOrg\Requests\Requests::getTransport()}
     408     *    (string|\WpOrg\Requests\Transport, default: {@see \WpOrg\Requests\Requests::getTransport()})
    337409     * - `hooks`: Hooks handler.
    338      *    (Requests_Hooker, default: new Requests_Hooks())
     410     *    (\WpOrg\Requests\HookManager, default: new WpOrg\Requests\Hooks())
    339411     * - `verify`: Should we verify SSL certificates? Allows passing in a custom
    340412     *    certificate file as a string. (Using true uses the system-wide root
    341413     *    certificate store instead, but this may have different behaviour
    342414     *    across transports.)
    343      *    (string|boolean, default: library/Requests/Transport/cacert.pem)
     415     *    (string|boolean, default: certificates/cacert.pem)
    344416     * - `verifyname`: Should we verify the common name in the SSL certificate?
    345417     *    (boolean, default: true)
     
    348420     *    HEAD/GET/DELETE, 'body' for POST/PUT/OPTIONS/PATCH)
    349421     *
    350      * @throws Requests_Exception On invalid URLs (`nonhttp`)
    351      *
    352      * @param string $url URL to request
     422     * @param string|Stringable $url URL to request
    353423     * @param array $headers Extra headers to send with the request
    354424     * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
    355425     * @param string $type HTTP request type (use Requests constants)
    356426     * @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()) {
     427     * @return \WpOrg\Requests\Response
     428     *
     429     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable.
     430     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $type argument is not a string.
     431     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
     432     * @throws \WpOrg\Requests\Exception On invalid URLs (`nonhttp`)
     433     */
     434    public static function request($url, $headers = [], $data = [], $type = self::GET, $options = []) {
     435        if (InputValidator::is_string_or_stringable($url) === false) {
     436            throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url));
     437        }
     438
     439        if (is_string($type) === false) {
     440            throw InvalidArgument::create(4, '$type', 'string', gettype($type));
     441        }
     442
     443        if (is_array($options) === false) {
     444            throw InvalidArgument::create(5, '$options', 'array', gettype($options));
     445        }
     446
    360447        if (empty($options['type'])) {
    361448            $options['type'] = $type;
     
    365452        self::set_defaults($url, $headers, $data, $type, $options);
    366453
    367         $options['hooks']->dispatch('requests.before_request', array(&$url, &$headers, &$data, &$type, &$options));
     454        $options['hooks']->dispatch('requests.before_request', [&$url, &$headers, &$data, &$type, &$options]);
    368455
    369456        if (!empty($options['transport'])) {
     
    376463        else {
    377464            $need_ssl     = (stripos($url, 'https://') === 0);
    378             $capabilities = array('ssl' => $need_ssl);
     465            $capabilities = [Capability::SSL => $need_ssl];
    379466            $transport    = self::get_transport($capabilities);
    380467        }
    381468        $response = $transport->request($url, $headers, $data, $options);
    382469
    383         $options['hooks']->dispatch('requests.before_parse', array(&$response, $url, $headers, $data, $type, $options));
     470        $options['hooks']->dispatch('requests.before_parse', [&$response, $url, $headers, $data, $type, $options]);
    384471
    385472        return self::parse_response($response, $url, $headers, $data, $options);
     
    397484     *
    398485     * - `url`: Request URL Same as the `$url` parameter to
    399      *    {@see Requests::request}
     486     *    {@see \WpOrg\Requests\Requests::request()}
    400487     *    (string, required)
    401488     * - `headers`: Associative array of header fields. Same as the `$headers`
    402      *    parameter to {@see Requests::request}
     489     *    parameter to {@see \WpOrg\Requests\Requests::request()}
    403490     *    (array, default: `array()`)
    404491     * - `data`: Associative array of data fields or a string. Same as the
    405      *    `$data` parameter to {@see Requests::request}
     492     *    `$data` parameter to {@see \WpOrg\Requests\Requests::request()}
    406493     *    (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`)
     494     * - `type`: HTTP request type (use \WpOrg\Requests\Requests constants). Same as the `$type`
     495     *    parameter to {@see \WpOrg\Requests\Requests::request()}
     496     *    (string, default: `\WpOrg\Requests\Requests::GET`)
    410497     * - `cookies`: Associative array of cookie name to value, or cookie jar.
    411      *    (array|Requests_Cookie_Jar)
     498     *    (array|\WpOrg\Requests\Cookie\Jar)
    412499     *
    413500     * If the `$options` parameter is specified, individual requests will
    414501     * 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.
     502     * or set all the types to `\WpOrg\Requests\Requests::POST`, for example.
    416503     *
    417504     * In addition, the `$options` parameter takes the following global options:
    418505     *
    419506     * - `complete`: A callback for when a request is complete. Takes two
    420      *    parameters, a Requests_Response/Requests_Exception reference, and the
     507     *    parameters, a \WpOrg\Requests\Response/\WpOrg\Requests\Exception reference, and the
    421508     *    ID from the request array (Note: this can also be overridden on a
    422509     *    per-request basis, although that's a little silly)
     
    424511     *
    425512     * @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()) {
     513     * @param array $options Global and default options (see {@see \WpOrg\Requests\Requests::request()})
     514     * @return array Responses (either \WpOrg\Requests\Response or a \WpOrg\Requests\Exception object)
     515     *
     516     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
     517     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
     518     */
     519    public static function request_multiple($requests, $options = []) {
     520        if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
     521            throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
     522        }
     523
     524        if (is_array($options) === false) {
     525            throw InvalidArgument::create(2, '$options', 'array', gettype($options));
     526        }
     527
    430528        $options = array_merge(self::get_default_options(true), $options);
    431529
    432530        if (!empty($options['hooks'])) {
    433             $options['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
     531            $options['hooks']->register('transport.internal.parse_response', [static::class, 'parse_multiple']);
    434532            if (!empty($options['complete'])) {
    435533                $options['hooks']->register('multiple.request.complete', $options['complete']);
     
    439537        foreach ($requests as $id => &$request) {
    440538            if (!isset($request['headers'])) {
    441                 $request['headers'] = array();
     539                $request['headers'] = [];
    442540            }
    443541            if (!isset($request['data'])) {
    444                 $request['data'] = array();
     542                $request['data'] = [];
    445543            }
    446544            if (!isset($request['type'])) {
     
    462560            // Ensure we only hook in once
    463561            if ($request['options']['hooks'] !== $options['hooks']) {
    464                 $request['options']['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
     562                $request['options']['hooks']->register('transport.internal.parse_response', [static::class, 'parse_multiple']);
    465563                if (!empty($request['options']['complete'])) {
    466564                    $request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']);
     
    488586                $request = $requests[$id];
    489587                self::parse_multiple($response, $request);
    490                 $request['options']['hooks']->dispatch('multiple.request.complete', array(&$response, $id));
     588                $request['options']['hooks']->dispatch('multiple.request.complete', [&$response, $id]);
    491589            }
    492590        }
     
    498596     * Get the default options
    499597     *
    500      * @see Requests::request() for values returned by this method
     598     * @see \WpOrg\Requests\Requests::request() for values returned by this method
    501599     * @param boolean $multirequest Is this a multirequest?
    502600     * @return array Default option values
    503601     */
    504602    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         );
     603        $defaults           = static::OPTION_DEFAULTS;
     604        $defaults['verify'] = self::$certificate_path;
     605
    526606        if ($multirequest !== false) {
    527607            $defaults['complete'] = null;
     
    536616     */
    537617    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';
     618        return self::$certificate_path;
    543619    }
    544620
     
    546622     * Set default certificate path.
    547623     *
    548      * @param string $path Certificate path, pointing to a PEM file.
     624     * @param string|Stringable|bool $path Certificate path, pointing to a PEM file.
     625     *
     626     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string, Stringable or boolean.
    549627     */
    550628    public static function set_certificate_path($path) {
     629        if (InputValidator::is_string_or_stringable($path) === false && is_bool($path) === false) {
     630            throw InvalidArgument::create(1, '$path', 'string|Stringable|bool', gettype($path));
     631        }
     632
    551633        self::$certificate_path = $path;
    552634    }
     
    560642     * @param string $type HTTP request type
    561643     * @param array $options Options for the request
    562      * @return array $options
     644     * @return void $options is updated with the results
     645     *
     646     * @throws \WpOrg\Requests\Exception When the $url is not an http(s) URL.
    563647     */
    564648    protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) {
    565649        if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) {
    566             throw new Requests_Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url);
     650            throw new Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url);
    567651        }
    568652
    569653        if (empty($options['hooks'])) {
    570             $options['hooks'] = new Requests_Hooks();
     654            $options['hooks'] = new Hooks();
    571655        }
    572656
    573657        if (is_array($options['auth'])) {
    574             $options['auth'] = new Requests_Auth_Basic($options['auth']);
     658            $options['auth'] = new Basic($options['auth']);
    575659        }
    576660        if ($options['auth'] !== false) {
     
    579663
    580664        if (is_string($options['proxy']) || is_array($options['proxy'])) {
    581             $options['proxy'] = new Requests_Proxy_HTTP($options['proxy']);
     665            $options['proxy'] = new Http($options['proxy']);
    582666        }
    583667        if ($options['proxy'] !== false) {
     
    586670
    587671        if (is_array($options['cookies'])) {
    588             $options['cookies'] = new Requests_Cookie_Jar($options['cookies']);
     672            $options['cookies'] = new Jar($options['cookies']);
    589673        }
    590674        elseif (empty($options['cookies'])) {
    591             $options['cookies'] = new Requests_Cookie_Jar();
     675            $options['cookies'] = new Jar();
    592676        }
    593677        if ($options['cookies'] !== false) {
     
    596680
    597681        if ($options['idn'] !== false) {
    598             $iri       = new Requests_IRI($url);
    599             $iri->host = Requests_IDNAEncoder::encode($iri->ihost);
     682            $iri       = new Iri($url);
     683            $iri->host = IdnaEncoder::encode($iri->ihost);
    600684            $url       = $iri->uri;
    601685        }
     
    605689
    606690        if (!isset($options['data_format'])) {
    607             if (in_array($type, array(self::HEAD, self::GET, self::DELETE), true)) {
     691            if (in_array($type, [self::HEAD, self::GET, self::DELETE], true)) {
    608692                $options['data_format'] = 'query';
    609693            }
     
    616700    /**
    617701     * 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`)
    622702     *
    623703     * @param string $headers Full response text including headers and body
     
    626706     * @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects
    627707     * @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects
    628      * @return Requests_Response
     708     * @return \WpOrg\Requests\Response
     709     *
     710     * @throws \WpOrg\Requests\Exception On missing head/body separator (`requests.no_crlf_separator`)
     711     * @throws \WpOrg\Requests\Exception On missing head/body separator (`noversion`)
     712     * @throws \WpOrg\Requests\Exception On missing head/body separator (`toomanyredirects`)
    629713     */
    630714    protected static function parse_response($headers, $url, $req_headers, $req_data, $options) {
    631         $return = new Requests_Response();
     715        $return = new Response();
    632716        if (!$options['blocking']) {
    633717            return $return;
     
    642726            if ($pos === false) {
    643727                // Crap!
    644                 throw new Requests_Exception('Missing header/body separator', 'requests.no_crlf_separator');
     728                throw new Exception('Missing header/body separator', 'requests.no_crlf_separator');
    645729            }
    646730
     
    659743        preg_match('#^HTTP/(1\.\d)[ \t]+(\d+)#i', array_shift($headers), $matches);
    660744        if (empty($matches)) {
    661             throw new Requests_Exception('Response could not be parsed', 'noversion', $headers);
     745            throw new Exception('Response could not be parsed', 'noversion', $headers);
    662746        }
    663747        $return->protocol_version = (float) $matches[1];
     
    686770        }
    687771
    688         $options['hooks']->dispatch('requests.before_redirect_check', array(&$return, $req_headers, $req_data, $options));
     772        $options['hooks']->dispatch('requests.before_redirect_check', [&$return, $req_headers, $req_data, $options]);
    689773
    690774        if ($return->is_redirect() && $options['follow_redirects'] === true) {
     
    697781                if (strpos($location, 'http://') !== 0 && strpos($location, 'https://') !== 0) {
    698782                    // relative redirect, for compatibility make it absolute
    699                     $location = Requests_IRI::absolutize($url, $location);
     783                    $location = Iri::absolutize($url, $location);
    700784                    $location = $location->uri;
    701785                }
    702786
    703                 $hook_args = array(
     787                $hook_args = [
    704788                    &$location,
    705789                    &$req_headers,
     
    707791                    &$options,
    708792                    $return,
    709                 );
     793                ];
    710794                $options['hooks']->dispatch('requests.before_redirect', $hook_args);
    711795                $redirected            = self::request($location, $req_headers, $req_data, $options['type'], $options);
     
    714798            }
    715799            elseif ($options['redirected'] >= $options['redirects']) {
    716                 throw new Requests_Exception('Too many redirects', 'toomanyredirects', $return);
     800                throw new Exception('Too many redirects', 'toomanyredirects', $return);
    717801            }
    718802        }
     
    720804        $return->redirects = $options['redirected'];
    721805
    722         $options['hooks']->dispatch('requests.after_request', array(&$return, $req_headers, $req_data, $options));
     806        $options['hooks']->dispatch('requests.after_request', [&$return, $req_headers, $req_data, $options]);
    723807        return $return;
    724808    }
     
    727811     * Callback for `transport.internal.parse_response`
    728812     *
    729      * Internal use only. Converts a raw HTTP response to a Requests_Response
     813     * Internal use only. Converts a raw HTTP response to a \WpOrg\Requests\Response
    730814     * while still executing a multiple request.
    731815     *
    732816     * @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
     817     * @param array $request Request data as passed into {@see \WpOrg\Requests\Requests::request_multiple()}
     818     * @return void `$response` is either set to a \WpOrg\Requests\Response instance, or a \WpOrg\Requests\Exception object
    735819     */
    736820    public static function parse_multiple(&$response, $request) {
     
    742826            $response = self::parse_response($response, $url, $headers, $data, $options);
    743827        }
    744         catch (Requests_Exception $e) {
     828        catch (Exception $e) {
    745829            $response = $e;
    746830        }
     
    750834     * Decoded a chunked body as per RFC 2616
    751835     *
    752      * @see https://tools.ietf.org/html/rfc2616#section-3.6.1
     836     * @link https://tools.ietf.org/html/rfc2616#section-3.6.1
    753837     * @param string $data Chunked body
    754838     * @return string Decoded body
     
    792876     * Convert a key => value array to a 'key: value' array for headers
    793877     *
    794      * @param array $array Dictionary of header values
     878     * @param iterable $dictionary Dictionary of header values
    795879     * @return array List of headers
    796      */
    797     public static function flatten($array) {
    798         $return = array();
    799         foreach ($array as $key => $value) {
     880     *
     881     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not iterable.
     882     */
     883    public static function flatten($dictionary) {
     884        if (InputValidator::is_iterable($dictionary) === false) {
     885            throw InvalidArgument::create(1, '$dictionary', 'iterable', gettype($dictionary));
     886        }
     887
     888        $return = [];
     889        foreach ($dictionary as $key => $value) {
    800890            $return[] = sprintf('%s: %s', $key, $value);
    801891        }
    802892        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);
    815893    }
    816894
     
    823901     * @param string $data Compressed data in one of the above formats
    824902     * @return string Decompressed string
     903     *
     904     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string.
    825905     */
    826906    public static function decompress($data) {
    827         if (substr($data, 0, 2) !== "\x1f\x8b" && substr($data, 0, 2) !== "\x78\x9c") {
     907        if (is_string($data) === false) {
     908            throw InvalidArgument::create(1, '$data', 'string', gettype($data));
     909        }
     910
     911        if (trim($data) === '') {
     912            // Empty body does not need further processing.
     913            return $data;
     914        }
     915
     916        $marker = substr($data, 0, 2);
     917        if (!isset(self::$magic_compression_headers[$marker])) {
    828918            // Not actually compressed. Probably cURL ruining this for us.
    829919            return $data;
     
    831921
    832922        if (function_exists('gzdecode')) {
    833             // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.gzdecodeFound -- Wrapped in function_exists() for PHP 5.2.
    834923            $decoded = @gzdecode($data);
    835924            if ($decoded !== false) {
     
    872961     * https://core.trac.wordpress.org/ticket/18273
    873962     *
    874      * @since 2.8.1
     963     * @since 1.6.0
    875964     * @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
     965     * @link https://www.php.net/gzinflate#70875
     966     * @link https://www.php.net/gzinflate#77336
    878967     *
    879968     * @param string $gz_data String to decompress.
    880969     * @return string|bool False on failure.
     970     *
     971     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string.
    881972     */
    882973    public static function compatible_gzinflate($gz_data) {
     974        if (is_string($gz_data) === false) {
     975            throw InvalidArgument::create(1, '$gz_data', 'string', gettype($gz_data));
     976        }
     977
     978        if (trim($gz_data) === '') {
     979            return false;
     980        }
     981
    883982        // Compressed data might contain a full zlib header, if so strip it for
    884983        // gzinflate()
     
    9101009        // byte Huffman marker for gzinflate()
    9111010        // The response is Huffman coded by many compressors such as
    912         // java.util.zip.Deflater, Rubys Zlib::Deflate, and .NET's
     1011        // java.util.zip.Deflater, Ruby's Zlib::Deflate, and .NET's
    9131012        // System.IO.Compression.DeflateStream.
    9141013        //
     
    9781077        return false;
    9791078    }
    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;
    1000     }
    10011079}
  • trunk/src/wp-includes/Requests/Response.php

    r50842 r52244  
    33 * HTTP response class
    44 *
    5  * Contains a response from Requests::request()
     5 * Contains a response from \WpOrg\Requests\Requests::request()
     6 *
    67 * @package Requests
    78 */
     9
     10namespace WpOrg\Requests;
     11
     12use WpOrg\Requests\Cookie\Jar;
     13use WpOrg\Requests\Exception;
     14use WpOrg\Requests\Exception\Http;
     15use WpOrg\Requests\Response\Headers;
    816
    917/**
    1018 * HTTP response class
    1119 *
    12  * Contains a response from Requests::request()
     20 * Contains a response from \WpOrg\Requests\Requests::request()
     21 *
    1322 * @package Requests
    1423 */
    15 class Requests_Response {
    16     /**
    17      * Constructor
    18      */
    19     public function __construct() {
    20         $this->headers = new Requests_Response_Headers();
    21         $this->cookies = new Requests_Cookie_Jar();
    22     }
     24class Response {
    2325
    2426    /**
     
    3941     * Headers, as an associative array
    4042     *
    41      * @var Requests_Response_Headers Array-like object representing headers
     43     * @var \WpOrg\Requests\Response\Headers Array-like object representing headers
    4244     */
    43     public $headers = array();
     45    public $headers = [];
    4446
    4547    /**
     
    8183     * Previous requests (from redirects)
    8284     *
    83      * @var array Array of Requests_Response objects
     85     * @var array Array of \WpOrg\Requests\Response objects
    8486     */
    85     public $history = array();
     87    public $history = [];
    8688
    8789    /**
    8890     * Cookies from the request
    8991     *
    90      * @var Requests_Cookie_Jar Array-like object representing a cookie jar
     92     * @var \WpOrg\Requests\Cookie\Jar Array-like object representing a cookie jar
    9193     */
    92     public $cookies = array();
     94    public $cookies = [];
     95
     96    /**
     97     * Constructor
     98     */
     99    public function __construct() {
     100        $this->headers = new Headers();
     101        $this->cookies = new Jar();
     102    }
    93103
    94104    /**
     
    99109    public function is_redirect() {
    100110        $code = $this->status_code;
    101         return in_array($code, array(300, 301, 302, 303, 307), true) || $code > 307 && $code < 400;
     111        return in_array($code, [300, 301, 302, 303, 307], true) || $code > 307 && $code < 400;
    102112    }
    103113
     
    105115     * Throws an exception if the request was not successful
    106116     *
    107      * @throws Requests_Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`)
    108      * @throws Requests_Exception_HTTP On non-successful status code. Exception class corresponds to code (e.g. {@see Requests_Exception_HTTP_404})
    109117     * @param boolean $allow_redirects Set to false to throw on a 3xx as well
     118     *
     119     * @throws \WpOrg\Requests\Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`)
     120     * @throws \WpOrg\Requests\Exception\Http On non-successful status code. Exception class corresponds to "Status" + code (e.g. {@see \WpOrg\Requests\Exception\Http\Status404})
    110121     */
    111122    public function throw_for_status($allow_redirects = true) {
    112123        if ($this->is_redirect()) {
    113             if (!$allow_redirects) {
    114                 throw new Requests_Exception('Redirection not allowed', 'response.no_redirects', $this);
     124            if ($allow_redirects !== true) {
     125                throw new Exception('Redirection not allowed', 'response.no_redirects', $this);
    115126            }
    116127        }
    117128        elseif (!$this->success) {
    118             $exception = Requests_Exception_HTTP::get_class($this->status_code);
     129            $exception = Http::get_class($this->status_code);
    119130            throw new $exception(null, $this);
    120131        }
    121132    }
     133
     134    /**
     135     * JSON decode the response body.
     136     *
     137     * The method parameters are the same as those for the PHP native `json_decode()` function.
     138     *
     139     * @link https://php.net/json-decode
     140     *
     141     * @param ?bool $associative Optional. When `true`, JSON objects will be returned as associative arrays;
     142     *                           When `false`, JSON objects will be returned as objects.
     143     *                           When `null`, JSON objects will be returned as associative arrays
     144     *                           or objects depending on whether `JSON_OBJECT_AS_ARRAY` is set in the flags.
     145     *                           Defaults to `true` (in contrast to the PHP native default of `null`).
     146     * @param int   $depth       Optional. Maximum nesting depth of the structure being decoded.
     147     *                           Defaults to `512`.
     148     * @param int   $options     Optional. Bitmask of JSON_BIGINT_AS_STRING, JSON_INVALID_UTF8_IGNORE,
     149     *                           JSON_INVALID_UTF8_SUBSTITUTE, JSON_OBJECT_AS_ARRAY, JSON_THROW_ON_ERROR.
     150     *                           Defaults to `0` (no options set).
     151     *
     152     * @return array
     153     *
     154     * @throws \WpOrg\Requests\Exception If `$this->body` is not valid json.
     155     */
     156    public function decode_body($associative = true, $depth = 512, $options = 0) {
     157        $data = json_decode($this->body, $associative, $depth, $options);
     158
     159        if (json_last_error() !== JSON_ERROR_NONE) {
     160            $last_error = json_last_error_msg();
     161            throw new Exception('Unable to parse JSON data: ' . $last_error, 'response.invalid', $this);
     162        }
     163
     164        return $data;
     165    }
    122166}
  • trunk/src/wp-includes/Requests/Response/Headers.php

    r50842 r52244  
    66 */
    77
     8namespace WpOrg\Requests\Response;
     9
     10use WpOrg\Requests\Exception;
     11use WpOrg\Requests\Exception\InvalidArgument;
     12use WpOrg\Requests\Utility\CaseInsensitiveDictionary;
     13use WpOrg\Requests\Utility\FilteredIterator;
     14
    815/**
    916 * Case-insensitive dictionary, suitable for HTTP headers
     
    1118 * @package Requests
    1219 */
    13 class Requests_Response_Headers extends Requests_Utility_CaseInsensitiveDictionary {
     20class Headers extends CaseInsensitiveDictionary {
    1421    /**
    1522     * Get the given header
    1623     *
    17      * Unlike {@see self::getValues()}, this returns a string. If there are
     24     * Unlike {@see \WpOrg\Requests\Response\Headers::getValues()}, this returns a string. If there are
    1825     * multiple values, it concatenates them with a comma as per RFC2616.
    1926     *
     
    2128     * Set-Cookie headers.
    2229     *
    23      * @param string $key
     30     * @param string $offset
    2431     * @return string|null Header value
    2532     */
    26     public function offsetGet($key) {
    27         $key = strtolower($key);
    28         if (!isset($this->data[$key])) {
     33    public function offsetGet($offset) {
     34        if (is_string($offset)) {
     35            $offset = strtolower($offset);
     36        }
     37
     38        if (!isset($this->data[$offset])) {
    2939            return null;
    3040        }
    3141
    32         return $this->flatten($this->data[$key]);
     42        return $this->flatten($this->data[$offset]);
    3343    }
    3444
     
    3646     * Set the given item
    3747     *
    38      * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
     48     * @param string $offset Item name
     49     * @param string $value Item value
    3950     *
    40      * @param string $key Item name
    41      * @param string $value Item value
     51     * @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`)
    4252     */
    43     public function offsetSet($key, $value) {
    44         if ($key === null) {
    45             throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
     53    public function offsetSet($offset, $value) {
     54        if ($offset === null) {
     55            throw new Exception('Object is a dictionary, not a list', 'invalidset');
    4656        }
    4757
    48         $key = strtolower($key);
    49 
    50         if (!isset($this->data[$key])) {
    51             $this->data[$key] = array();
     58        if (is_string($offset)) {
     59            $offset = strtolower($offset);
    5260        }
    5361
    54         $this->data[$key][] = $value;
     62        if (!isset($this->data[$offset])) {
     63            $this->data[$offset] = [];
     64        }
     65
     66        $this->data[$offset][] = $value;
    5567    }
    5668
     
    5870     * Get all values for a given header
    5971     *
    60      * @param string $key
     72     * @param string $offset
    6173     * @return array|null Header values
     74     *
     75     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not valid as an array key.
    6276     */
    63     public function getValues($key) {
    64         $key = strtolower($key);
    65         if (!isset($this->data[$key])) {
     77    public function getValues($offset) {
     78        if (!is_string($offset) && !is_int($offset)) {
     79            throw InvalidArgument::create(1, '$offset', 'string|int', gettype($offset));
     80        }
     81
     82        $offset = strtolower($offset);
     83        if (!isset($this->data[$offset])) {
    6684            return null;
    6785        }
    6886
    69         return $this->data[$key];
     87        return $this->data[$offset];
    7088    }
    7189
     
    7896     * @param string|array $value Value to flatten
    7997     * @return string Flattened value
     98     *
     99     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or an array.
    80100     */
    81101    public function flatten($value) {
    82         if (is_array($value)) {
    83             $value = implode(',', $value);
     102        if (is_string($value)) {
     103            return $value;
    84104        }
    85105
    86         return $value;
     106        if (is_array($value)) {
     107            return implode(',', $value);
     108        }
     109
     110        throw InvalidArgument::create(1, '$value', 'string|array', gettype($value));
    87111    }
    88112
     
    90114     * Get an iterator for the data
    91115     *
    92      * Converts the internal
    93      * @return ArrayIterator
     116     * Converts the internally stored values to a comma-separated string if there is more
     117     * than one value for a key.
     118     *
     119     * @return \ArrayIterator
    94120     */
    95121    public function getIterator() {
    96         return new Requests_Utility_FilteredIterator($this->data, array($this, 'flatten'));
     122        return new FilteredIterator($this->data, [$this, 'flatten']);
    97123    }
    98124}
  • trunk/src/wp-includes/Requests/Session.php

    r50842 r52244  
    33 * Session handler for persistent requests and default parameters
    44 *
    5  * @package Requests
    6  * @subpackage Session Handler
     5 * @package Requests\SessionHandler
    76 */
     7
     8namespace WpOrg\Requests;
     9
     10use WpOrg\Requests\Cookie\Jar;
     11use WpOrg\Requests\Exception\InvalidArgument;
     12use WpOrg\Requests\Iri;
     13use WpOrg\Requests\Requests;
     14use WpOrg\Requests\Utility\InputValidator;
    815
    916/**
     
    1522 * a shared cookie jar), then overridden for individual requests.
    1623 *
    17  * @package Requests
    18  * @subpackage Session Handler
     24 * @package Requests\SessionHandler
    1925 */
    20 class Requests_Session {
     26class Session {
    2127    /**
    2228     * Base URL for requests
     
    3339     * @var array
    3440     */
    35     public $headers = array();
     41    public $headers = [];
    3642
    3743    /**
     
    4349     * @var array
    4450     */
    45     public $data = array();
     51    public $data = [];
    4652
    4753    /**
     
    5662     * @var array
    5763     */
    58     public $options = array();
     64    public $options = [];
    5965
    6066    /**
    6167     * Create a new session
    6268     *
    63      * @param string|null $url Base URL for requests
     69     * @param string|Stringable|null $url Base URL for requests
    6470     * @param array $headers Default headers for requests
    6571     * @param array $data Default data for requests
    6672     * @param array $options Default options for requests
    67      */
    68     public function __construct($url = null, $headers = array(), $data = array(), $options = array()) {
     73     *
     74     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string, Stringable or null.
     75     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array.
     76     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data argument is not an array.
     77     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
     78     */
     79    public function __construct($url = null, $headers = [], $data = [], $options = []) {
     80        if ($url !== null && InputValidator::is_string_or_stringable($url) === false) {
     81            throw InvalidArgument::create(1, '$url', 'string|Stringable|null', gettype($url));
     82        }
     83
     84        if (is_array($headers) === false) {
     85            throw InvalidArgument::create(2, '$headers', 'array', gettype($headers));
     86        }
     87
     88        if (is_array($data) === false) {
     89            throw InvalidArgument::create(3, '$data', 'array', gettype($data));
     90        }
     91
     92        if (is_array($options) === false) {
     93            throw InvalidArgument::create(4, '$options', 'array', gettype($options));
     94        }
     95
    6996        $this->url     = $url;
    7097        $this->headers = $headers;
     
    73100
    74101        if (empty($this->options['cookies'])) {
    75             $this->options['cookies'] = new Requests_Cookie_Jar();
     102            $this->options['cookies'] = new Jar();
    76103        }
    77104    }
     
    80107     * Get a property's value
    81108     *
    82      * @param string $key Property key
     109     * @param string $name Property name.
    83110     * @return mixed|null Property value, null if none found
    84111     */
    85     public function __get($key) {
    86         if (isset($this->options[$key])) {
    87             return $this->options[$key];
     112    public function __get($name) {
     113        if (isset($this->options[$name])) {
     114            return $this->options[$name];
    88115        }
    89116
     
    94121     * Set a property's value
    95122     *
    96      * @param string $key Property key
     123     * @param string $name Property name.
    97124     * @param mixed $value Property value
    98125     */
    99     public function __set($key, $value) {
    100         $this->options[$key] = $value;
     126    public function __set($name, $value) {
     127        $this->options[$name] = $value;
    101128    }
    102129
     
    104131     * Remove a property's value
    105132     *
    106      * @param string $key Property key
    107      */
    108     public function __isset($key) {
    109         return isset($this->options[$key]);
     133     * @param string $name Property name.
     134     */
     135    public function __isset($name) {
     136        return isset($this->options[$name]);
    110137    }
    111138
     
    113140     * Remove a property's value
    114141     *
    115      * @param string $key Property key
    116      */
    117     public function __unset($key) {
    118         if (isset($this->options[$key])) {
    119             unset($this->options[$key]);
    120         }
     142     * @param string $name Property name.
     143     */
     144    public function __unset($name) {
     145        unset($this->options[$name]);
    121146    }
    122147
    123148    /**#@+
    124      * @see request()
     149     * @see \WpOrg\Requests\Session::request()
    125150     * @param string $url
    126151     * @param array $headers
    127152     * @param array $options
    128      * @return Requests_Response
     153     * @return \WpOrg\Requests\Response
    129154     */
    130155    /**
    131156     * Send a GET request
    132157     */
    133     public function get($url, $headers = array(), $options = array()) {
     158    public function get($url, $headers = [], $options = []) {
    134159        return $this->request($url, $headers, null, Requests::GET, $options);
    135160    }
     
    138163     * Send a HEAD request
    139164     */
    140     public function head($url, $headers = array(), $options = array()) {
     165    public function head($url, $headers = [], $options = []) {
    141166        return $this->request($url, $headers, null, Requests::HEAD, $options);
    142167    }
     
    145170     * Send a DELETE request
    146171     */
    147     public function delete($url, $headers = array(), $options = array()) {
     172    public function delete($url, $headers = [], $options = []) {
    148173        return $this->request($url, $headers, null, Requests::DELETE, $options);
    149174    }
     
    151176
    152177    /**#@+
    153      * @see request()
     178     * @see \WpOrg\Requests\Session::request()
    154179     * @param string $url
    155180     * @param array $headers
    156181     * @param array $data
    157182     * @param array $options
    158      * @return Requests_Response
     183     * @return \WpOrg\Requests\Response
    159184     */
    160185    /**
    161186     * Send a POST request
    162187     */
    163     public function post($url, $headers = array(), $data = array(), $options = array()) {
     188    public function post($url, $headers = [], $data = [], $options = []) {
    164189        return $this->request($url, $headers, $data, Requests::POST, $options);
    165190    }
     
    168193     * Send a PUT request
    169194     */
    170     public function put($url, $headers = array(), $data = array(), $options = array()) {
     195    public function put($url, $headers = [], $data = [], $options = []) {
    171196        return $this->request($url, $headers, $data, Requests::PUT, $options);
    172197    }
     
    175200     * Send a PATCH request
    176201     *
    177      * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the
    178      * specification recommends that should send an ETag
     202     * Note: Unlike {@see \WpOrg\Requests\Session::post()} and {@see \WpOrg\Requests\Session::put()},
     203     * `$headers` is required, as the specification recommends that should send an ETag
    179204     *
    180205     * @link https://tools.ietf.org/html/rfc5789
    181206     */
    182     public function patch($url, $headers, $data = array(), $options = array()) {
     207    public function patch($url, $headers, $data = [], $options = []) {
    183208        return $this->request($url, $headers, $data, Requests::PATCH, $options);
    184209    }
     
    191216     * parsing.
    192217     *
    193      * @see Requests::request()
    194      *
    195      * @throws Requests_Exception On invalid URLs (`nonhttp`)
     218     * @see \WpOrg\Requests\Requests::request()
    196219     *
    197220     * @param string $url URL to request
    198221     * @param array $headers Extra headers to send with the request
    199222     * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
    200      * @param string $type HTTP request type (use Requests constants)
    201      * @param array $options Options for the request (see {@see Requests::request})
    202      * @return Requests_Response
    203      */
    204     public function request($url, $headers = array(), $data = array(), $type = Requests::GET, $options = array()) {
     223     * @param string $type HTTP request type (use \WpOrg\Requests\Requests constants)
     224     * @param array $options Options for the request (see {@see \WpOrg\Requests\Requests::request()})
     225     * @return \WpOrg\Requests\Response
     226     *
     227     * @throws \WpOrg\Requests\Exception On invalid URLs (`nonhttp`)
     228     */
     229    public function request($url, $headers = [], $data = [], $type = Requests::GET, $options = []) {
    205230        $request = $this->merge_request(compact('url', 'headers', 'data', 'options'));
    206231
     
    211236     * Send multiple HTTP requests simultaneously
    212237     *
    213      * @see Requests::request_multiple()
    214      *
    215      * @param array $requests Requests data (see {@see Requests::request_multiple})
    216      * @param array $options Global and default options (see {@see Requests::request})
    217      * @return array Responses (either Requests_Response or a Requests_Exception object)
    218      */
    219     public function request_multiple($requests, $options = array()) {
     238     * @see \WpOrg\Requests\Requests::request_multiple()
     239     *
     240     * @param array $requests Requests data (see {@see \WpOrg\Requests\Requests::request_multiple()})
     241     * @param array $options Global and default options (see {@see \WpOrg\Requests\Requests::request()})
     242     * @return array Responses (either \WpOrg\Requests\Response or a \WpOrg\Requests\Exception object)
     243     *
     244     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
     245     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
     246     */
     247    public function request_multiple($requests, $options = []) {
     248        if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
     249            throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
     250        }
     251
     252        if (is_array($options) === false) {
     253            throw InvalidArgument::create(2, '$options', 'array', gettype($options));
     254        }
     255
    220256        foreach ($requests as $key => $request) {
    221257            $requests[$key] = $this->merge_request($request, false);
     
    233269     * Merge a request's data with the default data
    234270     *
    235      * @param array $request Request data (same form as {@see request_multiple})
     271     * @param array $request Request data (same form as {@see \WpOrg\Requests\Session::request_multiple()})
    236272     * @param boolean $merge_options Should we merge options as well?
    237273     * @return array Request data
     
    239275    protected function merge_request($request, $merge_options = true) {
    240276        if ($this->url !== null) {
    241             $request['url'] = Requests_IRI::absolutize($this->url, $request['url']);
     277            $request['url'] = Iri::absolutize($this->url, $request['url']);
    242278            $request['url'] = $request['url']->uri;
    243279        }
    244280
    245281        if (empty($request['headers'])) {
    246             $request['headers'] = array();
     282            $request['headers'] = [];
    247283        }
    248284        $request['headers'] = array_merge($this->headers, $request['headers']);
     
    257293        }
    258294
    259         if ($merge_options !== false) {
     295        if ($merge_options === true) {
    260296            $request['options'] = array_merge($this->options, $request['options']);
    261297
  • trunk/src/wp-includes/Requests/Ssl.php

    r52243 r52244  
    33 * SSL utilities for Requests
    44 *
    5  * @package Requests
    6  * @subpackage Utilities
     5 * @package Requests\Utilities
    76 */
     7
     8namespace WpOrg\Requests;
     9
     10use WpOrg\Requests\Exception\InvalidArgument;
     11use WpOrg\Requests\Utility\InputValidator;
    812
    913/**
     
    1216 * Collection of utilities for working with and verifying SSL certificates.
    1317 *
    14  * @package Requests
    15  * @subpackage Utilities
     18 * @package Requests\Utilities
    1619 */
    17 class Requests_SSL {
     20final class Ssl {
    1821    /**
    1922     * Verify the certificate against common name and subject alternative names
     
    2225     * names, leading things like 'https://www.github.com/' to be invalid.
    2326     *
    24      * @see https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
     27     * @link https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
    2528     *
    26      * @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
    27      * @param string $host Host name to verify against
     29     * @param string|Stringable $host Host name to verify against
    2830     * @param array $cert Certificate data from openssl_x509_parse()
    2931     * @return bool
     32     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $host argument is not a string or a stringable object.
     33     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $cert argument is not an array or array accessible.
    3034     */
    3135    public static function verify_certificate($host, $cert) {
     36        if (InputValidator::is_string_or_stringable($host) === false) {
     37            throw InvalidArgument::create(1, '$host', 'string|Stringable', gettype($host));
     38        }
     39
     40        if (InputValidator::has_array_access($cert) === false) {
     41            throw InvalidArgument::create(2, '$cert', 'array|ArrayAccess', gettype($cert));
     42        }
     43
    3244        $has_dns_alt = false;
    3345
    3446        // Check the subjectAltName
    35         if (!empty($cert['extensions']) && !empty($cert['extensions']['subjectAltName'])) {
     47        if (!empty($cert['extensions']['subjectAltName'])) {
    3648            $altnames = explode(',', $cert['extensions']['subjectAltName']);
    3749            foreach ($altnames as $altname) {
     
    5163                }
    5264            }
     65
     66            if ($has_dns_alt === true) {
     67                return false;
     68            }
    5369        }
    5470
    5571        // Fall back to checking the common name if we didn't get any dNSName
    5672        // alt names, as per RFC2818
    57         if (!$has_dns_alt && !empty($cert['subject']['CN'])) {
     73        if (!empty($cert['subject']['CN'])) {
    5874            // Check for a match
    59             if (self::match_domain($host, $cert['subject']['CN']) === true) {
    60                 return true;
    61             }
     75            return (self::match_domain($host, $cert['subject']['CN']) === true);
    6276        }
    6377
     
    7892     * the third rule.
    7993     *
    80      * @param string $reference Reference dNSName
     94     * @param string|Stringable $reference Reference dNSName
    8195     * @return boolean Is the name valid?
     96     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object.
    8297     */
    8398    public static function verify_reference_name($reference) {
     99        if (InputValidator::is_string_or_stringable($reference) === false) {
     100            throw InvalidArgument::create(1, '$reference', 'string|Stringable', gettype($reference));
     101        }
     102
     103        if ($reference === '') {
     104            return false;
     105        }
     106
     107        if (preg_match('`\s`', $reference) > 0) {
     108            // Whitespace detected. This can never be a dNSName.
     109            return false;
     110        }
     111
    84112        $parts = explode('.', $reference);
     113        if ($parts !== array_filter($parts)) {
     114            // DNSName cannot contain two dots next to each other.
     115            return false;
     116        }
    85117
    86118        // Check the first part of the name
     
    113145     * Match a hostname against a dNSName reference
    114146     *
    115      * @param string $host Requested host
    116      * @param string $reference dNSName to match against
     147     * @param string|Stringable $host Requested host
     148     * @param string|Stringable $reference dNSName to match against
    117149     * @return boolean Does the domain match?
     150     * @throws \WpOrg\Requests\Exception\InvalidArgument When either of the passed arguments is not a string or a stringable object.
    118151     */
    119152    public static function match_domain($host, $reference) {
     153        if (InputValidator::is_string_or_stringable($host) === false) {
     154            throw InvalidArgument::create(1, '$host', 'string|Stringable', gettype($host));
     155        }
     156
    120157        // Check if the reference is blocklisted first
    121158        if (self::verify_reference_name($reference) !== true) {
     
    124161
    125162        // Check for a direct match
    126         if ($host === $reference) {
     163        if ((string) $host === (string) $reference) {
    127164            return true;
    128165        }
    129166
    130167        // Calculate the valid wildcard match if the host is not an IP address
    131         // Also validates that the host has 3 parts or more, as per Firefox's
    132         // ruleset.
     168        // Also validates that the host has 3 parts or more, as per Firefox's ruleset,
     169        // as a wildcard reference is only allowed with 3 parts or more, so the
     170        // comparison will never match if host doesn't contain 3 parts or more as well.
    133171        if (ip2long($host) === false) {
    134172            $parts    = explode('.', $host);
    135173            $parts[0] = '*';
    136174            $wildcard = implode('.', $parts);
    137             if ($wildcard === $reference) {
     175            if ($wildcard === (string) $reference) {
    138176                return true;
    139177            }
  • trunk/src/wp-includes/Requests/Transport.php

    r50842 r52244  
    33 * Base HTTP transport
    44 *
    5  * @package Requests
    6  * @subpackage Transport
     5 * @package Requests\Transport
    76 */
     7
     8namespace WpOrg\Requests;
    89
    910/**
    1011 * Base HTTP transport
    1112 *
    12  * @package Requests
    13  * @subpackage Transport
     13 * @package Requests\Transport
    1414 */
    15 interface Requests_Transport {
     15interface Transport {
    1616    /**
    1717     * Perform a request
     
    2020     * @param array $headers Associative array of request headers
    2121     * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
    22      * @param array $options Request options, see {@see Requests::response()} for documentation
     22     * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
    2323     * @return string Raw HTTP result
    2424     */
    25     public function request($url, $headers = array(), $data = array(), $options = array());
     25    public function request($url, $headers = [], $data = [], $options = []);
    2626
    2727    /**
    2828     * Send multiple requests simultaneously
    2929     *
    30      * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see Requests_Transport::request}
    31      * @param array $options Global options, see {@see Requests::response()} for documentation
    32      * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
     30     * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see \WpOrg\Requests\Transport::request()}
     31     * @param array $options Global options, see {@see \WpOrg\Requests\Requests::response()} for documentation
     32     * @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well)
    3333     */
    3434    public function request_multiple($requests, $options);
    3535
    3636    /**
    37      * Self-test whether the transport can be used
    38      * @return bool
     37     * Self-test whether the transport can be used.
     38     *
     39     * The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}.
     40     *
     41     * @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
     42     * @return bool Whether the transport can be used.
    3943     */
    40     public static function test();
     44    public static function test($capabilities = []);
    4145}
  • trunk/src/wp-includes/Requests/Transport/Curl.php

    r52243 r52244  
    33 * cURL HTTP transport
    44 *
    5  * @package Requests
    6  * @subpackage Transport
     5 * @package Requests\Transport
    76 */
     7
     8namespace WpOrg\Requests\Transport;
     9
     10use RecursiveArrayIterator;
     11use RecursiveIteratorIterator;
     12use WpOrg\Requests\Capability;
     13use WpOrg\Requests\Exception;
     14use WpOrg\Requests\Exception\InvalidArgument;
     15use WpOrg\Requests\Exception\Transport\Curl as CurlException;
     16use WpOrg\Requests\Requests;
     17use WpOrg\Requests\Transport;
     18use WpOrg\Requests\Utility\InputValidator;
    819
    920/**
    1021 * cURL HTTP transport
    1122 *
    12  * @package Requests
    13  * @subpackage Transport
     23 * @package Requests\Transport
    1424 */
    15 class Requests_Transport_cURL implements Requests_Transport {
     25final class Curl implements Transport {
    1626    const CURL_7_10_5 = 0x070A05;
    1727    const CURL_7_16_2 = 0x071002;
     
    3444     * Information on the current request
    3545     *
    36      * @var array cURL information array, see {@see https://secure.php.net/curl_getinfo}
     46     * @var array cURL information array, see {@link https://www.php.net/curl_getinfo}
    3747     */
    3848    public $info;
     
    4858     * cURL handle
    4959     *
     60     * @var resource|\CurlHandle Resource in PHP < 8.0, Instance of CurlHandle in PHP >= 8.0.
     61     */
     62    private $handle;
     63
     64    /**
     65     * Hook dispatcher instance
     66     *
     67     * @var \WpOrg\Requests\Hooks
     68     */
     69    private $hooks;
     70
     71    /**
     72     * Have we finished the headers yet?
     73     *
     74     * @var boolean
     75     */
     76    private $done_headers = false;
     77
     78    /**
     79     * If streaming to a file, keep the file pointer
     80     *
    5081     * @var resource
    5182     */
    52     protected $handle;
    53 
    54     /**
    55      * Hook dispatcher instance
    56      *
    57      * @var Requests_Hooks
    58      */
    59     protected $hooks;
    60 
    61     /**
    62      * Have we finished the headers yet?
    63      *
    64      * @var boolean
    65      */
    66     protected $done_headers = false;
    67 
    68     /**
    69      * If streaming to a file, keep the file pointer
    70      *
    71      * @var resource
    72      */
    73     protected $stream_handle;
     83    private $stream_handle;
    7484
    7585    /**
     
    7888     * @var int
    7989     */
    80     protected $response_bytes;
     90    private $response_bytes;
    8191
    8292    /**
     
    8595     * @var int|bool Byte count, or false if no limit.
    8696     */
    87     protected $response_byte_limit;
     97    private $response_byte_limit;
    8898
    8999    /**
     
    122132     * Perform a request
    123133     *
    124      * @throws Requests_Exception On a cURL error (`curlerror`)
    125      *
    126      * @param string $url URL to request
     134     * @param string|Stringable $url URL to request
    127135     * @param array $headers Associative array of request headers
    128136     * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
    129      * @param array $options Request options, see {@see Requests::response()} for documentation
     137     * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
    130138     * @return string Raw HTTP result
    131      */
    132     public function request($url, $headers = array(), $data = array(), $options = array()) {
     139     *
     140     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable.
     141     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array.
     142     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data parameter is not an array or string.
     143     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
     144     * @throws \WpOrg\Requests\Exception       On a cURL error (`curlerror`)
     145     */
     146    public function request($url, $headers = [], $data = [], $options = []) {
     147        if (InputValidator::is_string_or_stringable($url) === false) {
     148            throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url));
     149        }
     150
     151        if (is_array($headers) === false) {
     152            throw InvalidArgument::create(2, '$headers', 'array', gettype($headers));
     153        }
     154
     155        if (!is_array($data) && !is_string($data)) {
     156            if ($data === null) {
     157                $data = '';
     158            } else {
     159                throw InvalidArgument::create(3, '$data', 'array|string', gettype($data));
     160            }
     161        }
     162
     163        if (is_array($options) === false) {
     164            throw InvalidArgument::create(4, '$options', 'array', gettype($options));
     165        }
     166
    133167        $this->hooks = $options['hooks'];
    134168
    135169        $this->setup_handle($url, $headers, $data, $options);
    136170
    137         $options['hooks']->dispatch('curl.before_send', array(&$this->handle));
     171        $options['hooks']->dispatch('curl.before_send', [&$this->handle]);
    138172
    139173        if ($options['filename'] !== false) {
    140             $this->stream_handle = fopen($options['filename'], 'wb');
     174            // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silenced the PHP native warning in favour of throwing an exception.
     175            $this->stream_handle = @fopen($options['filename'], 'wb');
     176            if ($this->stream_handle === false) {
     177                $error = error_get_last();
     178                throw new Exception($error['message'], 'fopen');
     179            }
    141180        }
    142181
     
    165204        $response = $this->response_data;
    166205
    167         $options['hooks']->dispatch('curl.after_send', array());
    168 
    169         if (curl_errno($this->handle) === 23 || curl_errno($this->handle) === 61) {
     206        $options['hooks']->dispatch('curl.after_send', []);
     207
     208        if (curl_errno($this->handle) === CURLE_WRITE_ERROR || curl_errno($this->handle) === CURLE_BAD_CONTENT_ENCODING) {
    170209            // Reset encoding and try again
    171210            curl_setopt($this->handle, CURLOPT_ENCODING, 'none');
     
    180219
    181220        // Need to remove the $this reference from the curl handle.
    182         // Otherwise Requests_Transport_cURL wont be garbage collected and the curl_close() will never be called.
     221        // Otherwise \WpOrg\Requests\Transport\Curl won't be garbage collected and the curl_close() will never be called.
    183222        curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null);
    184223        curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null);
     
    192231     * @param array $requests Request data
    193232     * @param array $options Global options
    194      * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
     233     * @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well)
     234     *
     235     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
     236     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
    195237     */
    196238    public function request_multiple($requests, $options) {
    197239        // If you're not requesting, we can't get any responses ¯\_(ツ)_/¯
    198240        if (empty($requests)) {
    199             return array();
     241            return [];
     242        }
     243
     244        if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
     245            throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
     246        }
     247
     248        if (is_array($options) === false) {
     249            throw InvalidArgument::create(2, '$options', 'array', gettype($options));
    200250        }
    201251
    202252        $multihandle = curl_multi_init();
    203         $subrequests = array();
    204         $subhandles  = array();
     253        $subrequests = [];
     254        $subhandles  = [];
    205255
    206256        $class = get_class($this);
     
    208258            $subrequests[$id] = new $class();
    209259            $subhandles[$id]  = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']);
    210             $request['options']['hooks']->dispatch('curl.before_multi_add', array(&$subhandles[$id]));
     260            $request['options']['hooks']->dispatch('curl.before_multi_add', [&$subhandles[$id]]);
    211261            curl_multi_add_handle($multihandle, $subhandles[$id]);
    212262        }
    213263
    214264        $completed       = 0;
    215         $responses       = array();
     265        $responses       = [];
    216266        $subrequestcount = count($subrequests);
    217267
    218         $request['options']['hooks']->dispatch('curl.before_multi_exec', array(&$multihandle));
     268        $request['options']['hooks']->dispatch('curl.before_multi_exec', [&$multihandle]);
    219269
    220270        do {
     
    226276            while ($status === CURLM_CALL_MULTI_PERFORM);
    227277
    228             $to_process = array();
     278            $to_process = [];
    229279
    230280            // Read the information as needed
     
    242292                    //get error string for handle.
    243293                    $reason          = curl_error($done['handle']);
    244                     $exception       = new Requests_Exception_Transport_cURL(
     294                    $exception       = new CurlException(
    245295                        $reason,
    246                         Requests_Exception_Transport_cURL::EASY,
     296                        CurlException::EASY,
    247297                        $done['handle'],
    248298                        $done['result']
    249299                    );
    250300                    $responses[$key] = $exception;
    251                     $options['hooks']->dispatch('transport.internal.parse_error', array(&$responses[$key], $requests[$key]));
     301                    $options['hooks']->dispatch('transport.internal.parse_error', [&$responses[$key], $requests[$key]]);
    252302                }
    253303                else {
    254304                    $responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options);
    255305
    256                     $options['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$key], $requests[$key]));
     306                    $options['hooks']->dispatch('transport.internal.parse_response', [&$responses[$key], $requests[$key]]);
    257307                }
    258308
     
    261311
    262312                if (!is_string($responses[$key])) {
    263                     $options['hooks']->dispatch('multiple.request.complete', array(&$responses[$key], $key));
     313                    $options['hooks']->dispatch('multiple.request.complete', [&$responses[$key], $key]);
    264314                }
    265315                $completed++;
     
    268318        while ($active || $completed < $subrequestcount);
    269319
    270         $request['options']['hooks']->dispatch('curl.after_multi_exec', array(&$multihandle));
     320        $request['options']['hooks']->dispatch('curl.after_multi_exec', [&$multihandle]);
    271321
    272322        curl_multi_close($multihandle);
     
    281331     * @param array $headers Associative array of request headers
    282332     * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
    283      * @param array $options Request options, see {@see Requests::response()} for documentation
    284      * @return resource Subrequest's cURL handle
     333     * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
     334     * @return resource|\CurlHandle Subrequest's cURL handle
    285335     */
    286336    public function &get_subrequest_handle($url, $headers, $data, $options) {
     
    308358     * @param array $headers Associative array of request headers
    309359     * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
    310      * @param array $options Request options, see {@see Requests::response()} for documentation
    311      */
    312     protected function setup_handle($url, $headers, $data, $options) {
    313         $options['hooks']->dispatch('curl.before_request', array(&$this->handle));
     360     * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
     361     */
     362    private function setup_handle($url, $headers, $data, $options) {
     363        $options['hooks']->dispatch('curl.before_request', [&$this->handle]);
    314364
    315365        // Force closing the connection for old versions of cURL (<7.22).
     
    343393            }
    344394            elseif (!is_string($data)) {
    345                 $data = http_build_query($data, null, '&');
     395                $data = http_build_query($data, '', '&');
    346396            }
    347397        }
     
    394444        }
    395445        curl_setopt($this->handle, CURLOPT_URL, $url);
    396         curl_setopt($this->handle, CURLOPT_REFERER, $url);
    397446        curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']);
    398447        if (!empty($headers)) {
     
    407456
    408457        if ($options['blocking'] === true) {
    409             curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, array($this, 'stream_headers'));
    410             curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, array($this, 'stream_body'));
     458            curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, [$this, 'stream_headers']);
     459            curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, [$this, 'stream_body']);
    411460            curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE);
    412461        }
     
    419468     * @param array $options Request options
    420469     * @return string|false HTTP response data including headers. False if non-blocking.
    421      * @throws Requests_Exception
     470     * @throws \WpOrg\Requests\Exception
    422471     */
    423472    public function process_response($response, $options) {
    424473        if ($options['blocking'] === false) {
    425474            $fake_headers = '';
    426             $options['hooks']->dispatch('curl.after_request', array(&$fake_headers));
     475            $options['hooks']->dispatch('curl.after_request', [&$fake_headers]);
    427476            return false;
    428477        }
     
    441490                curl_error($this->handle)
    442491            );
    443             throw new Requests_Exception($error, 'curlerror', $this->handle);
     492            throw new Exception($error, 'curlerror', $this->handle);
    444493        }
    445494        $this->info = curl_getinfo($this->handle);
    446495
    447         $options['hooks']->dispatch('curl.after_request', array(&$this->headers, &$this->info));
     496        $options['hooks']->dispatch('curl.after_request', [&$this->headers, &$this->info]);
    448497        return $this->headers;
    449498    }
     
    452501     * Collect the headers as they are received
    453502     *
    454      * @param resource $handle cURL resource
     503     * @param resource|\CurlHandle $handle cURL handle
    455504     * @param string $headers Header string
    456505     * @return integer Length of provided header
     
    477526     * @since 1.6.1
    478527     *
    479      * @param resource $handle cURL resource
     528     * @param resource|\CurlHandle $handle cURL handle
    480529     * @param string $data Body data
    481530     * @return integer Length of provided data
    482531     */
    483532    public function stream_body($handle, $data) {
    484         $this->hooks->dispatch('request.progress', array($data, $this->response_bytes, $this->response_byte_limit));
     533        $this->hooks->dispatch('request.progress', [$data, $this->response_bytes, $this->response_byte_limit]);
    485534        $data_length = strlen($data);
    486535
     
    514563     *
    515564     * @param string $url
    516      * @param array|object $data Data to build query using, see {@see https://secure.php.net/http_build_query}
     565     * @param array|object $data Data to build query using, see {@link https://www.php.net/http_build_query}
    517566     * @return string URL with data
    518567     */
    519     protected static function format_get($url, $data) {
     568    private static function format_get($url, $data) {
    520569        if (!empty($data)) {
    521570            $query     = '';
     
    528577            }
    529578
    530             $query .= '&' . http_build_query($data, null, '&');
     579            $query .= '&' . http_build_query($data, '', '&');
    531580            $query  = trim($query, '&');
    532581
     
    542591
    543592    /**
    544      * Whether this transport is valid
     593     * Self-test whether the transport can be used.
     594     *
     595     * The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}.
    545596     *
    546597     * @codeCoverageIgnore
    547      * @return boolean True if the transport is valid, false otherwise.
    548      */
    549     public static function test($capabilities = array()) {
     598     * @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
     599     * @return bool Whether the transport can be used.
     600     */
     601    public static function test($capabilities = []) {
    550602        if (!function_exists('curl_init') || !function_exists('curl_exec')) {
    551603            return false;
     
    553605
    554606        // If needed, check that our installed curl version supports SSL
    555         if (isset($capabilities['ssl']) && $capabilities['ssl']) {
     607        if (isset($capabilities[Capability::SSL]) && $capabilities[Capability::SSL]) {
    556608            $curl_version = curl_version();
    557609            if (!(CURL_VERSION_SSL & $curl_version['features'])) {
     
    569621     * @return string The "Expect" header.
    570622     */
    571     protected function get_expect_header($data) {
     623    private function get_expect_header($data) {
    572624        if (!is_array($data)) {
    573625            return strlen((string) $data) >= 1048576 ? '100-Continue' : '';
  • trunk/src/wp-includes/Requests/Transport/Fsockopen.php

    r52243 r52244  
    33 * fsockopen HTTP transport
    44 *
    5  * @package Requests
    6  * @subpackage Transport
     5 * @package Requests\Transport
    76 */
     7
     8namespace WpOrg\Requests\Transport;
     9
     10use WpOrg\Requests\Capability;
     11use WpOrg\Requests\Exception;
     12use WpOrg\Requests\Exception\InvalidArgument;
     13use WpOrg\Requests\Port;
     14use WpOrg\Requests\Requests;
     15use WpOrg\Requests\Ssl;
     16use WpOrg\Requests\Transport;
     17use WpOrg\Requests\Utility\CaseInsensitiveDictionary;
     18use WpOrg\Requests\Utility\InputValidator;
    819
    920/**
    1021 * fsockopen HTTP transport
    1122 *
    12  * @package Requests
    13  * @subpackage Transport
     23 * @package Requests\Transport
    1424 */
    15 class Requests_Transport_fsockopen implements Requests_Transport {
     25final class Fsockopen implements Transport {
    1626    /**
    1727     * Second to microsecond conversion
     
    3141     * Stream metadata
    3242     *
    33      * @var array Associative array of properties, see {@see https://secure.php.net/stream_get_meta_data}
     43     * @var array Associative array of properties, see {@link https://www.php.net/stream_get_meta_data}
    3444     */
    3545    public $info;
     
    4050     * @var int|bool Byte count, or false if no limit.
    4151     */
    42     protected $max_bytes = false;
    43 
    44     protected $connect_error = '';
     52    private $max_bytes = false;
     53
     54    private $connect_error = '';
    4555
    4656    /**
    4757     * Perform a request
    4858     *
    49      * @throws Requests_Exception On failure to connect to socket (`fsockopenerror`)
    50      * @throws Requests_Exception On socket timeout (`timeout`)
    51      *
    52      * @param string $url URL to request
     59     * @param string|Stringable $url URL to request
    5360     * @param array $headers Associative array of request headers
    5461     * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
    55      * @param array $options Request options, see {@see Requests::response()} for documentation
     62     * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
    5663     * @return string Raw HTTP result
    57      */
    58     public function request($url, $headers = array(), $data = array(), $options = array()) {
     64     *
     65     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable.
     66     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array.
     67     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data parameter is not an array or string.
     68     * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
     69     * @throws \WpOrg\Requests\Exception       On failure to connect to socket (`fsockopenerror`)
     70     * @throws \WpOrg\Requests\Exception       On socket timeout (`timeout`)
     71     */
     72    public function request($url, $headers = [], $data = [], $options = []) {
     73        if (InputValidator::is_string_or_stringable($url) === false) {
     74            throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url));
     75        }
     76
     77        if (is_array($headers) === false) {
     78            throw InvalidArgument::create(2, '$headers', 'array', gettype($headers));
     79        }
     80
     81        if (!is_array($data) && !is_string($data)) {
     82            if ($data === null) {
     83                $data = '';
     84            } else {
     85                throw InvalidArgument::create(3, '$data', 'array|string', gettype($data));
     86            }
     87        }
     88
     89        if (is_array($options) === false) {
     90            throw InvalidArgument::create(4, '$options', 'array', gettype($options));
     91        }
     92
    5993        $options['hooks']->dispatch('fsockopen.before_request');
    6094
    6195        $url_parts = parse_url($url);
    6296        if (empty($url_parts)) {
    63             throw new Requests_Exception('Invalid URL.', 'invalidurl', $url);
     97            throw new Exception('Invalid URL.', 'invalidurl', $url);
    6498        }
    6599        $host                     = $url_parts['host'];
    66100        $context                  = stream_context_create();
    67101        $verifyname               = false;
    68         $case_insensitive_headers = new Requests_Utility_CaseInsensitiveDictionary($headers);
     102        $case_insensitive_headers = new CaseInsensitiveDictionary($headers);
    69103
    70104        // HTTPS support
     
    72106            $remote_socket = 'ssl://' . $host;
    73107            if (!isset($url_parts['port'])) {
    74                 $url_parts['port'] = 443;
    75             }
    76 
    77             $context_options = array(
     108                $url_parts['port'] = Port::HTTPS;
     109            }
     110
     111            $context_options = [
    78112                'verify_peer'       => true,
    79113                'capture_peer_cert' => true,
    80             );
     114            ];
    81115            $verifyname      = true;
    82116
     
    106140            }
    107141
    108             stream_context_set_option($context, array('ssl' => $context_options));
     142            stream_context_set_option($context, ['ssl' => $context_options]);
    109143        }
    110144        else {
     
    115149
    116150        if (!isset($url_parts['port'])) {
    117             $url_parts['port'] = 80;
     151            $url_parts['port'] = Port::HTTP;
    118152        }
    119153        $remote_socket .= ':' . $url_parts['port'];
    120154
    121155        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
    122         set_error_handler(array($this, 'connect_error_handler'), E_WARNING | E_NOTICE);
    123 
    124         $options['hooks']->dispatch('fsockopen.remote_socket', array(&$remote_socket));
     156        set_error_handler([$this, 'connect_error_handler'], E_WARNING | E_NOTICE);
     157
     158        $options['hooks']->dispatch('fsockopen.remote_socket', [&$remote_socket]);
    125159
    126160        $socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context);
     
    129163
    130164