Ticket #33055: 33055.2.diff
File 33055.2.diff, 428.3 KB (added by , 9 years ago) |
---|
-
wp-includes/class-http.php
19 19 * @since 2.7.0 20 20 */ 21 21 class WP_Http { 22 /** 23 * Adapter to change Requests hooks to WP actions. 24 * 25 * @var WP_Requests_Hooks 26 */ 27 protected $hook_adapter; 22 28 23 29 /** 30 * Constructor. 31 */ 32 public function __construct() { 33 $this->hook_adapter = new WP_Requests_Hooks(); 34 } 35 36 /** 24 37 * Send an HTTP request to a URI. 25 38 * 26 39 * Please note: The only URI that are supported in the HTTP Transport implementation … … 182 195 return $pre; 183 196 184 197 if ( function_exists( 'wp_kses_bad_protocol' ) ) { 185 if ( $r['reject_unsafe_urls'] ) 198 if ( $r['reject_unsafe_urls'] ) { 186 199 $url = wp_http_validate_url( $url ); 200 } 187 201 if ( $url ) { 188 202 $url = wp_kses_bad_protocol( $url, array( 'http', 'https', 'ssl' ) ); 189 203 } … … 191 205 192 206 $arrURL = @parse_url( $url ); 193 207 194 if ( empty( $url ) || empty( $arrURL['scheme'] ) ) 208 if ( empty( $url ) || empty( $arrURL['scheme'] ) ) { 195 209 return new WP_Error('http_request_failed', __('A valid URL was not provided.')); 210 } 196 211 197 if ( $this->block_request( $url ) ) 212 if ( $this->block_request( $url ) ) { 198 213 return new WP_Error( 'http_request_failed', __( 'User has blocked requests through HTTP.' ) ); 199 200 /*201 * Determine if this is a https call and pass that on to the transport functions202 * so that we can blacklist the transports that do not support ssl verification203 */204 $r['ssl'] = $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl';205 206 // Determine if this request is to OUR install of WordPress.207 $homeURL = parse_url( get_bloginfo( 'url' ) );208 $r['local'] = 'localhost' == $arrURL['host'] || ( isset( $homeURL['host'] ) && $homeURL['host'] == $arrURL['host'] );209 unset( $homeURL );210 211 /*212 * If we are streaming to a file but no filename was given drop it in the WP temp dir213 * and pick its name using the basename of the $url.214 */215 if ( $r['stream'] && empty( $r['filename'] ) ) {216 $r['filename'] = get_temp_dir() . wp_unique_filename( get_temp_dir(), basename( $url ) );217 214 } 218 215 219 /* 220 * Force some settings if we are streaming to a file and check for existence and perms 221 * of destination directory. 222 */ 216 // If we are streaming to a file but no filename was given drop it in the WP temp dir 217 // and pick its name using the basename of the $url 223 218 if ( $r['stream'] ) { 219 if ( empty( $r['filename'] ) ) { 220 $r['filename'] = get_temp_dir() . basename( $url ); 221 } 222 223 // Force some settings if we are streaming to a file and check for existence and perms of destination directory 224 224 $r['blocking'] = true; 225 if ( ! wp_is_writable( dirname( $r['filename'] ) ) ) 225 if ( ! wp_is_writable( dirname( $r['filename'] ) ) ) { 226 226 return new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) ); 227 } 227 228 } 228 229 229 if ( is_null( $r['headers'] ) ) 230 if ( is_null( $r['headers'] ) ) { 230 231 $r['headers'] = array(); 232 } 231 233 234 // WP allows passing in headers as a string, weirdly. 232 235 if ( ! is_array( $r['headers'] ) ) { 233 $processedHeaders = self::processHeaders( $r['headers'], $url);236 $processedHeaders = WP_Http::processHeaders( $r['headers'] ); 234 237 $r['headers'] = $processedHeaders['headers']; 235 238 } 236 239 237 if ( isset( $r['headers']['User-Agent'] ) ) { 238 $r['user-agent'] = $r['headers']['User-Agent']; 239 unset( $r['headers']['User-Agent'] ); 240 // Setup arguments 241 $headers = $r['headers']; 242 $data = $r['body']; 243 $type = $r['method']; 244 $options = array( 245 'timeout' => $r['timeout'], 246 'useragent' => $r['user-agent'], 247 'blocking' => $r['blocking'], 248 'hooks' => $this->hook_adapter, 249 ); 250 251 if ( $r['stream'] ) { 252 $options['filename'] = $r['filename']; 240 253 } 254 if ( empty( $r['redirection'] ) ) { 255 $options['follow_redirects'] = false; 256 } 257 else { 258 $options['redirects'] = $r['redirection']; 259 } 241 260 242 if ( isset( $r['headers']['user-agent'] ) ) {243 $r['user-agent'] = $r['headers']['user-agent'];244 unset( $r['headers']['user-agent'] );261 // Use byte limit, if we can 262 if ( isset( $r['limit_response_size'] ) ) { 263 $options['max_bytes'] = $r['limit_response_size']; 245 264 } 246 265 247 if ( '1.1' == $r['httpversion'] && !isset( $r['headers']['connection'] ) ) { 248 $r['headers']['connection'] = 'close'; 266 // If we've got cookies, use them 267 if ( ! empty( $r['cookies'] ) ) { 268 $options['cookies'] = $r['cookies']; 249 269 } 250 270 251 // Construct Cookie: header if any cookies are set. 252 self::buildCookieHeader( $r ); 271 // SSL certificate handling 272 if ( ! $r['sslverify'] ) { 273 $options['verify'] = false; 274 } 275 else { 276 $options['verify'] = $r['sslcertificates']; 277 } 253 278 254 // Avoid issues where mbstring.func_overload is enabled. 255 mbstring_binary_safe_encoding(); 279 /** 280 * Filter whether SSL should be verified for non-local requests. 281 * 282 * @since 2.8.0 283 * 284 * @param bool $ssl_verify Whether to verify the SSL connection. Default true. 285 */ 286 $options['verify'] = apply_filters( 'https_ssl_verify', $options['verify'] ); 256 287 257 if ( ! isset( $r['headers']['Accept-Encoding'] ) ) { 258 if ( $encoding = WP_Http_Encoding::accept_encoding( $url, $r ) ) 259 $r['headers']['Accept-Encoding'] = $encoding; 288 try { 289 $response = Requests::request($url, $headers, $data, $type, $options); 260 290 } 291 catch ( Requests_Exception $e ) { 292 $response = new WP_Error( 'http_request_failed', $e->getMessage() ); 293 } 261 294 262 if ( ( ! is_null( $r['body'] ) && '' != $r['body'] ) || 'POST' == $r['method'] || 'PUT' == $r['method'] ) { 263 if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) { 264 $r['body'] = http_build_query( $r['body'], null, '&' ); 295 /** 296 * Fires after an HTTP API response is received and before the response is returned. 297 * 298 * @since 2.8.0 299 * 300 * @param array|WP_Error $response HTTP response or WP_Error object. 301 * @param string $context Context under which the hook is fired. 302 * @param string $class HTTP transport used. 303 * @param array $args HTTP request arguments. 304 * @param string $url The request URL. 305 */ 306 do_action( 'http_api_debug', $response, 'response', 'Requests', $r, $url ); 307 if ( is_wp_error( $response ) ) { 308 return $response; 309 } 265 310 266 if ( ! isset( $r['headers']['Content-Type'] ) ) 267 $r['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' ); 311 if ( ! $r['blocking'] ) { 312 return array( 313 'headers' => array(), 314 'body' => '', 315 'response' => array( 316 'code' => false, 317 'message' => false, 318 ), 319 'cookies' => array(), 320 ); 321 } 322 $data = array( 323 'headers' => $this->get_header_array( $response->headers ), 324 'body' => $response->body, 325 'response' => array( 326 'code' => $response->status_code, 327 'message' => get_status_header_desc( $response->status_code ), 328 ), 329 'cookies' => array(), 330 'filename' => $r['filename'] 331 ); 332 333 $cookies = $response->headers['set-cookie']; 334 if ( ! empty( $cookies ) ) { 335 $values = explode(',', $cookies); 336 foreach ($values as $value) { 337 $data['cookies'][] = new WP_Http_Cookie( $value ); 268 338 } 269 270 if ( '' === $r['body'] )271 $r['body'] = null;272 273 if ( ! isset( $r['headers']['Content-Length'] ) && ! isset( $r['headers']['content-length'] ) )274 $r['headers']['Content-Length'] = strlen( $r['body'] );275 339 } 276 340 277 $response = $this->_dispatch_request( $url, $r ); 341 /** 342 * Filter the HTTP API response immediately before the response is returned. 343 * 344 * @since 2.9.0 345 * 346 * @param array $data HTTP response. 347 * @param array $r HTTP request arguments. 348 * @param string $url The request URL. 349 */ 350 return apply_filters( 'http_response', $data, $r, $url ); 351 } 278 352 279 reset_mbstring_encoding(); 353 /** 354 * Convert headers to WP-style mixed strings and arrays 355 * 356 * @param Requests_Response_Headers $headers 357 * @return array 358 */ 359 protected function get_header_array( $headers ) { 360 $converted = array(); 280 361 281 if ( is_wp_error( $response ) ) 282 return $response; 283 284 // Append cookies that were used in this request to the response 285 if ( ! empty( $r['cookies'] ) ) { 286 $cookies_set = wp_list_pluck( $response['cookies'], 'name' ); 287 foreach ( $r['cookies'] as $cookie ) { 288 if ( ! in_array( $cookie->name, $cookies_set ) && $cookie->test( $url ) ) { 289 $response['cookies'][] = $cookie; 290 } 362 foreach ( $headers->getAll() as $key => $value ) { 363 if ( count( $value ) === 1 ) { 364 $converted[ $key ] = $value[0]; 291 365 } 366 else { 367 $converted[ $key ] = $value; 368 } 292 369 } 293 370 294 return $ response;371 return $converted; 295 372 } 296 373 297 374 /** -
wp-includes/class-wp-requests-hooks.php
1 <?php 2 3 /** 4 * Handles adding and dispatching events 5 * 6 * @package Requests 7 * @subpackage Utilities 8 */ 9 class WP_Requests_Hooks implements Requests_Hooker { 10 /** 11 * Constructor 12 */ 13 public function __construct() { 14 // pass 15 } 16 17 /** 18 * Register a callback for a hook 19 * 20 * Defers to the WP hooking system, but adds 10 to the priority since WP's 21 * default is 10 rather than 0. Also sets the parameter count as high as 22 * possible. 23 * 24 * @param string $hook Hook name 25 * @param callback $callback Function/method to call on event 26 * @param int $priority Priority number. <0 is executed earlier, >0 is executed later 27 */ 28 public function register($hook, $callback, $priority = 0) { 29 add_filter('requests-' . $hook, $callback, $priority + 10, 9999); 30 } 31 32 /** 33 * Dispatch a message 34 * 35 * @param string $hook Hook name 36 * @param array $parameters Parameters to pass to callbacks 37 * @return boolean Successfulness 38 */ 39 public function dispatch($hook, $parameters = array()) { 40 do_action_ref_array('requests-' . $hook, $parameters); 41 return true; 42 } 43 } -
wp-includes/http.php
33 33 34 34 /** WP_HTTP_Response class */ 35 35 require_once( ABSPATH . WPINC . '/class-wp-http-response.php' ); 36 37 /** Requests primary class */ 38 require_once( ABSPATH . WPINC . '/requests/Requests.php' ); 39 Requests::register_autoloader(); 40 41 /** WP_Requests_Hooks class */ 42 require_once( ABSPATH . WPINC . '/class-wp-requests-hooks.php' ); -
wp-includes/requests/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 -
wp-includes/requests/Requests/Auth.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Cookie/Jar.php
Property changes on: wp-includes/requests/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 * @deprecated Use {@see Requests_Cookie_Jar::normalize_cookie} 50 * @return Requests_Cookie 51 */ 52 public function normalizeCookie($cookie, $key = null) { 53 return $this->normalize_cookie($cookie, $key); 54 } 55 56 /** 57 * Check if the given item exists 58 * 59 * @param string $key Item key 60 * @return boolean Does the item exist? 61 */ 62 public function offsetExists($key) { 63 return isset($this->cookies[$key]); 64 } 65 66 /** 67 * Get the value for the item 68 * 69 * @param string $key Item key 70 * @return string Item value 71 */ 72 public function offsetGet($key) { 73 if (!isset($this->cookies[$key])) { 74 return null; 75 } 76 77 return $this->cookies[$key]; 78 } 79 80 /** 81 * Set the given item 82 * 83 * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`) 84 * 85 * @param string $key Item name 86 * @param string $value Item value 87 */ 88 public function offsetSet($key, $value) { 89 if ($key === null) { 90 throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset'); 91 } 92 93 $this->cookies[$key] = $value; 94 } 95 96 /** 97 * Unset the given header 98 * 99 * @param string $key 100 */ 101 public function offsetUnset($key) { 102 unset($this->cookies[$key]); 103 } 104 105 /** 106 * Get an iterator for the data 107 * 108 * @return ArrayIterator 109 */ 110 public function getIterator() { 111 return new ArrayIterator($this->cookies); 112 } 113 114 /** 115 * Register the cookie handler with the request's hooking system 116 * 117 * @param Requests_Hooker $hooks Hooking system 118 */ 119 public function register(Requests_Hooker $hooks) { 120 $hooks->register('requests.before_request', array($this, 'before_request')); 121 $hooks->register('requests.before_redirect_check', array($this, 'before_redirect_check')); 122 } 123 124 /** 125 * Add Cookie header to a request if we have any 126 * 127 * As per RFC 6265, cookies are separated by '; ' 128 * 129 * @param string $url 130 * @param array $headers 131 * @param array $data 132 * @param string $type 133 * @param array $options 134 */ 135 public function before_request($url, &$headers, &$data, &$type, &$options) { 136 if (!$url instanceof Requests_IRI) { 137 $url = new Requests_IRI($url); 138 } 139 140 if (!empty($this->cookies)) { 141 $cookies = array(); 142 foreach ($this->cookies as $key => $cookie) { 143 $cookie = $this->normalize_cookie($cookie, $key); 144 145 // Skip expired cookies 146 if ($cookie->is_expired()) { 147 continue; 148 } 149 150 if ($cookie->domain_matches($url->host)) { 151 $cookies[] = $cookie->format_for_header(); 152 } 153 } 154 155 $headers['Cookie'] = implode('; ', $cookies); 156 } 157 } 158 159 /** 160 * Parse all cookies from a response and attach them to the response 161 * 162 * @var Requests_Response $response 163 */ 164 public function before_redirect_check(Requests_Response &$return) { 165 $url = $return->url; 166 if (!$url instanceof Requests_IRI) { 167 $url = new Requests_IRI($url); 168 } 169 170 $cookies = Requests_Cookie::parse_from_headers($return->headers, $url); 171 $this->cookies = array_merge($this->cookies, $cookies); 172 $return->cookies = $this; 173 } 174 } 175 No newline at end of file -
wp-includes/requests/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 * @deprecated Use {@see Requests_Cookie::format_for_header} 318 * @return string 319 */ 320 public function formatForHeader() { 321 return $this->format_for_header(); 322 } 323 324 /** 325 * Format a cookie for a Set-Cookie header 326 * 327 * This is used when sending cookies to clients. This isn't really 328 * applicable to client-side usage, but might be handy for debugging. 329 * 330 * @return string Cookie formatted for Set-Cookie header 331 */ 332 public function format_for_set_cookie() { 333 $header_value = $this->format_for_header(); 334 if (!empty($this->attributes)) { 335 $parts = array(); 336 foreach ($this->attributes as $key => $value) { 337 // Ignore non-associative attributes 338 if (is_numeric($key)) { 339 $parts[] = $value; 340 } 341 else { 342 $parts[] = sprintf('%s=%s', $key, $value); 343 } 344 } 345 346 $header_value .= '; ' . implode('; ', $parts); 347 } 348 return $header_value; 349 } 350 351 /** 352 * Format a cookie for a Set-Cookie header 353 * 354 * @deprecated Use {@see Requests_Cookie::format_for_set_cookie} 355 * @return string 356 */ 357 public function formatForSetCookie() { 358 return $this->format_for_set_cookie(); 359 } 360 361 /** 362 * Get the cookie value 363 * 364 * Attributes and other data can be accessed via methods. 365 */ 366 public function __toString() { 367 return $this->value; 368 } 369 370 /** 371 * Parse a cookie string into a cookie object 372 * 373 * Based on Mozilla's parsing code in Firefox and related projects, which 374 * is an intentional deviation from RFC 2109 and RFC 2616. RFC 6265 375 * specifies some of this handling, but not in a thorough manner. 376 * 377 * @param string Cookie header value (from a Set-Cookie header) 378 * @return Requests_Cookie Parsed cookie object 379 */ 380 public static function parse($string, $name = '', $reference_time = null) { 381 $parts = explode(';', $string); 382 $kvparts = array_shift($parts); 383 384 if (!empty($name)) { 385 $value = $string; 386 } 387 elseif (strpos($kvparts, '=') === false) { 388 // Some sites might only have a value without the equals separator. 389 // Deviate from RFC 6265 and pretend it was actually a blank name 390 // (`=foo`) 391 // 392 // https://bugzilla.mozilla.org/show_bug.cgi?id=169091 393 $name = ''; 394 $value = $kvparts; 395 } 396 else { 397 list($name, $value) = explode('=', $kvparts, 2); 398 } 399 $name = trim($name); 400 $value = trim($value); 401 402 // Attribute key are handled case-insensitively 403 $attributes = new Requests_Utility_CaseInsensitiveDictionary(); 404 405 if (!empty($parts)) { 406 foreach ($parts as $part) { 407 if (strpos($part, '=') === false) { 408 $part_key = $part; 409 $part_value = true; 410 } 411 else { 412 list($part_key, $part_value) = explode('=', $part, 2); 413 $part_value = trim($part_value); 414 } 415 416 $part_key = trim($part_key); 417 $attributes[$part_key] = $part_value; 418 } 419 } 420 421 return new Requests_Cookie($name, $value, $attributes, array(), $reference_time); 422 } 423 424 /** 425 * Parse all Set-Cookie headers from request headers 426 * 427 * @param Requests_Response_Headers $headers Headers to parse from 428 * @param Requests_IRI|null $origin URI for comparing cookie origins 429 * @param int|null $time Reference time for expiration calculation 430 * @return array 431 */ 432 public static function parse_from_headers(Requests_Response_Headers $headers, Requests_IRI $origin = null, $time = null) { 433 $cookie_headers = $headers->getValues('Set-Cookie'); 434 if (empty($cookie_headers)) { 435 return array(); 436 } 437 438 $cookies = array(); 439 foreach ($cookie_headers as $header) { 440 $parsed = self::parse($header, '', $time); 441 442 // Default domain/path attributes 443 if (empty($parsed->attributes['domain']) && !empty($origin)) { 444 $parsed->attributes['domain'] = $origin->host; 445 $parsed->flags['host-only'] = true; 446 } 447 else { 448 $parsed->flags['host-only'] = false; 449 } 450 451 $path_is_valid = (!empty($parsed->attributes['path']) && $parsed->attributes['path'][0] === '/'); 452 if (!$path_is_valid && !empty($origin)) { 453 $path = $origin->path; 454 455 // Default path normalization as per RFC 6265 section 5.1.4 456 if (substr($path, 0, 1) !== '/') { 457 // If the uri-path is empty or if the first character of 458 // the uri-path is not a %x2F ("/") character, output 459 // %x2F ("/") and skip the remaining steps. 460 $path = '/'; 461 } 462 elseif (substr_count($path, '/') === 1) { 463 // If the uri-path contains no more than one %x2F ("/") 464 // character, output %x2F ("/") and skip the remaining 465 // step. 466 $path = '/'; 467 } 468 else { 469 // Output the characters of the uri-path from the first 470 // character up to, but not including, the right-most 471 // %x2F ("/"). 472 $path = substr($path, 0, strrpos($path, '/')); 473 } 474 $parsed->attributes['path'] = $path; 475 } 476 477 // Reject invalid cookie domains 478 if (!empty($origin) && !$parsed->domain_matches($origin->host)) { 479 continue; 480 } 481 482 $cookies[$parsed->name] = $parsed; 483 } 484 485 return $cookies; 486 } 487 488 /** 489 * Parse all Set-Cookie headers from request headers 490 * 491 * @deprecated Use {@see Requests_Cookie::parse_from_headers} 492 * @return string 493 */ 494 public static function parseFromHeaders(Requests_Response_Headers $headers) { 495 return self::parse_from_headers($headers); 496 } 497 } -
wp-includes/requests/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 -
wp-includes/requests/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 } -
wp-includes/requests/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 } -
wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/401.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/402.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/403.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/404.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/405.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/406.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/407.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/408.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/409.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/410.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/411.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/412.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/413.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/414.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/415.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/416.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/417.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/418.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/428.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/429.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/431.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/500.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/501.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/502.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/503.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/504.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/505.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/511.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP/Unknown.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception/HTTP.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Exception.php
Property changes on: wp-includes/requests/Requests/Exception/HTTP.php ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property
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 -
wp-includes/requests/Requests/Hooker.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Hooks.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/IDNAEncoder.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/IPv6.php
Property changes on: wp-includes/requests/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 } -
wp-includes/requests/Requests/IRI.php
Property changes on: wp-includes/requests/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 } -
wp-includes/requests/Requests/Proxy/HTTP.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/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 -
wp-includes/requests/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 } -
wp-includes/requests/Requests/Response.php
Property changes on: wp-includes/requests/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 } -
wp-includes/requests/Requests/SSL.php
Property changes on: wp-includes/requests/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 -
wp-includes/requests/Requests/Session.php
Property changes on: wp-includes/requests/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 $request['headers'] = array_merge($this->headers, $request['headers']); 244 245 if (is_array($request['data']) && is_array($this->data)) { 246 $request['data'] = array_merge($this->data, $request['data']); 247 } 248 249 if ($merge_options !== false) { 250 $request['options'] = array_merge($this->options, $request['options']); 251 252 // Disallow forcing the type, as that's a per request setting 253 unset($request['options']['type']); 254 } 255 256 return $request; 257 } 258 } -
wp-includes/requests/Requests/Transport/cURL.php
Property changes on: wp-includes/requests/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 return $this->headers; 180 } 181 182 /** 183 * Send multiple requests simultaneously 184 * 185 * @param array $requests Request data 186 * @param array $options Global options 187 * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well) 188 */ 189 public function request_multiple($requests, $options) { 190 // If you're not requesting, we can't get any responses ¯\_(ツ)_/¯ 191 if (empty($requests)) { 192 return array(); 193 } 194 195 $multihandle = curl_multi_init(); 196 $subrequests = array(); 197 $subhandles = array(); 198 199 $class = get_class($this); 200 foreach ($requests as $id => $request) { 201 $subrequests[$id] = new $class(); 202 $subhandles[$id] = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']); 203 $request['options']['hooks']->dispatch('curl.before_multi_add', array(&$subhandles[$id])); 204 curl_multi_add_handle($multihandle, $subhandles[$id]); 205 } 206 207 $completed = 0; 208 $responses = array(); 209 210 $request['options']['hooks']->dispatch('curl.before_multi_exec', array(&$multihandle)); 211 212 do { 213 $active = false; 214 215 do { 216 $status = curl_multi_exec($multihandle, $active); 217 } 218 while ($status === CURLM_CALL_MULTI_PERFORM); 219 220 $to_process = array(); 221 222 // Read the information as needed 223 while ($done = curl_multi_info_read($multihandle)) { 224 $key = array_search($done['handle'], $subhandles, true); 225 if (!isset($to_process[$key])) { 226 $to_process[$key] = $done; 227 } 228 } 229 230 // Parse the finished requests before we start getting the new ones 231 foreach ($to_process as $key => $done) { 232 $options = $requests[$key]['options']; 233 $responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options); 234 235 $options['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$key], $requests[$key])); 236 237 curl_multi_remove_handle($multihandle, $done['handle']); 238 curl_close($done['handle']); 239 240 if (!is_string($responses[$key])) { 241 $options['hooks']->dispatch('multiple.request.complete', array(&$responses[$key], $key)); 242 } 243 $completed++; 244 } 245 } 246 while ($active || $completed < count($subrequests)); 247 248 $request['options']['hooks']->dispatch('curl.after_multi_exec', array(&$multihandle)); 249 250 curl_multi_close($multihandle); 251 252 return $responses; 253 } 254 255 /** 256 * Get the cURL handle for use in a multi-request 257 * 258 * @param string $url URL to request 259 * @param array $headers Associative array of request headers 260 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD 261 * @param array $options Request options, see {@see Requests::response()} for documentation 262 * @return resource Subrequest's cURL handle 263 */ 264 public function &get_subrequest_handle($url, $headers, $data, $options) { 265 $this->setup_handle($url, $headers, $data, $options); 266 267 if ($options['filename'] !== false) { 268 $this->stream_handle = fopen($options['filename'], 'wb'); 269 } 270 271 $this->response_data = ''; 272 $this->response_bytes = 0; 273 $this->response_byte_limit = false; 274 if ($options['max_bytes'] !== false) { 275 $this->response_byte_limit = $options['max_bytes']; 276 } 277 $this->hooks = $options['hooks']; 278 279 return $this->handle; 280 } 281 282 /** 283 * Setup the cURL handle for the given data 284 * 285 * @param string $url URL to request 286 * @param array $headers Associative array of request headers 287 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD 288 * @param array $options Request options, see {@see Requests::response()} for documentation 289 */ 290 protected function setup_handle($url, $headers, $data, $options) { 291 $options['hooks']->dispatch('curl.before_request', array(&$this->handle)); 292 293 $headers = Requests::flatten($headers); 294 295 if (!empty($data)) { 296 $data_format = $options['data_format']; 297 298 if ($data_format === 'query') { 299 $url = self::format_get($url, $data); 300 $data = ''; 301 } 302 elseif (!is_string($data)) { 303 $data = http_build_query($data, null, '&'); 304 } 305 } 306 307 switch ($options['type']) { 308 case Requests::POST: 309 curl_setopt($this->handle, CURLOPT_POST, true); 310 curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data); 311 break; 312 case Requests::PATCH: 313 case Requests::PUT: 314 case Requests::DELETE: 315 case Requests::OPTIONS: 316 curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']); 317 curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data); 318 break; 319 case Requests::HEAD: 320 curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']); 321 curl_setopt($this->handle, CURLOPT_NOBODY, true); 322 break; 323 case Requests::TRACE: 324 curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']); 325 break; 326 } 327 328 if (is_int($options['timeout']) || $this->version < self::CURL_7_16_2) { 329 curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($options['timeout'])); 330 } 331 else { 332 curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($options['timeout'] * 1000)); 333 } 334 335 if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) { 336 curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout'])); 337 } 338 else { 339 curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000)); 340 } 341 curl_setopt($this->handle, CURLOPT_URL, $url); 342 curl_setopt($this->handle, CURLOPT_REFERER, $url); 343 curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']); 344 curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers); 345 346 if ($options['protocol_version'] === 1.1) { 347 curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 348 } 349 else { 350 curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 351 } 352 353 if (true === $options['blocking']) { 354 curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, array(&$this, 'stream_headers')); 355 curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, array(&$this, 'stream_body')); 356 curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE); 357 } 358 } 359 360 /** 361 * Process a response 362 * 363 * @param string $response Response data from the body 364 * @param array $options Request options 365 * @return string HTTP response data including headers 366 */ 367 public function process_response($response, $options) { 368 if ($options['blocking'] === false) { 369 $fake_headers = ''; 370 $options['hooks']->dispatch('curl.after_request', array(&$fake_headers)); 371 return false; 372 } 373 if ($options['filename'] !== false) { 374 fclose($this->stream_handle);