Make WordPress Core

Ticket #33055: 33055.4.diff

File 33055.4.diff, 213.4 KB (added by rmccue, 10 years ago)

Updated Requests, deduplicated certificates

  • src/wp-includes/Requests/Auth/Basic.php

     
     1<?php
     2/**
     3 * Basic Authentication provider
     4 *
     5 * @package Requests
     6 * @subpackage Authentication
     7 */
     8
     9/**
     10 * Basic Authentication provider
     11 *
     12 * Provides a handler for Basic HTTP authentication via the Authorization
     13 * header.
     14 *
     15 * @package Requests
     16 * @subpackage Authentication
     17 */
     18class Requests_Auth_Basic implements Requests_Auth {
     19        /**
     20         * Username
     21         *
     22         * @var string
     23         */
     24        public $user;
     25
     26        /**
     27         * Password
     28         *
     29         * @var string
     30         */
     31        public $pass;
     32
     33        /**
     34         * Constructor
     35         *
     36         * @throws Requests_Exception On incorrect number of arguments (`authbasicbadargs`)
     37         * @param array|null $args Array of user and password. Must have exactly two elements
     38         */
     39        public function __construct($args = null) {
     40                if (is_array($args)) {
     41                        if (count($args) !== 2) {
     42                                throw new Requests_Exception('Invalid number of arguments', 'authbasicbadargs');
     43                        }
     44
     45                        list($this->user, $this->pass) = $args;
     46                }
     47        }
     48
     49        /**
     50         * Register the necessary callbacks
     51         *
     52         * @see curl_before_send
     53         * @see fsockopen_header
     54         * @param Requests_Hooks $hooks Hook system
     55         */
     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'));
     59        }
     60
     61        /**
     62         * Set cURL parameters before the data is sent
     63         *
     64         * @param resource $handle cURL resource
     65         */
     66        public function curl_before_send(&$handle) {
     67                curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
     68                curl_setopt($handle, CURLOPT_USERPWD, $this->getAuthString());
     69        }
     70
     71        /**
     72         * Add extra headers to the request before sending
     73         *
     74         * @param string $out HTTP header string
     75         */
     76        public function fsockopen_header(&$out) {
     77                $out .= sprintf("Authorization: Basic %s\r\n", base64_encode($this->getAuthString()));
     78        }
     79
     80        /**
     81         * Get the authentication string (user:pass)
     82         *
     83         * @return string
     84         */
     85        public function getAuthString() {
     86                return $this->user . ':' . $this->pass;
     87        }
     88}
     89 No newline at end of file
  • src/wp-includes/Requests/Auth.php

    Property changes on: src/wp-includes/Requests/Auth/Basic.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Authentication provider interface
     4 *
     5 * @package Requests
     6 * @subpackage Authentication
     7 */
     8
     9/**
     10 * Authentication provider interface
     11 *
     12 * Implement this interface to act as an authentication provider.
     13 *
     14 * Parameters should be passed via the constructor where possible, as this
     15 * makes it much easier for users to use your provider.
     16 *
     17 * @see Requests_Hooks
     18 * @package Requests
     19 * @subpackage Authentication
     20 */
     21interface Requests_Auth {
     22        /**
     23         * Register hooks as needed
     24         *
     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
     27         * hooks you'll need.
     28         *
     29         * @see Requests_Hooks::register
     30         * @param Requests_Hooks $hooks Hook system
     31         */
     32        public function register(Requests_Hooks &$hooks);
     33}
     34 No newline at end of file
  • src/wp-includes/Requests/Cookie/Jar.php

    Property changes on: src/wp-includes/Requests/Auth.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Cookie holder object
     4 *
     5 * @package Requests
     6 * @subpackage Cookies
     7 */
     8
     9/**
     10 * Cookie holder object
     11 *
     12 * @package Requests
     13 * @subpackage Cookies
     14 */
     15class Requests_Cookie_Jar implements ArrayAccess, IteratorAggregate {
     16        /**
     17         * Actual item data
     18         *
     19         * @var array
     20         */
     21        protected $cookies = array();
     22
     23        /**
     24         * Create a new jar
     25         *
     26         * @param array $cookies Existing cookie values
     27         */
     28        public function __construct($cookies = array()) {
     29                $this->cookies = $cookies;
     30        }
     31
     32        /**
     33         * Normalise cookie data into a Requests_Cookie
     34         *
     35         * @param string|Requests_Cookie $cookie
     36         * @return Requests_Cookie
     37         */
     38        public function normalize_cookie($cookie, $key = null) {
     39                if ($cookie instanceof Requests_Cookie) {
     40                        return $cookie;
     41                }
     42
     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);
     55        }
     56
     57        /**
     58         * Check if the given item exists
     59         *
     60         * @param string $key Item key
     61         * @return boolean Does the item exist?
     62         */
     63        public function offsetExists($key) {
     64                return isset($this->cookies[$key]);
     65        }
     66
     67        /**
     68         * Get the value for the item
     69         *
     70         * @param string $key Item key
     71         * @return string Item value
     72         */
     73        public function offsetGet($key) {
     74                if (!isset($this->cookies[$key])) {
     75                        return null;
     76                }
     77
     78                return $this->cookies[$key];
     79        }
     80
     81        /**
     82         * Set the given item
     83         *
     84         * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
     85         *
     86         * @param string $key Item name
     87         * @param string $value Item value
     88         */
     89        public function offsetSet($key, $value) {
     90                if ($key === null) {
     91                        throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
     92                }
     93
     94                $this->cookies[$key] = $value;
     95        }
     96
     97        /**
     98         * Unset the given header
     99         *
     100         * @param string $key
     101         */
     102        public function offsetUnset($key) {
     103                unset($this->cookies[$key]);
     104        }
     105
     106        /**
     107         * Get an iterator for the data
     108         *
     109         * @return ArrayIterator
     110         */
     111        public function getIterator() {
     112                return new ArrayIterator($this->cookies);
     113        }
     114
     115        /**
     116         * Register the cookie handler with the request's hooking system
     117         *
     118         * @param Requests_Hooker $hooks Hooking system
     119         */
     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'));
     123        }
     124
     125        /**
     126         * Add Cookie header to a request if we have any
     127         *
     128         * As per RFC 6265, cookies are separated by '; '
     129         *
     130         * @param string $url
     131         * @param array $headers
     132         * @param array $data
     133         * @param string $type
     134         * @param array $options
     135         */
     136        public function before_request($url, &$headers, &$data, &$type, &$options) {
     137                if (!$url instanceof Requests_IRI) {
     138                        $url = new Requests_IRI($url);
     139                }
     140
     141                if (!empty($this->cookies)) {
     142                        $cookies = array();
     143                        foreach ($this->cookies as $key => $cookie) {
     144                                $cookie = $this->normalize_cookie($cookie, $key);
     145
     146                                // Skip expired cookies
     147                                if ($cookie->is_expired()) {
     148                                        continue;
     149                                }
     150
     151                                if ($cookie->domain_matches($url->host)) {
     152                                        $cookies[] = $cookie->format_for_header();
     153                                }
     154                        }
     155
     156                        $headers['Cookie'] = implode('; ', $cookies);
     157                }
     158        }
     159
     160        /**
     161         * Parse all cookies from a response and attach them to the response
     162         *
     163         * @var Requests_Response $response
     164         */
     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);
     169                }
     170
     171                $cookies = Requests_Cookie::parse_from_headers($return->headers, $url);
     172                $this->cookies = array_merge($this->cookies, $cookies);
     173                $return->cookies = $this;
     174        }
     175}
     176 No newline at end of file
  • src/wp-includes/Requests/Cookie.php

     
     1<?php
     2/**
     3 * Cookie storage object
     4 *
     5 * @package Requests
     6 * @subpackage Cookies
     7 */
     8
     9/**
     10 * Cookie storage object
     11 *
     12 * @package Requests
     13 * @subpackage Cookies
     14 */
     15class Requests_Cookie {
     16        /**
     17         * Cookie name.
     18         *
     19         * @var string
     20         */
     21        public $name;
     22
     23        /**
     24         * Cookie value.
     25         *
     26         * @var string
     27         */
     28        public $value;
     29
     30        /**
     31         * Cookie attributes
     32         *
     33         * Valid keys are (currently) path, domain, expires, max-age, secure and
     34         * httponly.
     35         *
     36         * @var Requests_Utility_CaseInsensitiveDictionary|array Array-like object
     37         */
     38        public $attributes = array();
     39
     40        /**
     41         * Cookie flags
     42         *
     43         * Valid keys are (currently) creation, last-access, persistent and
     44         * host-only.
     45         *
     46         * @var array
     47         */
     48        public $flags = array();
     49
     50        /**
     51         * Reference time for relative calculations
     52         *
     53         * This is used in place of `time()` when calculating Max-Age expiration and
     54         * checking time validity.
     55         *
     56         * @var int
     57         */
     58        public $reference_time = 0;
     59
     60        /**
     61         * Create a new cookie object
     62         *
     63         * @param string $name
     64         * @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) {
     68                $this->name = $name;
     69                $this->value = $value;
     70                $this->attributes = $attributes;
     71                $default_flags = array(
     72                        'creation' => time(),
     73                        'last-access' => time(),
     74                        'persistent' => false,
     75                        'host-only' => true,
     76                );
     77                $this->flags = array_merge($default_flags, $flags);
     78
     79                $this->reference_time = time();
     80                if ($reference_time !== null) {
     81                        $this->reference_time = $reference_time;
     82                }
     83
     84                $this->normalize();
     85        }
     86
     87        /**
     88         * Check if a cookie is expired.
     89         *
     90         * Checks the age against $this->reference_time to determine if the cookie
     91         * is expired.
     92         *
     93         * @return boolean True if expired, false if time is valid.
     94         */
     95        public function is_expired() {
     96                // RFC6265, s. 4.1.2.2:
     97                // If a cookie has both the Max-Age and the Expires attribute, the Max-
     98                // Age attribute has precedence and controls the expiration date of the
     99                // cookie.
     100                if (isset($this->attributes['max-age'])) {
     101                        $max_age = $this->attributes['max-age'];
     102                        return $max_age < $this->reference_time;
     103                }
     104
     105                if (isset($this->attributes['expires'])) {
     106                        $expires = $this->attributes['expires'];
     107                        return $expires < $this->reference_time;
     108                }
     109
     110                return false;
     111        }
     112
     113        /**
     114         * Check if a cookie is valid for a given URI
     115         *
     116         * @param Requests_IRI $uri URI to check
     117         * @return boolean Whether the cookie is valid for the given URI
     118         */
     119        public function uri_matches(Requests_IRI $uri) {
     120                if (!$this->domain_matches($uri->host)) {
     121                        return false;
     122                }
     123
     124                if (!$this->path_matches($uri->path)) {
     125                        return false;
     126                }
     127
     128                return empty($this->attributes['secure']) || $uri->scheme === 'https';
     129        }
     130
     131        /**
     132         * Check if a cookie is valid for a given domain
     133         *
     134         * @param string $string Domain to check
     135         * @return boolean Whether the cookie is valid for the given domain
     136         */
     137        public function domain_matches($string) {
     138                if (!isset($this->attributes['domain'])) {
     139                        // Cookies created manually; cookies created by Requests will set
     140                        // the domain to the requested domain
     141                        return true;
     142                }
     143
     144                $domain_string = $this->attributes['domain'];
     145                if ($domain_string === $string) {
     146                        // The domain string and the string are identical.
     147                        return true;
     148                }
     149
     150                // If the cookie is marked as host-only and we don't have an exact
     151                // match, reject the cookie
     152                if ($this->flags['host-only'] === true) {
     153                        return false;
     154                }
     155
     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));
     168                if (substr($prefix, -1) !== '.') {
     169                        // The last character of the string that is not included in the
     170                        // domain string should be a %x2E (".") character.
     171                        return false;
     172                }
     173
     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);
     176        }
     177
     178        /**
     179         * Check if a cookie is valid for a given path
     180         *
     181         * From the path-match check in RFC 6265 section 5.1.4
     182         *
     183         * @param string $request_path Path to check
     184         * @return boolean Whether the cookie is valid for the given path
     185         */
     186        public function path_matches($request_path) {
     187                if (empty($request_path)) {
     188                        // Normalize empty path to root
     189                        $request_path = '/';
     190                }
     191
     192                if (!isset($this->attributes['path'])) {
     193                        // Cookies created manually; cookies created by Requests will set
     194                        // the path to the requested path
     195                        return true;
     196                }
     197
     198                $cookie_path = $this->attributes['path'];
     199
     200                if ($cookie_path === $request_path) {
     201                        // The cookie-path and the request-path are identical.
     202                        return true;
     203                }
     204
     205                if (strlen($request_path) > strlen($cookie_path) && substr($request_path, 0, strlen($cookie_path)) === $cookie_path) {
     206                        if (substr($cookie_path, -1) === '/') {
     207                                // The cookie-path is a prefix of the request-path, and the last
     208                                // character of the cookie-path is %x2F ("/").
     209                                return true;
     210                        }
     211
     212                        if (substr($request_path, strlen($cookie_path), 1) === '/') {
     213                                // The cookie-path is a prefix of the request-path, and the
     214                                // first character of the request-path that is not included in
     215                                // the cookie-path is a %x2F ("/") character.
     216                                return true;
     217                        }
     218                }
     219
     220                return false;
     221        }
     222
     223        /**
     224         * Normalize cookie and attributes
     225         *
     226         * @return boolean Whether the cookie was successfully normalized
     227         */
     228        public function normalize() {
     229                foreach ($this->attributes as $key => $value) {
     230                        $orig_value = $value;
     231                        $value = $this->normalize_attribute($key, $value);
     232                        if ($value === null) {
     233                                unset($this->attributes[$key]);
     234                                continue;
     235                        }
     236
     237                        if ($value !== $orig_value) {
     238                                $this->attributes[$key] = $value;
     239                        }
     240                }
     241
     242                return true;
     243        }
     244
     245        /**
     246         * Parse an individual cookie attribute
     247         *
     248         * Handles parsing individual attributes from the cookie values.
     249         *
     250         * @param string $name Attribute name
     251         * @param string|boolean $value Attribute value (string value, or true if empty/flag)
     252         * @return mixed Value if available, or null if the attribute value is invalid (and should be skipped)
     253         */
     254        protected function normalize_attribute($name, $value) {
     255                switch (strtolower($name)) {
     256                        case 'expires':
     257                                // Expiration parsing, as per RFC 6265 section 5.2.1
     258                                if (is_int($value)) {
     259                                        return $value;
     260                                }
     261
     262                                $expiry_time = strtotime($value);
     263                                if ($expiry_time === false) {
     264                                        return null;
     265                                }
     266
     267                                return $expiry_time;
     268
     269                        case 'max-age':
     270                                // Expiration parsing, as per RFC 6265 section 5.2.2
     271                                if (is_int($value)) {
     272                                        return $value;
     273                                }
     274
     275                                // Check that we have a valid age
     276                                if (!preg_match('/^-?\d+$/', $value)) {
     277                                        return null;
     278                                }
     279
     280                                $delta_seconds = (int) $value;
     281                                if ($delta_seconds <= 0) {
     282                                        $expiry_time = 0;
     283                                }
     284                                else {
     285                                        $expiry_time = $this->reference_time + $delta_seconds;
     286                                }
     287
     288                                return $expiry_time;
     289
     290                        case 'domain':
     291                                // Domain normalization, as per RFC 6265 section 5.2.3
     292                                if ($value[0] === '.') {
     293                                        $value = substr($value, 1);
     294                                }
     295
     296                                return $value;
     297
     298                        default:
     299                                return $value;
     300                }
     301        }
     302
     303        /**
     304         * Format a cookie for a Cookie header
     305         *
     306         * This is used when sending cookies to a server.
     307         *
     308         * @return string Cookie formatted for Cookie header
     309         */
     310        public function format_for_header() {
     311                return sprintf('%s=%s', $this->name, $this->value);
     312        }
     313
     314        /**
     315         * Format a cookie for a Cookie header
     316         *
     317         * @codeCoverageIgnore
     318         * @deprecated Use {@see Requests_Cookie::format_for_header}
     319         * @return string
     320         */
     321        public function formatForHeader() {
     322                return $this->format_for_header();
     323        }
     324
     325        /**
     326         * Format a cookie for a Set-Cookie header
     327         *
     328         * This is used when sending cookies to clients. This isn't really
     329         * applicable to client-side usage, but might be handy for debugging.
     330         *
     331         * @return string Cookie formatted for Set-Cookie header
     332         */
     333        public function format_for_set_cookie() {
     334                $header_value = $this->format_for_header();
     335                if (!empty($this->attributes)) {
     336                        $parts = array();
     337                        foreach ($this->attributes as $key => $value) {
     338                                // Ignore non-associative attributes
     339                                if (is_numeric($key)) {
     340                                        $parts[] = $value;
     341                                }
     342                                else {
     343                                        $parts[] = sprintf('%s=%s', $key, $value);
     344                                }
     345                        }
     346
     347                        $header_value .= '; ' . implode('; ', $parts);
     348                }
     349                return $header_value;
     350        }
     351
     352        /**
     353         * Format a cookie for a Set-Cookie header
     354         *
     355         * @codeCoverageIgnore
     356         * @deprecated Use {@see Requests_Cookie::format_for_set_cookie}
     357         * @return string
     358         */
     359        public function formatForSetCookie() {
     360                return $this->format_for_set_cookie();
     361        }
     362
     363        /**
     364         * Get the cookie value
     365         *
     366         * Attributes and other data can be accessed via methods.
     367         */
     368        public function __toString() {
     369                return $this->value;
     370        }
     371
     372        /**
     373         * Parse a cookie string into a cookie object
     374         *
     375         * Based on Mozilla's parsing code in Firefox and related projects, which
     376         * is an intentional deviation from RFC 2109 and RFC 2616. RFC 6265
     377         * specifies some of this handling, but not in a thorough manner.
     378         *
     379         * @param string Cookie header value (from a Set-Cookie header)
     380         * @return Requests_Cookie Parsed cookie object
     381         */
     382        public static function parse($string, $name = '', $reference_time = null) {
     383                $parts = explode(';', $string);
     384                $kvparts = array_shift($parts);
     385
     386                if (!empty($name)) {
     387                        $value = $string;
     388                }
     389                elseif (strpos($kvparts, '=') === false) {
     390                        // Some sites might only have a value without the equals separator.
     391                        // Deviate from RFC 6265 and pretend it was actually a blank name
     392                        // (`=foo`)
     393                        //
     394                        // https://bugzilla.mozilla.org/show_bug.cgi?id=169091
     395                        $name = '';
     396                        $value = $kvparts;
     397                }
     398                else {
     399                        list($name, $value) = explode('=', $kvparts, 2);
     400                }
     401                $name = trim($name);
     402                $value = trim($value);
     403
     404                // Attribute key are handled case-insensitively
     405                $attributes = new Requests_Utility_CaseInsensitiveDictionary();
     406
     407                if (!empty($parts)) {
     408                        foreach ($parts as $part) {
     409                                if (strpos($part, '=') === false) {
     410                                        $part_key = $part;
     411                                        $part_value = true;
     412                                }
     413                                else {
     414                                        list($part_key, $part_value) = explode('=', $part, 2);
     415                                        $part_value = trim($part_value);
     416                                }
     417
     418                                $part_key = trim($part_key);
     419                                $attributes[$part_key] = $part_value;
     420                        }
     421                }
     422
     423                return new Requests_Cookie($name, $value, $attributes, array(), $reference_time);
     424        }
     425
     426        /**
     427         * Parse all Set-Cookie headers from request headers
     428         *
     429         * @param Requests_Response_Headers $headers Headers to parse from
     430         * @param Requests_IRI|null $origin URI for comparing cookie origins
     431         * @param int|null $time Reference time for expiration calculation
     432         * @return array
     433         */
     434        public static function parse_from_headers(Requests_Response_Headers $headers, Requests_IRI $origin = null, $time = null) {
     435                $cookie_headers = $headers->getValues('Set-Cookie');
     436                if (empty($cookie_headers)) {
     437                        return array();
     438                }
     439
     440                $cookies = array();
     441                foreach ($cookie_headers as $header) {
     442                        $parsed = self::parse($header, '', $time);
     443
     444                        // Default domain/path attributes
     445                        if (empty($parsed->attributes['domain']) && !empty($origin)) {
     446                                $parsed->attributes['domain'] = $origin->host;
     447                                $parsed->flags['host-only'] = true;
     448                        }
     449                        else {
     450                                $parsed->flags['host-only'] = false;
     451                        }
     452
     453                        $path_is_valid = (!empty($parsed->attributes['path']) && $parsed->attributes['path'][0] === '/');
     454                        if (!$path_is_valid && !empty($origin)) {
     455                                $path = $origin->path;
     456
     457                                // Default path normalization as per RFC 6265 section 5.1.4
     458                                if (substr($path, 0, 1) !== '/') {
     459                                        // If the uri-path is empty or if the first character of
     460                                        // the uri-path is not a %x2F ("/") character, output
     461                                        // %x2F ("/") and skip the remaining steps.
     462                                        $path = '/';
     463                                }
     464                                elseif (substr_count($path, '/') === 1) {
     465                                        // If the uri-path contains no more than one %x2F ("/")
     466                                        // character, output %x2F ("/") and skip the remaining
     467                                        // step.
     468                                        $path = '/';
     469                                }
     470                                else {
     471                                        // Output the characters of the uri-path from the first
     472                                        // character up to, but not including, the right-most
     473                                        // %x2F ("/").
     474                                        $path = substr($path, 0, strrpos($path, '/'));
     475                                }
     476                                $parsed->attributes['path'] = $path;
     477                        }
     478
     479                        // Reject invalid cookie domains
     480                        if (!empty($origin) && !$parsed->domain_matches($origin->host)) {
     481                                continue;
     482                        }
     483
     484                        $cookies[$parsed->name] = $parsed;
     485                }
     486
     487                return $cookies;
     488        }
     489
     490        /**
     491         * Parse all Set-Cookie headers from request headers
     492         *
     493         * @codeCoverageIgnore
     494         * @deprecated Use {@see Requests_Cookie::parse_from_headers}
     495         * @return string
     496         */
     497        public static function parseFromHeaders(Requests_Response_Headers $headers) {
     498                return self::parse_from_headers($headers);
     499        }
     500}
  • src/wp-includes/Requests/Exception/HTTP/304.php

     
     1<?php
     2/**
     3 * Exception for 304 Not Modified responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 304 Not Modified responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_304 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 304;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Not Modified';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/305.php

     
     1<?php
     2/**
     3 * Exception for 305 Use Proxy responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 305 Use Proxy responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_305 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 305;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Use Proxy';
     27}
  • src/wp-includes/Requests/Exception/HTTP/306.php

     
     1<?php
     2/**
     3 * Exception for 306 Switch Proxy responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 306 Switch Proxy responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_306 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 306;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Switch Proxy';
     27}
  • src/wp-includes/Requests/Exception/HTTP/400.php

     
     1<?php
     2/**
     3 * Exception for 400 Bad Request responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 400 Bad Request responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_400 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 400;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Bad Request';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/401.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/400.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 401 Unauthorized responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 401 Unauthorized responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_401 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 401;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Unauthorized';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/402.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/401.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 402 Payment Required responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 402 Payment Required responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_402 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 402;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Payment Required';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/403.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/402.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 403 Forbidden responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 403 Forbidden responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_403 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 403;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Forbidden';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/404.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/403.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 404 Not Found responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 404 Not Found responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_404 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 404;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Not Found';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/405.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/404.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 405 Method Not Allowed responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 405 Method Not Allowed responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_405 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 405;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Method Not Allowed';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/406.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/405.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 406 Not Acceptable responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 406 Not Acceptable responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_406 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 406;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Not Acceptable';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/407.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/406.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 407 Proxy Authentication Required responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 407 Proxy Authentication Required responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_407 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 407;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Proxy Authentication Required';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/408.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/407.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 408 Request Timeout responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 408 Request Timeout responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_408 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 408;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Request Timeout';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/409.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/408.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 409 Conflict responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 409 Conflict responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_409 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 409;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Conflict';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/410.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/409.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 410 Gone responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 410 Gone responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_410 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 410;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Gone';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/411.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/410.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 411 Length Required responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 411 Length Required responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_411 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 411;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Length Required';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/412.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/411.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 412 Precondition Failed responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 412 Precondition Failed responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_412 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 412;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Precondition Failed';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/413.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/412.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 413 Request Entity Too Large responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 413 Request Entity Too Large responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_413 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 413;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Request Entity Too Large';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/414.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/413.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 414 Request-URI Too Large responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 414 Request-URI Too Large responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_414 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 414;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Request-URI Too Large';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/415.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/414.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 415 Unsupported Media Type responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 415 Unsupported Media Type responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_415 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 415;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Unsupported Media Type';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/416.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/415.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 416 Requested Range Not Satisfiable responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 416 Requested Range Not Satisfiable responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_416 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 416;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Requested Range Not Satisfiable';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/417.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/416.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 417 Expectation Failed responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 417 Expectation Failed responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_417 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 417;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Expectation Failed';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/418.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/417.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 418 I'm A Teapot responses
     4 *
     5 * @see http://tools.ietf.org/html/rfc2324
     6 * @package Requests
     7 */
     8
     9/**
     10 * Exception for 418 I'm A Teapot responses
     11 *
     12 * @see http://tools.ietf.org/html/rfc2324
     13 * @package Requests
     14 */
     15class Requests_Exception_HTTP_418 extends Requests_Exception_HTTP {
     16        /**
     17         * HTTP status code
     18         *
     19         * @var integer
     20         */
     21        protected $code = 418;
     22
     23        /**
     24         * Reason phrase
     25         *
     26         * @var string
     27         */
     28        protected $reason = "I'm A Teapot";
     29}
     30 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/428.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/418.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 428 Precondition Required responses
     4 *
     5 * @see http://tools.ietf.org/html/rfc6585
     6 * @package Requests
     7 */
     8
     9/**
     10 * Exception for 428 Precondition Required responses
     11 *
     12 * @see http://tools.ietf.org/html/rfc6585
     13 * @package Requests
     14 */
     15class Requests_Exception_HTTP_428 extends Requests_Exception_HTTP {
     16        /**
     17         * HTTP status code
     18         *
     19         * @var integer
     20         */
     21        protected $code = 428;
     22
     23        /**
     24         * Reason phrase
     25         *
     26         * @var string
     27         */
     28        protected $reason = 'Precondition Required';
     29}
     30 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/429.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/428.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 429 Too Many Requests responses
     4 *
     5 * @see http://tools.ietf.org/html/draft-nottingham-http-new-status-04
     6 * @package Requests
     7 */
     8
     9/**
     10 * Exception for 429 Too Many Requests responses
     11 *
     12 * @see http://tools.ietf.org/html/draft-nottingham-http-new-status-04
     13 * @package Requests
     14 */
     15class Requests_Exception_HTTP_429 extends Requests_Exception_HTTP {
     16        /**
     17         * HTTP status code
     18         *
     19         * @var integer
     20         */
     21        protected $code = 429;
     22
     23        /**
     24         * Reason phrase
     25         *
     26         * @var string
     27         */
     28        protected $reason = 'Too Many Requests';
     29}
     30 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/431.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/429.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 431 Request Header Fields Too Large responses
     4 *
     5 * @see http://tools.ietf.org/html/rfc6585
     6 * @package Requests
     7 */
     8
     9/**
     10 * Exception for 431 Request Header Fields Too Large responses
     11 *
     12 * @see http://tools.ietf.org/html/rfc6585
     13 * @package Requests
     14 */
     15class Requests_Exception_HTTP_431 extends Requests_Exception_HTTP {
     16        /**
     17         * HTTP status code
     18         *
     19         * @var integer
     20         */
     21        protected $code = 431;
     22
     23        /**
     24         * Reason phrase
     25         *
     26         * @var string
     27         */
     28        protected $reason = 'Request Header Fields Too Large';
     29}
     30 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/500.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/431.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 500 Internal Server Error responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 500 Internal Server Error responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_500 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 500;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Internal Server Error';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/501.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/500.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 501 Not Implemented responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 501 Not Implemented responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_501 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 501;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Not Implemented';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/502.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/501.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 502 Bad Gateway responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 502 Bad Gateway responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_502 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 502;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Bad Gateway';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/503.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/502.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 503 Service Unavailable responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 503 Service Unavailable responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_503 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 503;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Service Unavailable';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/504.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/503.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 504 Gateway Timeout responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 504 Gateway Timeout responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_504 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 504;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Gateway Timeout';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/505.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/504.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 505 HTTP Version Not Supported responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for 505 HTTP Version Not Supported responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_505 extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 505;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'HTTP Version Not Supported';
     27}
     28 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/511.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/505.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for 511 Network Authentication Required responses
     4 *
     5 * @see http://tools.ietf.org/html/rfc6585
     6 * @package Requests
     7 */
     8
     9/**
     10 * Exception for 511 Network Authentication Required responses
     11 *
     12 * @see http://tools.ietf.org/html/rfc6585
     13 * @package Requests
     14 */
     15class Requests_Exception_HTTP_511 extends Requests_Exception_HTTP {
     16        /**
     17         * HTTP status code
     18         *
     19         * @var integer
     20         */
     21        protected $code = 511;
     22
     23        /**
     24         * Reason phrase
     25         *
     26         * @var string
     27         */
     28        protected $reason = 'Network Authentication Required';
     29}
     30 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP/Unknown.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/511.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception for unknown status responses
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for unknown status responses
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP_Unknown extends Requests_Exception_HTTP {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer|bool Code if available, false if an error occurred
     18         */
     19        protected $code = 0;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Unknown';
     27
     28        /**
     29         * Create a new exception
     30         *
     31         * If `$data` is an instance of {@see Requests_Response}, uses the status
     32         * code from it. Otherwise, sets as 0
     33         *
     34         * @param string|null $reason Reason phrase
     35         * @param mixed $data Associated data
     36         */
     37        public function __construct($reason = null, $data = null) {
     38                if ($data instanceof Requests_Response) {
     39                        $this->code = $data->status_code;
     40                }
     41
     42                parent::__construct($reason, $data);
     43        }
     44}
     45 No newline at end of file
  • src/wp-includes/Requests/Exception/HTTP.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP/Unknown.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Exception based on HTTP response
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception based on HTTP response
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception_HTTP extends Requests_Exception {
     14        /**
     15         * HTTP status code
     16         *
     17         * @var integer
     18         */
     19        protected $code = 0;
     20
     21        /**
     22         * Reason phrase
     23         *
     24         * @var string
     25         */
     26        protected $reason = 'Unknown';
     27
     28        /**
     29         * Create a new exception
     30         *
     31         * There is no mechanism to pass in the status code, as this is set by the
     32         * subclass used. Reason phrases can vary, however.
     33         *
     34         * @param string|null $reason Reason phrase
     35         * @param mixed $data Associated data
     36         */
     37        public function __construct($reason = null, $data = null) {
     38                if ($reason !== null) {
     39                        $this->reason = $reason;
     40                }
     41
     42                $message = sprintf('%d %s', $this->code, $this->reason);
     43                parent::__construct($message, 'httpresponse', $data, $this->code);
     44        }
     45
     46        /**
     47         * Get the status message
     48         */
     49        public function getReason() {
     50                return $this->reason;
     51        }
     52
     53        /**
     54         * Get the correct exception class for a given error code
     55         *
     56         * @param int|bool $code HTTP status code, or false if unavailable
     57         * @return string Exception class name to use
     58         */
     59        public static function get_class($code) {
     60                if (!$code) {
     61                        return 'Requests_Exception_HTTP_Unknown';
     62                }
     63
     64                $class = sprintf('Requests_Exception_HTTP_%d', $code);
     65                if (class_exists($class)) {
     66                        return $class;
     67                }
     68
     69                return 'Requests_Exception_HTTP_Unknown';
     70        }
     71}
     72 No newline at end of file
  • src/wp-includes/Requests/Exception/Transport/cURL.php

    Property changes on: src/wp-includes/Requests/Exception/HTTP.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2
     3class Requests_Exception_Transport_cURL extends Requests_Exception_Transport {
     4
     5        const EASY = 'cURLEasy';
     6        const MULTI = 'cURLMulti';
     7        const SHARE = 'cURLShare';
     8
     9        /**
     10         * cURL error code
     11         *
     12         * @var integer
     13         */
     14        protected $code = -1;
     15
     16        /**
     17         * Which type of cURL error
     18         *
     19         * EASY|MULTI|SHARE
     20         *
     21         * @var string
     22         */
     23        protected $type = 'Unknown';
     24
     25        /**
     26         * Clear text error message
     27         *
     28         * @var string
     29         */
     30        protected $reason = 'Unknown';
     31
     32        public function __construct($message, $type, $data = null, $code = 0) {
     33                if ($type !== null) {
     34                        $this->type = $type;
     35                }
     36
     37                if ($code !== null) {
     38                        $this->code = $code;
     39                }
     40
     41                if ($message !== null) {
     42                        $this->reason = $message;
     43                }
     44
     45                $message = sprintf('%d %s', $this->code, $this->reason);
     46                parent::__construct($message, $this->type, $data, $this->code);
     47        }
     48
     49        /**
     50         * Get the error message
     51         */
     52        public function getReason() {
     53                return $this->reason;
     54        }
     55
     56}
  • src/wp-includes/Requests/Exception/Transport.php

     
     1<?php
     2
     3class Requests_Exception_Transport extends Requests_Exception {
     4
     5}
  • src/wp-includes/Requests/Exception.php

     
     1<?php
     2/**
     3 * Exception for HTTP requests
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Exception for HTTP requests
     10 *
     11 * @package Requests
     12 */
     13class Requests_Exception extends Exception {
     14        /**
     15         * Type of exception
     16         *
     17         * @var string
     18         */
     19        protected $type;
     20
     21        /**
     22         * Data associated with the exception
     23         *
     24         * @var mixed
     25         */
     26        protected $data;
     27
     28        /**
     29         * Create a new exception
     30         *
     31         * @param string $message Exception message
     32         * @param string $type Exception type
     33         * @param mixed $data Associated data
     34         * @param integer $code Exception numerical code, if applicable
     35         */
     36        public function __construct($message, $type, $data = null, $code = 0) {
     37                parent::__construct($message, $code);
     38
     39                $this->type = $type;
     40                $this->data = $data;
     41        }
     42
     43        /**
     44         * Like {@see getCode()}, but a string code.
     45         *
     46         * @codeCoverageIgnore
     47         * @return string
     48         */
     49        public function getType() {
     50                return $this->type;
     51        }
     52
     53        /**
     54         * Gives any relevant data
     55         *
     56         * @codeCoverageIgnore
     57         * @return mixed
     58         */
     59        public function getData() {
     60                return $this->data;
     61        }
     62}
     63 No newline at end of file
  • src/wp-includes/Requests/Hooker.php

    Property changes on: src/wp-includes/Requests/Exception.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Event dispatcher
     4 *
     5 * @package Requests
     6 * @subpackage Utilities
     7 */
     8
     9/**
     10 * Event dispatcher
     11 *
     12 * @package Requests
     13 * @subpackage Utilities
     14 */
     15interface Requests_Hooker {
     16        /**
     17         * Register a callback for a hook
     18         *
     19         * @param string $hook Hook name
     20         * @param callback $callback Function/method to call on event
     21         * @param int $priority Priority number. <0 is executed earlier, >0 is executed later
     22         */
     23        public function register($hook, $callback, $priority = 0);
     24
     25        /**
     26         * Dispatch a message
     27         *
     28         * @param string $hook Hook name
     29         * @param array $parameters Parameters to pass to callbacks
     30         * @return boolean Successfulness
     31         */
     32        public function dispatch($hook, $parameters = array());
     33}
     34 No newline at end of file
  • src/wp-includes/Requests/Hooks.php

    Property changes on: src/wp-includes/Requests/Hooker.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Handles adding and dispatching events
     4 *
     5 * @package Requests
     6 * @subpackage Utilities
     7 */
     8
     9/**
     10 * Handles adding and dispatching events
     11 *
     12 * @package Requests
     13 * @subpackage Utilities
     14 */
     15class Requests_Hooks implements Requests_Hooker {
     16        /**
     17         * Registered callbacks for each hook
     18         *
     19         * @var array
     20         */
     21        protected $hooks = array();
     22
     23        /**
     24         * Constructor
     25         */
     26        public function __construct() {
     27                // pass
     28        }
     29
     30        /**
     31         * Register a callback for a hook
     32         *
     33         * @param string $hook Hook name
     34         * @param callback $callback Function/method to call on event
     35         * @param int $priority Priority number. <0 is executed earlier, >0 is executed later
     36         */
     37        public function register($hook, $callback, $priority = 0) {
     38                if (!isset($this->hooks[$hook])) {
     39                        $this->hooks[$hook] = array();
     40                }
     41                if (!isset($this->hooks[$hook][$priority])) {
     42                        $this->hooks[$hook][$priority] = array();
     43                }
     44
     45                $this->hooks[$hook][$priority][] = $callback;
     46        }
     47
     48        /**
     49         * Dispatch a message
     50         *
     51         * @param string $hook Hook name
     52         * @param array $parameters Parameters to pass to callbacks
     53         * @return boolean Successfulness
     54         */
     55        public function dispatch($hook, $parameters = array()) {
     56                if (empty($this->hooks[$hook])) {
     57                        return false;
     58                }
     59
     60                foreach ($this->hooks[$hook] as $priority => $hooked) {
     61                        foreach ($hooked as $callback) {
     62                                call_user_func_array($callback, $parameters);
     63                        }
     64                }
     65
     66                return true;
     67        }
     68}
     69 No newline at end of file
  • src/wp-includes/Requests/IDNAEncoder.php

    Property changes on: src/wp-includes/Requests/Hooks.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2
     3/**
     4 * IDNA URL encoder
     5 *
     6 * Note: Not fully compliant, as nameprep does nothing yet.
     7 *
     8 * @package Requests
     9 * @subpackage Utilities
     10 * @see http://tools.ietf.org/html/rfc3490 IDNA specification
     11 * @see http://tools.ietf.org/html/rfc3492 Punycode/Bootstrap specification
     12 */
     13class Requests_IDNAEncoder {
     14        /**
     15         * ACE prefix used for IDNA
     16         *
     17         * @see http://tools.ietf.org/html/rfc3490#section-5
     18         * @var string
     19         */
     20        const ACE_PREFIX = 'xn--';
     21
     22        /**#@+
     23         * Bootstrap constant for Punycode
     24         *
     25         * @see http://tools.ietf.org/html/rfc3492#section-5
     26         * @var int
     27         */
     28        const BOOTSTRAP_BASE         = 36;
     29        const BOOTSTRAP_TMIN         = 1;
     30        const BOOTSTRAP_TMAX         = 26;
     31        const BOOTSTRAP_SKEW         = 38;
     32        const BOOTSTRAP_DAMP         = 700;
     33        const BOOTSTRAP_INITIAL_BIAS = 72;
     34        const BOOTSTRAP_INITIAL_N    = 128;
     35        /**#@-*/
     36
     37        /**
     38         * Encode a hostname using Punycode
     39         *
     40         * @param string $string Hostname
     41         * @return string Punycode-encoded hostname
     42         */
     43        public static function encode($string) {
     44                $parts = explode('.', $string);
     45                foreach ($parts as &$part) {
     46                        $part = self::to_ascii($part);
     47                }
     48                return implode('.', $parts);
     49        }
     50
     51        /**
     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)
     60         * @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)) {
     65                        // 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);
     71                }
     72
     73                // Step 2: nameprep
     74                $string = self::nameprep($string);
     75
     76                // Step 3: UseSTD3ASCIIRules is false, continue
     77                // Step 4: Check if it's ASCII now
     78                if (self::is_ascii($string)) {
     79                        // 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);
     85                }
     86
     87                // 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);
     90                }
     91
     92                // Step 6: Encode with Punycode
     93                $string = self::punycode_encode($string);
     94
     95                // Step 7: Prepend ACE prefix
     96                $string = self::ACE_PREFIX . $string;
     97
     98                // 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
     108         *
     109         * @internal (Testing found regex was the fastest implementation)
     110         *
     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
     120         *
     121         * @todo Implement this based on RFC 3491 and the newer 5891
     122         * @param string $string
     123         * @return string Prepared string
     124         */
     125        protected static function nameprep($string) {
     126                return $string;
     127        }
     128
     129        /**
     130         * Convert a UTF-8 string to a UCS-4 codepoint array
     131         *
     132         * Based on Requests_IRI::replace_invalid_with_pct_encoding()
     133         *
     134         * @throws Requests_Exception Invalid UTF-8 codepoint (`idna.invalidcodepoint`)
     135         * @param string $input
     136         * @return array Unicode code points
     137         */
     138        protected static function utf8_to_codepoints($input) {
     139                $codepoints = array();
     140
     141                // Get number of bytes
     142                $strlen = strlen($input);
     143
     144                for ($position = 0; $position < $strlen; $position++) {
     145                        $value = ord($input[$position]);
     146
     147                        // One byte sequence:
     148                        if ((~$value & 0x80) === 0x80) {
     149                                $character = $value;
     150                                $length = 1;
     151                                $remaining = 0;
     152                        }
     153                        // Two byte sequence:
     154                        elseif (($value & 0xE0) === 0xC0) {
     155                                $character = ($value & 0x1F) << 6;
     156                                $length = 2;
     157                                $remaining = 1;
     158                        }
     159                        // Three byte sequence:
     160                        elseif (($value & 0xF0) === 0xE0) {
     161                                $character = ($value & 0x0F) << 12;
     162                                $length = 3;
     163                                $remaining = 2;
     164                        }
     165                        // Four byte sequence:
     166                        elseif (($value & 0xF8) === 0xF0) {
     167                                $character = ($value & 0x07) << 18;
     168                                $length = 4;
     169                                $remaining = 3;
     170                        }
     171                        // Invalid byte:
     172                        else {
     173                                throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $value);
     174                        }
     175
     176                        if ($remaining > 0) {
     177                                if ($position + $length > $strlen) {
     178                                        throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
     179                                }
     180                                for ($position++; $remaining > 0; $position++) {
     181                                        $value = ord($input[$position]);
     182
     183                                        // If it is invalid, count the sequence as invalid and reprocess the current byte:
     184                                        if (($value & 0xC0) !== 0x80) {
     185                                                throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
     186                                        }
     187
     188                                        $character |= ($value & 0x3F) << (--$remaining * 6);
     189                                }
     190                                $position--;
     191                        }
     192
     193                        if (
     194                                // Non-shortest form sequences are invalid
     195                                   $length > 1 && $character <= 0x7F
     196                                || $length > 2 && $character <= 0x7FF
     197                                || $length > 3 && $character <= 0xFFFF
     198                                // Outside of range of ucschar codepoints
     199                                // Noncharacters
     200                                || ($character & 0xFFFE) === 0xFFFE
     201                                || $character >= 0xFDD0 && $character <= 0xFDEF
     202                                || (
     203                                        // Everything else not in ucschar
     204                                           $character > 0xD7FF && $character < 0xF900
     205                                        || $character < 0x20
     206                                        || $character > 0x7E && $character < 0xA0
     207                                        || $character > 0xEFFFD
     208                                )
     209                        ) {
     210                                throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
     211                        }
     212
     213                        $codepoints[] = $character;
     214                }
     215
     216                return $codepoints;
     217        }
     218
     219        /**
     220         * RFC3492-compliant encoder
     221         *
     222         * @internal Pseudo-code from Section 6.3 is commented with "#" next to relevant code
     223         * @throws Requests_Exception On character outside of the domain (never happens with Punycode) (`idna.character_outside_domain`)
     224         *
     225         * @param string $input UTF-8 encoded string to encode
     226         * @return string Punycode-encoded string
     227         */
     228        public static function punycode_encode($input) {
     229                $output = '';
     230#               let n = initial_n
     231                $n = self::BOOTSTRAP_INITIAL_N;
     232#               let delta = 0
     233                $delta = 0;
     234#               let bias = initial_bias
     235                $bias = self::BOOTSTRAP_INITIAL_BIAS;
     236#               let h = b = the number of basic code points in the input
     237                $h = $b = 0; // see loop
     238#               copy them to the output in order
     239                $codepoints = self::utf8_to_codepoints($input);
     240                $extended = array();
     241
     242                foreach ($codepoints as $char) {
     243                        if ($char < 128) {
     244                                // Character is valid ASCII
     245                                // TODO: this should also check if it's valid for a URL
     246                                $output .= chr($char);
     247                                $h++;
     248                        }
     249                        // Check if the character is non-ASCII, but below initial n
     250                        // This never occurs for Punycode, so ignore in coverage
     251                        // @codeCoverageIgnoreStart
     252                        elseif ($char < $n) {
     253                                throw new Requests_Exception('Invalid character', 'idna.character_outside_domain', $char);
     254                        }
     255                        // @codeCoverageIgnoreEnd
     256                        else {
     257                                $extended[$char] = true;
     258                        }
     259                }
     260                $extended = array_keys($extended);
     261                sort($extended);
     262                $b = $h;
     263#               [copy them] followed by a delimiter if b > 0
     264                if (strlen($output) > 0) {
     265                        $output .= '-';
     266                }
     267#               {if the input contains a non-basic code point < n then fail}
     268#               while h < length(input) do begin
     269                while ($h < count($codepoints)) {
     270#                       let m = the minimum code point >= n in the input
     271                        $m = array_shift($extended);
     272                        //printf('next code point to insert is %s' . PHP_EOL, dechex($m));
     273#                       let delta = delta + (m - n) * (h + 1), fail on overflow
     274                        $delta += ($m - $n) * ($h + 1);
     275#                       let n = m
     276                        $n = $m;
     277#                       for each code point c in the input (in order) do begin
     278                        for ($num = 0; $num < count($codepoints); $num++) {
     279                                $c = $codepoints[$num];
     280#                               if c < n then increment delta, fail on overflow
     281                                if ($c < $n) {
     282                                        $delta++;
     283                                }
     284#                               if c == n then begin
     285                                elseif ($c === $n) {
     286#                                       let q = delta
     287                                        $q = $delta;
     288#                                       for k = base to infinity in steps of base do begin
     289                                        for ($k = self::BOOTSTRAP_BASE; ; $k += self::BOOTSTRAP_BASE) {
     290#                                               let t = tmin if k <= bias {+ tmin}, or
     291#                                                               tmax if k >= bias + tmax, or k - bias otherwise
     292                                                if ($k <= ($bias + self::BOOTSTRAP_TMIN)) {
     293                                                        $t = self::BOOTSTRAP_TMIN;
     294                                                }
     295                                                elseif ($k >= ($bias + self::BOOTSTRAP_TMAX)) {
     296                                                        $t = self::BOOTSTRAP_TMAX;
     297                                                }
     298                                                else {
     299                                                        $t = $k - $bias;
     300                                                }
     301#                                               if q < t then break
     302                                                if ($q < $t) {
     303                                                        break;
     304                                                }
     305#                                               output the code point for digit t + ((q - t) mod (base - t))
     306                                                $digit = $t + (($q - $t) % (self::BOOTSTRAP_BASE - $t));
     307                                                $output .= self::digit_to_char($digit);
     308#                                               let q = (q - t) div (base - t)
     309                                                $q = floor(($q - $t) / (self::BOOTSTRAP_BASE - $t));
     310#                                       end
     311                                        }
     312#                                       output the code point for digit q
     313                                        $output .= self::digit_to_char($q);
     314#                                       let bias = adapt(delta, h + 1, test h equals b?)
     315                                        $bias = self::adapt($delta, $h + 1, $h === $b);
     316#                                       let delta = 0
     317                                        $delta = 0;
     318#                                       increment h
     319                                        $h++;
     320#                               end
     321                                }
     322#                       end
     323                        }
     324#                       increment delta and n
     325                        $delta++;
     326                        $n++;
     327#               end
     328                }
     329
     330                return $output;
     331        }
     332
     333        /**
     334         * Convert a digit to its respective character
     335         *
     336         * @see http://tools.ietf.org/html/rfc3492#section-5
     337         * @throws Requests_Exception On invalid digit (`idna.invalid_digit`)
     338         *
     339         * @param int $digit Digit in the range 0-35
     340         * @return string Single character corresponding to digit
     341         */
     342        protected static function digit_to_char($digit) {
     343                // @codeCoverageIgnoreStart
     344                // As far as I know, this never happens, but still good to be sure.
     345                if ($digit < 0 || $digit > 35) {
     346                        throw new Requests_Exception(sprintf('Invalid digit %d', $digit), 'idna.invalid_digit', $digit);
     347                }
     348                // @codeCoverageIgnoreEnd
     349                $digits = 'abcdefghijklmnopqrstuvwxyz0123456789';
     350                return substr($digits, $digit, 1);
     351        }
     352
     353        /**
     354         * Adapt the bias
     355         *
     356         * @see http://tools.ietf.org/html/rfc3492#section-6.1
     357         * @param int $delta
     358         * @param int $numpoints
     359         * @param bool $firsttime
     360         * @return int New bias
     361         */
     362        protected static function adapt($delta, $numpoints, $firsttime) {
     363#       function adapt(delta,numpoints,firsttime):
     364#               if firsttime then let delta = delta div damp
     365                if ($firsttime) {
     366                        $delta = floor($delta / self::BOOTSTRAP_DAMP);
     367                }
     368#               else let delta = delta div 2
     369                else {
     370                        $delta = floor($delta / 2);
     371                }
     372#               let delta = delta + (delta div numpoints)
     373                $delta += floor($delta / $numpoints);
     374#               let k = 0
     375                $k = 0;
     376#               while delta > ((base - tmin) * tmax) div 2 do begin
     377                $max = floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN) * self::BOOTSTRAP_TMAX) / 2);
     378                while ($delta > $max) {
     379#                       let delta = delta div (base - tmin)
     380                        $delta = floor($delta / (self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN));
     381#                       let k = k + base
     382                        $k += self::BOOTSTRAP_BASE;
     383#               end
     384                }
     385#               return k + (((base - tmin + 1) * delta) div (delta + skew))
     386                return $k + floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN + 1) * $delta) / ($delta + self::BOOTSTRAP_SKEW));
     387        }
     388}
     389 No newline at end of file
  • src/wp-includes/Requests/IPv6.php

    Property changes on: src/wp-includes/Requests/IDNAEncoder.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Class to validate and to work with IPv6 addresses
     4 *
     5 * @package Requests
     6 * @subpackage Utilities
     7 */
     8
     9/**
     10 * Class to validate and to work with IPv6 addresses
     11 *
     12 * This was originally based on the PEAR class of the same name, but has been
     13 * entirely rewritten.
     14 *
     15 * @package Requests
     16 * @subpackage Utilities
     17 */
     18class Requests_IPv6 {
     19        /**
     20         * Uncompresses an IPv6 address
     21         *
     22         * RFC 4291 allows you to compress consecutive zero pieces in an address to
     23         * '::'. This method expects a valid IPv6 address and expands the '::' to
     24         * the required number of zero pieces.
     25         *
     26         * Example:  FF01::101   ->  FF01:0:0:0:0:0:0:101
     27         *           ::1         ->  0:0:0:0:0:0:0:1
     28         *
     29         * @author Alexander Merz <alexander.merz@web.de>
     30         * @author elfrink at introweb dot nl
     31         * @author Josh Peck <jmp at joshpeck dot org>
     32         * @copyright 2003-2005 The PHP Group
     33         * @license http://www.opensource.org/licenses/bsd-license.php
     34         * @param string $ip An IPv6 address
     35         * @return string The uncompressed IPv6 address
     36         */
     37        public static function uncompress($ip) {
     38                if (substr_count($ip, '::') !== 1) {
     39                        return $ip;
     40                }
     41
     42                list($ip1, $ip2) = explode('::', $ip);
     43                $c1 = ($ip1 === '') ? -1 : substr_count($ip1, ':');
     44                $c2 = ($ip2 === '') ? -1 : substr_count($ip2, ':');
     45
     46                if (strpos($ip2, '.') !== false) {
     47                        $c2++;
     48                }
     49                // ::
     50                if ($c1 === -1 && $c2 === -1) {
     51                        $ip = '0:0:0:0:0:0:0:0';
     52                }
     53                // ::xxx
     54                else if ($c1 === -1) {
     55                        $fill = str_repeat('0:', 7 - $c2);
     56                        $ip = str_replace('::', $fill, $ip);
     57                }
     58                // xxx::
     59                else if ($c2 === -1) {
     60                        $fill = str_repeat(':0', 7 - $c1);
     61                        $ip = str_replace('::', $fill, $ip);
     62                }
     63                // xxx::xxx
     64                else {
     65                        $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
     66                        $ip = str_replace('::', $fill, $ip);
     67                }
     68                return $ip;
     69        }
     70
     71        /**
     72         * Compresses an IPv6 address
     73         *
     74         * RFC 4291 allows you to compress consecutive zero pieces in an address to
     75         * '::'. This method expects a valid IPv6 address and compresses consecutive
     76         * zero pieces to '::'.
     77         *
     78         * Example:  FF01:0:0:0:0:0:0:101   ->  FF01::101
     79         *           0:0:0:0:0:0:0:1        ->  ::1
     80         *
     81         * @see uncompress()
     82         * @param string $ip An IPv6 address
     83         * @return string The compressed IPv6 address
     84         */
     85        public static function compress($ip) {
     86                // Prepare the IP to be compressed
     87                $ip = self::uncompress($ip);
     88                $ip_parts = self::split_v6_v4($ip);
     89
     90                // Replace all leading zeros
     91                $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
     92
     93                // Find bunches of zeros
     94                if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) {
     95                        $max = 0;
     96                        $pos = null;
     97                        foreach ($matches[0] as $match) {
     98                                if (strlen($match[0]) > $max) {
     99                                        $max = strlen($match[0]);
     100                                        $pos = $match[1];
     101                                }
     102                        }
     103
     104                        $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
     105                }
     106
     107                if ($ip_parts[1] !== '') {
     108                        return implode(':', $ip_parts);
     109                }
     110                else {
     111                        return $ip_parts[0];
     112                }
     113        }
     114
     115        /**
     116         * Splits an IPv6 address into the IPv6 and IPv4 representation parts
     117         *
     118         * RFC 4291 allows you to represent the last two parts of an IPv6 address
     119         * using the standard IPv4 representation
     120         *
     121         * Example:  0:0:0:0:0:0:13.1.68.3
     122         *           0:0:0:0:0:FFFF:129.144.52.38
     123         *
     124         * @param string $ip An IPv6 address
     125         * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part
     126         */
     127        protected static function split_v6_v4($ip) {
     128                if (strpos($ip, '.') !== false) {
     129                        $pos = strrpos($ip, ':');
     130                        $ipv6_part = substr($ip, 0, $pos);
     131                        $ipv4_part = substr($ip, $pos + 1);
     132                        return array($ipv6_part, $ipv4_part);
     133                }
     134                else {
     135                        return array($ip, '');
     136                }
     137        }
     138
     139        /**
     140         * Checks an IPv6 address
     141         *
     142         * Checks if the given IP is a valid IPv6 address
     143         *
     144         * @param string $ip An IPv6 address
     145         * @return bool true if $ip is a valid IPv6 address
     146         */
     147        public static function check_ipv6($ip) {
     148                $ip = self::uncompress($ip);
     149                list($ipv6, $ipv4) = self::split_v6_v4($ip);
     150                $ipv6 = explode(':', $ipv6);
     151                $ipv4 = explode('.', $ipv4);
     152                if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) {
     153                        foreach ($ipv6 as $ipv6_part) {
     154                                // The section can't be empty
     155                                if ($ipv6_part === '') {
     156                                        return false;
     157                                }
     158
     159                                // Nor can it be over four characters
     160                                if (strlen($ipv6_part) > 4) {
     161                                        return false;
     162                                }
     163
     164                                // Remove leading zeros (this is safe because of the above)
     165                                $ipv6_part = ltrim($ipv6_part, '0');
     166                                if ($ipv6_part === '') {
     167                                        $ipv6_part = '0';
     168                                }
     169
     170                                // Check the value is valid
     171                                $value = hexdec($ipv6_part);
     172                                if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) {
     173                                        return false;
     174                                }
     175                        }
     176                        if (count($ipv4) === 4) {
     177                                foreach ($ipv4 as $ipv4_part) {
     178                                        $value = (int) $ipv4_part;
     179                                        if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) {
     180                                                return false;
     181                                        }
     182                                }
     183                        }
     184                        return true;
     185                }
     186                else {
     187                        return false;
     188                }
     189        }
     190}
  • src/wp-includes/Requests/IRI.php

    Property changes on: src/wp-includes/Requests/IPv6.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * IRI parser/serialiser/normaliser
     4 *
     5 * @package Requests
     6 * @subpackage Utilities
     7 */
     8
     9/**
     10 * IRI parser/serialiser/normaliser
     11 *
     12 * Copyright (c) 2007-2010, Geoffrey Sneddon and Steve Minutillo.
     13 * All rights reserved.
     14 *
     15 * Redistribution and use in source and binary forms, with or without
     16 * modification, are permitted provided that the following conditions are met:
     17 *
     18 *  * Redistributions of source code must retain the above copyright notice,
     19 *       this list of conditions and the following disclaimer.
     20 *
     21 *  * Redistributions in binary form must reproduce the above copyright notice,
     22 *       this list of conditions and the following disclaimer in the documentation
     23 *       and/or other materials provided with the distribution.
     24 *
     25 *  * Neither the name of the SimplePie Team nor the names of its contributors
     26 *       may be used to endorse or promote products derived from this software
     27 *       without specific prior written permission.
     28 *
     29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     30 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     32 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
     33 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     39 * POSSIBILITY OF SUCH DAMAGE.
     40 *
     41 * @package Requests
     42 * @subpackage Utilities
     43 * @author Geoffrey Sneddon
     44 * @author Steve Minutillo
     45 * @copyright 2007-2009 Geoffrey Sneddon and Steve Minutillo
     46 * @license http://www.opensource.org/licenses/bsd-license.php
     47 * @link http://hg.gsnedders.com/iri/
     48 *
     49 * @property string $iri IRI we're working with
     50 * @property-read string $uri IRI in URI form, {@see to_uri}
     51 * @property string $scheme Scheme part of the IRI
     52 * @property string $authority Authority part, formatted for a URI (userinfo + host + port)
     53 * @property string $iauthority Authority part of the IRI (userinfo + host + port)
     54 * @property string $userinfo Userinfo part, formatted for a URI (after '://' and before '@')
     55 * @property string $iuserinfo Userinfo part of the IRI (after '://' and before '@')
     56 * @property string $host Host part, formatted for a URI
     57 * @property string $ihost Host part of the IRI
     58 * @property string $port Port part of the IRI (after ':')
     59 * @property string $path Path part, formatted for a URI (after first '/')
     60 * @property string $ipath Path part of the IRI (after first '/')
     61 * @property string $query Query part, formatted for a URI (after '?')
     62 * @property string $iquery Query part of the IRI (after '?')
     63 * @property string $fragment Fragment, formatted for a URI (after '#')
     64 * @property string $ifragment Fragment part of the IRI (after '#')
     65 */
     66class Requests_IRI {
     67        /**
     68         * Scheme
     69         *
     70         * @var string
     71         */
     72        protected $scheme = null;
     73
     74        /**
     75         * User Information
     76         *
     77         * @var string
     78         */
     79        protected $iuserinfo = null;
     80
     81        /**
     82         * ihost
     83         *
     84         * @var string
     85         */
     86        protected $ihost = null;
     87
     88        /**
     89         * Port
     90         *
     91         * @var string
     92         */
     93        protected $port = null;
     94
     95        /**
     96         * ipath
     97         *
     98         * @var string
     99         */
     100        protected $ipath = '';
     101
     102        /**
     103         * iquery
     104         *
     105         * @var string
     106         */
     107        protected $iquery = null;
     108
     109        /**
     110         * ifragment
     111         *
     112         * @var string
     113         */
     114        protected $ifragment = null;
     115
     116        /**
     117         * Normalization database
     118         *
     119         * Each key is the scheme, each value is an array with each key as the IRI
     120         * part and value as the default value for that part.
     121         */
     122        protected $normalization = array(
     123                'acap' => array(
     124                        'port' => 674
     125                ),
     126                'dict' => array(
     127                        'port' => 2628
     128                ),
     129                'file' => array(
     130                        'ihost' => 'localhost'
     131                ),
     132                'http' => array(
     133                        'port' => 80,
     134                ),
     135                'https' => array(
     136                        'port' => 443,
     137                ),
     138        );
     139
     140        /**
     141         * Return the entire IRI when you try and read the object as a string
     142         *
     143         * @return string
     144         */
     145        public function __toString() {
     146                return $this->get_iri();
     147        }
     148
     149        /**
     150         * Overload __set() to provide access via properties
     151         *
     152         * @param string $name Property name
     153         * @param mixed $value Property value
     154         */
     155        public function __set($name, $value) {
     156                if (method_exists($this, 'set_' . $name)) {
     157                        call_user_func(array($this, 'set_' . $name), $value);
     158                }
     159                elseif (
     160                           $name === 'iauthority'
     161                        || $name === 'iuserinfo'
     162                        || $name === 'ihost'
     163                        || $name === 'ipath'
     164                        || $name === 'iquery'
     165                        || $name === 'ifragment'
     166                ) {
     167                        call_user_func(array($this, 'set_' . substr($name, 1)), $value);
     168                }
     169        }
     170
     171        /**
     172         * Overload __get() to provide access via properties
     173         *
     174         * @param string $name Property name
     175         * @return mixed
     176         */
     177        public function __get($name) {
     178                // isset() returns false for null, we don't want to do that
     179                // Also why we use array_key_exists below instead of isset()
     180                $props = get_object_vars($this);
     181
     182                if (
     183                        $name === 'iri' ||
     184                        $name === 'uri' ||
     185                        $name === 'iauthority' ||
     186                        $name === 'authority'
     187                ) {
     188                        $method = 'get_' . $name;
     189                        $return = $this->$method();
     190                }
     191                elseif (array_key_exists($name, $props)) {
     192                        $return = $this->$name;
     193                }
     194                // host -> ihost
     195                elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) {
     196                        $name = $prop;
     197                        $return = $this->$prop;
     198                }
     199                // ischeme -> scheme
     200                elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) {
     201                        $name = $prop;
     202                        $return = $this->$prop;
     203                }
     204                else {
     205                        trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
     206                        $return = null;
     207                }
     208
     209                if ($return === null && isset($this->normalization[$this->scheme][$name])) {
     210                        return $this->normalization[$this->scheme][$name];
     211                }
     212                else {
     213                        return $return;
     214                }
     215        }
     216
     217        /**
     218         * Overload __isset() to provide access via properties
     219         *
     220         * @param string $name Property name
     221         * @return bool
     222         */
     223        public function __isset($name) {
     224                return (method_exists($this, 'get_' . $name) || isset($this->$name));
     225        }
     226
     227        /**
     228         * Overload __unset() to provide access via properties
     229         *
     230         * @param string $name Property name
     231         */
     232        public function __unset($name) {
     233                if (method_exists($this, 'set_' . $name)) {
     234                        call_user_func(array($this, 'set_' . $name), '');
     235                }
     236        }
     237
     238        /**
     239         * Create a new IRI object, from a specified string
     240         *
     241         * @param string|null $iri
     242         */
     243        public function __construct($iri = null) {
     244                $this->set_iri($iri);
     245        }
     246
     247        /**
     248         * Create a new IRI object by resolving a relative IRI
     249         *
     250         * Returns false if $base is not absolute, otherwise an IRI.
     251         *
     252         * @param IRI|string $base (Absolute) Base IRI
     253         * @param IRI|string $relative Relative IRI
     254         * @return IRI|false
     255         */
     256        public static function absolutize($base, $relative) {
     257                if (!($relative instanceof Requests_IRI)) {
     258                        $relative = new Requests_IRI($relative);
     259                }
     260                if (!$relative->is_valid()) {
     261                        return false;
     262                }
     263                elseif ($relative->scheme !== null) {
     264                        return clone $relative;
     265                }
     266
     267                if (!($base instanceof Requests_IRI)) {
     268                        $base = new Requests_IRI($base);
     269                }
     270                if ($base->scheme === null || !$base->is_valid()) {
     271                        return false;
     272                }
     273
     274                if ($relative->get_iri() !== '') {
     275                        if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) {
     276                                $target = clone $relative;
     277                                $target->scheme = $base->scheme;
     278                        }
     279                        else {
     280                                $target = new Requests_IRI;
     281                                $target->scheme = $base->scheme;
     282                                $target->iuserinfo = $base->iuserinfo;
     283                                $target->ihost = $base->ihost;
     284                                $target->port = $base->port;
     285                                if ($relative->ipath !== '') {
     286                                        if ($relative->ipath[0] === '/') {
     287                                                $target->ipath = $relative->ipath;
     288                                        }
     289                                        elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') {
     290                                                $target->ipath = '/' . $relative->ipath;
     291                                        }
     292                                        elseif (($last_segment = strrpos($base->ipath, '/')) !== false) {
     293                                                $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
     294                                        }
     295                                        else {
     296                                                $target->ipath = $relative->ipath;
     297                                        }
     298                                        $target->ipath = $target->remove_dot_segments($target->ipath);
     299                                        $target->iquery = $relative->iquery;
     300                                }
     301                                else {
     302                                        $target->ipath = $base->ipath;
     303                                        if ($relative->iquery !== null) {
     304                                                $target->iquery = $relative->iquery;
     305                                        }
     306                                        elseif ($base->iquery !== null) {
     307                                                $target->iquery = $base->iquery;
     308                                        }
     309                                }
     310                                $target->ifragment = $relative->ifragment;
     311                        }
     312                }
     313                else {
     314                        $target = clone $base;
     315                        $target->ifragment = null;
     316                }
     317                $target->scheme_normalization();
     318                return $target;
     319        }
     320
     321        /**
     322         * Parse an IRI into scheme/authority/path/query/fragment segments
     323         *
     324         * @param string $iri
     325         * @return array
     326         */
     327        protected function parse_iri($iri) {
     328                $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
     329                $has_match = preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match);
     330                if (!$has_match) {
     331                        throw new Requests_Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri);
     332                }
     333
     334                if ($match[1] === '') {
     335                        $match['scheme'] = null;
     336                }
     337                if (!isset($match[3]) || $match[3] === '') {
     338                        $match['authority'] = null;
     339                }
     340                if (!isset($match[5])) {
     341                        $match['path'] = '';
     342                }
     343                if (!isset($match[6]) || $match[6] === '') {
     344                        $match['query'] = null;
     345                }
     346                if (!isset($match[8]) || $match[8] === '') {
     347                        $match['fragment'] = null;
     348                }
     349                return $match;
     350        }
     351
     352        /**
     353         * Remove dot segments from a path
     354         *
     355         * @param string $input
     356         * @return string
     357         */
     358        protected function remove_dot_segments($input) {
     359                $output = '';
     360                while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') {
     361                        // A: If the input buffer begins with a prefix of "../" or "./",
     362                        // then remove that prefix from the input buffer; otherwise,
     363                        if (strpos($input, '../') === 0) {
     364                                $input = substr($input, 3);
     365                        }
     366                        elseif (strpos($input, './') === 0) {
     367                                $input = substr($input, 2);
     368                        }
     369                        // B: if the input buffer begins with a prefix of "/./" or "/.",
     370                        // where "." is a complete path segment, then replace that prefix
     371                        // with "/" in the input buffer; otherwise,
     372                        elseif (strpos($input, '/./') === 0) {
     373                                $input = substr($input, 2);
     374                        }
     375                        elseif ($input === '/.') {
     376                                $input = '/';
     377                        }
     378                        // C: if the input buffer begins with a prefix of "/../" or "/..",
     379                        // where ".." is a complete path segment, then replace that prefix
     380                        // with "/" in the input buffer and remove the last segment and its
     381                        // preceding "/" (if any) from the output buffer; otherwise,
     382                        elseif (strpos($input, '/../') === 0) {
     383                                $input = substr($input, 3);
     384                                $output = substr_replace($output, '', strrpos($output, '/'));
     385                        }
     386                        elseif ($input === '/..') {
     387                                $input = '/';
     388                                $output = substr_replace($output, '', strrpos($output, '/'));
     389                        }
     390                        // D: if the input buffer consists only of "." or "..", then remove
     391                        // that from the input buffer; otherwise,
     392                        elseif ($input === '.' || $input === '..') {
     393                                $input = '';
     394                        }
     395                        // E: move the first path segment in the input buffer to the end of
     396                        // the output buffer, including the initial "/" character (if any)
     397                        // and any subsequent characters up to, but not including, the next
     398                        // "/" character or the end of the input buffer
     399                        elseif (($pos = strpos($input, '/', 1)) !== false) {
     400                                $output .= substr($input, 0, $pos);
     401                                $input = substr_replace($input, '', 0, $pos);
     402                        }
     403                        else {
     404                                $output .= $input;
     405                                $input = '';
     406                        }
     407                }
     408                return $output . $input;
     409        }
     410
     411        /**
     412         * Replace invalid character with percent encoding
     413         *
     414         * @param string $string Input string
     415         * @param string $extra_chars Valid characters not in iunreserved or
     416         *                            iprivate (this is ASCII-only)
     417         * @param bool $iprivate Allow iprivate
     418         * @return string
     419         */
     420        protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) {
     421                // Normalize as many pct-encoded sections as possible
     422                $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string);
     423
     424                // Replace invalid percent characters
     425                $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
     426
     427                // Add unreserved and % to $extra_chars (the latter is safe because all
     428                // pct-encoded sections are now valid).
     429                $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
     430
     431                // Now replace any bytes that aren't allowed with their pct-encoded versions
     432                $position = 0;
     433                $strlen = strlen($string);
     434                while (($position += strspn($string, $extra_chars, $position)) < $strlen) {
     435                        $value = ord($string[$position]);
     436
     437                        // Start position
     438                        $start = $position;
     439
     440                        // By default we are valid
     441                        $valid = true;
     442
     443                        // No one byte sequences are valid due to the while.
     444                        // Two byte sequence:
     445                        if (($value & 0xE0) === 0xC0) {
     446                                $character = ($value & 0x1F) << 6;
     447                                $length = 2;
     448                                $remaining = 1;
     449                        }
     450                        // Three byte sequence:
     451                        elseif (($value & 0xF0) === 0xE0) {
     452                                $character = ($value & 0x0F) << 12;
     453                                $length = 3;
     454                                $remaining = 2;
     455                        }
     456                        // Four byte sequence:
     457                        elseif (($value & 0xF8) === 0xF0) {
     458                                $character = ($value & 0x07) << 18;
     459                                $length = 4;
     460                                $remaining = 3;
     461                        }
     462                        // Invalid byte:
     463                        else {
     464                                $valid = false;
     465                                $length = 1;
     466                                $remaining = 0;
     467                        }
     468
     469                        if ($remaining) {
     470                                if ($position + $length <= $strlen) {
     471                                        for ($position++; $remaining; $position++) {
     472                                                $value = ord($string[$position]);
     473
     474                                                // Check that the byte is valid, then add it to the character:
     475                                                if (($value & 0xC0) === 0x80) {
     476                                                        $character |= ($value & 0x3F) << (--$remaining * 6);
     477                                                }
     478                                                // If it is invalid, count the sequence as invalid and reprocess the current byte:
     479                                                else {
     480                                                        $valid = false;
     481                                                        $position--;
     482                                                        break;
     483                                                }
     484                                        }
     485                                }
     486                                else {
     487                                        $position = $strlen - 1;
     488                                        $valid = false;
     489                                }
     490                        }
     491
     492                        // Percent encode anything invalid or not in ucschar
     493                        if (
     494                                // Invalid sequences
     495                                !$valid
     496                                // Non-shortest form sequences are invalid
     497                                || $length > 1 && $character <= 0x7F
     498                                || $length > 2 && $character <= 0x7FF
     499                                || $length > 3 && $character <= 0xFFFF
     500                                // Outside of range of ucschar codepoints
     501                                // Noncharacters
     502                                || ($character & 0xFFFE) === 0xFFFE
     503                                || $character >= 0xFDD0 && $character <= 0xFDEF
     504                                || (
     505                                        // Everything else not in ucschar
     506                                           $character > 0xD7FF && $character < 0xF900
     507                                        || $character < 0xA0
     508                                        || $character > 0xEFFFD
     509                                )
     510                                && (
     511                                        // Everything not in iprivate, if it applies
     512                                           !$iprivate
     513                                        || $character < 0xE000
     514                                        || $character > 0x10FFFD
     515                                )
     516                        ) {
     517                                // If we were a character, pretend we weren't, but rather an error.
     518                                if ($valid) {
     519                                        $position--;
     520                                }
     521
     522                                for ($j = $start; $j <= $position; $j++) {
     523                                        $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
     524                                        $j += 2;
     525                                        $position += 2;
     526                                        $strlen += 2;
     527                                }
     528                        }
     529                }
     530
     531                return $string;
     532        }
     533
     534        /**
     535         * Callback function for preg_replace_callback.
     536         *
     537         * Removes sequences of percent encoded bytes that represent UTF-8
     538         * encoded characters in iunreserved
     539         *
     540         * @param array $match PCRE match
     541         * @return string Replacement
     542         */
     543        protected function remove_iunreserved_percent_encoded($match) {
     544                // As we just have valid percent encoded sequences we can just explode
     545                // and ignore the first member of the returned array (an empty string).
     546                $bytes = explode('%', $match[0]);
     547
     548                // Initialize the new string (this is what will be returned) and that
     549                // there are no bytes remaining in the current sequence (unsurprising
     550                // at the first byte!).
     551                $string = '';
     552                $remaining = 0;
     553
     554                // Loop over each and every byte, and set $value to its value
     555                for ($i = 1, $len = count($bytes); $i < $len; $i++) {
     556                        $value = hexdec($bytes[$i]);
     557
     558                        // If we're the first byte of sequence:
     559                        if (!$remaining) {
     560                                // Start position
     561                                $start = $i;
     562
     563                                // By default we are valid
     564                                $valid = true;
     565
     566                                // One byte sequence:
     567                                if ($value <= 0x7F) {
     568                                        $character = $value;
     569                                        $length = 1;
     570                                }
     571                                // Two byte sequence:
     572                                elseif (($value & 0xE0) === 0xC0) {
     573                                        $character = ($value & 0x1F) << 6;
     574                                        $length = 2;
     575                                        $remaining = 1;
     576                                }
     577                                // Three byte sequence:
     578                                elseif (($value & 0xF0) === 0xE0) {
     579                                        $character = ($value & 0x0F) << 12;
     580                                        $length = 3;
     581                                        $remaining = 2;
     582                                }
     583                                // Four byte sequence:
     584                                elseif (($value & 0xF8) === 0xF0) {
     585                                        $character = ($value & 0x07) << 18;
     586                                        $length = 4;
     587                                        $remaining = 3;
     588                                }
     589                                // Invalid byte:
     590                                else {
     591                                        $valid = false;
     592                                        $remaining = 0;
     593                                }
     594                        }
     595                        // Continuation byte:
     596                        else {
     597                                // Check that the byte is valid, then add it to the character:
     598                                if (($value & 0xC0) === 0x80) {
     599                                        $remaining--;
     600                                        $character |= ($value & 0x3F) << ($remaining * 6);
     601                                }
     602                                // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
     603                                else {
     604                                        $valid = false;
     605                                        $remaining = 0;
     606                                        $i--;
     607                                }
     608                        }
     609
     610                        // If we've reached the end of the current byte sequence, append it to Unicode::$data
     611                        if (!$remaining) {
     612                                // Percent encode anything invalid or not in iunreserved
     613                                if (
     614                                        // Invalid sequences
     615                                        !$valid
     616                                        // Non-shortest form sequences are invalid
     617                                        || $length > 1 && $character <= 0x7F
     618                                        || $length > 2 && $character <= 0x7FF
     619                                        || $length > 3 && $character <= 0xFFFF
     620                                        // Outside of range of iunreserved codepoints
     621                                        || $character < 0x2D
     622                                        || $character > 0xEFFFD
     623                                        // Noncharacters
     624                                        || ($character & 0xFFFE) === 0xFFFE
     625                                        || $character >= 0xFDD0 && $character <= 0xFDEF
     626                                        // Everything else not in iunreserved (this is all BMP)
     627                                        || $character === 0x2F
     628                                        || $character > 0x39 && $character < 0x41
     629                                        || $character > 0x5A && $character < 0x61
     630                                        || $character > 0x7A && $character < 0x7E
     631                                        || $character > 0x7E && $character < 0xA0
     632                                        || $character > 0xD7FF && $character < 0xF900
     633                                ) {
     634                                        for ($j = $start; $j <= $i; $j++) {
     635                                                $string .= '%' . strtoupper($bytes[$j]);
     636                                        }
     637                                }
     638                                else {
     639                                        for ($j = $start; $j <= $i; $j++) {
     640                                                $string .= chr(hexdec($bytes[$j]));
     641                                        }
     642                                }
     643                        }
     644                }
     645
     646                // If we have any bytes left over they are invalid (i.e., we are
     647                // mid-way through a multi-byte sequence)
     648                if ($remaining) {
     649                        for ($j = $start; $j < $len; $j++) {
     650                                $string .= '%' . strtoupper($bytes[$j]);
     651                        }
     652                }
     653
     654                return $string;
     655        }
     656
     657        protected function scheme_normalization() {
     658                if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) {
     659                        $this->iuserinfo = null;
     660                }
     661                if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) {
     662                        $this->ihost = null;
     663                }
     664                if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) {
     665                        $this->port = null;
     666                }
     667                if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) {
     668                        $this->ipath = '';
     669                }
     670                if (isset($this->ihost) && empty($this->ipath)) {
     671                        $this->ipath = '/';
     672                }
     673                if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) {
     674                        $this->iquery = null;
     675                }
     676                if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) {
     677                        $this->ifragment = null;
     678                }
     679        }
     680
     681        /**
     682         * Check if the object represents a valid IRI. This needs to be done on each
     683         * call as some things change depending on another part of the IRI.
     684         *
     685         * @return bool
     686         */
     687        public function is_valid() {
     688                $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
     689                if ($this->ipath !== '' &&
     690                        (
     691                                $isauthority && (
     692                                        $this->ipath[0] !== '/' ||
     693                                        substr($this->ipath, 0, 2) === '//'
     694                                ) ||
     695                                (
     696                                        $this->scheme === null &&
     697                                        !$isauthority &&
     698                                        strpos($this->ipath, ':') !== false &&
     699                                        (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
     700                                )
     701                        )
     702                ) {
     703                        return false;
     704                }
     705
     706                return true;
     707        }
     708
     709        /**
     710         * Set the entire IRI. Returns true on success, false on failure (if there
     711         * are any invalid characters).
     712         *
     713         * @param string $iri
     714         * @return bool
     715         */
     716        protected function set_iri($iri) {
     717                static $cache;
     718                if (!$cache) {
     719                        $cache = array();
     720                }
     721
     722                if ($iri === null) {
     723                        return true;
     724                }
     725                if (isset($cache[$iri])) {
     726                        list($this->scheme,
     727                                 $this->iuserinfo,
     728                                 $this->ihost,
     729                                 $this->port,
     730                                 $this->ipath,
     731                                 $this->iquery,
     732                                 $this->ifragment,
     733                                 $return) = $cache[$iri];
     734                        return $return;
     735                }
     736
     737                $parsed = $this->parse_iri((string) $iri);
     738
     739                $return = $this->set_scheme($parsed['scheme'])
     740                        && $this->set_authority($parsed['authority'])
     741                        && $this->set_path($parsed['path'])
     742                        && $this->set_query($parsed['query'])
     743                        && $this->set_fragment($parsed['fragment']);
     744
     745                $cache[$iri] = array($this->scheme,
     746                                                         $this->iuserinfo,
     747                                                         $this->ihost,
     748                                                         $this->port,
     749                                                         $this->ipath,
     750                                                         $this->iquery,
     751                                                         $this->ifragment,
     752                                                         $return);
     753                return $return;
     754        }
     755
     756        /**
     757         * Set the scheme. Returns true on success, false on failure (if there are
     758         * any invalid characters).
     759         *
     760         * @param string $scheme
     761         * @return bool
     762         */
     763        protected function set_scheme($scheme) {
     764                if ($scheme === null) {
     765                        $this->scheme = null;
     766                }
     767                elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) {
     768                        $this->scheme = null;
     769                        return false;
     770                }
     771                else {
     772                        $this->scheme = strtolower($scheme);
     773                }
     774                return true;
     775        }
     776
     777        /**
     778         * Set the authority. Returns true on success, false on failure (if there are
     779         * any invalid characters).
     780         *
     781         * @param string $authority
     782         * @return bool
     783         */
     784        protected function set_authority($authority) {
     785                static $cache;
     786                if (!$cache) {
     787                        $cache = array();
     788                }
     789
     790                if ($authority === null) {
     791                        $this->iuserinfo = null;
     792                        $this->ihost = null;
     793                        $this->port = null;
     794                        return true;
     795                }
     796                if (isset($cache[$authority])) {
     797                        list($this->iuserinfo,
     798                                 $this->ihost,
     799                                 $this->port,
     800                                 $return) = $cache[$authority];
     801
     802                        return $return;
     803                }
     804
     805                $remaining = $authority;
     806                if (($iuserinfo_end = strrpos($remaining, '@')) !== false) {
     807                        $iuserinfo = substr($remaining, 0, $iuserinfo_end);
     808                        $remaining = substr($remaining, $iuserinfo_end + 1);
     809                }
     810                else {
     811                        $iuserinfo = null;
     812                }
     813                if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false) {
     814                        $port = substr($remaining, $port_start + 1);
     815                        if ($port === false || $port === '') {
     816                                $port = null;
     817                        }
     818                        $remaining = substr($remaining, 0, $port_start);
     819                }
     820                else {
     821                        $port = null;
     822                }
     823
     824                $return = $this->set_userinfo($iuserinfo) &&
     825                                  $this->set_host($remaining) &&
     826                                  $this->set_port($port);
     827
     828                $cache[$authority] = array($this->iuserinfo,
     829                                                                   $this->ihost,
     830                                                                   $this->port,
     831                                                                   $return);
     832
     833                return $return;
     834        }
     835
     836        /**
     837         * Set the iuserinfo.
     838         *
     839         * @param string $iuserinfo
     840         * @return bool
     841         */
     842        protected function set_userinfo($iuserinfo) {
     843                if ($iuserinfo === null) {
     844                        $this->iuserinfo = null;
     845                }
     846                else {
     847                        $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
     848                        $this->scheme_normalization();
     849                }
     850
     851                return true;
     852        }
     853
     854        /**
     855         * Set the ihost. Returns true on success, false on failure (if there are
     856         * any invalid characters).
     857         *
     858         * @param string $ihost
     859         * @return bool
     860         */
     861        protected function set_host($ihost) {
     862                if ($ihost === null) {
     863                        $this->ihost = null;
     864                        return true;
     865                }
     866                if (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') {
     867                        if (Requests_IPv6::check_ipv6(substr($ihost, 1, -1))) {
     868                                $this->ihost = '[' . Requests_IPv6::compress(substr($ihost, 1, -1)) . ']';
     869                        }
     870                        else {
     871                                $this->ihost = null;
     872                                return false;
     873                        }
     874                }
     875                else {
     876                        $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
     877
     878                        // Lowercase, but ignore pct-encoded sections (as they should
     879                        // remain uppercase). This must be done after the previous step
     880                        // as that can add unescaped characters.
     881                        $position = 0;
     882                        $strlen = strlen($ihost);
     883                        while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) {
     884                                if ($ihost[$position] === '%') {
     885                                        $position += 3;
     886                                }
     887                                else {
     888                                        $ihost[$position] = strtolower($ihost[$position]);
     889                                        $position++;
     890                                }
     891                        }
     892
     893                        $this->ihost = $ihost;
     894                }
     895
     896                $this->scheme_normalization();
     897
     898                return true;
     899        }
     900
     901        /**
     902         * Set the port. Returns true on success, false on failure (if there are
     903         * any invalid characters).
     904         *
     905         * @param string $port
     906         * @return bool
     907         */
     908        protected function set_port($port) {
     909                if ($port === null) {
     910                        $this->port = null;
     911                        return true;
     912                }
     913
     914                if (strspn($port, '0123456789') === strlen($port)) {
     915                        $this->port = (int) $port;
     916                        $this->scheme_normalization();
     917                        return true;
     918                }
     919
     920                $this->port = null;
     921                return false;
     922        }
     923
     924        /**
     925         * Set the ipath.
     926         *
     927         * @param string $ipath
     928         * @return bool
     929         */
     930        protected function set_path($ipath) {
     931                static $cache;
     932                if (!$cache) {
     933                        $cache = array();
     934                }
     935
     936                $ipath = (string) $ipath;
     937
     938                if (isset($cache[$ipath])) {
     939                        $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
     940                }
     941                else {
     942                        $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
     943                        $removed = $this->remove_dot_segments($valid);
     944
     945                        $cache[$ipath] = array($valid, $removed);
     946                        $this->ipath = ($this->scheme !== null) ? $removed : $valid;
     947                }
     948                $this->scheme_normalization();
     949                return true;
     950        }
     951
     952        /**
     953         * Set the iquery.
     954         *
     955         * @param string $iquery
     956         * @return bool
     957         */
     958        protected function set_query($iquery) {
     959                if ($iquery === null) {
     960                        $this->iquery = null;
     961                }
     962                else {
     963                        $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
     964                        $this->scheme_normalization();
     965                }
     966                return true;
     967        }
     968
     969        /**
     970         * Set the ifragment.
     971         *
     972         * @param string $ifragment
     973         * @return bool
     974         */
     975        protected function set_fragment($ifragment) {
     976                if ($ifragment === null) {
     977                        $this->ifragment = null;
     978                }
     979                else {
     980                        $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
     981                        $this->scheme_normalization();
     982                }
     983                return true;
     984        }
     985
     986        /**
     987         * Convert an IRI to a URI (or parts thereof)
     988         *
     989         * @param string|bool IRI to convert (or false from {@see get_iri})
     990         * @return string|false URI if IRI is valid, false otherwise.
     991         */
     992        protected function to_uri($string) {
     993                if (!is_string($string)) {
     994                        return false;
     995                }
     996
     997                static $non_ascii;
     998                if (!$non_ascii) {
     999                        $non_ascii = implode('', range("\x80", "\xFF"));
     1000                }
     1001
     1002                $position = 0;
     1003                $strlen = strlen($string);
     1004                while (($position += strcspn($string, $non_ascii, $position)) < $strlen) {
     1005                        $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
     1006                        $position += 3;
     1007                        $strlen += 2;
     1008                }
     1009
     1010                return $string;
     1011        }
     1012
     1013        /**
     1014         * Get the complete IRI
     1015         *
     1016         * @return string
     1017         */
     1018        protected function get_iri() {
     1019                if (!$this->is_valid()) {
     1020                        return false;
     1021                }
     1022
     1023                $iri = '';
     1024                if ($this->scheme !== null) {
     1025                        $iri .= $this->scheme . ':';
     1026                }
     1027                if (($iauthority = $this->get_iauthority()) !== null) {
     1028                        $iri .= '//' . $iauthority;
     1029                }
     1030                $iri .= $this->ipath;
     1031                if ($this->iquery !== null) {
     1032                        $iri .= '?' . $this->iquery;
     1033                }
     1034                if ($this->ifragment !== null) {
     1035                        $iri .= '#' . $this->ifragment;
     1036                }
     1037
     1038                return $iri;
     1039        }
     1040
     1041        /**
     1042         * Get the complete URI
     1043         *
     1044         * @return string
     1045         */
     1046        protected function get_uri() {
     1047                return $this->to_uri($this->get_iri());
     1048        }
     1049
     1050        /**
     1051         * Get the complete iauthority
     1052         *
     1053         * @return string
     1054         */
     1055        protected function get_iauthority() {
     1056                if ($this->iuserinfo === null && $this->ihost === null && $this->port === null) {
     1057                        return null;
     1058                }
     1059
     1060                $iauthority = '';
     1061                if ($this->iuserinfo !== null) {
     1062                        $iauthority .= $this->iuserinfo . '@';
     1063                }
     1064                if ($this->ihost !== null) {
     1065                        $iauthority .= $this->ihost;
     1066                }
     1067                if ($this->port !== null) {
     1068                        $iauthority .= ':' . $this->port;
     1069                }
     1070                return $iauthority;
     1071        }
     1072
     1073        /**
     1074         * Get the complete authority
     1075         *
     1076         * @return string
     1077         */
     1078        protected function get_authority() {
     1079                $iauthority = $this->get_iauthority();
     1080                if (is_string($iauthority)) {
     1081                        return $this->to_uri($iauthority);
     1082                }
     1083                else {
     1084                        return $iauthority;
     1085                }
     1086        }
     1087}
  • src/wp-includes/Requests/Proxy/HTTP.php

    Property changes on: src/wp-includes/Requests/IRI.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * HTTP Proxy connection interface
     4 *
     5 * @package Requests
     6 * @subpackage Proxy
     7 * @since 1.6
     8 */
     9
     10/**
     11 * HTTP Proxy connection interface
     12 *
     13 * Provides a handler for connection via an HTTP proxy
     14 *
     15 * @package Requests
     16 * @subpackage Proxy
     17 * @since 1.6
     18 */
     19class Requests_Proxy_HTTP implements Requests_Proxy {
     20        /**
     21         * Proxy host and port
     22         *
     23         * Notation: "host:port" (eg 127.0.0.1:8080 or someproxy.com:3128)
     24         *
     25         * @var string
     26         */
     27        public $proxy;
     28
     29        /**
     30         * Username
     31         *
     32         * @var string
     33         */
     34        public $user;
     35
     36        /**
     37         * Password
     38         *
     39         * @var string
     40         */
     41        public $pass;
     42
     43        /**
     44         * Do we need to authenticate? (ie username & password have been provided)
     45         *
     46         * @var boolean
     47         */
     48        public $use_authentication;
     49
     50        /**
     51         * Constructor
     52         *
     53         * @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
     56         */
     57        public function __construct($args = null) {
     58                if (is_string($args)) {
     59                        $this->proxy = $args;
     60                }
     61                elseif (is_array($args)) {
     62                        if (count($args) == 1) {
     63                                list($this->proxy) = $args;
     64                        }
     65                        elseif (count($args) == 3) {
     66                                list($this->proxy, $this->user, $this->pass) = $args;
     67                                $this->use_authentication = true;
     68                        }
     69                        else {
     70                                throw new Requests_Exception('Invalid number of arguments', 'proxyhttpbadargs');
     71                        }
     72                }
     73        }
     74
     75        /**
     76         * Register the necessary callbacks
     77         *
     78         * @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
     84         */
     85        public function register(Requests_Hooks &$hooks) {
     86                $hooks->register('curl.before_send', array(&$this, 'curl_before_send'));
     87
     88                $hooks->register('fsockopen.remote_socket', array(&$this, 'fsockopen_remote_socket'));
     89                $hooks->register('fsockopen.remote_host_path', array(&$this, 'fsockopen_remote_host_path'));
     90                if ($this->use_authentication) {
     91                        $hooks->register('fsockopen.after_headers', array(&$this, 'fsockopen_header'));
     92                }
     93        }
     94
     95        /**
     96         * Set cURL parameters before the data is sent
     97         *
     98         * @since 1.6
     99         * @param resource $handle cURL resource
     100         */
     101        public function curl_before_send(&$handle) {
     102                curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
     103                curl_setopt($handle, CURLOPT_PROXY, $this->proxy);
     104
     105                if ($this->use_authentication) {
     106                        curl_setopt($handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
     107                        curl_setopt($handle, CURLOPT_PROXYUSERPWD, $this->get_auth_string());
     108                }
     109        }
     110
     111        /**
     112         * Alter remote socket information before opening socket connection
     113         *
     114         * @since 1.6
     115         * @param string $remote_socket Socket connection string
     116         */
     117        public function fsockopen_remote_socket(&$remote_socket) {
     118                $remote_socket = $this->proxy;
     119        }
     120
     121        /**
     122         * Alter remote path before getting stream data
     123         *
     124         * @since 1.6
     125         * @param string $path Path to send in HTTP request string ("GET ...")
     126         * @param string $url Full URL we're requesting
     127         */
     128        public function fsockopen_remote_host_path(&$path, $url) {
     129                $path = $url;
     130        }
     131
     132        /**
     133         * Add extra headers to the request before sending
     134         *
     135         * @since 1.6
     136         * @param string $out HTTP header string
     137         */
     138        public function fsockopen_header(&$out) {
     139                $out .= sprintf("Proxy-Authorization: Basic %s\r\n", base64_encode($this->get_auth_string()));
     140        }
     141
     142        /**
     143         * Get the authentication string (user:pass)
     144         *
     145         * @since 1.6
     146         * @return string
     147         */
     148        public function get_auth_string() {
     149                return $this->user . ':' . $this->pass;
     150        }
     151}
     152 No newline at end of file
  • src/wp-includes/Requests/Proxy.php

     
     1<?php
     2/**
     3 * Proxy connection interface
     4 *
     5 * @package Requests
     6 * @subpackage Proxy
     7 * @since 1.6
     8 */
     9
     10/**
     11 * Proxy connection interface
     12 *
     13 * Implement this interface to handle proxy settings and authentication
     14 *
     15 * Parameters should be passed via the constructor where possible, as this
     16 * makes it much easier for users to use your provider.
     17 *
     18 * @see Requests_Hooks
     19 * @package Requests
     20 * @subpackage Proxy
     21 * @since 1.6
     22 */
     23interface Requests_Proxy {
     24        /**
     25         * Register hooks as needed
     26         *
     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
     29         * hooks you'll need.
     30         *
     31         * @see Requests_Hooks::register
     32         * @param Requests_Hooks $hooks Hook system
     33         */
     34        public function register(Requests_Hooks &$hooks);
     35}
     36 No newline at end of file
  • src/wp-includes/Requests/Response/Headers.php

     
     1<?php
     2/**
     3 * Case-insensitive dictionary, suitable for HTTP headers
     4 *
     5 * @package Requests
     6 */
     7
     8/**
     9 * Case-insensitive dictionary, suitable for HTTP headers
     10 *
     11 * @package Requests
     12 */
     13class Requests_Response_Headers extends Requests_Utility_CaseInsensitiveDictionary {
     14        /**
     15         * Get the given header
     16         *
     17         * Unlike {@see self::getValues()}, this returns a string. If there are
     18         * multiple values, it concatenates them with a comma as per RFC2616.
     19         *
     20         * Avoid using this where commas may be used unquoted in values, such as
     21         * Set-Cookie headers.
     22         *
     23         * @param string $key
     24         * @return string Header value
     25         */
     26        public function offsetGet($key) {
     27                $key = strtolower($key);
     28                if (!isset($this->data[$key])) {
     29                        return null;
     30                }
     31
     32                return $this->flatten($this->data[$key]);
     33        }
     34
     35        /**
     36         * Set the given item
     37         *
     38         * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
     39         *
     40         * @param string $key Item name
     41         * @param string $value Item value
     42         */
     43        public function offsetSet($key, $value) {
     44                if ($key === null) {
     45                        throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
     46                }
     47
     48                $key = strtolower($key);
     49
     50                if (!isset($this->data[$key])) {
     51                        $this->data[$key] = array();
     52                }
     53
     54                $this->data[$key][] = $value;
     55        }
     56
     57        /**
     58         * Get all values for a given header
     59         *
     60         * @param string $key
     61         * @return array Header values
     62         */
     63        public function getValues($key) {
     64                $key = strtolower($key);
     65                if (!isset($this->data[$key])) {
     66                        return null;
     67                }
     68
     69                return $this->data[$key];
     70        }
     71
     72        /**
     73         * Flattens a value into a string
     74         *
     75         * Converts an array into a string by imploding values with a comma, as per
     76         * RFC2616's rules for folding headers.
     77         *
     78         * @param string|array $value Value to flatten
     79         * @return string Flattened value
     80         */
     81        public function flatten($value) {
     82                if (is_array($value)) {
     83                        $value = implode(',', $value);
     84                }
     85
     86                return $value;
     87        }
     88
     89        /**
     90         * Get an iterator for the data
     91         *
     92         * Converts the internal
     93         * @return ArrayIterator
     94         */
     95        public function getIterator() {
     96                return new Requests_Utility_FilteredIterator($this->data, array($this, 'flatten'));
     97        }
     98}
  • src/wp-includes/Requests/Response.php

    Property changes on: src/wp-includes/Requests/Response/Headers.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * HTTP response class
     4 *
     5 * Contains a response from Requests::request()
     6 * @package Requests
     7 */
     8
     9/**
     10 * HTTP response class
     11 *
     12 * Contains a response from Requests::request()
     13 * @package Requests
     14 */
     15class 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        }
     23
     24        /**
     25         * Response body
     26         *
     27         * @var string
     28         */
     29        public $body = '';
     30
     31        /**
     32         * Raw HTTP data from the transport
     33         *
     34         * @var string
     35         */
     36        public $raw = '';
     37
     38        /**
     39         * Headers, as an associative array
     40         *
     41         * @var Requests_Response_Headers Array-like object representing headers
     42         */
     43        public $headers = array();
     44
     45        /**
     46         * Status code, false if non-blocking
     47         *
     48         * @var integer|boolean
     49         */
     50        public $status_code = false;
     51
     52        /**
     53         * Protocol version, false if non-blocking
     54         * @var float|boolean
     55         */
     56        public $protocol_version = false;
     57
     58        /**
     59         * Whether the request succeeded or not
     60         *
     61         * @var boolean
     62         */
     63        public $success = false;
     64
     65        /**
     66         * Number of redirects the request used
     67         *
     68         * @var integer
     69         */
     70        public $redirects = 0;
     71
     72        /**
     73         * URL requested
     74         *
     75         * @var string
     76         */
     77        public $url = '';
     78
     79        /**
     80         * Previous requests (from redirects)
     81         *
     82         * @var array Array of Requests_Response objects
     83         */
     84        public $history = array();
     85
     86        /**
     87         * Cookies from the request
     88         *
     89         * @var Requests_Cookie_Jar Array-like object representing a cookie jar
     90         */
     91        public $cookies = array();
     92
     93        /**
     94         * Is the response a redirect?
     95         *
     96         * @return boolean True if redirect (3xx status), false if not.
     97         */
     98        public function is_redirect() {
     99                $code = $this->status_code;
     100                return in_array($code, array(300, 301, 302, 303, 307)) || $code > 307 && $code < 400;
     101        }
     102
     103        /**
     104         * Throws an exception if the request was not successful
     105         *
     106         * @throws Requests_Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`)
     107         * @throws Requests_Exception_HTTP On non-successful status code. Exception class corresponds to code (e.g. {@see Requests_Exception_HTTP_404})
     108         * @param boolean $allow_redirects Set to false to throw on a 3xx as well
     109         */
     110        public function throw_for_status($allow_redirects = true) {
     111                if ($this->is_redirect()) {
     112                        if (!$allow_redirects) {
     113                                throw new Requests_Exception('Redirection not allowed', 'response.no_redirects', $this);
     114                        }
     115                }
     116                elseif (!$this->success) {
     117                        $exception = Requests_Exception_HTTP::get_class($this->status_code);
     118                        throw new $exception(null, $this);
     119                }
     120        }
     121}
  • src/wp-includes/Requests/SSL.php

    Property changes on: src/wp-includes/Requests/Response.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * SSL utilities for Requests
     4 *
     5 * @package Requests
     6 * @subpackage Utilities
     7 */
     8
     9/**
     10 * SSL utilities for Requests
     11 *
     12 * Collection of utilities for working with and verifying SSL certificates.
     13 *
     14 * @package Requests
     15 * @subpackage Utilities
     16 */
     17class Requests_SSL {
     18        /**
     19         * Verify the certificate against common name and subject alternative names
     20         *
     21         * Unfortunately, PHP doesn't check the certificate against the alternative
     22         * names, leading things like 'https://www.github.com/' to be invalid.
     23         * Instead
     24         *
     25         * @see http://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
     26         *
     27         * @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
     28         * @param string $host Host name to verify against
     29         * @param array $cert Certificate data from openssl_x509_parse()
     30         * @return bool
     31         */
     32        public static function verify_certificate($host, $cert) {
     33                // Calculate the valid wildcard match if the host is not an IP address
     34                $parts = explode('.', $host);
     35                if (ip2long($host) === false) {
     36                        $parts[0] = '*';
     37                }
     38                $wildcard = implode('.', $parts);
     39
     40                $has_dns_alt = false;
     41
     42                // Check the subjectAltName
     43                if (!empty($cert['extensions']) && !empty($cert['extensions']['subjectAltName'])) {
     44                        $altnames = explode(',', $cert['extensions']['subjectAltName']);
     45                        foreach ($altnames as $altname) {
     46                                $altname = trim($altname);
     47                                if (strpos($altname, 'DNS:') !== 0) {
     48                                        continue;
     49                                }
     50
     51                                $has_dns_alt = true;
     52
     53                                // Strip the 'DNS:' prefix and trim whitespace
     54                                $altname = trim(substr($altname, 4));
     55
     56                                // Check for a match
     57                                if (self::match_domain($host, $altname) === true) {
     58                                        return true;
     59                                }
     60                        }
     61                }
     62
     63                // Fall back to checking the common name if we didn't get any dNSName
     64                // alt names, as per RFC2818
     65                if (!$has_dns_alt && !empty($cert['subject']['CN'])) {
     66                        // Check for a match
     67                        if (self::match_domain($host, $cert['subject']['CN']) === true) {
     68                                return true;
     69                        }
     70                }
     71
     72                return false;
     73        }
     74
     75        /**
     76         * Verify that a reference name is valid
     77         *
     78         * Verifies a dNSName for HTTPS usage, (almost) as per Firefox's rules:
     79         * - Wildcards can only occur in a name with more than 3 components
     80         * - Wildcards can only occur as the last character in the first
     81         *   component
     82         * - Wildcards may be preceded by additional characters
     83         *
     84         * We modify these rules to be a bit stricter and only allow the wildcard
     85         * character to be the full first component; that is, with the exclusion of
     86         * the third rule.
     87         *
     88         * @param string $reference Reference dNSName
     89         * @return boolean Is the name valid?
     90         */
     91        public static function verify_reference_name($reference) {
     92                $parts = explode('.', $reference);
     93
     94                // Check the first part of the name
     95                $first = array_shift($parts);
     96
     97                if (strpos($first, '*') !== false) {
     98                        // Check that the wildcard is the full part
     99                        if ($first !== '*') {
     100                                return false;
     101                        }
     102
     103                        // Check that we have at least 3 components (including first)
     104                        if (count($parts) < 2) {
     105                                return false;
     106                        }
     107                }
     108
     109                // Check the remaining parts
     110                foreach ($parts as $part) {
     111                        if (strpos($part, '*') !== false) {
     112                                return false;
     113                        }
     114                }
     115
     116                // Nothing found, verified!
     117                return true;
     118        }
     119
     120        /**
     121         * Match a hostname against a dNSName reference
     122         *
     123         * @param string $host Requested host
     124         * @param string $reference dNSName to match against
     125         * @return boolean Does the domain match?
     126         */
     127        public static function match_domain($host, $reference) {
     128                // Check if the reference is blacklisted first
     129                if (self::verify_reference_name($reference) !== true) {
     130                        return false;
     131                }
     132
     133                // Check for a direct match
     134                if ($host === $reference) {
     135                        return true;
     136                }
     137
     138                // Calculate the valid wildcard match if the host is not an IP address
     139                // Also validates that the host has 3 parts or more, as per Firefox's
     140                // ruleset.
     141                if (ip2long($host) === false) {
     142                        $parts = explode('.', $host);
     143                        $parts[0] = '*';
     144                        $wildcard = implode('.', $parts);
     145                        if ($wildcard === $reference) {
     146                                return true;
     147                        }
     148                }
     149
     150                return false;
     151        }
     152}
     153 No newline at end of file
  • src/wp-includes/Requests/Session.php

    Property changes on: src/wp-includes/Requests/SSL.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Session handler for persistent requests and default parameters
     4 *
     5 * @package Requests
     6 * @subpackage Session Handler
     7 */
     8
     9/**
     10 * Session handler for persistent requests and default parameters
     11 *
     12 * Allows various options to be set as default values, and merges both the
     13 * options and URL properties together. A base URL can be set for all requests,
     14 * with all subrequests resolved from this. Base options can be set (including
     15 * a shared cookie jar), then overridden for individual requests.
     16 *
     17 * @package Requests
     18 * @subpackage Session Handler
     19 */
     20class Requests_Session {
     21        /**
     22         * Base URL for requests
     23         *
     24         * URLs will be made absolute using this as the base
     25         * @var string|null
     26         */
     27        public $url = null;
     28
     29        /**
     30         * Base headers for requests
     31         * @var array
     32         */
     33        public $headers = array();
     34
     35        /**
     36         * Base data for requests
     37         *
     38         * If both the base data and the per-request data are arrays, the data will
     39         * be merged before sending the request.
     40         *
     41         * @var array
     42         */
     43        public $data = array();
     44
     45        /**
     46         * Base options for requests
     47         *
     48         * The base options are merged with the per-request data for each request.
     49         * The only default option is a shared cookie jar between requests.
     50         *
     51         * Values here can also be set directly via properties on the Session
     52         * object, e.g. `$session->useragent = 'X';`
     53         *
     54         * @var array
     55         */
     56        public $options = array();
     57
     58        /**
     59         * Create a new session
     60         *
     61         * @param string|null $url Base URL for requests
     62         * @param array $headers Default headers for requests
     63         * @param array $data Default data for requests
     64         * @param array $options Default options for requests
     65         */
     66        public function __construct($url = null, $headers = array(), $data = array(), $options = array()) {
     67                $this->url = $url;
     68                $this->headers = $headers;
     69                $this->data = $data;
     70                $this->options = $options;
     71
     72                if (empty($this->options['cookies'])) {
     73                        $this->options['cookies'] = new Requests_Cookie_Jar();
     74                }
     75        }
     76
     77        /**
     78         * Get a property's value
     79         *
     80         * @param string $key Property key
     81         * @return mixed|null Property value, null if none found
     82         */
     83        public function __get($key) {
     84                if (isset($this->options[$key])) {
     85                        return $this->options[$key];
     86                }
     87
     88                return null;
     89        }
     90
     91        /**
     92         * Set a property's value
     93         *
     94         * @param string $key Property key
     95         * @param mixed $value Property value
     96         */
     97        public function __set($key, $value) {
     98                $this->options[$key] = $value;
     99        }
     100
     101        /**
     102         * Remove a property's value
     103         *
     104         * @param string $key Property key
     105         */
     106        public function __isset($key) {
     107                return isset($this->options[$key]);
     108        }
     109
     110        /**
     111         * Remove a property's value
     112         *
     113         * @param string $key Property key
     114         */
     115        public function __unset($key) {
     116                if (isset($this->options[$key])) {
     117                        unset($this->options[$key]);
     118                }
     119        }
     120
     121        /**#@+
     122         * @see request()
     123         * @param string $url
     124         * @param array $headers
     125         * @param array $options
     126         * @return Requests_Response
     127         */
     128        /**
     129         * Send a GET request
     130         */
     131        public function get($url, $headers = array(), $options = array()) {
     132                return $this->request($url, $headers, null, Requests::GET, $options);
     133        }
     134
     135        /**
     136         * Send a HEAD request
     137         */
     138        public function head($url, $headers = array(), $options = array()) {
     139                return $this->request($url, $headers, null, Requests::HEAD, $options);
     140        }
     141
     142        /**
     143         * Send a DELETE request
     144         */
     145        public function delete($url, $headers = array(), $options = array()) {
     146                return $this->request($url, $headers, null, Requests::DELETE, $options);
     147        }
     148        /**#@-*/
     149
     150        /**#@+
     151         * @see request()
     152         * @param string $url
     153         * @param array $headers
     154         * @param array $data
     155         * @param array $options
     156         * @return Requests_Response
     157         */
     158        /**
     159         * Send a POST request
     160         */
     161        public function post($url, $headers = array(), $data = array(), $options = array()) {
     162                return $this->request($url, $headers, $data, Requests::POST, $options);
     163        }
     164
     165        /**
     166         * Send a PUT request
     167         */
     168        public function put($url, $headers = array(), $data = array(), $options = array()) {
     169                return $this->request($url, $headers, $data, Requests::PUT, $options);
     170        }
     171
     172        /**
     173         * Send a PATCH request
     174         *
     175         * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the
     176         * specification recommends that should send an ETag
     177         *
     178         * @link http://tools.ietf.org/html/rfc5789
     179         */
     180        public function patch($url, $headers, $data = array(), $options = array()) {
     181                return $this->request($url, $headers, $data, Requests::PATCH, $options);
     182        }
     183        /**#@-*/
     184
     185        /**
     186         * Main interface for HTTP requests
     187         *
     188         * This method initiates a request and sends it via a transport before
     189         * parsing.
     190         *
     191         * @see Requests::request()
     192         *
     193         * @throws Requests_Exception On invalid URLs (`nonhttp`)
     194         *
     195         * @param string $url URL to request
     196         * @param array $headers Extra headers to send with the request
     197         * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
     198         * @param string $type HTTP request type (use Requests constants)
     199         * @param array $options Options for the request (see {@see Requests::request})
     200         * @return Requests_Response
     201         */
     202        public function request($url, $headers = array(), $data = array(), $type = Requests::GET, $options = array()) {
     203                $request = $this->merge_request(compact('url', 'headers', 'data', 'options'));
     204
     205                return Requests::request($request['url'], $request['headers'], $request['data'], $type, $request['options']);
     206        }
     207
     208        /**
     209         * Send multiple HTTP requests simultaneously
     210         *
     211         * @see Requests::request_multiple()
     212         *
     213         * @param array $requests Requests data (see {@see Requests::request_multiple})
     214         * @param array $options Global and default options (see {@see Requests::request})
     215         * @return array Responses (either Requests_Response or a Requests_Exception object)
     216         */
     217        public function request_multiple($requests, $options = array()) {
     218                foreach ($requests as $key => $request) {
     219                        $requests[$key] = $this->merge_request($request, false);
     220                }
     221
     222                $options = array_merge($this->options, $options);
     223
     224                // Disallow forcing the type, as that's a per request setting
     225                unset($options['type']);
     226
     227                return Requests::request_multiple($requests, $options);
     228        }
     229
     230        /**
     231         * Merge a request's data with the default data
     232         *
     233         * @param array $request Request data (same form as {@see request_multiple})
     234         * @param boolean $merge_options Should we merge options as well?
     235         * @return array Request data
     236         */
     237        protected function merge_request($request, $merge_options = true) {
     238                if ($this->url !== null) {
     239                        $request['url'] = Requests_IRI::absolutize($this->url, $request['url']);
     240                        $request['url'] = $request['url']->uri;
     241                }
     242
     243                if (empty($request['headers'])) {
     244                        $request['headers'] = array();
     245                }
     246                $request['headers'] = array_merge($this->headers, $request['headers']);
     247
     248                if (empty($request['data'])) {
     249                        if (is_array($this->data)) {
     250                                $request['data'] = $this->data;
     251                        }
     252                }
     253                elseif (is_array($request['data']) && is_array($this->data)) {
     254                        $request['data'] = array_merge($this->data, $request['data']);
     255                }
     256
     257                if ($merge_options !== false) {
     258                        $request['options'] = array_merge($this->options, $request['options']);
     259
     260                        // Disallow forcing the type, as that's a per request setting
     261                        unset($request['options']['type']);
     262                }
     263
     264                return $request;
     265        }
     266}
  • src/wp-includes/Requests/Transport/cURL.php

    Property changes on: src/wp-includes/Requests/Session.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * cURL HTTP transport
     4 *
     5 * @package Requests
     6 * @subpackage Transport
     7 */
     8
     9/**
     10 * cURL HTTP transport
     11 *
     12 * @package Requests
     13 * @subpackage Transport
     14 */
     15class Requests_Transport_cURL implements Requests_Transport {
     16        const CURL_7_10_5 = 0x070A05;
     17        const CURL_7_16_2 = 0x071002;
     18
     19        /**
     20         * Raw HTTP data
     21         *
     22         * @var string
     23         */
     24        public $headers = '';
     25
     26        /**
     27         * Raw body data
     28         *
     29         * @var string
     30         */
     31        public $response_data = '';
     32
     33        /**
     34         * Information on the current request
     35         *
     36         * @var array cURL information array, see {@see http://php.net/curl_getinfo}
     37         */
     38        public $info;
     39
     40        /**
     41         * Version string
     42         *
     43         * @var long
     44         */
     45        public $version;
     46
     47        /**
     48         * cURL handle
     49         *
     50         * @var resource
     51         */
     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;
     74
     75        /**
     76         * How many bytes are in the response body?
     77         *
     78         * @var int
     79         */
     80        protected $response_bytes;
     81
     82        /**
     83         * What's the maximum number of bytes we should keep?
     84         *
     85         * @var int|bool Byte count, or false if no limit.
     86         */
     87        protected $response_byte_limit;
     88
     89        /**
     90         * Constructor
     91         */
     92        public function __construct() {
     93                $curl = curl_version();
     94                $this->version = $curl['version_number'];
     95                $this->handle = curl_init();
     96
     97                curl_setopt($this->handle, CURLOPT_HEADER, false);
     98                curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, 1);
     99                if ($this->version >= self::CURL_7_10_5) {
     100                        curl_setopt($this->handle, CURLOPT_ENCODING, '');
     101                }
     102                if (defined('CURLOPT_PROTOCOLS')) {
     103                        curl_setopt($this->handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
     104                }
     105                if (defined('CURLOPT_REDIR_PROTOCOLS')) {
     106                        curl_setopt($this->handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
     107                }
     108        }
     109
     110        /**
     111         * Destructor
     112         */
     113        public function __destruct() {
     114                if (is_resource($this->handle)) {
     115                        curl_close($this->handle);
     116                }
     117        }
     118
     119        /**
     120         * Perform a request
     121         *
     122         * @throws Requests_Exception On a cURL error (`curlerror`)
     123         *
     124         * @param string $url URL to request
     125         * @param array $headers Associative array of request headers
     126         * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
     127         * @param array $options Request options, see {@see Requests::response()} for documentation
     128         * @return string Raw HTTP result
     129         */
     130        public function request($url, $headers = array(), $data = array(), $options = array()) {
     131                $this->hooks = $options['hooks'];
     132
     133                $this->setup_handle($url, $headers, $data, $options);
     134
     135                $options['hooks']->dispatch('curl.before_send', array(&$this->handle));
     136
     137                if ($options['filename'] !== false) {
     138                        $this->stream_handle = fopen($options['filename'], 'wb');
     139                }
     140
     141                $this->response_data = '';
     142                $this->response_bytes = 0;
     143                $this->response_byte_limit = false;
     144                if ($options['max_bytes'] !== false) {
     145                        $this->response_byte_limit = $options['max_bytes'];
     146                }
     147
     148                if (isset($options['verify'])) {
     149                        if ($options['verify'] === false) {
     150                                curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
     151                                curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, 0);
     152                        }
     153                        elseif (is_string($options['verify'])) {
     154                                curl_setopt($this->handle, CURLOPT_CAINFO, $options['verify']);
     155                        }
     156                }
     157
     158                if (isset($options['verifyname']) && $options['verifyname'] === false) {
     159                        curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
     160                }
     161
     162                curl_exec($this->handle);
     163                $response = $this->response_data;
     164
     165                $options['hooks']->dispatch('curl.after_send', array());
     166
     167                if (curl_errno($this->handle) === 23 || curl_errno($this->handle) === 61) {
     168                        // Reset encoding and try again
     169                        curl_setopt($this->handle, CURLOPT_ENCODING, 'none');
     170
     171                        $this->response_data = '';
     172                        $this->response_bytes = 0;
     173                        curl_exec($this->handle);
     174                        $response = $this->response_data;
     175                }
     176
     177                $this->process_response($response, $options);
     178
     179                // Need to remove the $this reference from the curl handle.
     180                // Otherwise Requests_Transport_cURL wont be garbage collected and the curl_close() will never be called.
     181                curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null);
     182                curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null);
     183
     184                return $this->headers;
     185        }
     186
     187        /**
     188         * Send multiple requests simultaneously
     189         *
     190         * @param array $requests Request data
     191         * @param array $options Global options
     192         * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
     193         */
     194        public function request_multiple($requests, $options) {
     195                // If you're not requesting, we can't get any responses ¯\_(ツ)_/¯
     196                if (empty($requests)) {
     197                        return array();
     198                }
     199
     200                $multihandle = curl_multi_init();
     201                $subrequests = array();
     202                $subhandles = array();
     203
     204                $class = get_class($this);
     205                foreach ($requests as $id => $request) {
     206                        $subrequests[$id] = new $class();
     207                        $subhandles[$id] = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']);
     208                        $request['options']['hooks']->dispatch('curl.before_multi_add', array(&$subhandles[$id]));
     209                        curl_multi_add_handle($multihandle, $subhandles[$id]);
     210                }
     211
     212                $completed = 0;
     213                $responses = array();
     214
     215                $request['options']['hooks']->dispatch('curl.before_multi_exec', array(&$multihandle));
     216
     217                do {
     218                        $active = false;
     219
     220                        do {
     221                                $status = curl_multi_exec($multihandle, $active);
     222                        }
     223                        while ($status === CURLM_CALL_MULTI_PERFORM);
     224
     225                        $to_process = array();
     226
     227                        // Read the information as needed
     228                        while ($done = curl_multi_info_read($multihandle)) {
     229                                $key = array_search($done['handle'], $subhandles, true);
     230                                if (!isset($to_process[$key])) {
     231                                        $to_process[$key] = $done;
     232                                }
     233                        }
     234
     235                        // Parse the finished requests before we start getting the new ones
     236                        foreach ($to_process as $key => $done) {
     237                                $options = $requests[$key]['options'];
     238                                if (CURLE_OK !== $done['result']) {
     239                                        //get error string for handle.
     240                                        $reason = curl_error($done['handle']);
     241                                        $exception = new Requests_Exception_Transport_cURL(
     242                                                                        $reason,
     243                                                                        Requests_Exception_Transport_cURL::EASY,
     244                                                                        $done['handle'],
     245                                                                        $done['result']
     246                                                                );
     247                                        $responses[$key] = $exception;
     248                                        $options['hooks']->dispatch('transport.internal.parse_error', array(&$responses[$key], $requests[$key]));
     249                                }
     250                                else {
     251                                        $responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options);
     252
     253                                        $options['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$key], $requests[$key]));
     254                                }
     255
     256                                curl_multi_remove_handle($multihandle, $done['handle']);
     257                                curl_close($done['handle']);
     258
     259                                if (!is_string($responses[$key])) {
     260                                        $options['hooks']->dispatch('multiple.request.complete', array(&$responses[$key], $key));
     261                                }
     262                                $completed++;
     263                        }
     264                }
     265                while ($active || $completed < count($subrequests));
     266
     267                $request['options']['hooks']->dispatch('curl.after_multi_exec', array(&$multihandle));
     268
     269                curl_multi_close($multihandle);
     270
     271                return $responses;
     272        }
     273
     274        /**
     275         * Get the cURL handle for use in a multi-request
     276         *
     277         * @param string $url URL to request
     278         * @param array $headers Associative array of request headers
     279         * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
     280         * @param array $options Request options, see {@see Requests::response()} for documentation
     281         * @return resource Subrequest's cURL handle
     282         */
     283        public function &get_subrequest_handle($url, $headers, $data, $options) {
     284                $this->setup_handle($url, $headers, $data, $options);
     285
     286                if ($options['filename'] !== false) {
     287                        $this->stream_handle = fopen($options['filename'], 'wb');
     288                }
     289
     290                $this->response_data = '';
     291                $this->response_bytes = 0;
     292                $this->response_byte_limit = false;
     293                if ($options['max_bytes'] !== false) {
     294                        $this->response_byte_limit = $options['max_bytes'];
     295                }
     296                $this->hooks = $options['hooks'];
     297
     298                return $this->handle;
     299        }
     300
     301        /**
     302         * Setup the cURL handle for the given data
     303         *
     304         * @param string $url URL to request
     305         * @param array $headers Associative array of request headers
     306         * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
     307         * @param array $options Request options, see {@see Requests::response()} for documentation
     308         */
     309        protected function setup_handle($url, $headers, $data, $options) {
     310                $options['hooks']->dispatch('curl.before_request', array(&$this->handle));
     311
     312                $headers = Requests::flatten($headers);
     313
     314                if (!empty($data)) {
     315                        $data_format = $options['data_format'];
     316
     317                        if ($data_format === 'query') {
     318                                $url = self::format_get($url, $data);
     319                                $data = '';
     320                        }
     321                        elseif (!is_string($data)) {
     322                                $data = http_build_query($data, null, '&');
     323                        }
     324                }
     325
     326                switch ($options['type']) {
     327                        case Requests::POST:
     328                                curl_setopt($this->handle, CURLOPT_POST, true);
     329                                curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
     330                                break;
     331                        case Requests::PATCH:
     332                        case Requests::PUT:
     333                        case Requests::DELETE:
     334                        case Requests::OPTIONS:
     335                                curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
     336                                curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
     337                                break;
     338                        case Requests::HEAD:
     339                                curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
     340                                curl_setopt($this->handle, CURLOPT_NOBODY, true);
     341                                break;
     342                        case Requests::TRACE:
     343                                curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
     344                                break;
     345                }
     346
     347                if (is_int($options['timeout']) || $this->version < self::CURL_7_16_2) {
     348                        curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($options['timeout']));
     349                }
     350                else {
     351                        curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($options['timeout'] * 1000));
     352                }
     353
     354                if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) {
     355                        curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout']));
     356                }
     357                else {
     358                        curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000));
     359                }
     360                curl_setopt($this->handle, CURLOPT_URL, $url);
     361                curl_setopt($this->handle, CURLOPT_REFERER, $url);
     362                curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']);
     363                curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers);
     364
     365                if ($options['protocol_version'] === 1.1) {
     366                        curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
     367                }
     368                else {
     369                        curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
     370                }
     371
     372                if (true === $options['blocking']) {
     373                        curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, array(&$this, 'stream_headers'));
     374                        curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, array(&$this, 'stream_body'));
     375                        curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE);
     376                }
     377        }
     378
     379        /**
     380         * Process a response
     381         *
     382         * @param string $response Response data from the body
     383         * @param array $options Request options
     384         * @return string HTTP response data including headers
     385         */
     386        public function process_response($response, $options) {
     387                if ($options['blocking'] === false) {
     388                        $fake_headers = '';
     389                        $options['hooks']->dispatch('curl.after_request', array(&$fake_headers));
     390                        return false;
     391                }
     392                if ($options['filename'] !== false) {
     393                        fclose($this->stream_handle);
     394                        $this->headers = trim($this->headers);
     395                }
     396                else {
     397                        $this->headers .= $response;
     398                }
     399
     400                if (curl_errno($this->handle)) {
     401                        $error = sprintf(
     402                                'cURL error %s: %s',
     403                                curl_errno($this->handle),
     404                                curl_error($this->handle)
     405                        );
     406                        throw new Requests_Exception($error, 'curlerror', $this->handle);
     407                }
     408                $this->info = curl_getinfo($this->handle);
     409
     410                $options['hooks']->dispatch('curl.after_request', array(&$this->headers, &$this->info));
     411                return $this->headers;
     412        }
     413
     414        /**
     415         * Collect the headers as they are received
     416         *
     417         * @param resource $handle cURL resource
     418         * @param string $headers Header string
     419         * @return integer Length of provided header
     420         */
     421        public function stream_headers($handle, $headers) {
     422                // Why do we do this? cURL will send both the final response and any
     423                // interim responses, such as a 100 Continue. We don't need that.
     424                // (We may want to keep this somewhere just in case)
     425                if ($this->done_headers) {
     426                        $this->headers = '';
     427                        $this->done_headers = false;
     428                }
     429                $this->headers .= $headers;
     430
     431                if ($headers === "\r\n") {
     432                        $this->done_headers = true;
     433                }
     434                return strlen($headers);
     435        }
     436
     437        /**
     438         * Collect data as it's received
     439         *
     440         * @since 1.6.1
     441         *
     442         * @param resource $handle cURL resource
     443         * @param string $data Body data
     444         * @return integer Length of provided data
     445         */
     446        protected function stream_body($handle, $data) {
     447                $this->hooks->dispatch('request.progress', array($data, $this->response_bytes, $this->response_byte_limit));
     448                $data_length = strlen($data);
     449
     450                // Are we limiting the response size?
     451                if ($this->response_byte_limit) {
     452                        if ($this->response_bytes === $this->response_byte_limit) {
     453                                // Already at maximum, move on
     454                                return $data_length;
     455                        }
     456
     457                        if (($this->response_bytes + $data_length) > $this->response_byte_limit) {
     458                                // Limit the length
     459                                $limited_length = ($this->response_byte_limit - $this->response_bytes);
     460                                $data = substr($data, 0, $limited_length);
     461                        }
     462                }
     463
     464                if ($this->stream_handle) {
     465                        fwrite($this->stream_handle, $data);
     466                }
     467                else {
     468                        $this->response_data .= $data;
     469                }
     470
     471                $this->response_bytes += strlen($data);
     472                return $data_length;
     473        }
     474
     475        /**
     476         * Format a URL given GET data
     477         *
     478         * @param string $url
     479         * @param array|object $data Data to build query using, see {@see http://php.net/http_build_query}
     480         * @return string URL with data
     481         */
     482        protected static function format_get($url, $data) {
     483                if (!empty($data)) {
     484                        $url_parts = parse_url($url);
     485                        if (empty($url_parts['query'])) {
     486                                $query = $url_parts['query'] = '';
     487                        }
     488                        else {
     489                                $query = $url_parts['query'];
     490                        }
     491
     492                        $query .= '&' . http_build_query($data, null, '&');
     493                        $query = trim($query, '&');
     494
     495                        if (empty($url_parts['query'])) {
     496                                $url .= '?' . $query;
     497                        }
     498                        else {
     499                                $url = str_replace($url_parts['query'], $query, $url);
     500                        }
     501                }
     502                return $url;
     503        }
     504
     505        /**
     506         * Whether this transport is valid
     507         *
     508         * @codeCoverageIgnore
     509         * @return boolean True if the transport is valid, false otherwise.
     510         */
     511        public static function test($capabilities = array()) {
     512                if (!function_exists('curl_init') && !function_exists('curl_exec')) {
     513                        return false;
     514                }
     515
     516                // If needed, check that our installed curl version supports SSL
     517                if (isset($capabilities['ssl']) && $capabilities['ssl']) {
     518                        $curl_version = curl_version();
     519                        if (!(CURL_VERSION_SSL & $curl_version['features'])) {
     520                                return false;
     521                        }
     522                }
     523
     524                return true;
     525        }
     526}
  • src/wp-includes/Requests/Transport/fsockopen.php

    Property changes on: src/wp-includes/Requests/Transport/cURL.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * fsockopen HTTP transport
     4 *
     5 * @package Requests
     6 * @subpackage Transport
     7 */
     8
     9/**
     10 * fsockopen HTTP transport
     11 *
     12 * @package Requests
     13 * @subpackage Transport
     14 */
     15class Requests_Transport_fsockopen implements Requests_Transport {
     16        /**
     17         * Second to microsecond conversion
     18         *
     19         * @var integer
     20         */
     21        const SECOND_IN_MICROSECONDS = 1000000;
     22
     23        /**
     24         * Raw HTTP data
     25         *
     26         * @var string
     27         */
     28        public $headers = '';
     29
     30        /**
     31         * Stream metadata
     32         *
     33         * @var array Associative array of properties, see {@see http://php.net/stream_get_meta_data}
     34         */
     35        public $info;
     36
     37        /**
     38         * What's the maximum number of bytes we should keep?
     39         *
     40         * @var int|bool Byte count, or false if no limit.
     41         */
     42        protected $max_bytes = false;
     43
     44        protected $connect_error = '';
     45
     46        /**
     47         * Perform a request
     48         *
     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
     53         * @param array $headers Associative array of request headers
     54         * @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
     56         * @return string Raw HTTP result
     57         */
     58        public function request($url, $headers = array(), $data = array(), $options = array()) {
     59                $options['hooks']->dispatch('fsockopen.before_request');
     60
     61                $url_parts = parse_url($url);
     62                if (empty($url_parts)) {
     63                        throw new Requests_Exception('Invalid URL.', 'invalidurl', $url);
     64                }
     65                $host = $url_parts['host'];
     66                $context = stream_context_create();
     67                $verifyname = false;
     68                $case_insensitive_headers = new Requests_Utility_CaseInsensitiveDictionary($headers);
     69
     70                // HTTPS support
     71                if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
     72                        $remote_socket = 'ssl://' . $host;
     73                        $url_parts['port'] = 443;
     74
     75                        $context_options = array(
     76                                'verify_peer' => true,
     77                                // 'CN_match' => $host,
     78                                'capture_peer_cert' => true
     79                        );
     80                        $verifyname = true;
     81
     82                        // SNI, if enabled (OpenSSL >=0.9.8j)
     83                        if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) {
     84                                $context_options['SNI_enabled'] = true;
     85                                if (isset($options['verifyname']) && $options['verifyname'] === false) {
     86                                        $context_options['SNI_enabled'] = false;
     87                                }
     88                        }
     89
     90                        if (isset($options['verify'])) {
     91                                if ($options['verify'] === false) {
     92                                        $context_options['verify_peer'] = false;
     93                                }
     94                                elseif (is_string($options['verify'])) {
     95                                        $context_options['cafile'] = $options['verify'];
     96                                }
     97                        }
     98
     99                        if (isset($options['verifyname']) && $options['verifyname'] === false) {
     100                                $verifyname = false;
     101                        }
     102
     103                        stream_context_set_option($context, array('ssl' => $context_options));
     104                }
     105                else {
     106                        $remote_socket = 'tcp://' . $host;
     107                }
     108
     109                $this->max_bytes = $options['max_bytes'];
     110
     111                if (!isset($url_parts['port'])) {
     112                        $url_parts['port'] = 80;
     113                }
     114                $remote_socket .= ':' . $url_parts['port'];
     115
     116                set_error_handler(array($this, 'connect_error_handler'), E_WARNING | E_NOTICE);
     117
     118                $options['hooks']->dispatch('fsockopen.remote_socket', array(&$remote_socket));
     119
     120                $socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context);
     121
     122                restore_error_handler();
     123
     124                if ($verifyname && !$this->verify_certificate_from_context($host, $context)) {
     125                        throw new Requests_Exception('SSL certificate did not match the requested domain name', 'ssl.no_match');
     126                }
     127
     128                if (!$socket) {
     129                        if ($errno === 0) {
     130                                // Connection issue
     131                                throw new Requests_Exception(rtrim($this->connect_error), 'fsockopen.connect_error');
     132                        }
     133
     134                        throw new Requests_Exception($errstr, 'fsockopenerror', null, $errno);
     135                }
     136
     137                $data_format = $options['data_format'];
     138
     139                if ($data_format === 'query') {
     140                        $path = self::format_get($url_parts, $data);
     141                        $data = '';
     142                }
     143                else {
     144                        $path = self::format_get($url_parts, array());
     145                }
     146
     147                $options['hooks']->dispatch('fsockopen.remote_host_path', array(&$path, $url));
     148
     149                $request_body = '';
     150                $out = sprintf("%s %s HTTP/%.1f\r\n", $options['type'], $path, $options['protocol_version']);
     151
     152                if ($options['type'] !== Requests::TRACE) {
     153                        if (is_array($data)) {
     154                                $request_body = http_build_query($data, null, '&');
     155                        }
     156                        else {
     157                                $request_body = $data;
     158                        }
     159
     160                        if (!empty($data)) {
     161                                if (!isset($case_insensitive_headers['Content-Length'])) {
     162                                        $headers['Content-Length'] = strlen($request_body);
     163                                }
     164
     165                                if (!isset($case_insensitive_headers['Content-Type'])) {
     166                                        $headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
     167                                }
     168                        }
     169                }
     170
     171                if (!isset($case_insensitive_headers['Host'])) {
     172                        $out .= sprintf('Host: %s', $url_parts['host']);
     173
     174                        if ($url_parts['port'] !== 80) {
     175                                $out .= ':' . $url_parts['port'];
     176                        }
     177                        $out .= "\r\n";
     178                }
     179
     180                if (!isset($case_insensitive_headers['User-Agent'])) {
     181                        $out .= sprintf("User-Agent: %s\r\n", $options['useragent']);
     182                }
     183
     184                $accept_encoding = $this->accept_encoding();
     185                if (!isset($case_insensitive_headers['Accept-Encoding']) && !empty($accept_encoding)) {
     186                        $out .= sprintf("Accept-Encoding: %s\r\n", $accept_encoding);
     187                }
     188
     189                $headers = Requests::flatten($headers);
     190
     191                if (!empty($headers)) {
     192                        $out .= implode($headers, "\r\n") . "\r\n";
     193                }
     194
     195                $options['hooks']->dispatch('fsockopen.after_headers', array(&$out));
     196
     197                if (substr($out, -2) !== "\r\n") {
     198                        $out .= "\r\n";
     199                }
     200
     201                if (!isset($case_insensitive_headers['Connection'])) {
     202                        $out .= "Connection: Close\r\n";
     203                }
     204
     205                $out .= "\r\n" . $request_body;
     206
     207                $options['hooks']->dispatch('fsockopen.before_send', array(&$out));
     208
     209                fwrite($socket, $out);
     210                $options['hooks']->dispatch('fsockopen.after_send', array($out));
     211
     212                if (!$options['blocking']) {
     213                        fclose($socket);
     214                        $fake_headers = '';
     215                        $options['hooks']->dispatch('fsockopen.after_request', array(&$fake_headers));
     216                        return '';
     217                }
     218
     219                $timeout_sec = (int) floor($options['timeout']);
     220                if ($timeout_sec == $options['timeout']) {
     221                        $timeout_msec = 0;
     222                }
     223                else {
     224                        $timeout_msec = self::SECOND_IN_MICROSECONDS * $options['timeout'] % self::SECOND_IN_MICROSECONDS;
     225                }
     226                stream_set_timeout($socket, $timeout_sec, $timeout_msec);
     227
     228                $response = $body = $headers = '';
     229                $this->info = stream_get_meta_data($socket);
     230                $size = 0;
     231                $doingbody = false;
     232                $download = false;
     233                if ($options['filename']) {
     234                        $download = fopen($options['filename'], 'wb');
     235                }
     236
     237                while (!feof($socket)) {
     238                        $this->info = stream_get_meta_data($socket);
     239                        if ($this->info['timed_out']) {
     240                                throw new Requests_Exception('fsocket timed out', 'timeout');
     241                        }
     242
     243                        $block = fread($socket, Requests::BUFFER_SIZE);
     244                        if (!$doingbody) {
     245                                $response .= $block;
     246                                if (strpos($response, "\r\n\r\n")) {
     247                                        list($headers, $block) = explode("\r\n\r\n", $response, 2);
     248                                        $doingbody = true;
     249                                }
     250                        }
     251
     252                        // Are we in body mode now?
     253                        if ($doingbody) {
     254                                $options['hooks']->dispatch('request.progress', array($block, $size, $this->max_bytes));
     255                                $data_length = strlen($block);
     256                                if ($this->max_bytes) {
     257                                        // Have we already hit a limit?
     258                                        if ($size === $this->max_bytes) {
     259                                                continue;
     260                                        }
     261                                        if (($size + $data_length) > $this->max_bytes) {
     262                                                // Limit the length
     263                                                $limited_length = ($this->max_bytes - $size);
     264                                                $block = substr($block, 0, $limited_length);
     265                                        }
     266                                }
     267
     268                                $size += strlen($block);
     269                                if ($download) {
     270                                        fwrite($download, $block);
     271                                }
     272                                else {
     273                                        $body .= $block;
     274                                }
     275                        }
     276                }
     277                $this->headers = $headers;
     278
     279                if ($download) {
     280                        fclose($download);
     281                }
     282                else {
     283                        $this->headers .= "\r\n\r\n" . $body;
     284                }
     285                fclose($socket);
     286
     287                $options['hooks']->dispatch('fsockopen.after_request', array(&$this->headers, &$this->info));
     288                return $this->headers;
     289        }
     290
     291        /**
     292         * Send multiple requests simultaneously
     293         *
     294         * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see Requests_Transport::request}
     295         * @param array $options Global options, see {@see Requests::response()} for documentation
     296         * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
     297         */
     298        public function request_multiple($requests, $options) {
     299                $responses = array();
     300                $class = get_class($this);
     301                foreach ($requests as $id => $request) {
     302                        try {
     303                                $handler = new $class();
     304                                $responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']);
     305
     306                                $request['options']['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$id], $request));
     307                        }
     308                        catch (Requests_Exception $e) {
     309                                $responses[$id] = $e;
     310                        }
     311
     312                        if (!is_string($responses[$id])) {
     313                                $request['options']['hooks']->dispatch('multiple.request.complete', array(&$responses[$id], $id));
     314                        }
     315                }
     316
     317                return $responses;
     318        }
     319
     320        /**
     321         * Retrieve the encodings we can accept
     322         *
     323         * @return string Accept-Encoding header value
     324         */
     325        protected static function accept_encoding() {
     326                $type = array();
     327                if (function_exists('gzinflate')) {
     328                        $type[] = 'deflate;q=1.0';
     329                }
     330
     331                if (function_exists('gzuncompress')) {
     332                        $type[] = 'compress;q=0.5';
     333                }
     334
     335                $type[] = 'gzip;q=0.5';
     336
     337                return implode(', ', $type);
     338        }
     339
     340        /**
     341         * Format a URL given GET data
     342         *
     343         * @param array $url_parts
     344         * @param array|object $data Data to build query using, see {@see http://php.net/http_build_query}
     345         * @return string URL with data
     346         */
     347        protected static function format_get($url_parts, $data) {
     348                if (!empty($data)) {
     349                        if (empty($url_parts['query'])) {
     350                                $url_parts['query'] = '';
     351                        }
     352
     353                        $url_parts['query'] .= '&' . http_build_query($data, null, '&');
     354                        $url_parts['query'] = trim($url_parts['query'], '&');
     355                }
     356                if (isset($url_parts['path'])) {
     357                        if (isset($url_parts['query'])) {
     358                                $get = $url_parts['path'] . '?' . $url_parts['query'];
     359                        }
     360                        else {
     361                                $get = $url_parts['path'];
     362                        }
     363                }
     364                else {
     365                        $get = '/';
     366                }
     367                return $get;
     368        }
     369
     370        /**
     371         * Error handler for stream_socket_client()
     372         *
     373         * @param int $errno Error number (e.g. E_WARNING)
     374         * @param string $errstr Error message
     375         */
     376        public function connect_error_handler($errno, $errstr) {
     377                // Double-check we can handle it
     378                if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) {
     379                        // Return false to indicate the default error handler should engage
     380                        return false;
     381                }
     382
     383                $this->connect_error .= $errstr . "\n";
     384                return true;
     385        }
     386
     387        /**
     388         * Verify the certificate against common name and subject alternative names
     389         *
     390         * Unfortunately, PHP doesn't check the certificate against the alternative
     391         * names, leading things like 'https://www.github.com/' to be invalid.
     392         * Instead
     393         *
     394         * @see http://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
     395         *
     396         * @throws Requests_Exception On failure to connect via TLS (`fsockopen.ssl.connect_error`)
     397         * @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
     398         * @param string $host Host name to verify against
     399         * @param resource $context Stream context
     400         * @return bool
     401         */
     402        public function verify_certificate_from_context($host, $context) {
     403                $meta = stream_context_get_options($context);
     404
     405                // If we don't have SSL options, then we couldn't make the connection at
     406                // all
     407                if (empty($meta) || empty($meta['ssl']) || empty($meta['ssl']['peer_certificate'])) {
     408                        throw new Requests_Exception(rtrim($this->connect_error), 'ssl.connect_error');
     409                }
     410
     411                $cert = openssl_x509_parse($meta['ssl']['peer_certificate']);
     412
     413                return Requests_SSL::verify_certificate($host, $cert);
     414        }
     415
     416        /**
     417         * Whether this transport is valid
     418         *
     419         * @codeCoverageIgnore
     420         * @return boolean True if the transport is valid, false otherwise.
     421         */
     422        public static function test($capabilities = array()) {
     423                if (!function_exists('fsockopen')) {
     424                        return false;
     425                }
     426
     427                // If needed, check that streams support SSL
     428                if (isset($capabilities['ssl']) && $capabilities['ssl']) {
     429                        if (!extension_loaded('openssl') || !function_exists('openssl_x509_parse')) {
     430                                return false;
     431                        }
     432
     433                        // Currently broken, thanks to https://github.com/facebook/hhvm/issues/2156
     434                        if (defined('HHVM_VERSION')) {
     435                                return false;
     436                        }
     437                }
     438
     439                return true;
     440        }
     441}
  • src/wp-includes/Requests/Transport.php

    Property changes on: src/wp-includes/Requests/Transport/fsockopen.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Base HTTP transport
     4 *
     5 * @package Requests
     6 * @subpackage Transport
     7 */
     8
     9/**
     10 * Base HTTP transport
     11 *
     12 * @package Requests
     13 * @subpackage Transport
     14 */
     15interface Requests_Transport {
     16        /**
     17         * Perform a request
     18         *
     19         * @param string $url URL to request
     20         * @param array $headers Associative array of request headers
     21         * @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
     23         * @return string Raw HTTP result
     24         */
     25        public function request($url, $headers = array(), $data = array(), $options = array());
     26
     27        /**
     28         * Send multiple requests simultaneously
     29         *
     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)
     33         */
     34        public function request_multiple($requests, $options);
     35
     36        /**
     37         * Self-test whether the transport can be used
     38         * @return bool
     39         */
     40        public static function test();
     41}
     42 No newline at end of file
  • src/wp-includes/Requests/Utility/CaseInsensitiveDictionary.php

    Property changes on: src/wp-includes/Requests/Transport.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * Case-insensitive dictionary, suitable for HTTP headers
     4 *
     5 * @package Requests
     6 * @subpackage Utilities
     7 */
     8
     9/**
     10 * Case-insensitive dictionary, suitable for HTTP headers
     11 *
     12 * @package Requests
     13 * @subpackage Utilities
     14 */
     15class Requests_Utility_CaseInsensitiveDictionary implements ArrayAccess, IteratorAggregate {
     16        /**
     17         * Actual item data
     18         *
     19         * @var array
     20         */
     21        protected $data = array();
     22
     23        /**
     24         * Creates a case insensitive dictionary.
     25         *
     26         * @param array $data Dictionary/map to convert to case-insensitive
     27         */
     28        public function __construct(array $data = array()) {
     29                foreach ($data as $key => $value) {
     30                        $this->offsetSet($key, $value);
     31                }
     32        }
     33
     34        /**
     35         * Check if the given item exists
     36         *
     37         * @param string $key Item key
     38         * @return boolean Does the item exist?
     39         */
     40        public function offsetExists($key) {
     41                $key = strtolower($key);
     42                return isset($this->data[$key]);
     43        }
     44
     45        /**
     46         * Get the value for the item
     47         *
     48         * @param string $key Item key
     49         * @return string Item value
     50         */
     51        public function offsetGet($key) {
     52                $key = strtolower($key);
     53                if (!isset($this->data[$key])) {
     54                        return null;
     55                }
     56
     57                return $this->data[$key];
     58        }
     59
     60        /**
     61         * Set the given item
     62         *
     63         * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
     64         *
     65         * @param string $key Item name
     66         * @param string $value Item value
     67         */
     68        public function offsetSet($key, $value) {
     69                if ($key === null) {
     70                        throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
     71                }
     72
     73                $key = strtolower($key);
     74                $this->data[$key] = $value;
     75        }
     76
     77        /**
     78         * Unset the given header
     79         *
     80         * @param string $key
     81         */
     82        public function offsetUnset($key) {
     83                unset($this->data[strtolower($key)]);
     84        }
     85
     86        /**
     87         * Get an iterator for the data
     88         *
     89         * @return ArrayIterator
     90         */
     91        public function getIterator() {
     92                return new ArrayIterator($this->data);
     93        }
     94
     95        /**
     96         * Get the headers as an array
     97         *
     98         * @return array Header data
     99         */
     100        public function getAll() {
     101                return $this->data;
     102        }
     103}
  • src/wp-includes/Requests/Utility/FilteredIterator.php

     
     1<?php
     2/**
     3 * Iterator for arrays requiring filtered values
     4 *
     5 * @package Requests
     6 * @subpackage Utilities
     7 */
     8
     9/**
     10 * Iterator for arrays requiring filtered values
     11 *
     12 * @package Requests
     13 * @subpackage Utilities
     14 */
     15class Requests_Utility_FilteredIterator extends ArrayIterator {
     16        /**
     17         * Callback to run as a filter
     18         *
     19         * @var callable
     20         */
     21        protected $callback;
     22
     23        /**
     24         * Create a new iterator
     25         *
     26         * @param array $data
     27         * @param callable $callback Callback to be called on each value
     28         */
     29        public function __construct($data, $callback) {
     30                parent::__construct($data);
     31
     32                $this->callback = $callback;
     33        }
     34
     35        /**
     36         * Get the current item's value after filtering
     37         *
     38         * @return string
     39         */
     40        public function current() {
     41                $value = parent::current();
     42                $value = call_user_func($this->callback, $value);
     43                return $value;
     44        }
     45}
  • src/wp-includes/class-http.php

     
    77 * @since 2.7.0
    88 */
    99
     10if ( ! class_exists( 'Requests' ) ) {
     11        require( ABSPATH . WPINC . '/class-requests.php' );
     12
     13        Requests::register_autoloader();
     14        Requests::set_certificate_path( ABSPATH . WPINC . '/certificates/ca-bundle.crt' );
     15
     16        require( ABSPATH . WPINC . '/class-wp-requests-hooks.php' );
     17}
     18
    1019/**
    1120 * Core class used for managing HTTP transports and making HTTP requests.
    1221 *
     
    8695        const NETWORK_AUTHENTICATION_REQUIRED = 511;
    8796
    8897        /**
     98         * Adapter to change Requests hooks to WP actions.
     99         *
     100         * @var WP_Requests_Hooks
     101         */
     102        protected $hook_adapter;
     103
     104        /**
     105         * Constructor.
     106         */
     107        public function __construct() {
     108                $this->hook_adapter = new WP_Requests_Hooks();
     109        }
     110
     111        /**
    89112         * Send an HTTP request to a URI.
    90113         *
    91114         * Please note: The only URI that are supported in the HTTP Transport implementation
     
    247270                        return $pre;
    248271
    249272                if ( function_exists( 'wp_kses_bad_protocol' ) ) {
    250                         if ( $r['reject_unsafe_urls'] )
     273                        if ( $r['reject_unsafe_urls'] ) {
    251274                                $url = wp_http_validate_url( $url );
     275                        }
    252276                        if ( $url ) {
    253277                                $url = wp_kses_bad_protocol( $url, array( 'http', 'https', 'ssl' ) );
    254278                        }
     
    256280
    257281                $arrURL = @parse_url( $url );
    258282
    259                 if ( empty( $url ) || empty( $arrURL['scheme'] ) )
     283                if ( empty( $url ) || empty( $arrURL['scheme'] ) ) {
    260284                        return new WP_Error('http_request_failed', __('A valid URL was not provided.'));
     285                }
    261286
    262                 if ( $this->block_request( $url ) )
     287                if ( $this->block_request( $url ) ) {
    263288                        return new WP_Error( 'http_request_failed', __( 'User has blocked requests through HTTP.' ) );
    264 
    265                 /*
    266                  * Determine if this is a https call and pass that on to the transport functions
    267                  * so that we can blacklist the transports that do not support ssl verification
    268                  */
    269                 $r['ssl'] = $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl';
    270 
    271                 // Determine if this request is to OUR install of WordPress.
    272                 $homeURL = parse_url( get_bloginfo( 'url' ) );
    273                 $r['local'] = 'localhost' == $arrURL['host'] || ( isset( $homeURL['host'] ) && $homeURL['host'] == $arrURL['host'] );
    274                 unset( $homeURL );
    275 
    276                 /*
    277                  * If we are streaming to a file but no filename was given drop it in the WP temp dir
    278                  * and pick its name using the basename of the $url.
    279                  */
    280                 if ( $r['stream']  && empty( $r['filename'] ) ) {
    281                         $r['filename'] = get_temp_dir() . wp_unique_filename( get_temp_dir(), basename( $url ) );
    282289                }
    283290
    284                 /*
    285                  * Force some settings if we are streaming to a file and check for existence and perms
    286                  * of destination directory.
    287                  */
     291                // If we are streaming to a file but no filename was given drop it in the WP temp dir
     292                // and pick its name using the basename of the $url
    288293                if ( $r['stream'] ) {
     294                        if ( empty( $r['filename'] ) ) {
     295                                $r['filename'] = get_temp_dir() . basename( $url );
     296                        }
     297
     298                        // Force some settings if we are streaming to a file and check for existence and perms of destination directory
    289299                        $r['blocking'] = true;
    290                         if ( ! wp_is_writable( dirname( $r['filename'] ) ) )
     300                        if ( ! wp_is_writable( dirname( $r['filename'] ) ) ) {
    291301                                return new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) );
     302                        }
    292303                }
    293304
    294                 if ( is_null( $r['headers'] ) )
     305                if ( is_null( $r['headers'] ) ) {
    295306                        $r['headers'] = array();
     307                }
    296308
     309                // WP allows passing in headers as a string, weirdly.
    297310                if ( ! is_array( $r['headers'] ) ) {
    298                         $processedHeaders = self::processHeaders( $r['headers'], $url );
     311                        $processedHeaders = WP_Http::processHeaders( $r['headers'] );
    299312                        $r['headers'] = $processedHeaders['headers'];
    300313                }
    301314
    302                 if ( isset( $r['headers']['User-Agent'] ) ) {
    303                         $r['user-agent'] = $r['headers']['User-Agent'];
    304                         unset( $r['headers']['User-Agent'] );
     315                // Setup arguments
     316                $headers = $r['headers'];
     317                $data = $r['body'];
     318                $type = $r['method'];
     319                $options = array(
     320                        'timeout' => $r['timeout'],
     321                        'useragent' => $r['user-agent'],
     322                        'blocking' => $r['blocking'],
     323                        'hooks' => $this->hook_adapter,
     324                );
     325
     326                if ( $r['stream'] ) {
     327                        $options['filename'] = $r['filename'];
    305328                }
     329                if ( empty( $r['redirection'] ) ) {
     330                        $options['follow_redirects'] = false;
     331                }
     332                else {
     333                        $options['redirects'] = $r['redirection'];
     334                }
    306335
    307                 if ( isset( $r['headers']['user-agent'] ) ) {
    308                         $r['user-agent'] = $r['headers']['user-agent'];
    309                         unset( $r['headers']['user-agent'] );
     336                // Use byte limit, if we can
     337                if ( isset( $r['limit_response_size'] ) ) {
     338                        $options['max_bytes'] = $r['limit_response_size'];
    310339                }
    311340
    312                 if ( '1.1' == $r['httpversion'] && !isset( $r['headers']['connection'] ) ) {
    313                         $r['headers']['connection'] = 'close';
     341                // If we've got cookies, use them
     342                if ( ! empty( $r['cookies'] ) ) {
     343                        $options['cookies'] = $r['cookies'];
    314344                }
    315345
    316                 // Construct Cookie: header if any cookies are set.
    317                 self::buildCookieHeader( $r );
     346                // SSL certificate handling
     347                if ( ! $r['sslverify'] ) {
     348                        $options['verify'] = false;
     349                }
     350                else {
     351                        $options['verify'] = $r['sslcertificates'];
     352                }
    318353
    319                 // Avoid issues where mbstring.func_overload is enabled.
    320                 mbstring_binary_safe_encoding();
     354                /**
     355                 * Filter whether SSL should be verified for non-local requests.
     356                 *
     357                 * @since 2.8.0
     358                 *
     359                 * @param bool $ssl_verify Whether to verify the SSL connection. Default true.
     360                 */
     361                $options['verify'] = apply_filters( 'https_ssl_verify', $options['verify'] );
    321362
    322                 if ( ! isset( $r['headers']['Accept-Encoding'] ) ) {
    323                         if ( $encoding = WP_Http_Encoding::accept_encoding( $url, $r ) )
    324                                 $r['headers']['Accept-Encoding'] = $encoding;
     363                try {
     364                        $response = Requests::request( $url, $headers, $data, $type, $options );
    325365                }
     366                catch ( Requests_Exception $e ) {
     367                        $response = new WP_Error( 'http_request_failed', $e->getMessage() );
     368                }
    326369
    327                 if ( ( ! is_null( $r['body'] ) && '' != $r['body'] ) || 'POST' == $r['method'] || 'PUT' == $r['method'] ) {
    328                         if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) {
    329                                 $r['body'] = http_build_query( $r['body'], null, '&' );
     370                /**
     371                 * Fires after an HTTP API response is received and before the response is returned.
     372                 *
     373                 * @since 2.8.0
     374                 *
     375                 * @param array|WP_Error $response HTTP response or WP_Error object.
     376                 * @param string         $context  Context under which the hook is fired.
     377                 * @param string         $class    HTTP transport used.
     378                 * @param array          $args     HTTP request arguments.
     379                 * @param string         $url      The request URL.
     380                 */
     381                do_action( 'http_api_debug', $response, 'response', 'Requests', $r, $url );
     382                if ( is_wp_error( $response ) ) {
     383                        return $response;
     384                }
    330385
    331                                 if ( ! isset( $r['headers']['Content-Type'] ) )
    332                                         $r['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' );
    333                         }
    334 
    335                         if ( '' === $r['body'] )
    336                                 $r['body'] = null;
    337 
    338                         if ( ! isset( $r['headers']['Content-Length'] ) && ! isset( $r['headers']['content-length'] ) )
    339                                 $r['headers']['Content-Length'] = strlen( $r['body'] );
     386                if ( ! $r['blocking'] ) {
     387                        return array(
     388                                'headers' => array(),
     389                                'body' => '',
     390                                'response' => array(
     391                                        'code' => false,
     392                                        'message' => false,
     393                                ),
     394                                'cookies' => array(),
     395                        );
    340396                }
    341397
    342                 $response = $this->_dispatch_request( $url, $r );
     398                // Convert the response into an array
     399                $data = new WP_HTTP_Requests_Response( $response, $r['filename'] );
    343400
    344                 reset_mbstring_encoding();
     401                /**
     402                 * Filter the HTTP API response immediately before the response is returned.
     403                 *
     404                 * @since 2.9.0
     405                 *
     406                 * @param array  $data HTTP response.
     407                 * @param array  $r    HTTP request arguments.
     408                 * @param string $url  The request URL.
     409                 */
     410                return apply_filters( 'http_response', $data, $r, $url );
     411        }
    345412
    346                 if ( is_wp_error( $response ) )
    347                         return $response;
    348 
    349                 // Append cookies that were used in this request to the response
    350                 if ( ! empty( $r['cookies'] ) ) {
    351                         $cookies_set = wp_list_pluck( $response['cookies'], 'name' );
    352                         foreach ( $r['cookies'] as $cookie ) {
    353                                 if ( ! in_array( $cookie->name, $cookies_set ) && $cookie->test( $url ) ) {
    354                                         $response['cookies'][] = $cookie;
    355                                 }
    356                         }
     413        /**
     414         * Match redirect behaviour to browser handling.
     415         *
     416         * Changes 302 redirects from POST to GET to match browser handling. Per
     417         * RFC 7231, user agents can deviate from the strict reading of the
     418         * specification for compatibility purposes.
     419         *
     420         * @param string $location URL to redirect to.
     421         * @param array $headers Headers for the redirect.
     422         * @param array $options Redirect request options.
     423         * @param Requests_Response $original Response object.
     424         */
     425        public static function browser_redirect_compatibility( $location, $headers, $data, &$options, $original ) {
     426                // Browser compat
     427                if ( $original->status_code === 302 ) {
     428                        $options['type'] = Requests::GET;
    357429                }
    358 
    359                 return $response;
    360430        }
    361431
    362432        /**
  • src/wp-includes/class-requests.php

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

     
     1<?php
     2
     3/**
     4 * Wrapper object for a Requests_Response for compatibility.
     5 *
     6 * @package WordPress
     7 * @subpackage HTTP
     8 * @since 4.6.0
     9 */
     10class WP_HTTP_Requests_Response extends WP_HTTP_Response implements ArrayAccess {
     11        /**
     12         * Requests Response object.
     13         *
     14         * @var Requests_Response
     15         */
     16        protected $response;
     17
     18        /**
     19         * Filename the response was saved to.
     20         *
     21         * @var string|null
     22         */
     23        protected $filename;
     24
     25        /**
     26         * Constructor.
     27         */
     28        public function __construct( Requests_Response $response, $filename = '' ) {
     29                $this->response = $response;
     30                $this->filename = $filename;
     31        }
     32
     33        /**
     34         * Get the response object for the request.
     35         *
     36         * @return Requests_Response
     37         */
     38        public function get_response_object() {
     39                return $this->response;
     40        }
     41
     42        /**
     43         * Retrieves headers associated with the response.
     44         *
     45         * @return array Map of header name to header value.
     46         */
     47        public function get_headers() {
     48                // Ensure headers remain case-insensitive
     49                $converted = new Requests_Utility_CaseInsensitiveDictionary();
     50
     51                foreach ( $this->response->headers->getAll() as $key => $value ) {
     52                        if ( count( $value ) === 1 ) {
     53                                $converted[ $key ] = $value[0];
     54                        }
     55                        else {
     56                                $converted[ $key ] = $value;
     57                        }
     58                }
     59
     60                return $converted;
     61        }
     62
     63        /**
     64         * Sets all header values.
     65         *
     66         * @param array $headers Map of header name to header value.
     67         */
     68        public function set_headers( $headers ) {
     69                $this->response->headers = new Requests_Response_Headers( $headers );
     70        }
     71
     72        /**
     73         * Sets a single HTTP header.
     74         *
     75         * @param string $key     Header name.
     76         * @param string $value   Header value.
     77         * @param bool   $replace Optional. Whether to replace an existing header of the same name.
     78         *                        Default true.
     79         */
     80        public function header( $key, $value, $replace = true ) {
     81                if ( $replace ) {
     82                        unset( $this->response->headers[ $key ] );
     83                }
     84
     85                $this->response->headers[ $key ] = $value;
     86        }
     87
     88        /**
     89         * Retrieves the HTTP return code for the response.
     90         *
     91         * @return int The 3-digit HTTP status code.
     92         */
     93        public function get_status() {
     94                return $this->response->status_code;
     95        }
     96
     97        /**
     98         * Sets the 3-digit HTTP status code.
     99         *
     100         * @param int $code HTTP status.
     101         */
     102        public function set_status( $code ) {
     103                $this->response->status_code = absint( $code );
     104        }
     105
     106        /**
     107         * Retrieves the response data.
     108         *
     109         * @return mixed Response data.
     110         */
     111        public function get_data() {
     112                return $this->response->body;
     113        }
     114
     115        /**
     116         * Sets the response data.
     117         *
     118         * @param mixed $data Response data.
     119         */
     120        public function set_data( $data ) {
     121                $this->response->body = $data;
     122        }
     123
     124        /**
     125         * Get cookies from the response.
     126         *
     127         * @return WP_HTTP_Cookie[] List of cookie objects.
     128         */
     129        public function get_cookies() {
     130                $cookies = array();
     131                foreach ( $this->response->cookies as $cookie ) {
     132                        $cookies[] = new WP_Http_Cookie( array(
     133                                'name'    => $cookie->name,
     134                                'value'   => urldecode( $cookie->value ),
     135                                'expires' => $cookie->attributes['expires'],
     136                                'path'    => $cookie->attributes['path'],
     137                                'domain'  => $cookie->attributes['domain'],
     138                        ));
     139                }
     140
     141                return $cookies;
     142        }
     143
     144        /**
     145         * Check if an ArrayAccess offset exists.
     146         *
     147         * This is for backwards compatibility for array access.
     148         *
     149         * @param string|int $key Array offset.
     150         * @return bool True if the offset exists, false otherwise.
     151         */
     152        public function offsetExists( $key ) {
     153                $allowed = array( 'headers', 'body', 'response', 'cookies', 'filename' );
     154                return in_array( $key, $allowed );
     155        }
     156
     157        /**
     158         * Get an ArrayAccess value.
     159         *
     160         * This is for backwards compatibility for array access.
     161         *
     162         * @param string|int $key Array offset to get.
     163         * @return mixed Value if the key is a valid offset, null if invalid.
     164         */
     165        public function offsetGet( $key ) {
     166                switch ( $key ) {
     167                        case 'headers':
     168                                return $this->get_headers();
     169
     170                        case 'body':
     171                                return $this->get_data();
     172
     173                        case 'response':
     174                                return array(
     175                                        'code'    => $this->get_status(),
     176                                        'message' => get_status_header_desc( $this->get_status() ),
     177                                );
     178
     179                        case 'cookies':
     180                                return $this->get_cookies();
     181
     182                        case 'filename':
     183                                return $this->filename;
     184                }
     185
     186                return null;
     187        }
     188
     189        /**
     190         * Set an ArrayAccess value.
     191         *
     192         * This is for backwards compatibility for array access.
     193         *
     194         * @param string|int $key Array offset to set.
     195         * @param mixed $value Value to set.
     196         */
     197        public function offsetSet( $key, $value ) {
     198                switch ( $key ) {
     199                        case 'headers':
     200                                $this->set_headers( $value );
     201                                break;
     202
     203                        case 'body':
     204                                $this->set_data( $value );
     205                                break;
     206
     207                        case 'response':
     208                                if ( isset( $value['code'] ) ) {
     209                                        $this->set_status( $value['code'] );
     210                                }
     211                                break;
     212
     213                        case 'filename':
     214                                $this->filename = $value;
     215                                break;
     216                }
     217        }
     218
     219        /**
     220         * Unset an ArrayAccess value.
     221         *
     222         * This is for backwards compatibility for array access.
     223         *
     224         * @param string|int $key Array offset to remove.
     225         */
     226        public function offsetUnset( $key ) {
     227                $this->offsetSet( $key, null );
     228        }
     229}
  • src/wp-includes/class-wp-requests-hooks.php

     
     1<?php
     2/**
     3 * HTTP API: Requests hook bridge class
     4 *
     5 * @package WordPress
     6 * @subpackage HTTP
     7 * @since 4.6.0
     8 */
     9
     10/**
     11 * Bridge to connect Requests internal hooks to WordPress filters.
     12 *
     13 * @package WordPress
     14 * @subpackage HTTP
     15 * @since 4.6.0
     16 */
     17class WP_Requests_Hooks implements Requests_Hooker {
     18        /**
     19         * Register a callback for a hook
     20         *
     21         * Defers to the WP hooking system, but adds 10 to the priority since WP's
     22         * default is 10 rather than 0. Also sets the parameter count as high as
     23         * possible.
     24         *
     25         * @param string $hook Hook name
     26         * @param callback $callback Function/method to call on event
     27         * @param int $priority Priority number. <0 is executed earlier, >0 is executed later
     28         */
     29        public function register( $hook, $callback, $priority = 0 ) {
     30                add_filter( 'requests-' . $hook, $callback, $priority + 10, 9999 );
     31        }
     32
     33        /**
     34         * Dispatch a message
     35         *
     36         * @param string $hook Hook name
     37         * @param array $parameters Parameters to pass to callbacks
     38         * @return boolean Successfulness
     39         */
     40        public function dispatch( $hook, $parameters = array() ) {
     41                do_action_ref_array( 'requests-' . $hook, $parameters );
     42                return true;
     43        }
     44}
  • src/wp-includes/default-filters.php

     
    206206add_filter( 'xmlrpc_pingback_error',    'xmlrpc_pingback_error'               );
    207207add_filter( 'title_save_pre',           'trim'                                );
    208208
    209 add_filter( 'http_request_host_is_external', 'allowed_http_request_hosts', 10, 2 );
     209add_filter( 'http_request_host_is_external',    'allowed_http_request_hosts',                          10, 2 );
     210add_action( 'requests-requests.before_redirect', array( 'WP_Http', 'browser_redirect_compatibility' ), 10, 5 );
    210211
    211212// REST API filters.
    212213add_action( 'xmlrpc_rsd_apis',            'rest_output_rsd' );
  • src/wp-includes/http.php

     
    213213 * @return array The headers of the response. Empty array if incorrect parameter given.
    214214 */
    215215function wp_remote_retrieve_headers( $response ) {
    216         if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
     216        if ( is_wp_error( $response ) || ! isset( $response['headers'] ) ) {
    217217                return array();
     218        }
    218219
    219220        return $response['headers'];
    220221}
     
    229230 * @return string The header value. Empty string on if incorrect parameter given, or if the header doesn't exist.
    230231 */
    231232function wp_remote_retrieve_header( $response, $header ) {
    232         if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
     233        if ( is_wp_error( $response ) || ! isset( $response['headers'] ) ) {
    233234                return '';
     235        }
    234236
    235         if ( array_key_exists($header, $response['headers']) )
     237        if ( isset( $response['headers'][ $header ] ) ) {
    236238                return $response['headers'][$header];
     239        }
    237240
    238241        return '';
    239242}
  • src/wp-settings.php

     
    183183require( ABSPATH . WPINC . '/class-wp-http-cookie.php' );
    184184require( ABSPATH . WPINC . '/class-wp-http-encoding.php' );
    185185require( ABSPATH . WPINC . '/class-wp-http-response.php' );
     186require( ABSPATH . WPINC . '/class-wp-http-requests-response.php' );
    186187require( ABSPATH . WPINC . '/widgets.php' );
    187188require( ABSPATH . WPINC . '/class-wp-widget.php' );
    188189require( ABSPATH . WPINC . '/class-wp-widget-factory.php' );
  • tests/phpunit/tests/http/base.php

     
    289289                // Test 303 - POST to GET
    290290                $res = wp_remote_post( add_query_arg( 'response_code', 303, $url ), array( 'timeout' => 30 ) );
    291291                $this->assertEquals( 'GET', wp_remote_retrieve_body( $res ) );
    292 
    293                 // Test 304 - POST to POST
    294                 $res = wp_remote_post( add_query_arg( 'response_code', 304, $url ), array( 'timeout' => 30 ) );
    295                 $this->assertEquals( 'POST', wp_remote_retrieve_body( $res ) );
    296292        }
    297293
    298294        /**
  • tests/phpunit/tests/http/functions.php

     
    1919                $response = wp_remote_head( $url );
    2020                $headers = wp_remote_retrieve_headers( $response );
    2121
    22                 $this->assertInternalType( 'array', $headers, "Reply wasn't array." );
    2322                $this->assertEquals( 'image/jpeg', $headers['content-type'] );
    2423                $this->assertEquals( '40148', $headers['content-length'] );
    2524                $this->assertEquals( '200', wp_remote_retrieve_response_code( $response ) );
     
    3635                $url = 'https://asdftestblog1.files.wordpress.com/2007/09/awefasdfawef.jpg';
    3736                $headers = wp_remote_head( $url );
    3837
    39                 $this->assertInternalType( 'array', $headers, "Reply wasn't array." );
    4038                $this->assertEquals( '404', wp_remote_retrieve_response_code( $headers ) );
    4139        }
    4240
     
    4745                $headers = wp_remote_retrieve_headers( $response );
    4846
    4947                // should return the same headers as a head request
    50                 $this->assertInternalType( 'array', $headers, "Reply wasn't array." );
    5148                $this->assertEquals( 'image/jpeg', $headers['content-type'] );
    5249                $this->assertEquals( '40148', $headers['content-length'] );
    5350                $this->assertEquals( '200', wp_remote_retrieve_response_code( $response ) );
     
    6158                $headers = wp_remote_retrieve_headers( $response );
    6259
    6360                // should return the same headers as a head request
    64                 $this->assertInternalType( 'array', $headers, "Reply wasn't array." );
    6561                $this->assertEquals( 'image/jpeg', $headers['content-type'] );
    6662                $this->assertEquals( '40148', $headers['content-length'] );
    6763                $this->assertEquals( '200', wp_remote_retrieve_response_code( $response ) );
     
    8581                $response = wp_remote_head( $url );
    8682                $cookies  = wp_remote_retrieve_cookies( $response );
    8783
    88                 $this->assertInternalType( 'array', $cookies );
    8984                $this->assertNotEmpty( $cookies );
    9085
    9186                $cookie = wp_remote_retrieve_cookie( $response, 'wordpress_test_cookie' );