summaryrefslogtreecommitdiff
path: root/tests/src/Http/PSR7Worker.php
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/Http/PSR7Worker.php')
-rw-r--r--tests/src/Http/PSR7Worker.php214
1 files changed, 214 insertions, 0 deletions
diff --git a/tests/src/Http/PSR7Worker.php b/tests/src/Http/PSR7Worker.php
new file mode 100644
index 00000000..b985d288
--- /dev/null
+++ b/tests/src/Http/PSR7Worker.php
@@ -0,0 +1,214 @@
+<?php
+
+/**
+ * High-performance PHP process supervisor and load balancer written in Go
+ *
+ * @author Wolfy-J
+ */
+declare(strict_types=1);
+
+namespace Spiral\RoadRunner\Http;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestFactoryInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\StreamFactoryInterface;
+use Psr\Http\Message\UploadedFileFactoryInterface;
+use Psr\Http\Message\UploadedFileInterface;
+use Spiral\RoadRunner\WorkerInterface;
+
+/**
+ * Manages PSR-7 request and response.
+ */
+class PSR7Worker
+{
+ private HttpWorker $httpWorker;
+ private ServerRequestFactoryInterface $requestFactory;
+ private StreamFactoryInterface $streamFactory;
+ private UploadedFileFactoryInterface $uploadsFactory;
+
+ /** @var mixed[] */
+ private array $originalServer = [];
+
+ /** @var string[] Valid values for HTTP protocol version */
+ private static array $allowedVersions = ['1.0', '1.1', '2',];
+
+ /**
+ * @param WorkerInterface $worker
+ * @param ServerRequestFactoryInterface $requestFactory
+ * @param StreamFactoryInterface $streamFactory
+ * @param UploadedFileFactoryInterface $uploadsFactory
+ */
+ public function __construct(
+ WorkerInterface $worker,
+ ServerRequestFactoryInterface $requestFactory,
+ StreamFactoryInterface $streamFactory,
+ UploadedFileFactoryInterface $uploadsFactory
+ ) {
+ $this->httpWorker = new HttpWorker($worker);
+ $this->requestFactory = $requestFactory;
+ $this->streamFactory = $streamFactory;
+ $this->uploadsFactory = $uploadsFactory;
+ $this->originalServer = $_SERVER;
+ }
+
+ /**
+ * @return WorkerInterface
+ */
+ public function getWorker(): WorkerInterface
+ {
+ return $this->httpWorker->getWorker();
+ }
+
+ /**
+ * @return ServerRequestInterface|null
+ */
+ public function waitRequest(): ?ServerRequestInterface
+ {
+ $httpRequest = $this->httpWorker->waitRequest();
+ if ($httpRequest === null) {
+ return null;
+ }
+
+ $_SERVER = $this->configureServer($httpRequest['ctx']);
+
+ return $this->mapRequest($httpRequest, $_SERVER);
+ }
+
+ /**
+ * Send response to the application server.
+ *
+ * @param ResponseInterface $response
+ */
+ public function respond(ResponseInterface $response): void
+ {
+ $this->httpWorker->respond(
+ $response->getStatusCode(),
+ $response->getBody()->__toString(),
+ $response->getHeaders()
+ );
+ }
+
+ /**
+ * Returns altered copy of _SERVER variable. Sets ip-address,
+ * request-time and other values.
+ *
+ * @param Request $request
+ * @return mixed[]
+ */
+ protected function configureServer(Request $request): array
+ {
+ $server = $this->originalServer;
+
+ $server['REQUEST_URI'] = $request->uri;
+ $server['REQUEST_TIME'] = time();
+ $server['REQUEST_TIME_FLOAT'] = microtime(true);
+ $server['REMOTE_ADDR'] = $request->getRemoteAddr();
+ $server['REQUEST_METHOD'] = $request->method;
+
+ $server['HTTP_USER_AGENT'] = '';
+ foreach ($request->headers as $key => $value) {
+ $key = strtoupper(str_replace('-', '_', $key));
+ if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH'])) {
+ $server[$key] = implode(', ', $value);
+ } else {
+ $server['HTTP_' . $key] = implode(', ', $value);
+ }
+ }
+
+ return $server;
+ }
+
+ /**
+ * @param Request $httpRequest
+ * @param array $server
+ * @return ServerRequestInterface
+ */
+ protected function mapRequest(Request $httpRequest, array $server): ServerRequestInterface
+ {
+ $request = $this->requestFactory->createServerRequest(
+ $httpRequest->method,
+ $httpRequest->uri,
+ $_SERVER
+ );
+
+ $request = $request
+ ->withProtocolVersion(static::fetchProtocolVersion($httpRequest->protocol))
+ ->withCookieParams($httpRequest->cookies)
+ ->withQueryParams($httpRequest->query)
+ ->withUploadedFiles($this->wrapUploads($httpRequest->uploads));
+
+ foreach ($httpRequest->attributes as $name => $value) {
+ $request = $request->withAttribute($name, $value);
+ }
+
+ foreach ($httpRequest->headers as $name => $value) {
+ $request = $request->withHeader($name, $value);
+ }
+
+ if ($httpRequest->parsed) {
+ return $request->withParsedBody($httpRequest->getParsedBody());
+ }
+
+ if ($httpRequest->body !== null) {
+ return $request->withBody($this->streamFactory->createStream($httpRequest->body));
+ }
+
+ return $request;
+ }
+
+ /**
+ * Wraps all uploaded files with UploadedFile.
+ *
+ * @param array[] $files
+ * @return UploadedFileInterface[]|mixed[]
+ */
+ protected function wrapUploads(array $files): array
+ {
+ $result = [];
+ foreach ($files as $index => $f) {
+ if (!isset($f['name'])) {
+ $result[$index] = $this->wrapUploads($f);
+ continue;
+ }
+
+ if (UPLOAD_ERR_OK === $f['error']) {
+ $stream = $this->streamFactory->createStreamFromFile($f['tmpName']);
+ } else {
+ $stream = $this->streamFactory->createStream();
+ }
+
+ $result[$index] = $this->uploadsFactory->createUploadedFile(
+ $stream,
+ $f['size'],
+ $f['error'],
+ $f['name'],
+ $f['mime']
+ );
+ }
+
+ return $result;
+ }
+
+ /**
+ * Normalize HTTP protocol version to valid values
+ *
+ * @param string $version
+ * @return string
+ */
+ private static function fetchProtocolVersion(string $version): string
+ {
+ $v = substr($version, 5);
+
+ if ($v === '2.0') {
+ return '2';
+ }
+
+ // Fallback for values outside of valid protocol versions
+ if (!in_array($v, static::$allowedVersions, true)) {
+ return '1.1';
+ }
+
+ return $v;
+ }
+}