PK     Ӯ+]Մec  c    src/Proxy.phpnu         <?php
/**
 * Proxy connection interface
 *
 * @package Requests\Proxy
 * @since   1.6
 */

namespace WpOrg\Requests;

use WpOrg\Requests\Hooks;

/**
 * Proxy connection interface
 *
 * Implement this interface to handle proxy settings and authentication
 *
 * Parameters should be passed via the constructor where possible, as this
 * makes it much easier for users to use your provider.
 *
 * @see \WpOrg\Requests\Hooks
 *
 * @package Requests\Proxy
 * @since   1.6
 */
interface Proxy {
	/**
	 * Register hooks as needed
	 *
	 * This method is called in {@see \WpOrg\Requests\Requests::request()} when the user
	 * has set an instance as the 'auth' option. Use this callback to register all the
	 * hooks you'll need.
	 *
	 * @see \WpOrg\Requests\Hooks::register()
	 * @param \WpOrg\Requests\Hooks $hooks Hook system
	 */
	public function register(Hooks $hooks);
}
PK     Ӯ+]^		  	    src/Utility/InputValidator.phpnu         <?php
/**
 * Input validation utilities.
 *
 * @package Requests\Utilities
 */

namespace WpOrg\Requests\Utility;

use ArrayAccess;
use CurlHandle;
use Traversable;

/**
 * Input validation utilities.
 *
 * @package Requests\Utilities
 */
final class InputValidator {

	/**
	 * Verify that a received input parameter is of type string or is "stringable".
	 *
	 * @param mixed $input Input parameter to verify.
	 *
	 * @return bool
	 */
	public static function is_string_or_stringable($input) {
		return is_string($input) || self::is_stringable_object($input);
	}

	/**
	 * Verify whether a received input parameter is usable as an integer array key.
	 *
	 * @param mixed $input Input parameter to verify.
	 *
	 * @return bool
	 */
	public static function is_numeric_array_key($input) {
		if (is_int($input)) {
			return true;
		}

		if (!is_string($input)) {
			return false;
		}

		return (bool) preg_match('`^-?[0-9]+$`', $input);
	}

	/**
	 * Verify whether a received input parameter is "stringable".
	 *
	 * @param mixed $input Input parameter to verify.
	 *
	 * @return bool
	 */
	public static function is_stringable_object($input) {
		return is_object($input) && method_exists($input, '__toString');
	}

	/**
	 * Verify whether a received input parameter is _accessible as if it were an array_.
	 *
	 * @param mixed $input Input parameter to verify.
	 *
	 * @return bool
	 */
	public static function has_array_access($input) {
		return is_array($input) || $input instanceof ArrayAccess;
	}

	/**
	 * Verify whether a received input parameter is "iterable".
	 *
	 * @internal The PHP native `is_iterable()` function was only introduced in PHP 7.1
	 * and this library still supports PHP 5.6.
	 *
	 * @param mixed $input Input parameter to verify.
	 *
	 * @return bool
	 */
	public static function is_iterable($input) {
		return is_array($input) || $input instanceof Traversable;
	}

	/**
	 * Verify whether a received input parameter is a Curl handle.
	 *
	 * The PHP Curl extension worked with resources prior to PHP 8.0 and with
	 * an instance of the `CurlHandle` class since PHP 8.0.
	 * {@link https://www.php.net/manual/en/migration80.incompatible.php#migration80.incompatible.resource2object}
	 *
	 * @param mixed $input Input parameter to verify.
	 *
	 * @return bool
	 */
	public static function is_curl_handle($input) {
		if (is_resource($input)) {
			return get_resource_type($input) === 'curl';
		}

		if (is_object($input)) {
			return $input instanceof CurlHandle;
		}

		return false;
	}
}
PK     Ӯ+]5L	  	  )  src/Utility/CaseInsensitiveDictionary.phpnu         <?php
/**
 * Case-insensitive dictionary, suitable for HTTP headers
 *
 * @package Requests\Utilities
 */

namespace WpOrg\Requests\Utility;

use ArrayAccess;
use ArrayIterator;
use IteratorAggregate;
use ReturnTypeWillChange;
use WpOrg\Requests\Exception;

/**
 * Case-insensitive dictionary, suitable for HTTP headers
 *
 * @package Requests\Utilities
 */
class CaseInsensitiveDictionary implements ArrayAccess, IteratorAggregate {
	/**
	 * Actual item data
	 *
	 * @var array
	 */
	protected $data = [];

	/**
	 * Creates a case insensitive dictionary.
	 *
	 * @param array $data Dictionary/map to convert to case-insensitive
	 */
	public function __construct(array $data = []) {
		foreach ($data as $offset => $value) {
			$this->offsetSet($offset, $value);
		}
	}

	/**
	 * Check if the given item exists
	 *
	 * @param string $offset Item key
	 * @return boolean Does the item exist?
	 */
	#[ReturnTypeWillChange]
	public function offsetExists($offset) {
		if (is_string($offset)) {
			$offset = strtolower($offset);
		}

		return isset($this->data[$offset]);
	}

	/**
	 * Get the value for the item
	 *
	 * @param string $offset Item key
	 * @return string|null Item value (null if the item key doesn't exist)
	 */
	#[ReturnTypeWillChange]
	public function offsetGet($offset) {
		if (is_string($offset)) {
			$offset = strtolower($offset);
		}

		if (!isset($this->data[$offset])) {
			return null;
		}

		return $this->data[$offset];
	}

	/**
	 * Set the given item
	 *
	 * @param string $offset Item name
	 * @param string $value Item value
	 *
	 * @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`)
	 */
	#[ReturnTypeWillChange]
	public function offsetSet($offset, $value) {
		if ($offset === null) {
			throw new Exception('Object is a dictionary, not a list', 'invalidset');
		}

		if (is_string($offset)) {
			$offset = strtolower($offset);
		}

		$this->data[$offset] = $value;
	}

	/**
	 * Unset the given header
	 *
	 * @param string $offset The key for the item to unset.
	 */
	#[ReturnTypeWillChange]
	public function offsetUnset($offset) {
		if (is_string($offset)) {
			$offset = strtolower($offset);
		}

		unset($this->data[$offset]);
	}

	/**
	 * Get an iterator for the data
	 *
	 * @return \ArrayIterator
	 */
	#[ReturnTypeWillChange]
	public function getIterator() {
		return new ArrayIterator($this->data);
	}

	/**
	 * Get the headers as an array
	 *
	 * @return array Header data
	 */
	public function getAll() {
		return $this->data;
	}
}
PK     Ӯ+]m  m     src/Utility/FilteredIterator.phpnu         <?php
/**
 * Iterator for arrays requiring filtered values
 *
 * @package Requests\Utilities
 */

namespace WpOrg\Requests\Utility;

use ArrayIterator;
use ReturnTypeWillChange;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Utility\InputValidator;

/**
 * Iterator for arrays requiring filtered values
 *
 * @package Requests\Utilities
 */
final class FilteredIterator extends ArrayIterator {
	/**
	 * Callback to run as a filter
	 *
	 * @var callable
	 */
	private $callback;

	/**
	 * Create a new iterator
	 *
	 * @param array    $data     The array or object to be iterated on.
	 * @param callable $callback Callback to be called on each value
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data argument is not iterable.
	 */
	public function __construct($data, $callback) {
		if (InputValidator::is_iterable($data) === false) {
			throw InvalidArgument::create(1, '$data', 'iterable', gettype($data));
		}

		parent::__construct($data);

		if (is_callable($callback)) {
			$this->callback = $callback;
		}
	}

	/**
	 * Prevent unserialization of the object for security reasons.
	 *
	 * @phpcs:disable PHPCompatibility.FunctionNameRestrictions.NewMagicMethods.__unserializeFound
	 *
	 * @param array $data Restored array of data originally serialized.
	 *
	 * @return void
	 */
	#[ReturnTypeWillChange]
	public function __unserialize($data) {}
	// phpcs:enable

	/**
	 * Perform reinitialization tasks.
	 *
	 * Prevents a callback from being injected during unserialization of an object.
	 *
	 * @return void
	 */
	public function __wakeup() {
		unset($this->callback);
	}

	/**
	 * Get the current item's value after filtering
	 *
	 * @return string
	 */
	#[ReturnTypeWillChange]
	public function current() {
		$value = parent::current();

		if (is_callable($this->callback)) {
			$value = call_user_func($this->callback, $value);
		}

		return $value;
	}

	/**
	 * Prevent creating a PHP value from a stored representation of the object for security reasons.
	 *
	 * @param string $data The serialized string.
	 *
	 * @return void
	 */
	#[ReturnTypeWillChange]
	public function unserialize($data) {}
}
PK     Ӯ+]w	׺1  1    src/Ssl.phpnu         <?php
/**
 * SSL utilities for Requests
 *
 * @package Requests\Utilities
 */

namespace WpOrg\Requests;

use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Utility\InputValidator;

/**
 * SSL utilities for Requests
 *
 * Collection of utilities for working with and verifying SSL certificates.
 *
 * @package Requests\Utilities
 */
final class Ssl {
	/**
	 * Verify the certificate against common name and subject alternative names
	 *
	 * Unfortunately, PHP doesn't check the certificate against the alternative
	 * names, leading things like 'https://www.github.com/' to be invalid.
	 *
	 * @link https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
	 *
	 * @param string|Stringable $host Host name to verify against
	 * @param array $cert Certificate data from openssl_x509_parse()
	 * @return bool
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $host argument is not a string or a stringable object.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $cert argument is not an array or array accessible.
	 */
	public static function verify_certificate($host, $cert) {
		if (InputValidator::is_string_or_stringable($host) === false) {
			throw InvalidArgument::create(1, '$host', 'string|Stringable', gettype($host));
		}

		if (InputValidator::has_array_access($cert) === false) {
			throw InvalidArgument::create(2, '$cert', 'array|ArrayAccess', gettype($cert));
		}

		$has_dns_alt = false;

		// Check the subjectAltName
		if (!empty($cert['extensions']['subjectAltName'])) {
			$altnames = explode(',', $cert['extensions']['subjectAltName']);
			foreach ($altnames as $altname) {
				$altname = trim($altname);
				if (strpos($altname, 'DNS:') !== 0) {
					continue;
				}

				$has_dns_alt = true;

				// Strip the 'DNS:' prefix and trim whitespace
				$altname = trim(substr($altname, 4));

				// Check for a match
				if (self::match_domain($host, $altname) === true) {
					return true;
				}
			}

			if ($has_dns_alt === true) {
				return false;
			}
		}

		// Fall back to checking the common name if we didn't get any dNSName
		// alt names, as per RFC2818
		if (!empty($cert['subject']['CN'])) {
			// Check for a match
			return (self::match_domain($host, $cert['subject']['CN']) === true);
		}

		return false;
	}

	/**
	 * Verify that a reference name is valid
	 *
	 * Verifies a dNSName for HTTPS usage, (almost) as per Firefox's rules:
	 * - Wildcards can only occur in a name with more than 3 components
	 * - Wildcards can only occur as the last character in the first
	 *   component
	 * - Wildcards may be preceded by additional characters
	 *
	 * We modify these rules to be a bit stricter and only allow the wildcard
	 * character to be the full first component; that is, with the exclusion of
	 * the third rule.
	 *
	 * @param string|Stringable $reference Reference dNSName
	 * @return boolean Is the name valid?
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object.
	 */
	public static function verify_reference_name($reference) {
		if (InputValidator::is_string_or_stringable($reference) === false) {
			throw InvalidArgument::create(1, '$reference', 'string|Stringable', gettype($reference));
		}

		if ($reference === '') {
			return false;
		}

		if (preg_match('`\s`', $reference) > 0) {
			// Whitespace detected. This can never be a dNSName.
			return false;
		}

		$parts = explode('.', $reference);
		if ($parts !== array_filter($parts)) {
			// DNSName cannot contain two dots next to each other.
			return false;
		}

		// Check the first part of the name
		$first = array_shift($parts);

		if (strpos($first, '*') !== false) {
			// Check that the wildcard is the full part
			if ($first !== '*') {
				return false;
			}

			// Check that we have at least 3 components (including first)
			if (count($parts) < 2) {
				return false;
			}
		}

		// Check the remaining parts
		foreach ($parts as $part) {
			if (strpos($part, '*') !== false) {
				return false;
			}
		}

		// Nothing found, verified!
		return true;
	}

	/**
	 * Match a hostname against a dNSName reference
	 *
	 * @param string|Stringable $host Requested host
	 * @param string|Stringable $reference dNSName to match against
	 * @return boolean Does the domain match?
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When either of the passed arguments is not a string or a stringable object.
	 */
	public static function match_domain($host, $reference) {
		if (InputValidator::is_string_or_stringable($host) === false) {
			throw InvalidArgument::create(1, '$host', 'string|Stringable', gettype($host));
		}

		// Check if the reference is blocklisted first
		if (self::verify_reference_name($reference) !== true) {
			return false;
		}

		// Check for a direct match
		if ((string) $host === (string) $reference) {
			return true;
		}

		// Calculate the valid wildcard match if the host is not an IP address
		// Also validates that the host has 3 parts or more, as per Firefox's ruleset,
		// as a wildcard reference is only allowed with 3 parts or more, so the
		// comparison will never match if host doesn't contain 3 parts or more as well.
		if (ip2long($host) === false) {
			$parts    = explode('.', $host);
			$parts[0] = '*';
			$wildcard = implode('.', $parts);
			if ($wildcard === (string) $reference) {
				return true;
			}
		}

		return false;
	}
}
PK     Ӯ+]g^y  y    src/Proxy/Http.phpnu         <?php
/**
 * HTTP Proxy connection interface
 *
 * @package Requests\Proxy
 * @since   1.6
 */

namespace WpOrg\Requests\Proxy;

use WpOrg\Requests\Exception\ArgumentCount;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Hooks;
use WpOrg\Requests\Proxy;

/**
 * HTTP Proxy connection interface
 *
 * Provides a handler for connection via an HTTP proxy
 *
 * @package Requests\Proxy
 * @since   1.6
 */
final class Http implements Proxy {
	/**
	 * Proxy host and port
	 *
	 * Notation: "host:port" (eg 127.0.0.1:8080 or someproxy.com:3128)
	 *
	 * @var string
	 */
	public $proxy;

	/**
	 * Username
	 *
	 * @var string
	 */
	public $user;

	/**
	 * Password
	 *
	 * @var string
	 */
	public $pass;

	/**
	 * Do we need to authenticate? (ie username & password have been provided)
	 *
	 * @var boolean
	 */
	public $use_authentication;

	/**
	 * Constructor
	 *
	 * @since 1.6
	 *
	 * @param array|string|null $args Proxy as a string or an array of proxy, user and password.
	 *                                When passed as an array, must have exactly one (proxy)
	 *                                or three elements (proxy, user, password).
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not an array, a string or null.
	 * @throws \WpOrg\Requests\Exception\ArgumentCount On incorrect number of arguments (`proxyhttpbadargs`)
	 */
	public function __construct($args = null) {
		if (is_string($args)) {
			$this->proxy = $args;
		} elseif (is_array($args)) {
			if (count($args) === 1) {
				list($this->proxy) = $args;
			} elseif (count($args) === 3) {
				list($this->proxy, $this->user, $this->pass) = $args;
				$this->use_authentication                    = true;
			} else {
				throw ArgumentCount::create(
					'an array with exactly one element or exactly three elements',
					count($args),
					'proxyhttpbadargs'
				);
			}
		} elseif ($args !== null) {
			throw InvalidArgument::create(1, '$args', 'array|string|null', gettype($args));
		}
	}

	/**
	 * Register the necessary callbacks
	 *
	 * @since 1.6
	 * @see \WpOrg\Requests\Proxy\Http::curl_before_send()
	 * @see \WpOrg\Requests\Proxy\Http::fsockopen_remote_socket()
	 * @see \WpOrg\Requests\Proxy\Http::fsockopen_remote_host_path()
	 * @see \WpOrg\Requests\Proxy\Http::fsockopen_header()
	 * @param \WpOrg\Requests\Hooks $hooks Hook system
	 */
	public function register(Hooks $hooks) {
		$hooks->register('curl.before_send', [$this, 'curl_before_send']);

		$hooks->register('fsockopen.remote_socket', [$this, 'fsockopen_remote_socket']);
		$hooks->register('fsockopen.remote_host_path', [$this, 'fsockopen_remote_host_path']);
		if ($this->use_authentication) {
			$hooks->register('fsockopen.after_headers', [$this, 'fsockopen_header']);
		}
	}

	/**
	 * Set cURL parameters before the data is sent
	 *
	 * @since 1.6
	 * @param resource|\CurlHandle $handle cURL handle
	 */
	public function curl_before_send(&$handle) {
		curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
		curl_setopt($handle, CURLOPT_PROXY, $this->proxy);

		if ($this->use_authentication) {
			curl_setopt($handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
			curl_setopt($handle, CURLOPT_PROXYUSERPWD, $this->get_auth_string());
		}
	}

	/**
	 * Alter remote socket information before opening socket connection
	 *
	 * @since 1.6
	 * @param string $remote_socket Socket connection string
	 */
	public function fsockopen_remote_socket(&$remote_socket) {
		$remote_socket = $this->proxy;
	}

	/**
	 * Alter remote path before getting stream data
	 *
	 * @since 1.6
	 * @param string $path Path to send in HTTP request string ("GET ...")
	 * @param string $url Full URL we're requesting
	 */
	public function fsockopen_remote_host_path(&$path, $url) {
		$path = $url;
	}

	/**
	 * Add extra headers to the request before sending
	 *
	 * @since 1.6
	 * @param string $out HTTP header string
	 */
	public function fsockopen_header(&$out) {
		$out .= sprintf("Proxy-Authorization: Basic %s\r\n", base64_encode($this->get_auth_string()));
	}

	/**
	 * Get the authentication string (user:pass)
	 *
	 * @since 1.6
	 * @return string
	 */
	public function get_auth_string() {
		return $this->user . ':' . $this->pass;
	}
}
PK     Ӯ+]q1      src/Exception/ArgumentCount.phpnu         <?php

namespace WpOrg\Requests\Exception;

use WpOrg\Requests\Exception;

/**
 * Exception for when an incorrect number of arguments are passed to a method.
 *
 * Typically, this exception is used when all arguments for a method are optional,
 * but certain arguments need to be passed together, i.e. a method which can be called
 * with no arguments or with two arguments, but not with one argument.
 *
 * Along the same lines, this exception is also used if a method expects an array
 * with a certain number of elements and the provided number of elements does not comply.
 *
 * @package Requests\Exceptions
 * @since   2.0.0
 */
final class ArgumentCount extends Exception {

	/**
	 * Create a new argument count exception with a standardized text.
	 *
	 * @param string $expected The argument count expected as a phrase.
	 *                         For example: `at least 2 arguments` or `exactly 1 argument`.
	 * @param int    $received The actual argument count received.
	 * @param string $type     Exception type.
	 *
	 * @return \WpOrg\Requests\Exception\ArgumentCount
	 */
	public static function create($expected, $received, $type) {
		// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace
		$stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);

		return new self(
			sprintf(
				'%s::%s() expects %s, %d given',
				$stack[1]['class'],
				$stack[1]['function'],
				$expected,
				$received
			),
			$type
		);
	}
}
PK     Ӯ+]iA        src/Exception/Transport.phpnu         <?php
/**
 * Transport Exception
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception;

use WpOrg\Requests\Exception;

/**
 * Transport Exception
 *
 * @package Requests\Exceptions
 */
class Transport extends Exception {}
PK     Ӯ+]R  R  !  src/Exception/InvalidArgument.phpnu         <?php

namespace WpOrg\Requests\Exception;

use InvalidArgumentException;

/**
 * Exception for an invalid argument passed.
 *
 * @package Requests\Exceptions
 * @since   2.0.0
 */
final class InvalidArgument extends InvalidArgumentException {

	/**
	 * Create a new invalid argument exception with a standardized text.
	 *
	 * @param int    $position The argument position in the function signature. 1-based.
	 * @param string $name     The argument name in the function signature.
	 * @param string $expected The argument type expected as a string.
	 * @param string $received The actual argument type received.
	 *
	 * @return \WpOrg\Requests\Exception\InvalidArgument
	 */
	public static function create($position, $name, $expected, $received) {
		// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace
		$stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);

		return new self(
			sprintf(
				'%s::%s(): Argument #%d (%s) must be of type %s, %s given',
				$stack[1]['class'],
				$stack[1]['function'],
				$position,
				$name,
				$expected,
				$received
			)
		);
	}
}
PK     Ӯ+]        src/Exception/Http/Status500.phpnu         <?php
/**
 * Exception for 500 Internal Server Error responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 500 Internal Server Error responses
 *
 * @package Requests\Exceptions
 */
final class Status500 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 500;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Internal Server Error';
}
PK     Ӯ+]4,  ,     src/Exception/Http/Status418.phpnu         <?php
/**
 * Exception for 418 I'm A Teapot responses
 *
 * @link https://tools.ietf.org/html/rfc2324
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 418 I'm A Teapot responses
 *
 * @link https://tools.ietf.org/html/rfc2324
 *
 * @package Requests\Exceptions
 */
final class Status418 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 418;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = "I'm A Teapot";
}
PK     Ӯ+][F       src/Exception/Http/Status411.phpnu         <?php
/**
 * Exception for 411 Length Required responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 411 Length Required responses
 *
 * @package Requests\Exceptions
 */
final class Status411 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 411;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Length Required';
}
PK     Ӯ+]       src/Exception/Http/Status416.phpnu         <?php
/**
 * Exception for 416 Requested Range Not Satisfiable responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 416 Requested Range Not Satisfiable responses
 *
 * @package Requests\Exceptions
 */
final class Status416 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 416;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Requested Range Not Satisfiable';
}
PK     Ӯ+]]       src/Exception/Http/Status407.phpnu         <?php
/**
 * Exception for 407 Proxy Authentication Required responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 407 Proxy Authentication Required responses
 *
 * @package Requests\Exceptions
 */
final class Status407 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 407;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Proxy Authentication Required';
}
PK     Ӯ+]ǿH7       src/Exception/Http/Status400.phpnu         <?php
/**
 * Exception for 400 Bad Request responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 400 Bad Request responses
 *
 * @package Requests\Exceptions
 */
final class Status400 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 400;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Bad Request';
}
PK     Ӯ+]       src/Exception/Http/Status304.phpnu         <?php
/**
 * Exception for 304 Not Modified responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 304 Not Modified responses
 *
 * @package Requests\Exceptions
 */
final class Status304 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 304;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Not Modified';
}
PK     Ӯ+]       src/Exception/Http/Status409.phpnu         <?php
/**
 * Exception for 409 Conflict responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 409 Conflict responses
 *
 * @package Requests\Exceptions
 */
final class Status409 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 409;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Conflict';
}
PK     Ӯ+]e  e     src/Exception/Http/Status511.phpnu         <?php
/**
 * Exception for 511 Network Authentication Required responses
 *
 * @link https://tools.ietf.org/html/rfc6585
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 511 Network Authentication Required responses
 *
 * @link https://tools.ietf.org/html/rfc6585
 *
 * @package Requests\Exceptions
 */
final class Status511 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 511;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Network Authentication Required';
}
PK     Ӯ+]f+       src/Exception/Http/Status417.phpnu         <?php
/**
 * Exception for 417 Expectation Failed responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 417 Expectation Failed responses
 *
 * @package Requests\Exceptions
 */
final class Status417 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 417;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Expectation Failed';
}
PK     Ӯ+]η.p       src/Exception/Http/Status410.phpnu         <?php
/**
 * Exception for 410 Gone responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 410 Gone responses
 *
 * @package Requests\Exceptions
 */
final class Status410 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 410;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Gone';
}
PK     Ӯ+]*    $  src/Exception/Http/StatusUnknown.phpnu         <?php
/**
 * Exception for unknown status responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Response;

/**
 * Exception for unknown status responses
 *
 * @package Requests\Exceptions
 */
final class StatusUnknown extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer|bool Code if available, false if an error occurred
	 */
	protected $code = 0;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Unknown';

	/**
	 * Create a new exception
	 *
	 * If `$data` is an instance of {@see \WpOrg\Requests\Response}, uses the status
	 * code from it. Otherwise, sets as 0
	 *
	 * @param string|null $reason Reason phrase
	 * @param mixed $data Associated data
	 */
	public function __construct($reason = null, $data = null) {
		if ($data instanceof Response) {
			$this->code = (int) $data->status_code;
		}

		parent::__construct($reason, $data);
	}
}
PK     Ӯ+]mk       src/Exception/Http/Status501.phpnu         <?php
/**
 * Exception for 501 Not Implemented responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 501 Not Implemented responses
 *
 * @package Requests\Exceptions
 */
final class Status501 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 501;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Not Implemented';
}
PK     Ӯ+]kT       src/Exception/Http/Status408.phpnu         <?php
/**
 * Exception for 408 Request Timeout responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 408 Request Timeout responses
 *
 * @package Requests\Exceptions
 */
final class Status408 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 408;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Request Timeout';
}
PK     Ӯ+]       src/Exception/Http/Status305.phpnu         <?php
/**
 * Exception for 305 Use Proxy responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 305 Use Proxy responses
 *
 * @package Requests\Exceptions
 */
final class Status305 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 305;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Use Proxy';
}
PK     Ӯ+]        src/Exception/Http/Status401.phpnu         <?php
/**
 * Exception for 401 Unauthorized responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 401 Unauthorized responses
 *
 * @package Requests\Exceptions
 */
final class Status401 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 401;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Unauthorized';
}
PK     Ӯ+]Sb       src/Exception/Http/Status406.phpnu         <?php
/**
 * Exception for 406 Not Acceptable responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 406 Not Acceptable responses
 *
 * @package Requests\Exceptions
 */
final class Status406 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 406;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Not Acceptable';
}
PK     Ӯ+]h$a       src/Exception/Http/Status306.phpnu         <?php
/**
 * Exception for 306 Switch Proxy responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 306 Switch Proxy responses
 *
 * @package Requests\Exceptions
 */
final class Status306 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 306;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Switch Proxy';
}
PK     Ӯ+]wא       src/Exception/Http/Status405.phpnu         <?php
/**
 * Exception for 405 Method Not Allowed responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 405 Method Not Allowed responses
 *
 * @package Requests\Exceptions
 */
final class Status405 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 405;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Method Not Allowed';
}
PK     Ӯ+]{       src/Exception/Http/Status402.phpnu         <?php
/**
 * Exception for 402 Payment Required responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 402 Payment Required responses
 *
 * @package Requests\Exceptions
 */
final class Status402 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 402;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Payment Required';
}
PK     Ӯ+]hm       src/Exception/Http/Status413.phpnu         <?php
/**
 * Exception for 413 Request Entity Too Large responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 413 Request Entity Too Large responses
 *
 * @package Requests\Exceptions
 */
final class Status413 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 413;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Request Entity Too Large';
}
PK     Ӯ+]2d       src/Exception/Http/Status414.phpnu         <?php
/**
 * Exception for 414 Request-URI Too Large responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 414 Request-URI Too Large responses
 *
 * @package Requests\Exceptions
 */
final class Status414 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 414;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Request-URI Too Large';
}
PK     Ӯ+]^:G  G     src/Exception/Http/Status428.phpnu         <?php
/**
 * Exception for 428 Precondition Required responses
 *
 * @link https://tools.ietf.org/html/rfc6585
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 428 Precondition Required responses
 *
 * @link https://tools.ietf.org/html/rfc6585
 *
 * @package Requests\Exceptions
 */
final class Status428 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 428;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Precondition Required';
}
PK     Ӯ+]m       src/Exception/Http/Status505.phpnu         <?php
/**
 * Exception for 505 HTTP Version Not Supported responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 505 HTTP Version Not Supported responses
 *
 * @package Requests\Exceptions
 */
final class Status505 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 505;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'HTTP Version Not Supported';
}
PK     Ӯ+]       src/Exception/Http/Status502.phpnu         <?php
/**
 * Exception for 502 Bad Gateway responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 502 Bad Gateway responses
 *
 * @package Requests\Exceptions
 */
final class Status502 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 502;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Bad Gateway';
}
PK     Ӯ+]       src/Exception/Http/Status403.phpnu         <?php
/**
 * Exception for 403 Forbidden responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 403 Forbidden responses
 *
 * @package Requests\Exceptions
 */
final class Status403 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 403;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Forbidden';
}
PK     Ӯ+]y       src/Exception/Http/Status404.phpnu         <?php
/**
 * Exception for 404 Not Found responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 404 Not Found responses
 *
 * @package Requests\Exceptions
 */
final class Status404 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 404;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Not Found';
}
PK     Ӯ+]&Xe  e     src/Exception/Http/Status431.phpnu         <?php
/**
 * Exception for 431 Request Header Fields Too Large responses
 *
 * @link https://tools.ietf.org/html/rfc6585
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 431 Request Header Fields Too Large responses
 *
 * @link https://tools.ietf.org/html/rfc6585
 *
 * @package Requests\Exceptions
 */
final class Status431 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 431;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Request Header Fields Too Large';
}
PK     Ӯ+]w;       src/Exception/Http/Status503.phpnu         <?php
/**
 * Exception for 503 Service Unavailable responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 503 Service Unavailable responses
 *
 * @package Requests\Exceptions
 */
final class Status503 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 503;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Service Unavailable';
}
PK     Ӯ+]kf       src/Exception/Http/Status504.phpnu         <?php
/**
 * Exception for 504 Gateway Timeout responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 504 Gateway Timeout responses
 *
 * @package Requests\Exceptions
 */
final class Status504 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 504;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Gateway Timeout';
}
PK     Ӯ+](s  s     src/Exception/Http/Status429.phpnu         <?php
/**
 * Exception for 429 Too Many Requests responses
 *
 * @link https://tools.ietf.org/html/draft-nottingham-http-new-status-04
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 429 Too Many Requests responses
 *
 * @link https://tools.ietf.org/html/draft-nottingham-http-new-status-04
 *
 * @package Requests\Exceptions
 */
final class Status429 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 429;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Too Many Requests';
}
PK     Ӯ+]P       src/Exception/Http/Status415.phpnu         <?php
/**
 * Exception for 415 Unsupported Media Type responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 415 Unsupported Media Type responses
 *
 * @package Requests\Exceptions
 */
final class Status415 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 415;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Unsupported Media Type';
}
PK     Ӯ+]`       src/Exception/Http/Status412.phpnu         <?php
/**
 * Exception for 412 Precondition Failed responses
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Http;

use WpOrg\Requests\Exception\Http;

/**
 * Exception for 412 Precondition Failed responses
 *
 * @package Requests\Exceptions
 */
final class Status412 extends Http {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 412;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Precondition Failed';
}
PK     Ӯ+]*u  u     src/Exception/Transport/Curl.phpnu         <?php
/**
 * CURL Transport Exception.
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception\Transport;

use WpOrg\Requests\Exception\Transport;

/**
 * CURL Transport Exception.
 *
 * @package Requests\Exceptions
 */
final class Curl extends Transport {

	const EASY  = 'cURLEasy';
	const MULTI = 'cURLMulti';
	const SHARE = 'cURLShare';

	/**
	 * cURL error code
	 *
	 * @var integer
	 */
	protected $code = -1;

	/**
	 * Which type of cURL error
	 *
	 * EASY|MULTI|SHARE
	 *
	 * @var string
	 */
	protected $type = 'Unknown';

	/**
	 * Clear text error message
	 *
	 * @var string
	 */
	protected $reason = 'Unknown';

	/**
	 * Create a new exception.
	 *
	 * @param string $message Exception message.
	 * @param string $type    Exception type.
	 * @param mixed  $data    Associated data, if applicable.
	 * @param int    $code    Exception numerical code, if applicable.
	 */
	public function __construct($message, $type, $data = null, $code = 0) {
		if ($type !== null) {
			$this->type = $type;
		}

		if ($code !== null) {
			$this->code = (int) $code;
		}

		if ($message !== null) {
			$this->reason = $message;
		}

		$message = sprintf('%d %s', $this->code, $this->reason);
		parent::__construct($message, $this->type, $data, $this->code);
	}

	/**
	 * Get the error message.
	 *
	 * @return string
	 */
	public function getReason() {
		return $this->reason;
	}

}
PK     Ӯ+]&      src/Exception/Http.phpnu         <?php
/**
 * Exception based on HTTP response
 *
 * @package Requests\Exceptions
 */

namespace WpOrg\Requests\Exception;

use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\Http\StatusUnknown;

/**
 * Exception based on HTTP response
 *
 * @package Requests\Exceptions
 */
class Http extends Exception {
	/**
	 * HTTP status code
	 *
	 * @var integer
	 */
	protected $code = 0;

	/**
	 * Reason phrase
	 *
	 * @var string
	 */
	protected $reason = 'Unknown';

	/**
	 * Create a new exception
	 *
	 * There is no mechanism to pass in the status code, as this is set by the
	 * subclass used. Reason phrases can vary, however.
	 *
	 * @param string|null $reason Reason phrase
	 * @param mixed $data Associated data
	 */
	public function __construct($reason = null, $data = null) {
		if ($reason !== null) {
			$this->reason = $reason;
		}

		$message = sprintf('%d %s', $this->code, $this->reason);
		parent::__construct($message, 'httpresponse', $data, $this->code);
	}

	/**
	 * Get the status message.
	 *
	 * @return string
	 */
	public function getReason() {
		return $this->reason;
	}

	/**
	 * Get the correct exception class for a given error code
	 *
	 * @param int|bool $code HTTP status code, or false if unavailable
	 * @return string Exception class name to use
	 */
	public static function get_class($code) {
		if (!$code) {
			return StatusUnknown::class;
		}

		$class = sprintf('\WpOrg\Requests\Exception\Http\Status%d', $code);
		if (class_exists($class)) {
			return $class;
		}

		return StatusUnknown::class;
	}
}
PK     Ӯ+]ޣ@      src/Capability.phpnu         <?php
/**
 * Capability interface declaring the known capabilities.
 *
 * @package Requests\Utilities
 */

namespace WpOrg\Requests;

/**
 * Capability interface declaring the known capabilities.
 *
 * This is used as the authoritative source for which capabilities can be queried.
 *
 * @package Requests\Utilities
 */
interface Capability {

	/**
	 * Support for SSL.
	 *
	 * @var string
	 */
	const SSL = 'ssl';

	/**
	 * Collection of all capabilities supported in Requests.
	 *
	 * Note: this does not automatically mean that the capability will be supported for your chosen transport!
	 *
	 * @var string[]
	 */
	const ALL = [
		self::SSL,
	];
}
PK     Ӯ+]/yQ#  #    src/Session.phpnu         <?php
/**
 * Session handler for persistent requests and default parameters
 *
 * @package Requests\SessionHandler
 */

namespace WpOrg\Requests;

use WpOrg\Requests\Cookie\Jar;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Iri;
use WpOrg\Requests\Requests;
use WpOrg\Requests\Utility\InputValidator;

/**
 * Session handler for persistent requests and default parameters
 *
 * Allows various options to be set as default values, and merges both the
 * options and URL properties together. A base URL can be set for all requests,
 * with all subrequests resolved from this. Base options can be set (including
 * a shared cookie jar), then overridden for individual requests.
 *
 * @package Requests\SessionHandler
 */
class Session {
	/**
	 * Base URL for requests
	 *
	 * URLs will be made absolute using this as the base
	 *
	 * @var string|null
	 */
	public $url = null;

	/**
	 * Base headers for requests
	 *
	 * @var array
	 */
	public $headers = [];

	/**
	 * Base data for requests
	 *
	 * If both the base data and the per-request data are arrays, the data will
	 * be merged before sending the request.
	 *
	 * @var array
	 */
	public $data = [];

	/**
	 * Base options for requests
	 *
	 * The base options are merged with the per-request data for each request.
	 * The only default option is a shared cookie jar between requests.
	 *
	 * Values here can also be set directly via properties on the Session
	 * object, e.g. `$session->useragent = 'X';`
	 *
	 * @var array
	 */
	public $options = [];

	/**
	 * Create a new session
	 *
	 * @param string|Stringable|null $url Base URL for requests
	 * @param array $headers Default headers for requests
	 * @param array $data Default data for requests
	 * @param array $options Default options for requests
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string, Stringable or null.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data argument is not an array.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
	 */
	public function __construct($url = null, $headers = [], $data = [], $options = []) {
		if ($url !== null && InputValidator::is_string_or_stringable($url) === false) {
			throw InvalidArgument::create(1, '$url', 'string|Stringable|null', gettype($url));
		}

		if (is_array($headers) === false) {
			throw InvalidArgument::create(2, '$headers', 'array', gettype($headers));
		}

		if (is_array($data) === false) {
			throw InvalidArgument::create(3, '$data', 'array', gettype($data));
		}

		if (is_array($options) === false) {
			throw InvalidArgument::create(4, '$options', 'array', gettype($options));
		}

		$this->url     = $url;
		$this->headers = $headers;
		$this->data    = $data;
		$this->options = $options;

		if (empty($this->options['cookies'])) {
			$this->options['cookies'] = new Jar();
		}
	}

	/**
	 * Get a property's value
	 *
	 * @param string $name Property name.
	 * @return mixed|null Property value, null if none found
	 */
	public function __get($name) {
		if (isset($this->options[$name])) {
			return $this->options[$name];
		}

		return null;
	}

	/**
	 * Set a property's value
	 *
	 * @param string $name Property name.
	 * @param mixed $value Property value
	 */
	public function __set($name, $value) {
		$this->options[$name] = $value;
	}

	/**
	 * Remove a property's value
	 *
	 * @param string $name Property name.
	 */
	public function __isset($name) {
		return isset($this->options[$name]);
	}

	/**
	 * Remove a property's value
	 *
	 * @param string $name Property name.
	 */
	public function __unset($name) {
		unset($this->options[$name]);
	}

	/**#@+
	 * @see \WpOrg\Requests\Session::request()
	 * @param string $url
	 * @param array $headers
	 * @param array $options
	 * @return \WpOrg\Requests\Response
	 */
	/**
	 * Send a GET request
	 */
	public function get($url, $headers = [], $options = []) {
		return $this->request($url, $headers, null, Requests::GET, $options);
	}

	/**
	 * Send a HEAD request
	 */
	public function head($url, $headers = [], $options = []) {
		return $this->request($url, $headers, null, Requests::HEAD, $options);
	}

	/**
	 * Send a DELETE request
	 */
	public function delete($url, $headers = [], $options = []) {
		return $this->request($url, $headers, null, Requests::DELETE, $options);
	}
	/**#@-*/

	/**#@+
	 * @see \WpOrg\Requests\Session::request()
	 * @param string $url
	 * @param array $headers
	 * @param array $data
	 * @param array $options
	 * @return \WpOrg\Requests\Response
	 */
	/**
	 * Send a POST request
	 */
	public function post($url, $headers = [], $data = [], $options = []) {
		return $this->request($url, $headers, $data, Requests::POST, $options);
	}

	/**
	 * Send a PUT request
	 */
	public function put($url, $headers = [], $data = [], $options = []) {
		return $this->request($url, $headers, $data, Requests::PUT, $options);
	}

	/**
	 * Send a PATCH request
	 *
	 * Note: Unlike {@see \WpOrg\Requests\Session::post()} and {@see \WpOrg\Requests\Session::put()},
	 * `$headers` is required, as the specification recommends that should send an ETag
	 *
	 * @link https://tools.ietf.org/html/rfc5789
	 */
	public function patch($url, $headers, $data = [], $options = []) {
		return $this->request($url, $headers, $data, Requests::PATCH, $options);
	}
	/**#@-*/

	/**
	 * Main interface for HTTP requests
	 *
	 * This method initiates a request and sends it via a transport before
	 * parsing.
	 *
	 * @see \WpOrg\Requests\Requests::request()
	 *
	 * @param string $url URL to request
	 * @param array $headers Extra headers to send with the request
	 * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
	 * @param string $type HTTP request type (use \WpOrg\Requests\Requests constants)
	 * @param array $options Options for the request (see {@see \WpOrg\Requests\Requests::request()})
	 * @return \WpOrg\Requests\Response
	 *
	 * @throws \WpOrg\Requests\Exception On invalid URLs (`nonhttp`)
	 */
	public function request($url, $headers = [], $data = [], $type = Requests::GET, $options = []) {
		$request = $this->merge_request(compact('url', 'headers', 'data', 'options'));

		return Requests::request($request['url'], $request['headers'], $request['data'], $type, $request['options']);
	}

	/**
	 * Send multiple HTTP requests simultaneously
	 *
	 * @see \WpOrg\Requests\Requests::request_multiple()
	 *
	 * @param array $requests Requests data (see {@see \WpOrg\Requests\Requests::request_multiple()})
	 * @param array $options Global and default options (see {@see \WpOrg\Requests\Requests::request()})
	 * @return array Responses (either \WpOrg\Requests\Response or a \WpOrg\Requests\Exception object)
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
	 */
	public function request_multiple($requests, $options = []) {
		if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
			throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
		}

		if (is_array($options) === false) {
			throw InvalidArgument::create(2, '$options', 'array', gettype($options));
		}

		foreach ($requests as $key => $request) {
			$requests[$key] = $this->merge_request($request, false);
		}

		$options = array_merge($this->options, $options);

		// Disallow forcing the type, as that's a per request setting
		unset($options['type']);

		return Requests::request_multiple($requests, $options);
	}

	public function __wakeup() {
		throw new \LogicException( __CLASS__ . ' should never be unserialized' );
	}

	/**
	 * Merge a request's data with the default data
	 *
	 * @param array $request Request data (same form as {@see \WpOrg\Requests\Session::request_multiple()})
	 * @param boolean $merge_options Should we merge options as well?
	 * @return array Request data
	 */
	protected function merge_request($request, $merge_options = true) {
		if ($this->url !== null) {
			$request['url'] = Iri::absolutize($this->url, $request['url']);
			$request['url'] = $request['url']->uri;
		}

		if (empty($request['headers'])) {
			$request['headers'] = [];
		}

		$request['headers'] = array_merge($this->headers, $request['headers']);

		if (empty($request['data'])) {
			if (is_array($this->data)) {
				$request['data'] = $this->data;
			}
		} elseif (is_array($request['data']) && is_array($this->data)) {
			$request['data'] = array_merge($this->data, $request['data']);
		}

		if ($merge_options === true) {
			$request['options'] = array_merge($this->options, $request['options']);

			// Disallow forcing the type, as that's a per request setting
			unset($request['options']['type']);
		}

		return $request;
	}
}
PK     Ӯ+]ח      src/Response.phpnu         <?php
/**
 * HTTP response class
 *
 * Contains a response from \WpOrg\Requests\Requests::request()
 *
 * @package Requests
 */

namespace WpOrg\Requests;

use WpOrg\Requests\Cookie\Jar;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\Http;
use WpOrg\Requests\Response\Headers;

/**
 * HTTP response class
 *
 * Contains a response from \WpOrg\Requests\Requests::request()
 *
 * @package Requests
 */
class Response {

	/**
	 * Response body
	 *
	 * @var string
	 */
	public $body = '';

	/**
	 * Raw HTTP data from the transport
	 *
	 * @var string
	 */
	public $raw = '';

	/**
	 * Headers, as an associative array
	 *
	 * @var \WpOrg\Requests\Response\Headers Array-like object representing headers
	 */
	public $headers = [];

	/**
	 * Status code, false if non-blocking
	 *
	 * @var integer|boolean
	 */
	public $status_code = false;

	/**
	 * Protocol version, false if non-blocking
	 *
	 * @var float|boolean
	 */
	public $protocol_version = false;

	/**
	 * Whether the request succeeded or not
	 *
	 * @var boolean
	 */
	public $success = false;

	/**
	 * Number of redirects the request used
	 *
	 * @var integer
	 */
	public $redirects = 0;

	/**
	 * URL requested
	 *
	 * @var string
	 */
	public $url = '';

	/**
	 * Previous requests (from redirects)
	 *
	 * @var array Array of \WpOrg\Requests\Response objects
	 */
	public $history = [];

	/**
	 * Cookies from the request
	 *
	 * @var \WpOrg\Requests\Cookie\Jar Array-like object representing a cookie jar
	 */
	public $cookies = [];

	/**
	 * Constructor
	 */
	public function __construct() {
		$this->headers = new Headers();
		$this->cookies = new Jar();
	}

	/**
	 * Is the response a redirect?
	 *
	 * @return boolean True if redirect (3xx status), false if not.
	 */
	public function is_redirect() {
		$code = $this->status_code;
		return in_array($code, [300, 301, 302, 303, 307], true) || $code > 307 && $code < 400;
	}

	/**
	 * Throws an exception if the request was not successful
	 *
	 * @param boolean $allow_redirects Set to false to throw on a 3xx as well
	 *
	 * @throws \WpOrg\Requests\Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`)
	 * @throws \WpOrg\Requests\Exception\Http On non-successful status code. Exception class corresponds to "Status" + code (e.g. {@see \WpOrg\Requests\Exception\Http\Status404})
	 */
	public function throw_for_status($allow_redirects = true) {
		if ($this->is_redirect()) {
			if ($allow_redirects !== true) {
				throw new Exception('Redirection not allowed', 'response.no_redirects', $this);
			}
		} elseif (!$this->success) {
			$exception = Http::get_class($this->status_code);
			throw new $exception(null, $this);
		}
	}

	/**
	 * JSON decode the response body.
	 *
	 * The method parameters are the same as those for the PHP native `json_decode()` function.
	 *
	 * @link https://php.net/json-decode
	 *
	 * @param bool|null $associative Optional. When `true`, JSON objects will be returned as associative arrays;
	 *                               When `false`, JSON objects will be returned as objects.
	 *                               When `null`, JSON objects will be returned as associative arrays
	 *                               or objects depending on whether `JSON_OBJECT_AS_ARRAY` is set in the flags.
	 *                               Defaults to `true` (in contrast to the PHP native default of `null`).
	 * @param int       $depth       Optional. Maximum nesting depth of the structure being decoded.
	 *                               Defaults to `512`.
	 * @param int       $options     Optional. Bitmask of JSON_BIGINT_AS_STRING, JSON_INVALID_UTF8_IGNORE,
	 *                               JSON_INVALID_UTF8_SUBSTITUTE, JSON_OBJECT_AS_ARRAY, JSON_THROW_ON_ERROR.
	 *                               Defaults to `0` (no options set).
	 *
	 * @return array
	 *
	 * @throws \WpOrg\Requests\Exception If `$this->body` is not valid json.
	 */
	public function decode_body($associative = true, $depth = 512, $options = 0) {
		$data = json_decode($this->body, $associative, $depth, $options);

		if (json_last_error() !== JSON_ERROR_NONE) {
			$last_error = json_last_error_msg();
			throw new Exception('Unable to parse JSON data: ' . $last_error, 'response.invalid', $this);
		}

		return $data;
	}
}
PK     Ӯ+]Z	  	    src/Auth/Basic.phpnu         <?php
/**
 * Basic Authentication provider
 *
 * @package Requests\Authentication
 */

namespace WpOrg\Requests\Auth;

use WpOrg\Requests\Auth;
use WpOrg\Requests\Exception\ArgumentCount;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Hooks;

/**
 * Basic Authentication provider
 *
 * Provides a handler for Basic HTTP authentication via the Authorization
 * header.
 *
 * @package Requests\Authentication
 */
class Basic implements Auth {
	/**
	 * Username
	 *
	 * @var string
	 */
	public $user;

	/**
	 * Password
	 *
	 * @var string
	 */
	public $pass;

	/**
	 * Constructor
	 *
	 * @since 2.0 Throws an `InvalidArgument` exception.
	 * @since 2.0 Throws an `ArgumentCount` exception instead of the Requests base `Exception.
	 *
	 * @param array|null $args Array of user and password. Must have exactly two elements
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not an array or null.
	 * @throws \WpOrg\Requests\Exception\ArgumentCount   On incorrect number of array elements (`authbasicbadargs`).
	 */
	public function __construct($args = null) {
		if (is_array($args)) {
			if (count($args) !== 2) {
				throw ArgumentCount::create('an array with exactly two elements', count($args), 'authbasicbadargs');
			}

			list($this->user, $this->pass) = $args;
			return;
		}

		if ($args !== null) {
			throw InvalidArgument::create(1, '$args', 'array|null', gettype($args));
		}
	}

	/**
	 * Register the necessary callbacks
	 *
	 * @see \WpOrg\Requests\Auth\Basic::curl_before_send()
	 * @see \WpOrg\Requests\Auth\Basic::fsockopen_header()
	 * @param \WpOrg\Requests\Hooks $hooks Hook system
	 */
	public function register(Hooks $hooks) {
		$hooks->register('curl.before_send', [$this, 'curl_before_send']);
		$hooks->register('fsockopen.after_headers', [$this, 'fsockopen_header']);
	}

	/**
	 * Set cURL parameters before the data is sent
	 *
	 * @param resource|\CurlHandle $handle cURL handle
	 */
	public function curl_before_send(&$handle) {
		curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		curl_setopt($handle, CURLOPT_USERPWD, $this->getAuthString());
	}

	/**
	 * Add extra headers to the request before sending
	 *
	 * @param string $out HTTP header string
	 */
	public function fsockopen_header(&$out) {
		$out .= sprintf("Authorization: Basic %s\r\n", base64_encode($this->getAuthString()));
	}

	/**
	 * Get the authentication string (user:pass)
	 *
	 * @return string
	 */
	public function getAuthString() {
		return $this->user . ':' . $this->pass;
	}
}
PK     Ӯ+]YP>  >    src/Transport/Fsockopen.phpnu         <?php
/**
 * fsockopen HTTP transport
 *
 * @package Requests\Transport
 */

namespace WpOrg\Requests\Transport;

use WpOrg\Requests\Capability;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Port;
use WpOrg\Requests\Requests;
use WpOrg\Requests\Ssl;
use WpOrg\Requests\Transport;
use WpOrg\Requests\Utility\CaseInsensitiveDictionary;
use WpOrg\Requests\Utility\InputValidator;

/**
 * fsockopen HTTP transport
 *
 * @package Requests\Transport
 */
final class Fsockopen implements Transport {
	/**
	 * Second to microsecond conversion
	 *
	 * @var integer
	 */
	const SECOND_IN_MICROSECONDS = 1000000;

	/**
	 * Raw HTTP data
	 *
	 * @var string
	 */
	public $headers = '';

	/**
	 * Stream metadata
	 *
	 * @var array Associative array of properties, see {@link https://www.php.net/stream_get_meta_data}
	 */
	public $info;

	/**
	 * What's the maximum number of bytes we should keep?
	 *
	 * @var int|bool Byte count, or false if no limit.
	 */
	private $max_bytes = false;

	/**
	 * Cache for received connection errors.
	 *
	 * @var string
	 */
	private $connect_error = '';

	/**
	 * Perform a request
	 *
	 * @param string|Stringable $url URL to request
	 * @param array $headers Associative array of request headers
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
	 * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
	 * @return string Raw HTTP result
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data parameter is not an array or string.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
	 * @throws \WpOrg\Requests\Exception       On failure to connect to socket (`fsockopenerror`)
	 * @throws \WpOrg\Requests\Exception       On socket timeout (`timeout`)
	 */
	public function request($url, $headers = [], $data = [], $options = []) {
		if (InputValidator::is_string_or_stringable($url) === false) {
			throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url));
		}

		if (is_array($headers) === false) {
			throw InvalidArgument::create(2, '$headers', 'array', gettype($headers));
		}

		if (!is_array($data) && !is_string($data)) {
			if ($data === null) {
				$data = '';
			} else {
				throw InvalidArgument::create(3, '$data', 'array|string', gettype($data));
			}
		}

		if (is_array($options) === false) {
			throw InvalidArgument::create(4, '$options', 'array', gettype($options));
		}

		$options['hooks']->dispatch('fsockopen.before_request');

		$url_parts = parse_url($url);
		if (empty($url_parts)) {
			throw new Exception('Invalid URL.', 'invalidurl', $url);
		}

		$host                     = $url_parts['host'];
		$context                  = stream_context_create();
		$verifyname               = false;
		$case_insensitive_headers = new CaseInsensitiveDictionary($headers);

		// HTTPS support
		if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
			$remote_socket = 'ssl://' . $host;
			if (!isset($url_parts['port'])) {
				$url_parts['port'] = Port::HTTPS;
			}

			$context_options = [
				'verify_peer'       => true,
				'capture_peer_cert' => true,
			];
			$verifyname      = true;

			// SNI, if enabled (OpenSSL >=0.9.8j)
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.openssl_tlsext_server_nameFound
			if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) {
				$context_options['SNI_enabled'] = true;
				if (isset($options['verifyname']) && $options['verifyname'] === false) {
					$context_options['SNI_enabled'] = false;
				}
			}

			if (isset($options['verify'])) {
				if ($options['verify'] === false) {
					$context_options['verify_peer']      = false;
					$context_options['verify_peer_name'] = false;
					$verifyname                          = false;
				} elseif (is_string($options['verify'])) {
					$context_options['cafile'] = $options['verify'];
				}
			}

			if (isset($options['verifyname']) && $options['verifyname'] === false) {
				$context_options['verify_peer_name'] = false;
				$verifyname                          = false;
			}

			// Handle the PHP 8.4 deprecation (PHP 9.0 removal) of the function signature we use for stream_context_set_option().
			// Ref: https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures#stream_context_set_option
			if (function_exists('stream_context_set_options')) {
				// PHP 8.3+.
				stream_context_set_options($context, ['ssl' => $context_options]);
			} else {
				// PHP < 8.3.
				stream_context_set_option($context, ['ssl' => $context_options]);
			}
		} else {
			$remote_socket = 'tcp://' . $host;
		}

		$this->max_bytes = $options['max_bytes'];

		if (!isset($url_parts['port'])) {
			$url_parts['port'] = Port::HTTP;
		}

		$remote_socket .= ':' . $url_parts['port'];

		// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
		set_error_handler([$this, 'connect_error_handler'], E_WARNING | E_NOTICE);

		$options['hooks']->dispatch('fsockopen.remote_socket', [&$remote_socket]);

		$socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context);

		restore_error_handler();

		if ($verifyname && !$this->verify_certificate_from_context($host, $context)) {
			throw new Exception('SSL certificate did not match the requested domain name', 'ssl.no_match');
		}

		if (!$socket) {
			if ($errno === 0) {
				// Connection issue
				throw new Exception(rtrim($this->connect_error), 'fsockopen.connect_error');
			}

			throw new Exception($errstr, 'fsockopenerror', null, $errno);
		}

		$data_format = $options['data_format'];

		if ($data_format === 'query') {
			$path = self::format_get($url_parts, $data);
			$data = '';
		} else {
			$path = self::format_get($url_parts, []);
		}

		$options['hooks']->dispatch('fsockopen.remote_host_path', [&$path, $url]);

		$request_body = '';
		$out          = sprintf("%s %s HTTP/%.1F\r\n", $options['type'], $path, $options['protocol_version']);

		if ($options['type'] !== Requests::TRACE) {
			if (is_array($data)) {
				$request_body = http_build_query($data, '', '&');
			} else {
				$request_body = $data;
			}

			// Always include Content-length on POST requests to prevent
			// 411 errors from some servers when the body is empty.
			if (!empty($data) || $options['type'] === Requests::POST) {
				if (!isset($case_insensitive_headers['Content-Length'])) {
					$headers['Content-Length'] = strlen($request_body);
				}

				if (!isset($case_insensitive_headers['Content-Type'])) {
					$headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
				}
			}
		}

		if (!isset($case_insensitive_headers['Host'])) {
			$out         .= sprintf('Host: %s', $url_parts['host']);
			$scheme_lower = strtolower($url_parts['scheme']);

			if (($scheme_lower === 'http' && $url_parts['port'] !== Port::HTTP) || ($scheme_lower === 'https' && $url_parts['port'] !== Port::HTTPS)) {
				$out .= ':' . $url_parts['port'];
			}

			$out .= "\r\n";
		}

		if (!isset($case_insensitive_headers['User-Agent'])) {
			$out .= sprintf("User-Agent: %s\r\n", $options['useragent']);
		}

		$accept_encoding = $this->accept_encoding();
		if (!isset($case_insensitive_headers['Accept-Encoding']) && !empty($accept_encoding)) {
			$out .= sprintf("Accept-Encoding: %s\r\n", $accept_encoding);
		}

		$headers = Requests::flatten($headers);

		if (!empty($headers)) {
			$out .= implode("\r\n", $headers) . "\r\n";
		}

		$options['hooks']->dispatch('fsockopen.after_headers', [&$out]);

		if (substr($out, -2) !== "\r\n") {
			$out .= "\r\n";
		}

		if (!isset($case_insensitive_headers['Connection'])) {
			$out .= "Connection: Close\r\n";
		}

		$out .= "\r\n" . $request_body;

		$options['hooks']->dispatch('fsockopen.before_send', [&$out]);

		fwrite($socket, $out);
		$options['hooks']->dispatch('fsockopen.after_send', [$out]);

		if (!$options['blocking']) {
			fclose($socket);
			$fake_headers = '';
			$options['hooks']->dispatch('fsockopen.after_request', [&$fake_headers]);
			return '';
		}

		$timeout_sec = (int) floor($options['timeout']);
		if ($timeout_sec === $options['timeout']) {
			$timeout_msec = 0;
		} else {
			$timeout_msec = self::SECOND_IN_MICROSECONDS * $options['timeout'] % self::SECOND_IN_MICROSECONDS;
		}

		stream_set_timeout($socket, $timeout_sec, $timeout_msec);

		$response   = '';
		$body       = '';
		$headers    = '';
		$this->info = stream_get_meta_data($socket);
		$size       = 0;
		$doingbody  = false;
		$download   = false;
		if ($options['filename']) {
			// phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silenced the PHP native warning in favour of throwing an exception.
			$download = @fopen($options['filename'], 'wb');
			if ($download === false) {
				$error = error_get_last();
				throw new Exception($error['message'], 'fopen');
			}
		}

		while (!feof($socket)) {
			$this->info = stream_get_meta_data($socket);
			if ($this->info['timed_out']) {
				throw new Exception('fsocket timed out', 'timeout');
			}

			$block = fread($socket, Requests::BUFFER_SIZE);
			if (!$doingbody) {
				$response .= $block;
				if (strpos($response, "\r\n\r\n")) {
					list($headers, $block) = explode("\r\n\r\n", $response, 2);
					$doingbody             = true;
				}
			}

			// Are we in body mode now?
			if ($doingbody) {
				$options['hooks']->dispatch('request.progress', [$block, $size, $this->max_bytes]);
				$data_length = strlen($block);
				if ($this->max_bytes) {
					// Have we already hit a limit?
					if ($size === $this->max_bytes) {
						continue;
					}

					if (($size + $data_length) > $this->max_bytes) {
						// Limit the length
						$limited_length = ($this->max_bytes - $size);
						$block          = substr($block, 0, $limited_length);
					}
				}

				$size += strlen($block);
				if ($download) {
					fwrite($download, $block);
				} else {
					$body .= $block;
				}
			}
		}

		$this->headers = $headers;

		if ($download) {
			fclose($download);
		} else {
			$this->headers .= "\r\n\r\n" . $body;
		}

		fclose($socket);

		$options['hooks']->dispatch('fsockopen.after_request', [&$this->headers, &$this->info]);
		return $this->headers;
	}

	/**
	 * Send multiple requests simultaneously
	 *
	 * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see \WpOrg\Requests\Transport::request()}
	 * @param array $options Global options, see {@see \WpOrg\Requests\Requests::response()} for documentation
	 * @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well)
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
	 */
	public function request_multiple($requests, $options) {
		// If you're not requesting, we can't get any responses ¯\_(ツ)_/¯
		if (empty($requests)) {
			return [];
		}

		if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
			throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
		}

		if (is_array($options) === false) {
			throw InvalidArgument::create(2, '$options', 'array', gettype($options));
		}

		$responses = [];
		$class     = get_class($this);
		foreach ($requests as $id => $request) {
			try {
				$handler        = new $class();
				$responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']);

				$request['options']['hooks']->dispatch('transport.internal.parse_response', [&$responses[$id], $request]);
			} catch (Exception $e) {
				$responses[$id] = $e;
			}

			if (!is_string($responses[$id])) {
				$request['options']['hooks']->dispatch('multiple.request.complete', [&$responses[$id], $id]);
			}
		}

		return $responses;
	}

	/**
	 * Retrieve the encodings we can accept
	 *
	 * @return string Accept-Encoding header value
	 */
	private static function accept_encoding() {
		$type = [];
		if (function_exists('gzinflate')) {
			$type[] = 'deflate;q=1.0';
		}

		if (function_exists('gzuncompress')) {
			$type[] = 'compress;q=0.5';
		}

		$type[] = 'gzip;q=0.5';

		return implode(', ', $type);
	}

	/**
	 * Format a URL given GET data
	 *
	 * @param array        $url_parts Array of URL parts as received from {@link https://www.php.net/parse_url}
	 * @param array|object $data Data to build query using, see {@link https://www.php.net/http_build_query}
	 * @return string URL with data
	 */
	private static function format_get($url_parts, $data) {
		if (!empty($data)) {
			if (empty($url_parts['query'])) {
				$url_parts['query'] = '';
			}

			$url_parts['query'] .= '&' . http_build_query($data, '', '&');
			$url_parts['query']  = trim($url_parts['query'], '&');
		}

		if (isset($url_parts['path'])) {
			if (isset($url_parts['query'])) {
				$get = $url_parts['path'] . '?' . $url_parts['query'];
			} else {
				$get = $url_parts['path'];
			}
		} else {
			$get = '/';
		}

		return $get;
	}

	/**
	 * Error handler for stream_socket_client()
	 *
	 * @param int $errno Error number (e.g. E_WARNING)
	 * @param string $errstr Error message
	 */
	public function connect_error_handler($errno, $errstr) {
		// Double-check we can handle it
		if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) {
			// Return false to indicate the default error handler should engage
			return false;
		}

		$this->connect_error .= $errstr . "\n";
		return true;
	}

	/**
	 * Verify the certificate against common name and subject alternative names
	 *
	 * Unfortunately, PHP doesn't check the certificate against the alternative
	 * names, leading things like 'https://www.github.com/' to be invalid.
	 * Instead
	 *
	 * @link https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
	 *
	 * @param string $host Host name to verify against
	 * @param resource $context Stream context
	 * @return bool
	 *
	 * @throws \WpOrg\Requests\Exception On failure to connect via TLS (`fsockopen.ssl.connect_error`)
	 * @throws \WpOrg\Requests\Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
	 */
	public function verify_certificate_from_context($host, $context) {
		$meta = stream_context_get_options($context);

		// If we don't have SSL options, then we couldn't make the connection at
		// all
		if (empty($meta) || empty($meta['ssl']) || empty($meta['ssl']['peer_certificate'])) {
			throw new Exception(rtrim($this->connect_error), 'ssl.connect_error');
		}

		$cert = openssl_x509_parse($meta['ssl']['peer_certificate']);

		return Ssl::verify_certificate($host, $cert);
	}

	/**
	 * Self-test whether the transport can be used.
	 *
	 * The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}.
	 *
	 * @codeCoverageIgnore
	 * @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
	 * @return bool Whether the transport can be used.
	 */
	public static function test($capabilities = []) {
		if (!function_exists('fsockopen')) {
			return false;
		}

		// If needed, check that streams support SSL
		if (isset($capabilities[Capability::SSL]) && $capabilities[Capability::SSL]) {
			if (!extension_loaded('openssl') || !function_exists('openssl_x509_parse')) {
				return false;
			}
		}

		return true;
	}
}
PK     Ӯ+]j;sL  sL    src/Transport/Curl.phpnu         <?php
/**
 * cURL HTTP transport
 *
 * @package Requests\Transport
 */

namespace WpOrg\Requests\Transport;

use RecursiveArrayIterator;
use RecursiveIteratorIterator;
use WpOrg\Requests\Capability;
use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Exception\Transport\Curl as CurlException;
use WpOrg\Requests\Requests;
use WpOrg\Requests\Transport;
use WpOrg\Requests\Utility\InputValidator;

/**
 * cURL HTTP transport
 *
 * @package Requests\Transport
 */
final class Curl implements Transport {
	const CURL_7_10_5 = 0x070A05;
	const CURL_7_16_2 = 0x071002;

	/**
	 * Raw HTTP data
	 *
	 * @var string
	 */
	public $headers = '';

	/**
	 * Raw body data
	 *
	 * @var string
	 */
	public $response_data = '';

	/**
	 * Information on the current request
	 *
	 * @var array cURL information array, see {@link https://www.php.net/curl_getinfo}
	 */
	public $info;

	/**
	 * cURL version number
	 *
	 * @var int
	 */
	public $version;

	/**
	 * cURL handle
	 *
	 * @var resource|\CurlHandle Resource in PHP < 8.0, Instance of CurlHandle in PHP >= 8.0.
	 */
	private $handle;

	/**
	 * Hook dispatcher instance
	 *
	 * @var \WpOrg\Requests\Hooks
	 */
	private $hooks;

	/**
	 * Have we finished the headers yet?
	 *
	 * @var boolean
	 */
	private $done_headers = false;

	/**
	 * If streaming to a file, keep the file pointer
	 *
	 * @var resource
	 */
	private $stream_handle;

	/**
	 * How many bytes are in the response body?
	 *
	 * @var int
	 */
	private $response_bytes;

	/**
	 * What's the maximum number of bytes we should keep?
	 *
	 * @var int|bool Byte count, or false if no limit.
	 */
	private $response_byte_limit;

	/**
	 * Constructor
	 */
	public function __construct() {
		$curl          = curl_version();
		$this->version = $curl['version_number'];
		$this->handle  = curl_init();

		curl_setopt($this->handle, CURLOPT_HEADER, false);
		curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, 1);
		if ($this->version >= self::CURL_7_10_5) {
			curl_setopt($this->handle, CURLOPT_ENCODING, '');
		}

		if (defined('CURLOPT_PROTOCOLS')) {
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_protocolsFound
			curl_setopt($this->handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
		}

		if (defined('CURLOPT_REDIR_PROTOCOLS')) {
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_redir_protocolsFound
			curl_setopt($this->handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
		}
	}

	/**
	 * Destructor
	 */
	public function __destruct() {
		if (is_resource($this->handle)) {
			curl_close($this->handle);
		}
	}

	/**
	 * Perform a request
	 *
	 * @param string|Stringable $url URL to request
	 * @param array $headers Associative array of request headers
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
	 * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
	 * @return string Raw HTTP result
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data parameter is not an array or string.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
	 * @throws \WpOrg\Requests\Exception       On a cURL error (`curlerror`)
	 */
	public function request($url, $headers = [], $data = [], $options = []) {
		if (InputValidator::is_string_or_stringable($url) === false) {
			throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url));
		}

		if (is_array($headers) === false) {
			throw InvalidArgument::create(2, '$headers', 'array', gettype($headers));
		}

		if (!is_array($data) && !is_string($data)) {
			if ($data === null) {
				$data = '';
			} else {
				throw InvalidArgument::create(3, '$data', 'array|string', gettype($data));
			}
		}

		if (is_array($options) === false) {
			throw InvalidArgument::create(4, '$options', 'array', gettype($options));
		}

		$this->hooks = $options['hooks'];

		$this->setup_handle($url, $headers, $data, $options);

		$options['hooks']->dispatch('curl.before_send', [&$this->handle]);

		if ($options['filename'] !== false) {
			// phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silenced the PHP native warning in favour of throwing an exception.
			$this->stream_handle = @fopen($options['filename'], 'wb');
			if ($this->stream_handle === false) {
				$error = error_get_last();
				throw new Exception($error['message'], 'fopen');
			}
		}

		$this->response_data       = '';
		$this->response_bytes      = 0;
		$this->response_byte_limit = false;
		if ($options['max_bytes'] !== false) {
			$this->response_byte_limit = $options['max_bytes'];
		}

		if (isset($options['verify'])) {
			if ($options['verify'] === false) {
				curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
				curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, 0);
			} elseif (is_string($options['verify'])) {
				curl_setopt($this->handle, CURLOPT_CAINFO, $options['verify']);
			}
		}

		if (isset($options['verifyname']) && $options['verifyname'] === false) {
			curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
		}

		curl_exec($this->handle);
		$response = $this->response_data;

		$options['hooks']->dispatch('curl.after_send', []);

		if (curl_errno($this->handle) === CURLE_WRITE_ERROR || curl_errno($this->handle) === CURLE_BAD_CONTENT_ENCODING) {
			// Reset encoding and try again
			curl_setopt($this->handle, CURLOPT_ENCODING, 'none');

			$this->response_data  = '';
			$this->response_bytes = 0;
			curl_exec($this->handle);
			$response = $this->response_data;
		}

		$this->process_response($response, $options);

		// Need to remove the $this reference from the curl handle.
		// Otherwise \WpOrg\Requests\Transport\Curl won't be garbage collected and the curl_close() will never be called.
		curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null);
		curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null);

		return $this->headers;
	}

	/**
	 * Send multiple requests simultaneously
	 *
	 * @param array $requests Request data
	 * @param array $options Global options
	 * @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well)
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
	 */
	public function request_multiple($requests, $options) {
		// If you're not requesting, we can't get any responses ¯\_(ツ)_/¯
		if (empty($requests)) {
			return [];
		}

		if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
			throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
		}

		if (is_array($options) === false) {
			throw InvalidArgument::create(2, '$options', 'array', gettype($options));
		}

		$multihandle = curl_multi_init();
		$subrequests = [];
		$subhandles  = [];

		$class = get_class($this);
		foreach ($requests as $id => $request) {
			$subrequests[$id] = new $class();
			$subhandles[$id]  = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']);
			$request['options']['hooks']->dispatch('curl.before_multi_add', [&$subhandles[$id]]);
			curl_multi_add_handle($multihandle, $subhandles[$id]);
		}

		$completed       = 0;
		$responses       = [];
		$subrequestcount = count($subrequests);

		$request['options']['hooks']->dispatch('curl.before_multi_exec', [&$multihandle]);

		do {
			$active = 0;

			do {
				$status = curl_multi_exec($multihandle, $active);
			} while ($status === CURLM_CALL_MULTI_PERFORM);

			$to_process = [];

			// Read the information as needed
			while ($done = curl_multi_info_read($multihandle)) {
				$key = array_search($done['handle'], $subhandles, true);
				if (!isset($to_process[$key])) {
					$to_process[$key] = $done;
				}
			}

			// Parse the finished requests before we start getting the new ones
			foreach ($to_process as $key => $done) {
				$options = $requests[$key]['options'];
				if ($done['result'] !== CURLE_OK) {
					//get error string for handle.
					$reason          = curl_error($done['handle']);
					$exception       = new CurlException(
						$reason,
						CurlException::EASY,
						$done['handle'],
						$done['result']
					);
					$responses[$key] = $exception;
					$options['hooks']->dispatch('transport.internal.parse_error', [&$responses[$key], $requests[$key]]);
				} else {
					$responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options);

					$options['hooks']->dispatch('transport.internal.parse_response', [&$responses[$key], $requests[$key]]);
				}

				curl_multi_remove_handle($multihandle, $done['handle']);
				curl_close($done['handle']);

				if (!is_string($responses[$key])) {
					$options['hooks']->dispatch('multiple.request.complete', [&$responses[$key], $key]);
				}

				$completed++;
			}
		} while ($active || $completed < $subrequestcount);

		$request['options']['hooks']->dispatch('curl.after_multi_exec', [&$multihandle]);

		curl_multi_close($multihandle);

		return $responses;
	}

	/**
	 * Get the cURL handle for use in a multi-request
	 *
	 * @param string $url URL to request
	 * @param array $headers Associative array of request headers
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
	 * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
	 * @return resource|\CurlHandle Subrequest's cURL handle
	 */
	public function &get_subrequest_handle($url, $headers, $data, $options) {
		$this->setup_handle($url, $headers, $data, $options);

		if ($options['filename'] !== false) {
			$this->stream_handle = fopen($options['filename'], 'wb');
		}

		$this->response_data       = '';
		$this->response_bytes      = 0;
		$this->response_byte_limit = false;
		if ($options['max_bytes'] !== false) {
			$this->response_byte_limit = $options['max_bytes'];
		}

		$this->hooks = $options['hooks'];

		return $this->handle;
	}

	/**
	 * Setup the cURL handle for the given data
	 *
	 * @param string $url URL to request
	 * @param array $headers Associative array of request headers
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
	 * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
	 */
	private function setup_handle($url, $headers, $data, $options) {
		$options['hooks']->dispatch('curl.before_request', [&$this->handle]);

		// Force closing the connection for old versions of cURL (<7.22).
		if (!isset($headers['Connection'])) {
			$headers['Connection'] = 'close';
		}

		/**
		 * Add "Expect" header.
		 *
		 * By default, cURL adds a "Expect: 100-Continue" to most requests. This header can
		 * add as much as a second to the time it takes for cURL to perform a request. To
		 * prevent this, we need to set an empty "Expect" header. To match the behaviour of
		 * Guzzle, we'll add the empty header to requests that are smaller than 1 MB and use
		 * HTTP/1.1.
		 *
		 * https://curl.se/mail/lib-2017-07/0013.html
		 */
		if (!isset($headers['Expect']) && $options['protocol_version'] === 1.1) {
			$headers['Expect'] = $this->get_expect_header($data);
		}

		$headers = Requests::flatten($headers);

		if (!empty($data)) {
			$data_format = $options['data_format'];

			if ($data_format === 'query') {
				$url  = self::format_get($url, $data);
				$data = '';
			} elseif (!is_string($data)) {
				$data = http_build_query($data, '', '&');
			}
		}

		switch ($options['type']) {
			case Requests::POST:
				curl_setopt($this->handle, CURLOPT_POST, true);
				curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
				break;
			case Requests::HEAD:
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
				curl_setopt($this->handle, CURLOPT_NOBODY, true);
				break;
			case Requests::TRACE:
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
				break;
			case Requests::PATCH:
			case Requests::PUT:
			case Requests::DELETE:
			case Requests::OPTIONS:
			default:
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
				if (!empty($data)) {
					curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
				}
		}

		// cURL requires a minimum timeout of 1 second when using the system
		// DNS resolver, as it uses `alarm()`, which is second resolution only.
		// There's no way to detect which DNS resolver is being used from our
		// end, so we need to round up regardless of the supplied timeout.
		//
		// https://github.com/curl/curl/blob/4f45240bc84a9aa648c8f7243be7b79e9f9323a5/lib/hostip.c#L606-L609
		$timeout = max($options['timeout'], 1);

		if (is_int($timeout) || $this->version < self::CURL_7_16_2) {
			curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($timeout));
		} else {
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_timeout_msFound
			curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($timeout * 1000));
		}

		if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) {
			curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout']));
		} else {
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_connecttimeout_msFound
			curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000));
		}

		curl_setopt($this->handle, CURLOPT_URL, $url);
		curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']);
		if (!empty($headers)) {
			curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers);
		}

		if ($options['protocol_version'] === 1.1) {
			curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
		} else {
			curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
		}

		if ($options['blocking'] === true) {
			curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, [$this, 'stream_headers']);
			curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, [$this, 'stream_body']);
			curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE);
		}
	}

	/**
	 * Process a response
	 *
	 * @param string $response Response data from the body
	 * @param array $options Request options
	 * @return string|false HTTP response data including headers. False if non-blocking.
	 * @throws \WpOrg\Requests\Exception If the request resulted in a cURL error.
	 */
	public function process_response($response, $options) {
		if ($options['blocking'] === false) {
			$fake_headers = '';
			$options['hooks']->dispatch('curl.after_request', [&$fake_headers]);
			return false;
		}

		if ($options['filename'] !== false && $this->stream_handle) {
			fclose($this->stream_handle);
			$this->headers = trim($this->headers);
		} else {
			$this->headers .= $response;
		}

		if (curl_errno($this->handle)) {
			$error = sprintf(
				'cURL error %s: %s',
				curl_errno($this->handle),
				curl_error($this->handle)
			);
			throw new Exception($error, 'curlerror', $this->handle);
		}

		$this->info = curl_getinfo($this->handle);

		$options['hooks']->dispatch('curl.after_request', [&$this->headers, &$this->info]);
		return $this->headers;
	}

	/**
	 * Collect the headers as they are received
	 *
	 * @param resource|\CurlHandle $handle cURL handle
	 * @param string $headers Header string
	 * @return integer Length of provided header
	 */
	public function stream_headers($handle, $headers) {
		// Why do we do this? cURL will send both the final response and any
		// interim responses, such as a 100 Continue. We don't need that.
		// (We may want to keep this somewhere just in case)
		if ($this->done_headers) {
			$this->headers      = '';
			$this->done_headers = false;
		}

		$this->headers .= $headers;

		if ($headers === "\r\n") {
			$this->done_headers = true;
		}

		return strlen($headers);
	}

	/**
	 * Collect data as it's received
	 *
	 * @since 1.6.1
	 *
	 * @param resource|\CurlHandle $handle cURL handle
	 * @param string $data Body data
	 * @return integer Length of provided data
	 */
	public function stream_body($handle, $data) {
		$this->hooks->dispatch('request.progress', [$data, $this->response_bytes, $this->response_byte_limit]);
		$data_length = strlen($data);

		// Are we limiting the response size?
		if ($this->response_byte_limit) {
			if ($this->response_bytes === $this->response_byte_limit) {
				// Already at maximum, move on
				return $data_length;
			}

			if (($this->response_bytes + $data_length) > $this->response_byte_limit) {
				// Limit the length
				$limited_length = ($this->response_byte_limit - $this->response_bytes);
				$data           = substr($data, 0, $limited_length);
			}
		}

		if ($this->stream_handle) {
			fwrite($this->stream_handle, $data);
		} else {
			$this->response_data .= $data;
		}

		$this->response_bytes += strlen($data);
		return $data_length;
	}

	/**
	 * Format a URL given GET data
	 *
	 * @param string       $url  Original URL.
	 * @param array|object $data Data to build query using, see {@link https://www.php.net/http_build_query}
	 * @return string URL with data
	 */
	private static function format_get($url, $data) {
		if (!empty($data)) {
			$query     = '';
			$url_parts = parse_url($url);
			if (empty($url_parts['query'])) {
				$url_parts['query'] = '';
			} else {
				$query = $url_parts['query'];
			}

			$query .= '&' . http_build_query($data, '', '&');
			$query  = trim($query, '&');

			if (empty($url_parts['query'])) {
				$url .= '?' . $query;
			} else {
				$url = str_replace($url_parts['query'], $query, $url);
			}
		}

		return $url;
	}

	/**
	 * Self-test whether the transport can be used.
	 *
	 * The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}.
	 *
	 * @codeCoverageIgnore
	 * @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
	 * @return bool Whether the transport can be used.
	 */
	public static function test($capabilities = []) {
		if (!function_exists('curl_init') || !function_exists('curl_exec')) {
			return false;
		}

		// If needed, check that our installed curl version supports SSL
		if (isset($capabilities[Capability::SSL]) && $capabilities[Capability::SSL]) {
			$curl_version = curl_version();
			if (!(CURL_VERSION_SSL & $curl_version['features'])) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Get the correct "Expect" header for the given request data.
	 *
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD.
	 * @return string The "Expect" header.
	 */
	private function get_expect_header($data) {
		if (!is_array($data)) {
			return strlen((string) $data) >= 1048576 ? '100-Continue' : '';
		}

		$bytesize = 0;
		$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($data));

		foreach ($iterator as $datum) {
			$bytesize += strlen((string) $datum);

			if ($bytesize >= 1048576) {
				return '100-Continue';
			}
		}

		return '';
	}
}
PK     Ӯ+]^      src/Response/Headers.phpnu         <?php
/**
 * Case-insensitive dictionary, suitable for HTTP headers
 *
 * @package Requests
 */

namespace WpOrg\Requests\Response;

use WpOrg\Requests\Exception;
use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Utility\CaseInsensitiveDictionary;
use WpOrg\Requests\Utility\FilteredIterator;

/**
 * Case-insensitive dictionary, suitable for HTTP headers
 *
 * @package Requests
 */
class Headers extends CaseInsensitiveDictionary {
	/**
	 * Get the given header
	 *
	 * Unlike {@see \WpOrg\Requests\Response\Headers::getValues()}, this returns a string. If there are
	 * multiple values, it concatenates them with a comma as per RFC2616.
	 *
	 * Avoid using this where commas may be used unquoted in values, such as
	 * Set-Cookie headers.
	 *
	 * @param string $offset Name of the header to retrieve.
	 * @return string|null Header value
	 */
	public function offsetGet($offset) {
		if (is_string($offset)) {
			$offset = strtolower($offset);
		}

		if (!isset($this->data[$offset])) {
			return null;
		}

		return $this->flatten($this->data[$offset]);
	}

	/**
	 * Set the given item
	 *
	 * @param string $offset Item name
	 * @param string $value Item value
	 *
	 * @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`)
	 */
	public function offsetSet($offset, $value) {
		if ($offset === null) {
			throw new Exception('Object is a dictionary, not a list', 'invalidset');
		}

		if (is_string($offset)) {
			$offset = strtolower($offset);
		}

		if (!isset($this->data[$offset])) {
			$this->data[$offset] = [];
		}

		$this->data[$offset][] = $value;
	}

	/**
	 * Get all values for a given header
	 *
	 * @param string $offset Name of the header to retrieve.
	 * @return array|null Header values
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not valid as an array key.
	 */
	public function getValues($offset) {
		if (!is_string($offset) && !is_int($offset)) {
			throw InvalidArgument::create(1, '$offset', 'string|int', gettype($offset));
		}

		if (is_string($offset)) {
			$offset = strtolower($offset);
		}

		if (!isset($this->data[$offset])) {
			return null;
		}

		return $this->data[$offset];
	}

	/**
	 * Flattens a value into a string
	 *
	 * Converts an array into a string by imploding values with a comma, as per
	 * RFC2616's rules for folding headers.
	 *
	 * @param string|array $value Value to flatten
	 * @return string Flattened value
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or an array.
	 */
	public function flatten($value) {
		if (is_string($value)) {
			return $value;
		}

		if (is_array($value)) {
			return implode(',', $value);
		}

		throw InvalidArgument::create(1, '$value', 'string|array', gettype($value));
	}

	/**
	 * Get an iterator for the data
	 *
	 * Converts the internally stored values to a comma-separated string if there is more
	 * than one value for a key.
	 *
	 * @return \ArrayIterator
	 */
	public function getIterator() {
		return new FilteredIterator($this->data, [$this, 'flatten']);
	}
}
PK     Ӯ+]rw$  w$    src/Autoload.phpnu         <?php
/**
 * Autoloader for Requests for PHP.
 *
 * Include this file if you'd like to avoid having to create your own autoloader.
 *
 * @package Requests
 * @since   2.0.0
 *
 * @codeCoverageIgnore
 */

namespace WpOrg\Requests;

/*
 * Ensure the autoloader is only declared once.
 * This safeguard is in place as this is the typical entry point for this library
 * and this file being required unconditionally could easily cause
 * fatal "Class already declared" errors.
 */
if (class_exists('WpOrg\Requests\Autoload') === false) {

	/**
	 * Autoloader for Requests for PHP.
	 *
	 * This autoloader supports the PSR-4 based Requests 2.0.0 classes in a case-sensitive manner
	 * as the most common server OS-es are case-sensitive and the file names are in mixed case.
	 *
	 * For the PSR-0 Requests 1.x BC-layer, requested classes will be treated case-insensitively.
	 *
	 * @package Requests
	 */
	final class Autoload {

		/**
		 * List of the old PSR-0 class names in lowercase as keys with their PSR-4 case-sensitive name as a value.
		 *
		 * @var array
		 */
		private static $deprecated_classes = [
			// Interfaces.
			'requests_auth'                              => '\WpOrg\Requests\Auth',
			'requests_hooker'                            => '\WpOrg\Requests\HookManager',
			'requests_proxy'                             => '\WpOrg\Requests\Proxy',
			'requests_transport'                         => '\WpOrg\Requests\Transport',

			// Classes.
			'requests_cookie'                            => '\WpOrg\Requests\Cookie',
			'requests_exception'                         => '\WpOrg\Requests\Exception',
			'requests_hooks'                             => '\WpOrg\Requests\Hooks',
			'requests_idnaencoder'                       => '\WpOrg\Requests\IdnaEncoder',
			'requests_ipv6'                              => '\WpOrg\Requests\Ipv6',
			'requests_iri'                               => '\WpOrg\Requests\Iri',
			'requests_response'                          => '\WpOrg\Requests\Response',
			'requests_session'                           => '\WpOrg\Requests\Session',
			'requests_ssl'                               => '\WpOrg\Requests\Ssl',
			'requests_auth_basic'                        => '\WpOrg\Requests\Auth\Basic',
			'requests_cookie_jar'                        => '\WpOrg\Requests\Cookie\Jar',
			'requests_proxy_http'                        => '\WpOrg\Requests\Proxy\Http',
			'requests_response_headers'                  => '\WpOrg\Requests\Response\Headers',
			'requests_transport_curl'                    => '\WpOrg\Requests\Transport\Curl',
			'requests_transport_fsockopen'               => '\WpOrg\Requests\Transport\Fsockopen',
			'requests_utility_caseinsensitivedictionary' => '\WpOrg\Requests\Utility\CaseInsensitiveDictionary',
			'requests_utility_filterediterator'          => '\WpOrg\Requests\Utility\FilteredIterator',
			'requests_exception_http'                    => '\WpOrg\Requests\Exception\Http',
			'requests_exception_transport'               => '\WpOrg\Requests\Exception\Transport',
			'requests_exception_transport_curl'          => '\WpOrg\Requests\Exception\Transport\Curl',
			'requests_exception_http_304'                => '\WpOrg\Requests\Exception\Http\Status304',
			'requests_exception_http_305'                => '\WpOrg\Requests\Exception\Http\Status305',
			'requests_exception_http_306'                => '\WpOrg\Requests\Exception\Http\Status306',
			'requests_exception_http_400'                => '\WpOrg\Requests\Exception\Http\Status400',
			'requests_exception_http_401'                => '\WpOrg\Requests\Exception\Http\Status401',
			'requests_exception_http_402'                => '\WpOrg\Requests\Exception\Http\Status402',
			'requests_exception_http_403'                => '\WpOrg\Requests\Exception\Http\Status403',
			'requests_exception_http_404'                => '\WpOrg\Requests\Exception\Http\Status404',
			'requests_exception_http_405'                => '\WpOrg\Requests\Exception\Http\Status405',
			'requests_exception_http_406'                => '\WpOrg\Requests\Exception\Http\Status406',
			'requests_exception_http_407'                => '\WpOrg\Requests\Exception\Http\Status407',
			'requests_exception_http_408'                => '\WpOrg\Requests\Exception\Http\Status408',
			'requests_exception_http_409'                => '\WpOrg\Requests\Exception\Http\Status409',
			'requests_exception_http_410'                => '\WpOrg\Requests\Exception\Http\Status410',
			'requests_exception_http_411'                => '\WpOrg\Requests\Exception\Http\Status411',
			'requests_exception_http_412'                => '\WpOrg\Requests\Exception\Http\Status412',
			'requests_exception_http_413'                => '\WpOrg\Requests\Exception\Http\Status413',
			'requests_exception_http_414'                => '\WpOrg\Requests\Exception\Http\Status414',
			'requests_exception_http_415'                => '\WpOrg\Requests\Exception\Http\Status415',
			'requests_exception_http_416'                => '\WpOrg\Requests\Exception\Http\Status416',
			'requests_exception_http_417'                => '\WpOrg\Requests\Exception\Http\Status417',
			'requests_exception_http_418'                => '\WpOrg\Requests\Exception\Http\Status418',
			'requests_exception_http_428'                => '\WpOrg\Requests\Exception\Http\Status428',
			'requests_exception_http_429'                => '\WpOrg\Requests\Exception\Http\Status429',
			'requests_exception_http_431'                => '\WpOrg\Requests\Exception\Http\Status431',
			'requests_exception_http_500'                => '\WpOrg\Requests\Exception\Http\Status500',
			'requests_exception_http_501'                => '\WpOrg\Requests\Exception\Http\Status501',
			'requests_exception_http_502'                => '\WpOrg\Requests\Exception\Http\Status502',
			'requests_exception_http_503'                => '\WpOrg\Requests\Exception\Http\Status503',
			'requests_exception_http_504'                => '\WpOrg\Requests\Exception\Http\Status504',
			'requests_exception_http_505'                => '\WpOrg\Requests\Exception\Http\Status505',
			'requests_exception_http_511'                => '\WpOrg\Requests\Exception\Http\Status511',
			'requests_exception_http_unknown'            => '\WpOrg\Requests\Exception\Http\StatusUnknown',
		];

		/**
		 * Register the autoloader.
		 *
		 * Note: the autoloader is *prepended* in the autoload queue.
		 * This is done to ensure that the Requests 2.0 autoloader takes precedence
		 * over a potentially (dependency-registered) Requests 1.x autoloader.
		 *
		 * @internal This method contains a safeguard against the autoloader being
		 * registered multiple times. This safeguard uses a global constant to
		 * (hopefully/in most cases) still function correctly, even if the
		 * class would be renamed.
		 *
		 * @return void
		 */
		public static function register() {
			if (defined('REQUESTS_AUTOLOAD_REGISTERED') === false) {
				spl_autoload_register([self::class, 'load'], true);
				define('REQUESTS_AUTOLOAD_REGISTERED', true);
			}
		}

		/**
		 * Autoloader.
		 *
		 * @param string $class_name Name of the class name to load.
		 *
		 * @return bool Whether a class was loaded or not.
		 */
		public static function load($class_name) {
			// Check that the class starts with "Requests" (PSR-0) or "WpOrg\Requests" (PSR-4).
			$psr_4_prefix_pos = strpos($class_name, 'WpOrg\\Requests\\');

			if (stripos($class_name, 'Requests') !== 0 && $psr_4_prefix_pos !== 0) {
				return false;
			}

			$class_lower = strtolower($class_name);

			if ($class_lower === 'requests') {
				// Reference to the original PSR-0 Requests class.
				$file = dirname(__DIR__) . '/library/Requests.php';
			} elseif ($psr_4_prefix_pos === 0) {
				// PSR-4 classname.
				$file = __DIR__ . '/' . strtr(substr($class_name, 15), '\\', '/') . '.php';
			}

			if (isset($file) && file_exists($file)) {
				include $file;
				return true;
			}

			/*
			 * Okay, so the class starts with "Requests", but we couldn't find the file.
			 * If this is one of the deprecated/renamed PSR-0 classes being requested,
			 * let's alias it to the new name and throw a deprecation notice.
			 */
			if (isset(self::$deprecated_classes[$class_lower])) {
				/*
				 * Integrators who cannot yet upgrade to the PSR-4 class names can silence deprecations
				 * by defining a `REQUESTS_SILENCE_PSR0_DEPRECATIONS` constant and setting it to `true`.
				 * The constant needs to be defined before the first deprecated class is requested
				 * via this autoloader.
				 */
				if (!defined('REQUESTS_SILENCE_PSR0_DEPRECATIONS') || REQUESTS_SILENCE_PSR0_DEPRECATIONS !== true) {
					// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
					trigger_error(
						'The PSR-0 `Requests_...` class names in the Requests library are deprecated.'
						. ' Switch to the PSR-4 `WpOrg\Requests\...` class names at your earliest convenience.',
						E_USER_DEPRECATED
					);

					// Prevent the deprecation notice from being thrown twice.
					if (!defined('REQUESTS_SILENCE_PSR0_DEPRECATIONS')) {
						define('REQUESTS_SILENCE_PSR0_DEPRECATIONS', true);
					}
				}

				// Create an alias and let the autoloader recursively kick in to load the PSR-4 class.
				return class_alias(self::$deprecated_classes[$class_lower], $class_name, true);
			}

			return false;
		}
	}
}
PK     Ӯ+];      src/Ipv6.phpnu         <?php
/**
 * Class to validate and to work with IPv6 addresses
 *
 * @package Requests\Utilities
 */

namespace WpOrg\Requests;

use WpOrg\Requests\Exception\InvalidArgument;
use WpOrg\Requests\Utility\InputValidator;

/**
 * Class to validate and to work with IPv6 addresses
 *
 * This was originally based on the PEAR class of the same name, but has been
 * entirely rewritten.
 *
 * @package Requests\Utilities
 */
final class Ipv6 {
	/**
	 * Uncompresses an IPv6 address
	 *
	 * RFC 4291 allows you to compress consecutive zero pieces in an address to
	 * '::'. This method expects a valid IPv6 address and expands the '::' to
	 * the required number of zero pieces.
	 *
	 * Example:  FF01::101   ->  FF01:0:0:0:0:0:0:101
	 *           ::1         ->  0:0:0:0:0:0:0:1
	 *
	 * @author Alexander Merz <alexander.merz@web.de>
	 * @author elfrink at introweb dot nl
	 * @author Josh Peck <jmp at joshpeck dot org>
	 * @copyright 2003-2005 The PHP Group
	 * @license https://opensource.org/licenses/bsd-license.php
	 *
	 * @param string|Stringable $ip An IPv6 address
	 * @return string The uncompressed IPv6 address
	 *
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object.
	 */
	public static function uncompress($ip) {
		if (InputValidator::is_string_or_stringable($ip) === false) {
			throw InvalidArgument::create(1, '$ip', 'string|Stringable', gettype($ip));
		}

		$ip = (string) $ip;

		if (substr_count($ip, '::') !== 1) {
			return $ip;
		}

		list($ip1, $ip2) = explode('::', $ip);
		$c1              = ($ip1 === '') ? -1 : substr_count($ip1, ':');
		$c2              = ($ip2 === '') ? -1 : substr_count($ip2, ':');

		if (strpos($ip2, '.') !== false) {
			$c2++;
		}

		if ($c1 === -1 && $c2 === -1) {
			// ::
			$ip = '0:0:0:0:0:0:0:0';
		} elseif ($c1 === -1) {
			// ::xxx
			$fill = str_repeat('0:', 7 - $c2);
			$ip   = str_replace('::', $fill, $ip);
		} elseif ($c2 === -1) {
			// xxx::
			$fill = str_repeat(':0', 7 - $c1);
			$ip   = str_replace('::', $fill, $ip);
		} else {
			// xxx::xxx
			$fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
			$ip   = str_replace('::', $fill, $ip);
		}

		return $ip;
	}

	/**
	 * Compresses an IPv6 address
	 *
	 * RFC 4291 allows you to compress consecutive zero pieces in an address to
	 * '::'. This method expects a valid IPv6 address and compresses consecutive
	 * zero pieces to '::'.
	 *
	 * Example:  FF01:0:0:0:0:0:0:101   ->  FF01::101
	 *           0:0:0:0:0:0:0:1        ->  ::1
	 *
	 * @see \WpOrg\Requests\Ipv6::uncompress()
	 *
	 * @param string $ip An IPv6 address
	 * @return string The compressed IPv6 address
	 */
	public static function compress($ip) {
		// Prepare the IP to be compressed.
		// Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method.
		$ip       = self::uncompress($ip);
		$ip_parts = self::split_v6_v4($ip);

		// Replace all leading zeros
		$ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);

		// Find bunches of zeros
		if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) {
			$max = 0;
			$pos = null;
			foreach ($matches[0] as $match) {
				if (strlen($match[0]) > $max) {
					$max = strlen($match[0]);
					$pos = $match[1];
				}
			}

			$ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
		}

		if ($ip_parts[1] !== '') {
			return implode(':', $ip_parts);
		} else {
			return $ip_parts[0];
		}
	}

	/**
	 * Splits an IPv6 address into the IPv6 and IPv4 representation parts
	 *
	 * RFC 4291 allows you to represent the last two parts of an IPv6 address
	 * using the standard IPv4 representation
	 *
	 * Example:  0:0:0:0:0:0:13.1.68.3
	 *           0:0:0:0:0:FFFF:129.144.52.38
	 *
	 * @param string $ip An IPv6 address
	 * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part
	 */
	private static function split_v6_v4($ip) {
		if (strpos($ip, '.') !== false) {
			$pos       = strrpos($ip, ':');
			$ipv6_part = substr($ip, 0, $pos);
			$ipv4_part = substr($ip, $pos + 1);
			return [$ipv6_part, $ipv4_part];
		} else {
			return [$ip, ''];
		}
	}

	/**
	 * Checks an IPv6 address
	 *
	 * Checks if the given IP is a valid IPv6 address
	 *
	 * @param string $ip An IPv6 address
	 * @return bool true if $ip is a valid IPv6 address
	 */
	public static function check_ipv6($ip) {
		// Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method.
		$ip                = self::uncompress($ip);
		list($ipv6, $ipv4) = self::split_v6_v4($ip);
		$ipv6              = explode(':', $ipv6);
		$ipv4              = explode('.', $ipv4);
		if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) {
			foreach ($ipv6 as $ipv6_part) {
				// The section can't be empty
				if ($ipv6_part === '') {
					return false;
				}

				// Nor can it be over four characters
				if (strlen($ipv6_part) > 4) {
					return false;
				}

				// Remove leading zeros (this is safe because of the above)
				$ipv6_part = ltrim($ipv6_part, '0');
				if ($ipv6_part === '') {
					$ipv6_part = '0';
				}

				// Check the value is valid
				$value = hexdec($ipv6_part);
				if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) {
					return false;
				}
			}

			if (count($ipv4) === 4) {
				foreach ($ipv4 as $ipv4_part) {
					$value = (int) $ipv4_part;
					if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) {
						return false;
					}
				}
			}

			return true;
		} else {
			return false;
		}
	}
}
PK     Ӯ+]C      src/HookManager.phpnu         <?php
/**
 * Event dispatcher
 *
 * @package Requests\EventDispatcher
 */

namespace WpOrg\Requests;

/**
 * Event dispatcher
 *
 * @package Requests\EventDispatcher
 */
interface HookManager {
	/**
	 * Register a callback for a hook
	 *
	 * @param string $hook Hook name
	 * @param callable $callback Function/method to call on event
	 * @param int $priority Priority number. <0 is executed earlier, >0 is executed later
	 */
	public function register($hook, $callback, $priority = 0);

	/**
	 * Dispatch a message
	 *
	 * @param string $hook Hook name
	 * @param array $parameters Parameters to pass to callbacks
	 * @return boolean Successfulness
	 */
	public function dispatch($hook, $parameters = []);
}
PK     Ӯ+])      library/Requests.phpnu         <?php
/**
 * Loads the old Requests class file when the autoloader
 * references the original PSR-0 Requests class.
 *
 * @deprecated 6.2.0
 * @package WordPress
 * @subpackage Requests
 * @since 6.2.0
 */

include_once ABSPATH . WPINC . '/class-requests.php';
PK       Ӯ+]Մec  c                  src/Proxy.phpnu         PK       Ӯ+]^		  	                src/Utility/InputValidator.phpnu         PK       Ӯ+]5L	  	  )              src/Utility/CaseInsensitiveDictionary.phpnu         PK       Ӯ+]m  m                 src/Utility/FilteredIterator.phpnu         PK       Ӯ+]w	׺1  1                 src/Ssl.phpnu         PK       Ӯ+]g^y  y              6  src/Proxy/Http.phpnu         PK       Ӯ+]q1                F  src/Exception/ArgumentCount.phpnu         PK       Ӯ+]iA                  L  src/Exception/Transport.phpnu         PK       Ӯ+]R  R  !            N  src/Exception/InvalidArgument.phpnu         PK       Ӯ+]                  R  src/Exception/Http/Status500.phpnu         PK       Ӯ+]4,  ,               T  src/Exception/Http/Status418.phpnu         PK       Ӯ+][F                 ^W  src/Exception/Http/Status411.phpnu         PK       Ӯ+]                 Y  src/Exception/Http/Status416.phpnu         PK       Ӯ+]]                 [  src/Exception/Http/Status407.phpnu         PK       Ӯ+]ǿH7                 '^  src/Exception/Http/Status400.phpnu         PK       Ӯ+]                 @`  src/Exception/Http/Status304.phpnu         PK       Ӯ+]                 \b  src/Exception/Http/Status409.phpnu         PK       Ӯ+]e  e               ld  src/Exception/Http/Status511.phpnu         PK       Ӯ+]f+                 !g  src/Exception/Http/Status417.phpnu         PK       Ӯ+]η.p                 Oi  src/Exception/Http/Status410.phpnu         PK       Ӯ+]*    $            Sk  src/Exception/Http/StatusUnknown.phpnu         PK       Ӯ+]mk                 qo  src/Exception/Http/Status501.phpnu         PK       Ӯ+]kT                 q  src/Exception/Http/Status408.phpnu         PK       Ӯ+]                 s  src/Exception/Http/Status305.phpnu         PK       Ӯ+]                  u  src/Exception/Http/Status401.phpnu         PK       Ӯ+]Sb                 w  src/Exception/Http/Status406.phpnu         PK       Ӯ+]h$a                 z  src/Exception/Http/Status306.phpnu         PK       Ӯ+]wא                 (|  src/Exception/Http/Status405.phpnu         PK       Ӯ+]{                 V~  src/Exception/Http/Status402.phpnu         PK       Ӯ+]hm                 ~  src/Exception/Http/Status413.phpnu         PK       Ӯ+]2d                   src/Exception/Http/Status414.phpnu         PK       Ӯ+]^:G  G                 src/Exception/Http/Status428.phpnu         PK       Ӯ+]m                   src/Exception/Http/Status505.phpnu         PK       Ӯ+]                 ҉  src/Exception/Http/Status502.phpnu         PK       Ӯ+]                   src/Exception/Http/Status403.phpnu         PK       Ӯ+]y                   src/Exception/Http/Status404.phpnu         PK       Ӯ+]&Xe  e                 src/Exception/Http/Status431.phpnu         PK       Ӯ+]w;                 ƒ  src/Exception/Http/Status503.phpnu         PK       Ӯ+]kf                   src/Exception/Http/Status504.phpnu         PK       Ӯ+](s  s                 src/Exception/Http/Status429.phpnu         PK       Ӯ+]P                 ߙ  src/Exception/Http/Status415.phpnu         PK       Ӯ+]`                   src/Exception/Http/Status412.phpnu         PK       Ӯ+]*u  u               J  src/Exception/Transport/Curl.phpnu         PK       Ӯ+]&                  src/Exception/Http.phpnu         PK       Ӯ+]ޣ@                [  src/Capability.phpnu         PK       Ӯ+]/yQ#  #              )  src/Session.phpnu         PK       Ӯ+]ח                  src/Response.phpnu         PK       Ӯ+]Z	  	                src/Auth/Basic.phpnu         PK       Ӯ+]YP>  >              #  src/Transport/Fsockopen.phpnu         PK       Ӯ+]j;sL  sL              * src/Transport/Curl.phpnu         PK       Ӯ+]^                Bw src/Response/Headers.phpnu         PK       Ӯ+]rw$  w$               src/Autoload.phpnu         PK       Ӯ+];                ^ src/Ipv6.phpnu         PK       Ӯ+]C                 src/HookManager.phpnu         PK       Ӯ+])                 library/Requests.phpnu         PK    7 7   