From b2d682441e51dd2c273d9884d083dd2af27d15c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Sun, 26 Sep 2021 19:19:35 +0200 Subject: [PATCH] Expose all status code constants via `Response` class --- README.md | 71 +++++++++++++---------- composer.json | 4 +- examples/51-server-hello-world.php | 3 +- examples/52-server-count-visitors.php | 3 +- examples/53-server-whatsmyip.php | 3 +- examples/54-server-query-parameter.php | 3 +- examples/55-server-cookie-handling.php | 5 +- examples/56-server-sleep.php | 3 +- examples/57-server-error-handling.php | 3 +- examples/58-server-stream-response.php | 5 +- examples/59-server-json-api.php | 9 ++- examples/61-server-hello-world-https.php | 3 +- examples/62-server-form-upload.php | 3 +- examples/63-server-streaming-request.php | 6 +- examples/71-server-http-proxy.php | 5 +- examples/72-server-http-connect-proxy.php | 7 +-- examples/81-server-upgrade-echo.php | 5 +- examples/82-server-upgrade-chat.php | 5 +- examples/99-server-benchmark-download.php | 7 +-- src/HttpServer.php | 2 +- src/Io/RequestHeaderParser.php | 12 ++-- src/Io/Sender.php | 4 +- src/Io/StreamingServer.php | 19 +++--- src/Message/Response.php | 17 ++++-- 24 files changed, 101 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 23010002..50797fe6 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ require __DIR__ . '/vendor/autoload.php'; $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) { return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -735,7 +735,7 @@ object and expects a [response](#server-response) object in return: ```php $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) { return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -953,7 +953,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf $body .= "The requested path is: " . $request->getUri()->getPath(); return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -995,7 +995,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf $body = "Your IP is: " . $request->getServerParams()['REMOTE_ADDR']; return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -1027,7 +1027,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf } return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/html' ), @@ -1074,7 +1074,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf $name = $request->getParsedBody()['name'] ?? 'anonymous'; return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array(), "Hello $name!\n" ); @@ -1099,7 +1099,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf $name = $data->name ?? 'anonymous'; return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array('Content-Type' => 'application/json'), json_encode(['message' => "Hello $name!"]) ); @@ -1122,7 +1122,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf $name = isset($files['avatar']) ? $files['avatar']->getClientFilename() : 'nothing'; return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array(), "Uploaded $name\n" ); @@ -1205,7 +1205,7 @@ $http = new React\Http\HttpServer( $body->on('end', function () use ($resolve, &$bytes){ $resolve(new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -1216,7 +1216,7 @@ $http = new React\Http\HttpServer( // an error occures e.g. on invalid chunked encoded data or an unexpected 'end' event $body->on('error', function (Exception $e) use ($resolve, &$bytes) { $resolve(new React\Http\Message\Response( - 400, + React\Http\Message\Response::STATUS_BAD_REQUEST, array( 'Content-Type' => 'text/plain' ), @@ -1272,7 +1272,7 @@ $http = new React\Http\HttpServer( $body .= 'This example does not accept chunked transfer encoding.'; return new React\Http\Message\Response( - 411, + React\Http\Message\Response::STATUS_LENGTH_REQUIRED, array( 'Content-Type' => 'text/plain' ), @@ -1281,7 +1281,7 @@ $http = new React\Http\HttpServer( } return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -1343,7 +1343,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf $body = "Your cookie value is: " . $request->getCookieParams()[$key]; return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -1352,7 +1352,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf } return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain', 'Set-Cookie' => urlencode($key) . '=' . urlencode('test;more') @@ -1410,7 +1410,7 @@ In its most simple form, you can use it like this: ```php $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) { return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -1440,7 +1440,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf return new Promise(function ($resolve, $reject) { Loop::addTimer(1.5, function() use ($resolve) { $response = new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -1487,7 +1487,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf }); return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -1568,7 +1568,7 @@ a `string` response body like this: ```php $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) { return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -1593,7 +1593,7 @@ $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterf }); return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Length' => '13', 'Content-Type' => 'text/plain', @@ -1663,7 +1663,7 @@ a custom `Server` response header like this: ```php $http = new React\Http\HttpServer(function (ServerRequestInterface $request) { return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Server' => 'PHP/3' ) @@ -1678,7 +1678,7 @@ string value like this: ```php $http = new React\Http\HttpServer(function (ServerRequestInterface $request) { return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Server' => '' ) @@ -1693,7 +1693,7 @@ like this: ```php $http = new React\Http\HttpServer(function (ServerRequestInterface $request) { return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Date' => gmdate('D, d M Y H:i:s \G\M\T') ) @@ -1708,7 +1708,7 @@ like this: ```php $http = new React\Http\HttpServer(function (ServerRequestInterface $request) { return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Date' => '' ) @@ -1786,7 +1786,7 @@ encourages [Third-Party Middleware](#third-party-middleware) implementations. In order to use middleware request handlers, simply pass a list of all callables as defined above to the [`HttpServer`](#httpserver). The following example adds a middleware request handler that adds the current time to the request as a -header (`Request-Time`) and a final request handler that always returns a 200 code without a body: +header (`Request-Time`) and a final request handler that always returns a `200 OK` status code without a body: ```php $http = new React\Http\HttpServer( @@ -1795,7 +1795,7 @@ $http = new React\Http\HttpServer( return $next($request); }, function (Psr\Http\Message\ServerRequestInterface $request) { - return new React\Http\Message\Response(200); + return new React\Http\Message\Response(React\Http\Message\Response::STATUS_OK); } ); ``` @@ -1821,7 +1821,7 @@ $http = new React\Http\HttpServer( }); }, function (Psr\Http\Message\ServerRequestInterface $request) { - return new React\Http\Message\Response(200); + return new React\Http\Message\Response(React\Http\Message\Response::STATUS_OK); } ); ``` @@ -1842,7 +1842,7 @@ $http = new React\Http\HttpServer( }); return $promise->then(null, function (Exception $e) { return new React\Http\Message\Response( - 500, + React\Http\Message\Response::STATUS_INTERNAL_SERVER_ERROR, array(), 'Internal error: ' . $e->getMessage() ); @@ -1852,7 +1852,7 @@ $http = new React\Http\HttpServer( if (mt_rand(0, 1) === 1) { throw new RuntimeException('Database error'); } - return new React\Http\Message\Response(200); + return new React\Http\Message\Response(React\Http\Message\Response::STATUS_OK); } ); ``` @@ -2439,7 +2439,7 @@ represent an outgoing server response message. ```php $response = new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/html' ), @@ -2452,6 +2452,13 @@ This class implements the which in turn extends the [PSR-7 `MessageInterface`](https://www.php-fig.org/psr/psr-7/#31-psrhttpmessagemessageinterface). +On top of this, this class implements the +[PSR-7 Message Util `StatusCodeInterface`](https://github.com/php-fig/http-message-util/blob/master/src/StatusCodeInterface.php) +which means that most common HTTP status codes are available as class +constants with the `STATUS_*` prefix. For instance, the `200 OK` and +`404 Not Found` status codes can used as `Response::STATUS_OK` and +`Response::STATUS_NOT_FOUND` respectively. + > Internally, this implementation builds on top of an existing incoming response message and only adds required streaming support. This base class is considered an implementation detail that may change in the future. @@ -2516,7 +2523,7 @@ $http = new React\Http\HttpServer( }); $body->on('close', function () use (&$bytes, $resolve) { $resolve(new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, [], "Received $bytes bytes\n" )); @@ -2653,7 +2660,7 @@ $http = new React\Http\HttpServer( new React\Http\Middleware\RequestBodyBufferMiddleware(16 * 1024 * 1024), // 16 MiB function (Psr\Http\Message\ServerRequestInterface $request) { // The body from $request->getBody() is now fully available without the need to stream it - return new React\Http\Message\Response(200); + return new React\Http\Message\Response(React\Http\Message\Response::STATUS_OK); }, ); ``` @@ -2700,7 +2707,7 @@ $handler = function (Psr\Http\Message\ServerRequestInterface $request) { } return new React\Http\Message\Response( - 200, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), diff --git a/composer.json b/composer.json index 1939accf..8a5c7df6 100644 --- a/composer.json +++ b/composer.json @@ -28,14 +28,14 @@ "require": { "php": ">=5.3.0", "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "fig/http-message-util": "^1.1", "psr/http-message": "^1.0", "react/event-loop": "^1.2", "react/promise": "^2.3 || ^1.2.1", "react/promise-stream": "^1.1", "react/socket": "^1.9", "react/stream": "^1.2", - "ringcentral/psr7": "^1.2", - "fig/http-message-util": "^1.1" + "ringcentral/psr7": "^1.2" }, "require-dev": { "clue/block-react": "^1.1", diff --git a/examples/51-server-hello-world.php b/examples/51-server-hello-world.php index 2d9dc766..88831525 100644 --- a/examples/51-server-hello-world.php +++ b/examples/51-server-hello-world.php @@ -1,6 +1,5 @@ 'text/plain' ), diff --git a/examples/52-server-count-visitors.php b/examples/52-server-count-visitors.php index 8e219ad0..bdd53af9 100644 --- a/examples/52-server-count-visitors.php +++ b/examples/52-server-count-visitors.php @@ -1,6 +1,5 @@ 'text/plain' ), diff --git a/examples/53-server-whatsmyip.php b/examples/53-server-whatsmyip.php index 14ad2da8..e0835a82 100644 --- a/examples/53-server-whatsmyip.php +++ b/examples/53-server-whatsmyip.php @@ -1,6 +1,5 @@ getServerParams()['REMOTE_ADDR']; return new Response( - StatusCodeInterface::STATUS_OK, + Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), diff --git a/examples/54-server-query-parameter.php b/examples/54-server-query-parameter.php index e3854626..18dd56b0 100644 --- a/examples/54-server-query-parameter.php +++ b/examples/54-server-query-parameter.php @@ -1,6 +1,5 @@ 'text/html' ), diff --git a/examples/55-server-cookie-handling.php b/examples/55-server-cookie-handling.php index 7a093d24..8260fc33 100644 --- a/examples/55-server-cookie-handling.php +++ b/examples/55-server-cookie-handling.php @@ -1,6 +1,5 @@ getCookieParams()[$key]; return new Response( - StatusCodeInterface::STATUS_OK, + Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -22,7 +21,7 @@ } return new Response( - StatusCodeInterface::STATUS_OK, + Response::STATUS_OK, array( 'Content-Type' => 'text/plain', 'Set-Cookie' => urlencode($key) . '=' . urlencode('test;more') diff --git a/examples/56-server-sleep.php b/examples/56-server-sleep.php index cfc805d3..6bb6f82b 100644 --- a/examples/56-server-sleep.php +++ b/examples/56-server-sleep.php @@ -1,6 +1,5 @@ 'text/plain' ), diff --git a/examples/57-server-error-handling.php b/examples/57-server-error-handling.php index 72b9c02b..71cbad15 100644 --- a/examples/57-server-error-handling.php +++ b/examples/57-server-error-handling.php @@ -1,6 +1,5 @@ 'text/plain' ), diff --git a/examples/58-server-stream-response.php b/examples/58-server-stream-response.php index 596ca6fc..015ddd9a 100644 --- a/examples/58-server-stream-response.php +++ b/examples/58-server-stream-response.php @@ -1,6 +1,5 @@ getMethod() !== 'GET' || $request->getUri()->getPath() !== '/') { - return new Response(StatusCodeInterface::STATUS_NOT_FOUND); + return new Response(Response::STATUS_NOT_FOUND); } $stream = new ThroughStream(); @@ -31,7 +30,7 @@ }); return new Response( - StatusCodeInterface::STATUS_OK, + Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), diff --git a/examples/59-server-json-api.php b/examples/59-server-json-api.php index 8a1ba358..0d50b52b 100644 --- a/examples/59-server-json-api.php +++ b/examples/59-server-json-api.php @@ -6,7 +6,6 @@ // $ php examples/59-server-json-api.php 8080 // $ curl -v http://localhost:8080/ -H 'Content-Type: application/json' -d '{"name":"Alice"}' -use Fig\Http\Message\StatusCodeInterface; use Psr\Http\Message\ServerRequestInterface; use React\Http\Message\Response; @@ -15,7 +14,7 @@ $http = new React\Http\HttpServer(function (ServerRequestInterface $request) { if ($request->getHeaderLine('Content-Type') !== 'application/json') { return new Response( - StatusCodeInterface::STATUS_UNSUPPORTED_MEDIA_TYPE, + Response::STATUS_UNSUPPORTED_MEDIA_TYPE, array( 'Content-Type' => 'application/json' ), @@ -26,7 +25,7 @@ $input = json_decode($request->getBody()->getContents()); if (json_last_error() !== JSON_ERROR_NONE) { return new Response( - StatusCodeInterface::STATUS_BAD_REQUEST, + Response::STATUS_BAD_REQUEST, array( 'Content-Type' => 'application/json' ), @@ -36,7 +35,7 @@ if (!isset($input->name) || !is_string($input->name)) { return new Response( - StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY, + Response::STATUS_UNPROCESSABLE_ENTITY, array( 'Content-Type' => 'application/json' ), @@ -45,7 +44,7 @@ } return new Response( - StatusCodeInterface::STATUS_OK, + Response::STATUS_OK, array( 'Content-Type' => 'application/json' ), diff --git a/examples/61-server-hello-world-https.php b/examples/61-server-hello-world-https.php index f563282e..2fd6f9af 100644 --- a/examples/61-server-hello-world-https.php +++ b/examples/61-server-hello-world-https.php @@ -1,6 +1,5 @@ 'text/plain' ), diff --git a/examples/62-server-form-upload.php b/examples/62-server-form-upload.php index b09f178d..899caa0a 100644 --- a/examples/62-server-form-upload.php +++ b/examples/62-server-form-upload.php @@ -7,7 +7,6 @@ // $ curl --form name=test --form age=30 http://localhost:8080/ // $ curl --form name=hi --form avatar=@avatar.png http://localhost:8080/ -use Fig\Http\Message\StatusCodeInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\UploadedFileInterface; use React\Http\Message\Response; @@ -111,7 +110,7 @@ HTML; return new Response( - StatusCodeInterface::STATUS_OK, + Response::STATUS_OK, array( 'Content-Type' => 'text/html; charset=UTF-8' ), diff --git a/examples/63-server-streaming-request.php b/examples/63-server-streaming-request.php index 073d0e0e..b20b8f08 100644 --- a/examples/63-server-streaming-request.php +++ b/examples/63-server-streaming-request.php @@ -1,7 +1,5 @@ on('end', function () use ($resolve, &$bytes){ $resolve(new React\Http\Message\Response( - StatusCodeInterface::STATUS_OK, + React\Http\Message\Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), @@ -33,7 +31,7 @@ function (Psr\Http\Message\ServerRequestInterface $request) { // an error occures e.g. on invalid chunked encoded data or an unexpected 'end' event $body->on('error', function (Exception $e) use ($resolve, &$bytes) { $resolve(new React\Http\Message\Response( - StatusCodeInterface::STATUS_BAD_REQUEST, + React\Http\Message\Response::STATUS_BAD_REQUEST, array( 'Content-Type' => 'text/plain' ), diff --git a/examples/71-server-http-proxy.php b/examples/71-server-http-proxy.php index 3029dd7f..e0bf8404 100644 --- a/examples/71-server-http-proxy.php +++ b/examples/71-server-http-proxy.php @@ -3,7 +3,6 @@ // $ php examples/71-server-http-proxy.php 8080 // $ curl -v --proxy http://localhost:8080 http://reactphp.org/ -use Fig\Http\Message\StatusCodeInterface; use Psr\Http\Message\RequestInterface; use React\Http\Message\Response; use RingCentral\Psr7; @@ -17,7 +16,7 @@ $http = new React\Http\HttpServer(function (RequestInterface $request) { if (strpos($request->getRequestTarget(), '://') === false) { return new Response( - StatusCodeInterface::STATUS_BAD_REQUEST, + Response::STATUS_BAD_REQUEST, array( 'Content-Type' => 'text/plain' ), @@ -37,7 +36,7 @@ // left up as an exercise: use an HTTP client to send the outgoing request // and forward the incoming response to the original client request return new Response( - StatusCodeInterface::STATUS_OK, + Response::STATUS_OK, array( 'Content-Type' => 'text/plain' ), diff --git a/examples/72-server-http-connect-proxy.php b/examples/72-server-http-connect-proxy.php index 55b03a84..0500822a 100644 --- a/examples/72-server-http-connect-proxy.php +++ b/examples/72-server-http-connect-proxy.php @@ -3,7 +3,6 @@ // $ php examples/72-server-http-connect-proxy.php 8080 // $ curl -v --proxy http://localhost:8080 https://reactphp.org/ -use Fig\Http\Message\StatusCodeInterface; use Psr\Http\Message\ServerRequestInterface; use React\Http\Message\Response; use React\Socket\Connector; @@ -20,7 +19,7 @@ $http = new React\Http\HttpServer(function (ServerRequestInterface $request) use ($connector) { if ($request->getMethod() !== 'CONNECT') { return new Response( - StatusCodeInterface::STATUS_METHOD_NOT_ALLOWED, + Response::STATUS_METHOD_NOT_ALLOWED, array( 'Content-Type' => 'text/plain', 'Allow' => 'CONNECT' @@ -34,14 +33,14 @@ function (ConnectionInterface $remote) { // connection established => forward data return new Response( - StatusCodeInterface::STATUS_OK, + Response::STATUS_OK, array(), $remote ); }, function (Exception $e) { return new Response( - StatusCodeInterface::STATUS_BAD_GATEWAY, + Response::STATUS_BAD_GATEWAY, array( 'Content-Type' => 'text/plain' ), diff --git a/examples/81-server-upgrade-echo.php b/examples/81-server-upgrade-echo.php index 4fa54def..cd3dc156 100644 --- a/examples/81-server-upgrade-echo.php +++ b/examples/81-server-upgrade-echo.php @@ -17,7 +17,6 @@ < world */ -use Fig\Http\Message\StatusCodeInterface; use Psr\Http\Message\ServerRequestInterface; use React\EventLoop\Loop; use React\Http\Message\Response; @@ -31,7 +30,7 @@ $http = new React\Http\HttpServer(function (ServerRequestInterface $request) { if ($request->getHeaderLine('Upgrade') !== 'echo' || $request->getProtocolVersion() === '1.0') { return new Response( - StatusCodeInterface::STATUS_UPGRADE_REQUIRED, + Response::STATUS_UPGRADE_REQUIRED, array( 'Upgrade' => 'echo' ), @@ -49,7 +48,7 @@ }); return new Response( - StatusCodeInterface::STATUS_SWITCHING_PROTOCOLS, + Response::STATUS_SWITCHING_PROTOCOLS, array( 'Upgrade' => 'echo' ), diff --git a/examples/82-server-upgrade-chat.php b/examples/82-server-upgrade-chat.php index 84117203..bd791fb0 100644 --- a/examples/82-server-upgrade-chat.php +++ b/examples/82-server-upgrade-chat.php @@ -19,7 +19,6 @@ Hint: try this with multiple connections :) */ -use Fig\Http\Message\StatusCodeInterface; use Psr\Http\Message\ServerRequestInterface; use React\EventLoop\Loop; use React\Http\Message\Response; @@ -39,7 +38,7 @@ $http = new React\Http\HttpServer(function (ServerRequestInterface $request) use ($chat) { if ($request->getHeaderLine('Upgrade') !== 'chat' || $request->getProtocolVersion() === '1.0') { return new Response( - StatusCodeInterface::STATUS_UPGRADE_REQUIRED, + Response::STATUS_UPGRADE_REQUIRED, array( 'Upgrade' => 'chat' ), @@ -77,7 +76,7 @@ }); return new Response( - StatusCodeInterface::STATUS_SWITCHING_PROTOCOLS, + Response::STATUS_SWITCHING_PROTOCOLS, array( 'Upgrade' => 'chat' ), diff --git a/examples/99-server-benchmark-download.php b/examples/99-server-benchmark-download.php index f7117aa5..6c737605 100644 --- a/examples/99-server-benchmark-download.php +++ b/examples/99-server-benchmark-download.php @@ -15,7 +15,6 @@ // $ docker run -it --rm --net=host skandyla/wrk -t8 -c10 -d20 http://localhost:8080/ use Evenement\EventEmitter; -use Fig\Http\Message\StatusCodeInterface; use Psr\Http\Message\ServerRequestInterface; use React\Http\Message\Response; use React\Stream\ReadableStreamInterface; @@ -95,7 +94,7 @@ public function getSize() switch ($request->getUri()->getPath()) { case '/': return new Response( - StatusCodeInterface::STATUS_OK, + Response::STATUS_OK, array( 'Content-Type' => 'text/html' ), @@ -108,13 +107,13 @@ public function getSize() $stream = new ChunkRepeater(str_repeat('.', 1000000), 10000); break; default: - return new Response(StatusCodeInterface::STATUS_NOT_FOUND); + return new Response(Response::STATUS_NOT_FOUND); } React\EventLoop\Loop::addTimer(0, array($stream, 'resume')); return new Response( - StatusCodeInterface::STATUS_OK, + Response::STATUS_OK, array( 'Content-Type' => 'application/octet-data', 'Content-Length' => $stream->getSize() diff --git a/src/HttpServer.php b/src/HttpServer.php index 95ccc5ff..f2334733 100644 --- a/src/HttpServer.php +++ b/src/HttpServer.php @@ -26,7 +26,7 @@ * ```php * $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) { * return new React\Http\Message\Response( - * 200, + * React\Http\Message\Response::STATUS_OK, * array( * 'Content-Type' => 'text/plain' * ), diff --git a/src/Io/RequestHeaderParser.php b/src/Io/RequestHeaderParser.php index a6136e2f..743c006c 100644 --- a/src/Io/RequestHeaderParser.php +++ b/src/Io/RequestHeaderParser.php @@ -3,8 +3,8 @@ namespace React\Http\Io; use Evenement\EventEmitter; -use Fig\Http\Message\StatusCodeInterface; use Psr\Http\Message\ServerRequestInterface; +use React\Http\Message\Response; use React\Http\Message\ServerRequest; use React\Socket\ConnectionInterface; use Exception; @@ -40,7 +40,7 @@ public function handle(ConnectionInterface $conn) $fn = null; $that->emit('error', array( - new \OverflowException("Maximum header size of {$maxSize} exceeded.", StatusCodeInterface::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE), + new \OverflowException("Maximum header size of {$maxSize} exceeded.", Response::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE), $conn )); return; @@ -128,7 +128,7 @@ public function parseRequest($headers, $remoteSocketUri, $localSocketUri) // only support HTTP/1.1 and HTTP/1.0 requests if ($start['version'] !== '1.1' && $start['version'] !== '1.0') { - throw new \InvalidArgumentException('Received request with invalid protocol version', StatusCodeInterface::STATUS_VERSION_NOT_SUPPORTED); + throw new \InvalidArgumentException('Received request with invalid protocol version', Response::STATUS_VERSION_NOT_SUPPORTED); } // match all request header fields into array, thanks to @kelunik for checking the HTTP specs and coming up with this regex @@ -257,20 +257,20 @@ public function parseRequest($headers, $remoteSocketUri, $localSocketUri) // ensure message boundaries are valid according to Content-Length and Transfer-Encoding request headers if ($request->hasHeader('Transfer-Encoding')) { if (\strtolower($request->getHeaderLine('Transfer-Encoding')) !== 'chunked') { - throw new \InvalidArgumentException('Only chunked-encoding is allowed for Transfer-Encoding', StatusCodeInterface::STATUS_NOT_IMPLEMENTED); + throw new \InvalidArgumentException('Only chunked-encoding is allowed for Transfer-Encoding', Response::STATUS_NOT_IMPLEMENTED); } // Transfer-Encoding: chunked and Content-Length header MUST NOT be used at the same time // as per https://tools.ietf.org/html/rfc7230#section-3.3.3 if ($request->hasHeader('Content-Length')) { - throw new \InvalidArgumentException('Using both `Transfer-Encoding: chunked` and `Content-Length` is not allowed', StatusCodeInterface::STATUS_BAD_REQUEST); + throw new \InvalidArgumentException('Using both `Transfer-Encoding: chunked` and `Content-Length` is not allowed', Response::STATUS_BAD_REQUEST); } } elseif ($request->hasHeader('Content-Length')) { $string = $request->getHeaderLine('Content-Length'); if ((string)(int)$string !== $string) { // Content-Length value is not an integer or not a single integer - throw new \InvalidArgumentException('The value of `Content-Length` is not valid', StatusCodeInterface::STATUS_BAD_REQUEST); + throw new \InvalidArgumentException('The value of `Content-Length` is not valid', Response::STATUS_BAD_REQUEST); } } diff --git a/src/Io/Sender.php b/src/Io/Sender.php index 6e2d661e..2f04c797 100644 --- a/src/Io/Sender.php +++ b/src/Io/Sender.php @@ -2,11 +2,11 @@ namespace React\Http\Io; -use Fig\Http\Message\StatusCodeInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use React\EventLoop\LoopInterface; use React\Http\Client\Client as HttpClient; +use React\Http\Message\Response; use React\Promise\PromiseInterface; use React\Promise\Deferred; use React\Socket\ConnectorInterface; @@ -111,7 +111,7 @@ public function send(RequestInterface $request) $requestStream->on('response', function (ResponseInterface $response, ReadableStreamInterface $body) use ($deferred, $request) { $length = null; $code = $response->getStatusCode(); - if ($request->getMethod() === 'HEAD' || ($code >= 100 && $code < 200) || $code == StatusCodeInterface::STATUS_NO_CONTENT || $code == StatusCodeInterface::STATUS_NOT_MODIFIED) { + if ($request->getMethod() === 'HEAD' || ($code >= 100 && $code < 200) || $code == Response::STATUS_NO_CONTENT || $code == Response::STATUS_NOT_MODIFIED) { $length = 0; } elseif (\strtolower($response->getHeaderLine('Transfer-Encoding')) === 'chunked') { $body = new ChunkedDecoder($body); diff --git a/src/Io/StreamingServer.php b/src/Io/StreamingServer.php index c7039f50..dd4c0584 100644 --- a/src/Io/StreamingServer.php +++ b/src/Io/StreamingServer.php @@ -3,7 +3,6 @@ namespace React\Http\Io; use Evenement\EventEmitter; -use Fig\Http\Message\StatusCodeInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use React\EventLoop\LoopInterface; @@ -32,7 +31,7 @@ * ```php * $server = new StreamingServer($loop, function (ServerRequestInterface $request) { * return new Response( - * 200, + * Response::STATUS_OK, * array( * 'Content-Type' => 'text/plain' * ), @@ -121,7 +120,7 @@ public function __construct(LoopInterface $loop, $requestHandler) // parsing failed => assume dummy request and send appropriate error $that->writeError( $conn, - $e->getCode() !== 0 ? $e->getCode() : StatusCodeInterface::STATUS_BAD_REQUEST, + $e->getCode() !== 0 ? $e->getCode() : Response::STATUS_BAD_REQUEST, new ServerRequest('GET', '/') ); }); @@ -183,7 +182,7 @@ function ($response) use ($that, $conn, $request) { $exception = new \RuntimeException($message); $that->emit('error', array($exception)); - return $that->writeError($conn, 500, $request); + return $that->writeError($conn, Response::STATUS_INTERNAL_SERVER_ERROR, $request); } $that->handleResponse($conn, $request, $response); }, @@ -200,7 +199,7 @@ function ($error) use ($that, $conn, $request) { $exception = new \RuntimeException($message, null, $previous); $that->emit('error', array($exception)); - return $that->writeError($conn, StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR, $request); + return $that->writeError($conn, Response::STATUS_INTERNAL_SERVER_ERROR, $request); } ); } @@ -263,10 +262,10 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt // assign "Content-Length" header automatically $chunked = false; - if (($method === 'CONNECT' && $code >= 200 && $code < 300) || ($code >= 100 && $code < 200) || $code === StatusCodeInterface::STATUS_NO_CONTENT) { + if (($method === 'CONNECT' && $code >= 200 && $code < 300) || ($code >= 100 && $code < 200) || $code === Response::STATUS_NO_CONTENT) { // 2xx response to CONNECT and 1xx and 204 MUST NOT include Content-Length or Transfer-Encoding header $response = $response->withoutHeader('Content-Length'); - } elseif ($code === 304 && ($response->hasHeader('Content-Length') || $body->getSize() === 0)) { + } elseif ($code === Response::STATUS_NOT_MODIFIED && ($response->hasHeader('Content-Length') || $body->getSize() === 0)) { // 304 Not Modified: preserve explicit Content-Length and preserve missing header if body is empty } elseif ($body->getSize() !== null) { // assign Content-Length header when using a "normal" buffered body string @@ -286,7 +285,7 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt // assign "Connection" header automatically $persist = false; - if ($code === StatusCodeInterface::STATUS_SWITCHING_PROTOCOLS) { + if ($code === Response::STATUS_SWITCHING_PROTOCOLS) { // 101 (Switching Protocols) response uses Connection: upgrade header // This implies that this stream now uses another protocol and we // may not persist this connection for additional requests. @@ -308,7 +307,7 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt // 101 (Switching Protocols) response (for Upgrade request) forwards upgraded data through duplex stream // 2xx (Successful) response to CONNECT forwards tunneled application data through duplex stream - if (($code === StatusCodeInterface::STATUS_SWITCHING_PROTOCOLS || ($method === 'CONNECT' && $code >= 200 && $code < 300)) && $body instanceof HttpBodyStream && $body->input instanceof WritableStreamInterface) { + if (($code === Response::STATUS_SWITCHING_PROTOCOLS || ($method === 'CONNECT' && $code >= 200 && $code < 300)) && $body instanceof HttpBodyStream && $body->input instanceof WritableStreamInterface) { if ($request->getBody()->isReadable()) { // request is still streaming => wait for request close before forwarding following data from connection $request->getBody()->on('close', function () use ($connection, $body) { @@ -334,7 +333,7 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt // response to HEAD and 1xx, 204 and 304 responses MUST NOT include a body // exclude status 101 (Switching Protocols) here for Upgrade request handling above - if ($method === 'HEAD' || $code === 100 || ($code > StatusCodeInterface::STATUS_SWITCHING_PROTOCOLS && $code < 200) || $code === StatusCodeInterface::STATUS_NO_CONTENT || $code === StatusCodeInterface::STATUS_NOT_MODIFIED) { + if ($method === 'HEAD' || ($code >= 100 && $code < 200 && $code !== Response::STATUS_SWITCHING_PROTOCOLS) || $code === Response::STATUS_NO_CONTENT || $code === Response::STATUS_NOT_MODIFIED) { $body->close(); $body = ''; } diff --git a/src/Message/Response.php b/src/Message/Response.php index 638fe02a..0cf685af 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -3,17 +3,17 @@ namespace React\Http\Message; use Fig\Http\Message\StatusCodeInterface; +use Psr\Http\Message\StreamInterface; use React\Http\Io\HttpBodyStream; use React\Stream\ReadableStreamInterface; use RingCentral\Psr7\Response as Psr7Response; -use Psr\Http\Message\StreamInterface; /** * Represents an outgoing server response message. * * ```php * $response = new React\Http\Message\Response( - * 200, + * React\Http\Message\Response::STATUS_OK, * array( * 'Content-Type' => 'text/html' * ), @@ -26,16 +26,23 @@ * which in turn extends the * [PSR-7 `MessageInterface`](https://www.php-fig.org/psr/psr-7/#31-psrhttpmessagemessageinterface). * + * On top of this, this class implements the + * [PSR-7 Message Util `StatusCodeInterface`](https://github.com/php-fig/http-message-util/blob/master/src/StatusCodeInterface.php) + * which means that most common HTTP status codes are available as class + * constants with the `STATUS_*` prefix. For instance, the `200 OK` and + * `404 Not Found` status codes can used as `Response::STATUS_OK` and + * `Response::STATUS_NOT_FOUND` respectively. + * * > Internally, this implementation builds on top of an existing incoming * response message and only adds required streaming support. This base class is * considered an implementation detail that may change in the future. * * @see \Psr\Http\Message\ResponseInterface */ -final class Response extends Psr7Response +final class Response extends Psr7Response implements StatusCodeInterface { /** - * @param int $status HTTP status code (e.g. 200/404) + * @param int $status HTTP status code (e.g. 200/404), see `self::STATUS_*` constants * @param array $headers additional response headers * @param string|ReadableStreamInterface|StreamInterface $body response body * @param string $version HTTP protocol version (e.g. 1.1/1.0) @@ -43,7 +50,7 @@ final class Response extends Psr7Response * @throws \InvalidArgumentException for an invalid body */ public function __construct( - $status = StatusCodeInterface::STATUS_OK, + $status = self::STATUS_OK, array $headers = array(), $body = '', $version = '1.1',