diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Diactoros/ServerRequestFactory.php | 26 | ||||
-rw-r--r-- | src/Diactoros/StreamFactory.php | 45 | ||||
-rw-r--r-- | src/Diactoros/UploadedFileFactory.php | 35 | ||||
-rw-r--r-- | src/Exception/RoadRunnerException.php | 2 | ||||
-rw-r--r-- | src/HttpClient.php | 74 | ||||
-rw-r--r-- | src/PSR7Client.php | 77 | ||||
-rw-r--r-- | src/Worker.php | 4 |
7 files changed, 222 insertions, 41 deletions
diff --git a/src/Diactoros/ServerRequestFactory.php b/src/Diactoros/ServerRequestFactory.php new file mode 100644 index 00000000..4d427121 --- /dev/null +++ b/src/Diactoros/ServerRequestFactory.php @@ -0,0 +1,26 @@ +<?php +declare(strict_types=1); + +/** + * High-performance PHP process supervisor and load balancer written in Go + * + * @author Wolfy-J + */ + +namespace Spiral\RoadRunner\Diactoros; + +use Psr\Http\Message\ServerRequestFactoryInterface; +use Psr\Http\Message\ServerRequestInterface; +use Zend\Diactoros\ServerRequest; + +final class ServerRequestFactory implements ServerRequestFactoryInterface +{ + /** + * @inheritdoc + */ + public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface + { + $uploadedFiles = []; + return new ServerRequest($serverParams, $uploadedFiles, $uri, $method); + } +}
\ No newline at end of file diff --git a/src/Diactoros/StreamFactory.php b/src/Diactoros/StreamFactory.php new file mode 100644 index 00000000..6004ef11 --- /dev/null +++ b/src/Diactoros/StreamFactory.php @@ -0,0 +1,45 @@ +<?php +declare(strict_types=1); + +/** + * High-performance PHP process supervisor and load balancer written in Go + * + * @author Wolfy-J + */ + +namespace Spiral\RoadRunner\Diactoros; + +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\StreamInterface; +use Zend\Diactoros\Stream; + +final class StreamFactory implements StreamFactoryInterface +{ + /** + * @inheritdoc + */ + public function createStream(string $content = ''): StreamInterface + { + $resource = fopen('php://temp', 'r+'); + fwrite($resource, $content); + rewind($resource); + return $this->createStreamFromResource($resource); + } + + /** + * @inheritdoc + */ + public function createStreamFromFile(string $file, string $mode = 'r'): StreamInterface + { + $resource = fopen($file, $mode); + return $this->createStreamFromResource($resource); + } + + /** + * @inheritdoc + */ + public function createStreamFromResource($resource): StreamInterface + { + return new Stream($resource); + } +}
\ No newline at end of file diff --git a/src/Diactoros/UploadedFileFactory.php b/src/Diactoros/UploadedFileFactory.php new file mode 100644 index 00000000..1543a826 --- /dev/null +++ b/src/Diactoros/UploadedFileFactory.php @@ -0,0 +1,35 @@ +<?php +declare(strict_types=1); + +/** + * High-performance PHP process supervisor and load balancer written in Go + * + * @author Wolfy-J + */ + +namespace Spiral\RoadRunner\Diactoros; + +use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UploadedFileFactoryInterface; +use Psr\Http\Message\UploadedFileInterface; +use Zend\Diactoros\UploadedFile; + +final class UploadedFileFactory implements UploadedFileFactoryInterface +{ + /** + * @inheritdoc + */ + public function createUploadedFile( + StreamInterface $stream, + int $size = null, + int $error = \UPLOAD_ERR_OK, + string $clientFilename = null, + string $clientMediaType = null + ): UploadedFileInterface { + if ($size === null) { + $size = $stream->getSize(); + } + + return new UploadedFile($stream, $size, $error, $clientFilename, $clientMediaType); + } +}
\ No newline at end of file diff --git a/src/Exception/RoadRunnerException.php b/src/Exception/RoadRunnerException.php index ee99bb2b..7c5c5929 100644 --- a/src/Exception/RoadRunnerException.php +++ b/src/Exception/RoadRunnerException.php @@ -1,4 +1,6 @@ <?php +declare(strict_types=1); + /** * High-performance PHP process supervisor and load balancer written in Go * diff --git a/src/HttpClient.php b/src/HttpClient.php new file mode 100644 index 00000000..e469dd30 --- /dev/null +++ b/src/HttpClient.php @@ -0,0 +1,74 @@ +<?php +declare(strict_types=1); + +/** + * High-performance PHP process supervisor and load balancer written in Go + * + * @author Alex Bond + */ + +namespace Spiral\RoadRunner; + +class HttpClient +{ + /** @var Worker */ + private $worker; + + /** + * @param Worker $worker + */ + public function __construct(Worker $worker) + { + $this->worker = $worker; + } + + /** + * @return Worker + */ + public function getWorker(): Worker + { + return $this->worker; + } + + /** + * @return array|null Request information as ['ctx'=>[], 'body'=>string] or null if termination request or invalid context. + */ + public function acceptRequest() + { + $body = $this->getWorker()->receive($ctx); + if (empty($body) && empty($ctx)) { + // termination request + return null; + } + + $ctx = json_decode($ctx, true); + if (is_null($ctx)) { + // invalid context + return null; + } + + return ['ctx' => $ctx, 'body' => $body]; + } + + /** + * Send response to the application server. + * + * @param int $status Http status code + * @param string $body Body of response + * @param string[][] $headers An associative array of the message's headers. Each + * key MUST be a header name, and each value MUST be an array of strings + * for that header. + */ + public function respond(int $status, string $body, array $headers = []) + { + if (empty($headers)) { + // this is required to represent empty header set as map and not as array + $headers = new \stdClass(); + } + + $this->getWorker()->send( + $body, + json_encode(['status' => $status, 'headers' => $headers]) + ); + } +} diff --git a/src/PSR7Client.php b/src/PSR7Client.php index 0b148884..8229b7d5 100644 --- a/src/PSR7Client.php +++ b/src/PSR7Client.php @@ -1,4 +1,6 @@ <?php +declare(strict_types=1); + /** * High-performance PHP process supervisor and load balancer written in Go * @@ -7,7 +9,6 @@ namespace Spiral\RoadRunner; -use Http\Factory\Diactoros; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestFactoryInterface; use Psr\Http\Message\ServerRequestInterface; @@ -19,8 +20,8 @@ use Psr\Http\Message\UploadedFileFactoryInterface; */ class PSR7Client { - /** @var Worker */ - private $worker; + /** @var HttpClient */ + private $httpClient; /** @var ServerRequestFactoryInterface */ private $requestFactory; @@ -31,6 +32,8 @@ class PSR7Client /*** @var UploadedFileFactoryInterface */ private $uploadsFactory; + private $originalServer = []; + /** @var array Valid values for HTTP protocol version */ private static $allowedVersions = ['1.0', '1.1', '2',]; @@ -46,10 +49,11 @@ class PSR7Client StreamFactoryInterface $streamFactory = null, UploadedFileFactoryInterface $uploadsFactory = null ) { - $this->worker = $worker; + $this->httpClient = new HttpClient($worker); $this->requestFactory = $requestFactory ?? new Diactoros\ServerRequestFactory(); $this->streamFactory = $streamFactory ?? new Diactoros\StreamFactory(); $this->uploadsFactory = $uploadsFactory ?? new Diactoros\UploadedFileFactory(); + $this->originalServer = $_SERVER; } /** @@ -57,7 +61,7 @@ class PSR7Client */ public function getWorker(): Worker { - return $this->worker; + return $this->httpClient->getWorker(); } /** @@ -65,46 +69,40 @@ class PSR7Client */ public function acceptRequest() { - $body = $this->worker->receive($ctx); - if (empty($body) && empty($ctx)) { - // termination request - return null; - } - - if (empty($ctx = json_decode($ctx, true))) { - // invalid context + $rawRequest = $this->httpClient->acceptRequest(); + if ($rawRequest === null) { return null; } - $_SERVER = $this->configureServer($ctx); + $_SERVER = $this->configureServer($rawRequest['ctx']); $request = $this->requestFactory->createServerRequest( - $ctx['method'], - $ctx['uri'], + $rawRequest['ctx']['method'], + $rawRequest['ctx']['uri'], $_SERVER ); - parse_str($ctx['rawQuery'], $query); + parse_str($rawRequest['ctx']['rawQuery'], $query); $request = $request - ->withProtocolVersion(static::fetchProtocolVersion($ctx['protocol'])) - ->withCookieParams($ctx['cookies']) + ->withProtocolVersion(static::fetchProtocolVersion($rawRequest['ctx']['protocol'])) + ->withCookieParams($rawRequest['ctx']['cookies']) ->withQueryParams($query) - ->withUploadedFiles($this->wrapUploads($ctx['uploads'])); + ->withUploadedFiles($this->wrapUploads($rawRequest['ctx']['uploads'])); - foreach ($ctx['attributes'] as $name => $value) { + foreach ($rawRequest['ctx']['attributes'] as $name => $value) { $request = $request->withAttribute($name, $value); } - foreach ($ctx['headers'] as $name => $value) { + foreach ($rawRequest['ctx']['headers'] as $name => $value) { $request = $request->withHeader($name, $value); } - if ($ctx['parsed']) { - $request = $request->withParsedBody(json_decode($body, true)); + if ($rawRequest['ctx']['parsed']) { + $request = $request->withParsedBody(json_decode($rawRequest['body'], true)); } else { - if ($body !== null) { - $request = $request->withBody($this->streamFactory->createStream($body)); + if ($rawRequest['body'] !== null) { + $request = $request->withBody($this->streamFactory->createStream($rawRequest['body'])); } } @@ -118,16 +116,11 @@ class PSR7Client */ public function respond(ResponseInterface $response) { - $headers = $response->getHeaders(); - if (empty($headers)) { - // this is required to represent empty header set as map and not as array - $headers = new \stdClass(); - } - - $this->worker->send($response->getBody(), json_encode([ - 'status' => $response->getStatusCode(), - 'headers' => $headers - ])); + $this->httpClient->respond( + $response->getStatusCode(), + $response->getBody()->__toString(), + $response->getHeaders() + ); } /** @@ -139,15 +132,19 @@ class PSR7Client */ protected function configureServer(array $ctx): array { - $server = $_SERVER; + $server = $this->originalServer; $server['REQUEST_TIME'] = time(); $server['REQUEST_TIME_FLOAT'] = microtime(true); $server['REMOTE_ADDR'] = $ctx['attributes']['ipAddress'] ?? $ctx['remoteAddr'] ?? '127.0.0.1'; - $server['REMOTE_ADDR'] = $ctx['attributes']['ipAddress'] ?? $ctx['remoteAddr'] ?? '127.0.0.1'; $server['HTTP_USER_AGENT'] = ''; - if (isset($ctx['headers']['User-Agent'][0])) { - $server['HTTP_USER_AGENT'] = $ctx['headers']['User-Agent'][0]; + foreach ($ctx['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; diff --git a/src/Worker.php b/src/Worker.php index 7f92a714..da80e461 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1,4 +1,6 @@ <?php +declare(strict_types=1); + /** * High-performance PHP process supervisor and load balancer written in Go * @@ -132,7 +134,7 @@ class Worker * * @throws RoadRunnerException */ - private function handleControl(string $body = null, &$header = null, int $flags): bool + private function handleControl(string $body = null, &$header = null, int $flags = 0): bool { $header = $body; if (is_null($body) || $flags & Relay::PAYLOAD_RAW) { |