summaryrefslogtreecommitdiffstats
path: root/vendor/react/http/src/Client
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:38:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:38:42 +0000
commitc3ca98e1b35123f226c7f4c596b5dee78caa4223 (patch)
tree9b6eb109283da55e7d9064baa9fac795a40264cb /vendor/react/http/src/Client
parentInitial commit. (diff)
downloadicinga-php-thirdparty-c3ca98e1b35123f226c7f4c596b5dee78caa4223.tar.xz
icinga-php-thirdparty-c3ca98e1b35123f226c7f4c596b5dee78caa4223.zip
Adding upstream version 0.11.0.upstream/0.11.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/react/http/src/Client')
-rw-r--r--vendor/react/http/src/Client/Client.php31
-rw-r--r--vendor/react/http/src/Client/Request.php237
-rw-r--r--vendor/react/http/src/Client/RequestData.php128
3 files changed, 396 insertions, 0 deletions
diff --git a/vendor/react/http/src/Client/Client.php b/vendor/react/http/src/Client/Client.php
new file mode 100644
index 0000000..7a97349
--- /dev/null
+++ b/vendor/react/http/src/Client/Client.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace React\Http\Client;
+
+use React\EventLoop\LoopInterface;
+use React\Socket\ConnectorInterface;
+use React\Socket\Connector;
+
+/**
+ * @internal
+ */
+class Client
+{
+ private $connector;
+
+ public function __construct(LoopInterface $loop, ConnectorInterface $connector = null)
+ {
+ if ($connector === null) {
+ $connector = new Connector(array(), $loop);
+ }
+
+ $this->connector = $connector;
+ }
+
+ public function request($method, $url, array $headers = array(), $protocolVersion = '1.0')
+ {
+ $requestData = new RequestData($method, $url, $headers, $protocolVersion);
+
+ return new Request($this->connector, $requestData);
+ }
+}
diff --git a/vendor/react/http/src/Client/Request.php b/vendor/react/http/src/Client/Request.php
new file mode 100644
index 0000000..51e0331
--- /dev/null
+++ b/vendor/react/http/src/Client/Request.php
@@ -0,0 +1,237 @@
+<?php
+
+namespace React\Http\Client;
+
+use Evenement\EventEmitter;
+use React\Promise;
+use React\Socket\ConnectionInterface;
+use React\Socket\ConnectorInterface;
+use React\Stream\WritableStreamInterface;
+use RingCentral\Psr7 as gPsr;
+
+/**
+ * @event response
+ * @event drain
+ * @event error
+ * @event end
+ * @internal
+ */
+class Request extends EventEmitter implements WritableStreamInterface
+{
+ const STATE_INIT = 0;
+ const STATE_WRITING_HEAD = 1;
+ const STATE_HEAD_WRITTEN = 2;
+ const STATE_END = 3;
+
+ private $connector;
+ private $requestData;
+
+ private $stream;
+ private $buffer;
+ private $responseFactory;
+ private $state = self::STATE_INIT;
+ private $ended = false;
+
+ private $pendingWrites = '';
+
+ public function __construct(ConnectorInterface $connector, RequestData $requestData)
+ {
+ $this->connector = $connector;
+ $this->requestData = $requestData;
+ }
+
+ public function isWritable()
+ {
+ return self::STATE_END > $this->state && !$this->ended;
+ }
+
+ private function writeHead()
+ {
+ $this->state = self::STATE_WRITING_HEAD;
+
+ $requestData = $this->requestData;
+ $streamRef = &$this->stream;
+ $stateRef = &$this->state;
+ $pendingWrites = &$this->pendingWrites;
+ $that = $this;
+
+ $promise = $this->connect();
+ $promise->then(
+ function (ConnectionInterface $stream) use ($requestData, &$streamRef, &$stateRef, &$pendingWrites, $that) {
+ $streamRef = $stream;
+
+ $stream->on('drain', array($that, 'handleDrain'));
+ $stream->on('data', array($that, 'handleData'));
+ $stream->on('end', array($that, 'handleEnd'));
+ $stream->on('error', array($that, 'handleError'));
+ $stream->on('close', array($that, 'handleClose'));
+
+ $headers = (string) $requestData;
+
+ $more = $stream->write($headers . $pendingWrites);
+
+ $stateRef = Request::STATE_HEAD_WRITTEN;
+
+ // clear pending writes if non-empty
+ if ($pendingWrites !== '') {
+ $pendingWrites = '';
+
+ if ($more) {
+ $that->emit('drain');
+ }
+ }
+ },
+ array($this, 'closeError')
+ );
+
+ $this->on('close', function() use ($promise) {
+ $promise->cancel();
+ });
+ }
+
+ public function write($data)
+ {
+ if (!$this->isWritable()) {
+ return false;
+ }
+
+ // write directly to connection stream if already available
+ if (self::STATE_HEAD_WRITTEN <= $this->state) {
+ return $this->stream->write($data);
+ }
+
+ // otherwise buffer and try to establish connection
+ $this->pendingWrites .= $data;
+ if (self::STATE_WRITING_HEAD > $this->state) {
+ $this->writeHead();
+ }
+
+ return false;
+ }
+
+ public function end($data = null)
+ {
+ if (!$this->isWritable()) {
+ return;
+ }
+
+ if (null !== $data) {
+ $this->write($data);
+ } else if (self::STATE_WRITING_HEAD > $this->state) {
+ $this->writeHead();
+ }
+
+ $this->ended = true;
+ }
+
+ /** @internal */
+ public function handleDrain()
+ {
+ $this->emit('drain');
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ $this->buffer .= $data;
+
+ // buffer until double CRLF (or double LF for compatibility with legacy servers)
+ if (false !== strpos($this->buffer, "\r\n\r\n") || false !== strpos($this->buffer, "\n\n")) {
+ try {
+ $response = gPsr\parse_response($this->buffer);
+ $bodyChunk = (string) $response->getBody();
+ } catch (\InvalidArgumentException $exception) {
+ $this->emit('error', array($exception));
+ }
+
+ $this->buffer = null;
+
+ $this->stream->removeListener('drain', array($this, 'handleDrain'));
+ $this->stream->removeListener('data', array($this, 'handleData'));
+ $this->stream->removeListener('end', array($this, 'handleEnd'));
+ $this->stream->removeListener('error', array($this, 'handleError'));
+ $this->stream->removeListener('close', array($this, 'handleClose'));
+
+ if (!isset($response)) {
+ return;
+ }
+
+ $this->stream->on('close', array($this, 'handleClose'));
+
+ $this->emit('response', array($response, $this->stream));
+
+ $this->stream->emit('data', array($bodyChunk));
+ }
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ $this->closeError(new \RuntimeException(
+ "Connection ended before receiving response"
+ ));
+ }
+
+ /** @internal */
+ public function handleError(\Exception $error)
+ {
+ $this->closeError(new \RuntimeException(
+ "An error occurred in the underlying stream",
+ 0,
+ $error
+ ));
+ }
+
+ /** @internal */
+ public function handleClose()
+ {
+ $this->close();
+ }
+
+ /** @internal */
+ public function closeError(\Exception $error)
+ {
+ if (self::STATE_END <= $this->state) {
+ return;
+ }
+ $this->emit('error', array($error));
+ $this->close();
+ }
+
+ public function close()
+ {
+ if (self::STATE_END <= $this->state) {
+ return;
+ }
+
+ $this->state = self::STATE_END;
+ $this->pendingWrites = '';
+
+ if ($this->stream) {
+ $this->stream->close();
+ }
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ protected function connect()
+ {
+ $scheme = $this->requestData->getScheme();
+ if ($scheme !== 'https' && $scheme !== 'http') {
+ return Promise\reject(
+ new \InvalidArgumentException('Invalid request URL given')
+ );
+ }
+
+ $host = $this->requestData->getHost();
+ $port = $this->requestData->getPort();
+
+ if ($scheme === 'https') {
+ $host = 'tls://' . $host;
+ }
+
+ return $this->connector
+ ->connect($host . ':' . $port);
+ }
+}
diff --git a/vendor/react/http/src/Client/RequestData.php b/vendor/react/http/src/Client/RequestData.php
new file mode 100644
index 0000000..a5908a0
--- /dev/null
+++ b/vendor/react/http/src/Client/RequestData.php
@@ -0,0 +1,128 @@
+<?php
+
+namespace React\Http\Client;
+
+/**
+ * @internal
+ */
+class RequestData
+{
+ private $method;
+ private $url;
+ private $headers;
+ private $protocolVersion;
+
+ public function __construct($method, $url, array $headers = array(), $protocolVersion = '1.0')
+ {
+ $this->method = $method;
+ $this->url = $url;
+ $this->headers = $headers;
+ $this->protocolVersion = $protocolVersion;
+ }
+
+ private function mergeDefaultheaders(array $headers)
+ {
+ $port = ($this->getDefaultPort() === $this->getPort()) ? '' : ":{$this->getPort()}";
+ $connectionHeaders = ('1.1' === $this->protocolVersion) ? array('Connection' => 'close') : array();
+ $authHeaders = $this->getAuthHeaders();
+
+ $defaults = array_merge(
+ array(
+ 'Host' => $this->getHost().$port,
+ 'User-Agent' => 'ReactPHP/1',
+ ),
+ $connectionHeaders,
+ $authHeaders
+ );
+
+ // remove all defaults that already exist in $headers
+ $lower = array_change_key_case($headers, CASE_LOWER);
+ foreach ($defaults as $key => $_) {
+ if (isset($lower[strtolower($key)])) {
+ unset($defaults[$key]);
+ }
+ }
+
+ return array_merge($defaults, $headers);
+ }
+
+ public function getScheme()
+ {
+ return parse_url($this->url, PHP_URL_SCHEME);
+ }
+
+ public function getHost()
+ {
+ return parse_url($this->url, PHP_URL_HOST);
+ }
+
+ public function getPort()
+ {
+ return (int) parse_url($this->url, PHP_URL_PORT) ?: $this->getDefaultPort();
+ }
+
+ public function getDefaultPort()
+ {
+ return ('https' === $this->getScheme()) ? 443 : 80;
+ }
+
+ public function getPath()
+ {
+ $path = parse_url($this->url, PHP_URL_PATH);
+ $queryString = parse_url($this->url, PHP_URL_QUERY);
+
+ // assume "/" path by default, but allow "OPTIONS *"
+ if ($path === null) {
+ $path = ($this->method === 'OPTIONS' && $queryString === null) ? '*': '/';
+ }
+ if ($queryString !== null) {
+ $path .= '?' . $queryString;
+ }
+
+ return $path;
+ }
+
+ public function setProtocolVersion($version)
+ {
+ $this->protocolVersion = $version;
+ }
+
+ public function __toString()
+ {
+ $headers = $this->mergeDefaultheaders($this->headers);
+
+ $data = '';
+ $data .= "{$this->method} {$this->getPath()} HTTP/{$this->protocolVersion}\r\n";
+ foreach ($headers as $name => $values) {
+ foreach ((array)$values as $value) {
+ $data .= "$name: $value\r\n";
+ }
+ }
+ $data .= "\r\n";
+
+ return $data;
+ }
+
+ private function getUrlUserPass()
+ {
+ $components = parse_url($this->url);
+
+ if (isset($components['user'])) {
+ return array(
+ 'user' => $components['user'],
+ 'pass' => isset($components['pass']) ? $components['pass'] : null,
+ );
+ }
+ }
+
+ private function getAuthHeaders()
+ {
+ if (null !== $auth = $this->getUrlUserPass()) {
+ return array(
+ 'Authorization' => 'Basic ' . base64_encode($auth['user'].':'.$auth['pass']),
+ );
+ }
+
+ return array();
+ }
+}