Ticket #33055: 33055.4.diff
| File 33055.4.diff, 213.4 KB (added by , 10 years ago) |
|---|
-
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 */ 18 class 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 */ 21 interface 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 */ 15 class 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 */ 15 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 15 class 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 */ 15 class 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 */ 15 class 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 */ 15 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 13 class 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 */ 15 class 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 */ 13 class 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 */ 13 class 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 3 class 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 3 class 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 */ 13 class 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 */ 15 interface 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 */ 15 class 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 */ 13 class 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 */ 18 class 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 */ 66 class 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 */ 19 class 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 */ 23 interface 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 */ 13 class 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 */ 15 class Requests_Response { 16 /** 17 * Constructor 18 */ 19 public function __construct() { 20 $this->headers = new Requests_Response_Headers(); 21 $this->cookies = new Requests_Cookie_Jar(); 22 } 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 */ 17 class 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 */ 20 class 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 */ 15 class 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 */ 15 class 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 */ 15 interface 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 */ 15 class 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 */ 15 class 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
7 7 * @since 2.7.0 8 8 */ 9 9 10 if ( ! class_exists( 'Requests' ) ) { 11 require( ABSPATH . WPINC . '/class-requests.php' ); 12 13 Requests::register_autoloader(); 14 Requests::set_certificate_path( ABSPATH . WPINC . '/certificates/ca-bundle.crt' ); 15 16 require( ABSPATH . WPINC . '/class-wp-requests-hooks.php' ); 17 } 18 10 19 /** 11 20 * Core class used for managing HTTP transports and making HTTP requests. 12 21 * … … 86 95 const NETWORK_AUTHENTICATION_REQUIRED = 511; 87 96 88 97 /** 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 /** 89 112 * Send an HTTP request to a URI. 90 113 * 91 114 * Please note: The only URI that are supported in the HTTP Transport implementation … … 247 270 return $pre; 248 271 249 272 if ( function_exists( 'wp_kses_bad_protocol' ) ) { 250 if ( $r['reject_unsafe_urls'] ) 273 if ( $r['reject_unsafe_urls'] ) { 251 274 $url = wp_http_validate_url( $url ); 275 } 252 276 if ( $url ) { 253 277 $url = wp_kses_bad_protocol( $url, array( 'http', 'https', 'ssl' ) ); 254 278 } … … 256 280 257 281 $arrURL = @parse_url( $url ); 258 282 259 if ( empty( $url ) || empty( $arrURL['scheme'] ) ) 283 if ( empty( $url ) || empty( $arrURL['scheme'] ) ) { 260 284 return new WP_Error('http_request_failed', __('A valid URL was not provided.')); 285 } 261 286 262 if ( $this->block_request( $url ) ) 287 if ( $this->block_request( $url ) ) { 263 288 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 functions267 * so that we can blacklist the transports that do not support ssl verification268 */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 dir278 * 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 ) );282 289 } 283 290 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 288 293 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 289 299 $r['blocking'] = true; 290 if ( ! wp_is_writable( dirname( $r['filename'] ) ) ) 300 if ( ! wp_is_writable( dirname( $r['filename'] ) ) ) { 291 301 return new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) ); 302 } 292 303 } 293 304 294 if ( is_null( $r['headers'] ) ) 305 if ( is_null( $r['headers'] ) ) { 295 306 $r['headers'] = array(); 307 } 296 308 309 // WP allows passing in headers as a string, weirdly. 297 310 if ( ! is_array( $r['headers'] ) ) { 298 $processedHeaders = self::processHeaders( $r['headers'], $url);311 $processedHeaders = WP_Http::processHeaders( $r['headers'] ); 299 312 $r['headers'] = $processedHeaders['headers']; 300 313 } 301 314 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']; 305 328 } 329 if ( empty( $r['redirection'] ) ) { 330 $options['follow_redirects'] = false; 331 } 332 else { 333 $options['redirects'] = $r['redirection']; 334 } 306 335 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']; 310 339 } 311 340 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']; 314 344 } 315 345 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 } 318 353 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'] ); 321 362 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 ); 325 365 } 366 catch ( Requests_Exception $e ) { 367 $response = new WP_Error( 'http_request_failed', $e->getMessage() ); 368 } 326 369 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 } 330 385 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 ); 340 396 } 341 397 342 $response = $this->_dispatch_request( $url, $r ); 398 // Convert the response into an array 399 $data = new WP_HTTP_Requests_Response( $response, $r['filename'] ); 343 400 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 } 345 412 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; 357 429 } 358 359 return $response;360 430 } 361 431 362 432 /** -
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 */ 21 class 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 */ 10 class 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 */ 17 class 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
206 206 add_filter( 'xmlrpc_pingback_error', 'xmlrpc_pingback_error' ); 207 207 add_filter( 'title_save_pre', 'trim' ); 208 208 209 add_filter( 'http_request_host_is_external', 'allowed_http_request_hosts', 10, 2 ); 209 add_filter( 'http_request_host_is_external', 'allowed_http_request_hosts', 10, 2 ); 210 add_action( 'requests-requests.before_redirect', array( 'WP_Http', 'browser_redirect_compatibility' ), 10, 5 ); 210 211 211 212 // REST API filters. 212 213 add_action( 'xmlrpc_rsd_apis', 'rest_output_rsd' ); -
src/wp-includes/http.php
213 213 * @return array The headers of the response. Empty array if incorrect parameter given. 214 214 */ 215 215 function 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'] ) ) { 217 217 return array(); 218 } 218 219 219 220 return $response['headers']; 220 221 } … … 229 230 * @return string The header value. Empty string on if incorrect parameter given, or if the header doesn't exist. 230 231 */ 231 232 function 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'] ) ) { 233 234 return ''; 235 } 234 236 235 if ( array_key_exists($header, $response['headers']) )237 if ( isset( $response['headers'][ $header ] ) ) { 236 238 return $response['headers'][$header]; 239 } 237 240 238 241 return ''; 239 242 } -
src/wp-settings.php
183 183 require( ABSPATH . WPINC . '/class-wp-http-cookie.php' ); 184 184 require( ABSPATH . WPINC . '/class-wp-http-encoding.php' ); 185 185 require( ABSPATH . WPINC . '/class-wp-http-response.php' ); 186 require( ABSPATH . WPINC . '/class-wp-http-requests-response.php' ); 186 187 require( ABSPATH . WPINC . '/widgets.php' ); 187 188 require( ABSPATH . WPINC . '/class-wp-widget.php' ); 188 189 require( ABSPATH . WPINC . '/class-wp-widget-factory.php' ); -
tests/phpunit/tests/http/base.php
289 289 // Test 303 - POST to GET 290 290 $res = wp_remote_post( add_query_arg( 'response_code', 303, $url ), array( 'timeout' => 30 ) ); 291 291 $this->assertEquals( 'GET', wp_remote_retrieve_body( $res ) ); 292 293 // Test 304 - POST to POST294 $res = wp_remote_post( add_query_arg( 'response_code', 304, $url ), array( 'timeout' => 30 ) );295 $this->assertEquals( 'POST', wp_remote_retrieve_body( $res ) );296 292 } 297 293 298 294 /** -
tests/phpunit/tests/http/functions.php
19 19 $response = wp_remote_head( $url ); 20 20 $headers = wp_remote_retrieve_headers( $response ); 21 21 22 $this->assertInternalType( 'array', $headers, "Reply wasn't array." );23 22 $this->assertEquals( 'image/jpeg', $headers['content-type'] ); 24 23 $this->assertEquals( '40148', $headers['content-length'] ); 25 24 $this->assertEquals( '200', wp_remote_retrieve_response_code( $response ) ); … … 36 35 $url = 'https://asdftestblog1.files.wordpress.com/2007/09/awefasdfawef.jpg'; 37 36 $headers = wp_remote_head( $url ); 38 37 39 $this->assertInternalType( 'array', $headers, "Reply wasn't array." );40 38 $this->assertEquals( '404', wp_remote_retrieve_response_code( $headers ) ); 41 39 } 42 40 … … 47 45 $headers = wp_remote_retrieve_headers( $response ); 48 46 49 47 // should return the same headers as a head request 50 $this->assertInternalType( 'array', $headers, "Reply wasn't array." );51 48 $this->assertEquals( 'image/jpeg', $headers['content-type'] ); 52 49 $this->assertEquals( '40148', $headers['content-length'] ); 53 50 $this->assertEquals( '200', wp_remote_retrieve_response_code( $response ) ); … … 61 58 $headers = wp_remote_retrieve_headers( $response ); 62 59 63 60 // should return the same headers as a head request 64 $this->assertInternalType( 'array', $headers, "Reply wasn't array." );65 61 $this->assertEquals( 'image/jpeg', $headers['content-type'] ); 66 62 $this->assertEquals( '40148', $headers['content-length'] ); 67 63 $this->assertEquals( '200', wp_remote_retrieve_response_code( $response ) ); … … 85 81 $response = wp_remote_head( $url ); 86 82 $cookies = wp_remote_retrieve_cookies( $response ); 87 83 88 $this->assertInternalType( 'array', $cookies );89 84 $this->assertNotEmpty( $cookies ); 90 85 91 86 $cookie = wp_remote_retrieve_cookie( $response, 'wordpress_test_cookie' );
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)