diff --git a/README.md b/README.md index f9244b0..83d468e 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,6 @@ composer require sunrise/http-message ## Documentation navigation -- [Headers as objects](#headers-as-objects) -- - [Implemented headers](https://github.com/sunrise-php/http-message/blob/master/docs/headers.md) - [Server request from global environment](#server-request-from-global-environment) - [HTML and JSON responses](#html-and-json-responses) - - [HTML response](#html-response) @@ -34,47 +32,7 @@ composer require sunrise/http-message ## How to use -⚠️ We highly recommend that you study [PSR-7](https://www.php-fig.org/psr/psr-7/) and [PSR-17](https://www.php-fig.org/psr/psr-17/) because only superficial examples will be presented below. - -### Headers as objects - -If you want to use headers as objects, then follow the example below: - -```php -use Sunrise\Http\Message\HeaderInterface; - -final class SomeHeader implements HeaderInterface -{ - // some code... -} - -$message->withHeader(...new SomeHeader()); -``` - -... or you can extend your header from the base header which contains the necessary methods for validation and formatting: - -```php -use Sunrise\Http\Message\Header; - -final class SomeHeader extends Header -{ - // some code... -} - -$message->withHeader(...new SomeHeader()); -``` - -Below is an example of how you can set cookies using the already implemented [Set-Cookie](https://github.com/sunrise-php/http-message/blob/master/docs/headers.md#Set-Cookie) header: - -```php -use Sunrise\Http\Message\Header\SetCookieHeader; - -$cookie = new SetCookieHeader('sessionid', '38afes7a8'); - -$message->withAddedHeader(...$cookie); -``` - -You can see already implemented headers [here](https://github.com/sunrise-php/http-message/blob/master/docs/headers.md). +We highly recommend that you study [PSR-7](https://www.php-fig.org/psr/psr-7/) and [PSR-17](https://www.php-fig.org/psr/psr-17/) because only superficial examples will be presented below. ### Server request from global environment @@ -106,7 +64,7 @@ use Sunrise\Http\Message\Response\JsonResponse; $response = new JsonResponse(200, $data); ``` -You can also specify [encoding flags](https://www.php.net/manual/en/json.constants.php#constant.json-hex-tag) and maximum nesting depth like bellow: +You can also specify [encoding flags](https://www.php.net/manual/en/json.constants.php#constant.json-hex-tag) and maximum nesting depth like below: ```php $response = new JsonResponse(200, $data, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE, 512); @@ -144,7 +102,7 @@ $memoryStream = new PhpMemoryStream('r+b'); #### PHP temporary stream -More details about the stream at [the official page](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory). +More details about the stream at the [official page](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory). ```php use Sunrise\Http\Message\Stream\PhpTempStream; @@ -177,6 +135,17 @@ $tmpfileStream = new TmpfileStream(); $tmpfileStream->getMetadata('uri'); ``` +If you don't need the above behavior, you can use another temporary file stream: + +```php +use Sunrise\Http\Message\Stream\TempFileStream; + +$tempFileStream = new TempFileStream(); + +// Returns the file path... +$tempFileStream->getMetadata('uri'); +``` + ### PSR-7 and PSR-17 The following classes implement PSR-7: @@ -205,9 +174,9 @@ Any exceptions of this package can be caught through the interface: use Sunrise\Http\Message\Exception\ExceptionInterface; try { - // some code with the package... + // some code... } catch (ExceptionInterface $e) { - // the package error... + // some logic... } ``` diff --git a/composer.json b/composer.json index 3a6b2da..6600e85 100644 --- a/composer.json +++ b/composer.json @@ -7,10 +7,10 @@ "fenric", "sunrise", "http", + "header", "message", "request", "response", - "header", "stream", "uri", "upload", @@ -60,7 +60,8 @@ "scripts": { "test": [ "phpcs", - "psalm", + "psalm --no-cache", + "phpstan analyse src --level=9", "XDEBUG_MODE=coverage phpunit --coverage-text --colors=always" ], "build": [ diff --git a/docs/headers.md b/docs/headers.md deleted file mode 100644 index 44f2d71..0000000 --- a/docs/headers.md +++ /dev/null @@ -1,618 +0,0 @@ -### HTTP Headers - -#### Access-Control-Allow-Credentials - -> Usage link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials - -```php -use Sunrise\Http\Message\Header\AccessControlAllowCredentialsHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new AccessControlAllowCredentialsHeader(); -$response = $response->withHeader(...$header); -``` - -#### Access-Control-Allow-Headers - -> Usage link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers - -```php -use Sunrise\Http\Message\Header\AccessControlAllowHeadersHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new AccessControlAllowHeadersHeader('X-Custom-Header', 'Upgrade-Insecure-Requests'); -$response = $response->withHeader(...$header); -``` - -#### Access-Control-Allow-Methods - -> Usage link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods - -```php -use Sunrise\Http\Message\Header\AccessControlAllowMethodsHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new AccessControlAllowMethodsHeader('OPTIONS', 'HEAD', 'GET'); -$response = $response->withHeader(...$header); -``` - -#### Access-Control-Allow-Origin - -> Usage link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin - -```php -use Sunrise\Http\Message\Header\AccessControlAllowOriginHeader; -use Sunrise\Http\Message\ResponseFactory; -use Sunrise\Uri\UriFactory; - -$response = (new ResponseFactory)->createResponse(); - -// A response that tells the browser to allow code from any origin to access -// a resource will include the following: -$header = new AccessControlAllowOriginHeader(null); -$response = $response->withHeader(...$header); - -// A response that tells the browser to allow requesting code from the origin -// https://developer.mozilla.org to access a resource will include the following: -$uri = (new UriFactory)->createUri('https://developer.mozilla.org'); -$header = new AccessControlAllowOriginHeader($uri); -$response = $response->withHeader(...$header); -``` - -#### Access-Control-Expose-Headers - -> Usage link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers - -```php -use Sunrise\Http\Message\Header\AccessControlExposeHeadersHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new AccessControlExposeHeadersHeader('Content-Length', 'X-Kuma-Revision'); -$response = $response->withHeader(...$header); -``` - -#### Access-Control-Max-Age - -> Usage link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age - -```php -use Sunrise\Http\Message\Header\AccessControlMaxAgeHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new AccessControlMaxAgeHeader(600); -$response = $response->withHeader(...$header); -``` - -#### Age - -> Usage link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Age - -```php -use Sunrise\Http\Message\Header\AgeHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new AgeHeader(24); -$response = $response->withHeader(...$header); -``` - -#### Allow - -> Usage link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Allow - -```php -use Sunrise\Http\Message\Header\AllowHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new AllowHeader('OPTIONS', 'HEAD', 'GET'); -$response = $response->withHeader(...$header); -``` - -#### Cache-Control - -> Usage link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control - -```php -use Sunrise\Http\Message\Header\CacheControlHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -// Preventing caching -$header = new CacheControlHeader(['no-cache' => '', 'no-store' => '', 'must-revalidate' => '']); -$response = $response->withHeader(...$header); - -// Caching static assets -$header = new CacheControlHeader(['public' => '', 'max-age' => '31536000']); -$response = $response->withHeader(...$header); -``` - -#### Clear-Site-Data - -> Usage link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data - -```php -use Sunrise\Http\Message\Header\ClearSiteDataHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -// Single directive -$header = new ClearSiteDataHeader(['cache']); -$response = $response->withHeader(...$header); - -// Multiple directives (comma separated) -$header = new ClearSiteDataHeader(['cache', 'cookies']); -$response = $response->withHeader(...$header); - -// Wild card -$header = new ClearSiteDataHeader(['*']); -$response = $response->withHeader(...$header); -``` - -#### Connection - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection - -```php -use Sunrise\Http\Message\Header\ConnectionHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -// close -$header = new ConnectionHeader(ConnectionHeader::CONNECTION_CLOSE); -$response = $response->withHeader(...$header); - -// keep-alive -$header = new ConnectionHeader(ConnectionHeader::CONNECTION_KEEP_ALIVE); -$response = $response->withHeader(...$header); -``` - -#### Content-Disposition - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition - -```php -use Sunrise\Http\Message\Header\ContentDispositionHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -// As a response header for the main body -$header = new ContentDispositionHeader('attachment', ['filename' => 'filename.jpg']); -$response = $response->withHeader(...$header); - -// As a header for a multipart body -$header = new ContentDispositionHeader('form-data', ['name' => 'fieldName', 'filename' => 'filename.jpg']); -$response = $response->withHeader(...$header); -``` - -#### Content-Encoding - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding - -```php -use Sunrise\Http\Message\Header\ContentEncodingHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new ContentEncodingHeader('gzip'); -$response = $response->withHeader(...$header); -``` - -#### Content-Language - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language - -```php -use Sunrise\Http\Message\Header\ContentLanguageHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new ContentLanguageHeader('de-DE', 'en-CA'); -$response = $response->withHeader(...$header); -``` - -#### Content-Length - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length - -```php -use Sunrise\Http\Message\Header\ContentLengthHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new ContentLengthHeader(4096); -$response = $response->withHeader(...$header); -``` - -#### Content-Location - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Location - -```php -use Sunrise\Http\Message\Header\ContentLocationHeader; -use Sunrise\Http\Message\ResponseFactory; -use Sunrise\Uri\UriFactory; - -$response = (new ResponseFactory)->createResponse(); - -$uri = (new UriFactory)->createUri('https://example.com/documents/foo'); -$header = new ContentLocationHeader($uri); -$response = $response->withHeader(...$header); -``` - -#### Content-MD5 - -> Useful link: https://tools.ietf.org/html/rfc1864 - -```php -use Sunrise\Http\Message\Header\ContentMD5Header; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new ContentMD5Header('MzAyMWU2OGRmOWE3MjAwMTM1NzI1YzYzMzEzNjlhMjI='); -$response = $response->withHeader(...$header); -``` - -#### Content-Range - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range - -```php -use Sunrise\Http\Message\Header\ContentRangeHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new ContentRangeHeader( - 200, // An integer in the given unit indicating the beginning of the request range. - 1000, // An integer in the given unit indicating the end of the requested range. - 67589 // The total size of the document. -); -$response = $response->withHeader(...$header); -``` - -#### Content-Security-Policy - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy - -```php -use Sunrise\Http\Message\Header\ContentSecurityPolicyHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -// Pre-existing site that uses too much inline code to fix but wants -// to ensure resources are loaded only over https and disable plugins: -$header = new ContentSecurityPolicyHeader(['default-src' => "https: 'unsafe-eval' 'unsafe-inline'", 'object-src' => "'none'"]); -$response = $response->withAddedHeader(...$header); - -// Don't implement the above policy yet; instead just report -// violations that would have occurred: -$header = new ContentSecurityPolicyHeader(['default-src' => 'https:', 'report-uri' => '/csp-violation-report-endpoint/']); -$response = $response->withAddedHeader(...$header); -``` - -#### Content-Security-Policy-Report-Only - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only - -```php -use Sunrise\Http\Message\Header\ContentSecurityPolicyReportOnlyHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -// This header reports violations that would have occurred. -// You can use this to iteratively work on your content security policy. -// You observe how your site behaves, watching for violation reports, -// then choose the desired policy enforced by the Content-Security-Policy header. -$header = new ContentSecurityPolicyReportOnlyHeader(['default-src' => 'https:', 'report-uri' => '/csp-violation-report-endpoint/']); -$response = $response->withAddedHeader(...$header); - -// If you still want to receive reporting, but also want -// to enforce a policy, use the Content-Security-Policy header with the report-uri directive. -$header = new ContentSecurityPolicyReportOnlyHeader(['default-src' => 'https:', 'report-uri' => '/csp-violation-report-endpoint/']); -$response = $response->withAddedHeader(...$header); -``` - -#### Content-Type - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type - -```php -use Sunrise\Http\Message\Header\ContentTypeHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new ContentTypeHeader('application/json', ['charset' => 'utf-8']); -$response = $response->withHeader(...$header); -``` - -#### Cookie - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie - -```php -use Sunrise\Http\Message\Header\CookieHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new CookieHeader(['name' => 'value', 'name2' => 'value2', 'name3' => 'value3']); -$response = $response->withHeader(...$header); -``` - -#### Date - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Date - -```php -use DateTime; -use Sunrise\Http\Message\Header\DateHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new DateHeader(new DateTime('now')); -$response = $response->withHeader(...$header); -``` - -#### Etag - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag - -```php -use Sunrise\Http\Message\Header\EtagHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new EtagHeader('33a64df551425fcc55e4d42a148795d9f25f89d4'); -$response = $response->withHeader(...$header); -``` - -#### Expires - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires - -```php -use DateTime; -use Sunrise\Http\Message\Header\ExpiresHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new ExpiresHeader(new DateTime('1 day ago')); -$response = $response->withHeader(...$header); -``` - -#### Keep-Alive - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive - -```php -use Sunrise\Http\Message\Header\KeepAliveHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new KeepAliveHeader(['timeout' => '5', 'max' => '1000']); -$response = $response->withHeader(...$header); -``` - -#### Last-Modified - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified - -```php -use DateTime; -use Sunrise\Http\Message\Header\LastModifiedHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new LastModifiedHeader(new DateTime('1 year ago')); -$response = $response->withHeader(...$header); -``` - -#### Link - -> Useful link: https://www.w3.org/wiki/LinkHeader - -```php -use Sunrise\Http\Message\Header\LinkHeader; -use Sunrise\Http\Message\ResponseFactory; -use Sunrise\Uri\UriFactory; - -$response = (new ResponseFactory)->createResponse(); - -$uri = (new UriFactory)->createUri('meta.rdf'); -$header = new LinkHeader($uri, ['rel' => 'meta']); -$response = $response->withHeader(...$header); -``` - -#### Location - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location - -```php -use Sunrise\Http\Message\Header\LocationHeader; -use Sunrise\Http\Message\ResponseFactory; -use Sunrise\Uri\UriFactory; - -$response = (new ResponseFactory)->createResponse(); - -$uri = (new UriFactory)->createUri('/'); -$header = new LocationHeader($uri); -$response = $response->withHeader(...$header); -``` - -#### Refresh - -> Useful link: https://en.wikipedia.org/wiki/Meta_refresh - -```php -use Sunrise\Http\Message\Header\RefreshHeader; -use Sunrise\Http\Message\ResponseFactory; -use Sunrise\Uri\UriFactory; - -$response = (new ResponseFactory)->createResponse(); - -$uri = (new UriFactory)->createUri('/login'); -$header = new RefreshHeader(3, $uri); -$response = $response->withHeader(...$header); -``` - -#### Retry-After - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After - -```php -use DateTime; -use Sunrise\Http\Message\Header\RetryAfterHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new RetryAfterHeader(new DateTime('+30 second')); -$response = $response->withHeader(...$header); -``` - -#### Set-Cookie - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie - -```php -use DateTime; -use Sunrise\Http\Message\Header\SetCookieHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -// Session cookie -// Session cookies will get removed when the client is shut down. -// They don't specify the Expires or Max-Age directives. -// Note that web browser have often enabled session restoring. -$header = new SetCookieHeader('sessionid', '38afes7a8', null, ['path' => '/', 'httponly' => true]); -$response = $response->withAddedHeader(...$header); - -// Permanent cookie -// Instead of expiring when the client is closed, permanent cookies expire -// at a specific date (Expires) or after a specific length of time (Max-Age). -$header = new SetCookieHeader('id', 'a3fWa', new DateTime('+1 day'), ['secure' => true, 'httponly' => true]); -$response = $response->withAddedHeader(...$header); - -// Invalid domains -// A cookie belonging to a domain that does not include the origin server -// should be rejected by the user agent. The following cookie will be rejected -// if it was set by a server hosted on originalcompany.com. -$header = new SetCookieHeader('qwerty', '219ffwef9w0f', new DateTime('+1 day'), ['domain' => 'somecompany.co.uk', 'path' => '/']); -$response = $response->withAddedHeader(...$header); -``` - -#### Sunset - -> Useful link: https://tools.ietf.org/id/draft-wilde-sunset-header-03.html - -```php -use DateTime; -use Sunrise\Http\Message\Header\SunsetHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new SunsetHeader(new DateTime('2038-01-19 03:14:07')); -$response = $response->withHeader(...$header); -``` - -#### Trailer - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer - -```php -use Sunrise\Http\Message\Header\TrailerHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new TrailerHeader('Expires', 'X-Streaming-Error'); -$response = $response->withHeader(...$header); -``` - -#### Transfer-Encoding - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding - -```php -use Sunrise\Http\Message\Header\TransferEncodingHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new TransferEncodingHeader('gzip', 'chunked'); -$response = $response->withHeader(...$header); -``` - -#### Vary - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary - -```php -use Sunrise\Http\Message\Header\VaryHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new VaryHeader('User-Agent', 'Content-Language'); -$response = $response->withHeader(...$header); -``` - -#### WWW-Authenticate - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate - -```php -use Sunrise\Http\Message\Header\WWWAuthenticateHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new WWWAuthenticateHeader(WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_BASIC, ['realm' => 'Access to the staging site', 'charset' => 'UTF-8']); -$response = $response->withHeader(...$header); -``` - -#### Warning - -> Useful link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Warning - -```php -use DateTime; -use Sunrise\Http\Message\Header\WarningHeader; -use Sunrise\Http\Message\ResponseFactory; - -$response = (new ResponseFactory)->createResponse(); - -$header = new WarningHeader(WarningHeader::HTTP_WARNING_CODE_RESPONSE_IS_STALE, 'anderson/1.3.37', 'Response is stale', new DateTime('now')); -$response = $response->withHeader(...$header); -``` diff --git a/functions/server_request_files.php b/functions/server_request_files.php index ce8d050..2f53581 100644 --- a/functions/server_request_files.php +++ b/functions/server_request_files.php @@ -24,14 +24,17 @@ /** * Import constants */ +use const UPLOAD_ERR_OK; use const UPLOAD_ERR_NO_FILE; /** - * Gets the request uploaded files + * Gets the request's uploaded files * - * Note that not sent files will not be handled. + * Please note that unsent files will not be handled, + * also note that if a file fails to upload successfully, + * a stream will not be created for it. * - * @param array|null $rawUploadedFiles + * @param array|null $files * * @return array * @@ -40,19 +43,29 @@ * @link https://www.php.net/manual/ru/features.file-upload.multiple.php * @link https://github.com/php/php-src/blob/8c5b41cefb88b753c630b731956ede8d9da30c5d/main/rfc1867.c */ -function server_request_files(?array $rawUploadedFiles = null): array +function server_request_files(?array $files = null): array { - $rawUploadedFiles ??= $_FILES; + $files ??= $_FILES; - $walker = function ($path, $size, $error, $name, $type) use (&$walker) { - if (! is_array($path)) { - return new UploadedFile(new FileStream($path, 'rb'), $size, $error, $name, $type); + $walker = static function ($path, $size, $error, $name, $type) use (&$walker) { + if (!is_array($path)) { + // It makes no sense to create a stream + // if the file has not been successfully uploaded. + $stream = UPLOAD_ERR_OK <> $error ? null : new FileStream($path, 'rb'); + + return new UploadedFile($stream, $size, $error, $name, $type); } $result = []; foreach ($path as $key => $_) { if (UPLOAD_ERR_NO_FILE <> $error[$key]) { - $result[$key] = $walker($path[$key], $size[$key], $error[$key], $name[$key], $type[$key]); + $result[$key] = $walker( + $path[$key], + $size[$key], + $error[$key], + $name[$key], + $type[$key] + ); } } @@ -60,9 +73,15 @@ function server_request_files(?array $rawUploadedFiles = null): array }; $result = []; - foreach ($rawUploadedFiles as $key => $file) { + foreach ($files as $key => $file) { if (UPLOAD_ERR_NO_FILE <> $file['error']) { - $result[$key] = $walker($file['tmp_name'], $file['size'], $file['error'], $file['name'], $file['type']); + $result[$key] = $walker( + $file['tmp_name'], + $file['size'], + $file['error'], + $file['name'], + $file['type'] + ); } } diff --git a/functions/server_request_method.php b/functions/server_request_method.php index 8ebcb21..34c544a 100644 --- a/functions/server_request_method.php +++ b/functions/server_request_method.php @@ -11,6 +11,11 @@ namespace Sunrise\Http\Message; +/** + * Import classes + */ +use Fig\Http\Message\RequestMethodInterface; + /** * Gets the request method * @@ -25,5 +30,5 @@ function server_request_method(?array $serverParams = null): string { $serverParams ??= $_SERVER; - return $serverParams['REQUEST_METHOD'] ?? Request::METHOD_GET; + return $serverParams['REQUEST_METHOD'] ?? RequestMethodInterface::METHOD_GET; } diff --git a/functions/server_request_protocol_version.php b/functions/server_request_protocol_version.php index 2edc6ab..fdff200 100644 --- a/functions/server_request_protocol_version.php +++ b/functions/server_request_protocol_version.php @@ -18,7 +18,7 @@ use function sscanf; /** - * Gets the request protocol version + * Gets the request's protocol version * * @param array|null $serverParams * diff --git a/src/Exception/FailedStreamOperationException.php b/src/Exception/FailedStreamOperationException.php deleted file mode 100644 index 30e6369..0000000 --- a/src/Exception/FailedStreamOperationException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * FailedStreamOperationException - */ -class FailedStreamOperationException extends RuntimeException -{ -} diff --git a/src/Exception/FailedUploadedFileOperationException.php b/src/Exception/FailedUploadedFileOperationException.php deleted file mode 100644 index 9046ded..0000000 --- a/src/Exception/FailedUploadedFileOperationException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * FailedUploadedFileOperationException - */ -class FailedUploadedFileOperationException extends RuntimeException -{ -} diff --git a/src/Exception/InvalidHeaderException.php b/src/Exception/InvalidHeaderException.php deleted file mode 100644 index 5a60100..0000000 --- a/src/Exception/InvalidHeaderException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * InvalidHeaderException - */ -class InvalidHeaderException extends InvalidArgumentException -{ -} diff --git a/src/Exception/InvalidHeaderNameException.php b/src/Exception/InvalidHeaderNameException.php deleted file mode 100644 index 8e3b545..0000000 --- a/src/Exception/InvalidHeaderNameException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * InvalidHeaderNameException - */ -class InvalidHeaderNameException extends InvalidHeaderException -{ -} diff --git a/src/Exception/InvalidHeaderValueException.php b/src/Exception/InvalidHeaderValueException.php deleted file mode 100644 index 571182d..0000000 --- a/src/Exception/InvalidHeaderValueException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * InvalidHeaderValueException - */ -class InvalidHeaderValueException extends InvalidHeaderException -{ -} diff --git a/src/Exception/InvalidHeaderValueParameterException.php b/src/Exception/InvalidHeaderValueParameterException.php deleted file mode 100644 index b537bba..0000000 --- a/src/Exception/InvalidHeaderValueParameterException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * InvalidHeaderValueParameterException - */ -class InvalidHeaderValueParameterException extends InvalidHeaderValueException -{ -} diff --git a/src/Exception/InvalidStreamException.php b/src/Exception/InvalidStreamException.php deleted file mode 100644 index bada40e..0000000 --- a/src/Exception/InvalidStreamException.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * InvalidStreamException - */ -class InvalidStreamException extends RuntimeException -{ - - /** - * @return self - */ - final public static function noResource(): self - { - return new self('The stream without a resource so the operation is not possible'); - } -} diff --git a/src/Exception/InvalidStreamOperationException.php b/src/Exception/InvalidStreamOperationException.php deleted file mode 100644 index 093af94..0000000 --- a/src/Exception/InvalidStreamOperationException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * InvalidStreamOperationException - */ -class InvalidStreamOperationException extends RuntimeException -{ -} diff --git a/src/Exception/InvalidUploadedFileException.php b/src/Exception/InvalidUploadedFileException.php deleted file mode 100644 index 38293e5..0000000 --- a/src/Exception/InvalidUploadedFileException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * InvalidUploadedFileException - */ -class InvalidUploadedFileException extends RuntimeException -{ -} diff --git a/src/Exception/InvalidUploadedFileOperationException.php b/src/Exception/InvalidUploadedFileOperationException.php deleted file mode 100644 index cf481db..0000000 --- a/src/Exception/InvalidUploadedFileOperationException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * InvalidUploadedFileOperationException - */ -class InvalidUploadedFileOperationException extends RuntimeException -{ -} diff --git a/src/Exception/InvalidUriComponentException.php b/src/Exception/InvalidUriComponentException.php deleted file mode 100644 index faa43a6..0000000 --- a/src/Exception/InvalidUriComponentException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * InvalidUriComponentException - */ -class InvalidUriComponentException extends InvalidUriException -{ -} diff --git a/src/Exception/InvalidUriException.php b/src/Exception/InvalidUriException.php deleted file mode 100644 index 707d3db..0000000 --- a/src/Exception/InvalidUriException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Exception; - -/** - * InvalidUriException - */ -class InvalidUriException extends InvalidArgumentException -{ -} diff --git a/src/Header.php b/src/Header.php deleted file mode 100644 index abd8846..0000000 --- a/src/Header.php +++ /dev/null @@ -1,258 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Exception\InvalidHeaderValueParameterException; -use ArrayIterator; -use DateTime; -use DateTimeImmutable; -use DateTimeInterface; -use DateTimeZone; -use Traversable; - -/** - * Import functions - */ -use function gettype; -use function is_int; -use function is_string; -use function preg_match; -use function sprintf; - -/** - * HTTP Header Field - */ -abstract class Header implements HeaderInterface -{ - - /** - * Regular Expression for a token validation - * - * @link https://tools.ietf.org/html/rfc7230#section-3.2 - * - * @var string - */ - public const RFC7230_VALID_TOKEN = '/^[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]+$/'; - - /** - * Regular Expression for a field value validation - * - * @link https://tools.ietf.org/html/rfc7230#section-3.2 - * - * @var string - */ - public const RFC7230_VALID_FIELD_VALUE = '/^[\x09\x20-\x7E\x80-\xFF]*$/'; - - /** - * Regular Expression for a quoted string validation - * - * @link https://tools.ietf.org/html/rfc7230#section-3.2 - * - * @var string - */ - public const RFC7230_VALID_QUOTED_STRING = '/^[\x09\x20\x21\x23-\x5B\x5D-\x7E\x80-\xFF]*$/'; - - /** - * Date and time format - * - * @link https://www.rfc-editor.org/rfc/rfc822#section-5 - * - * @var string - */ - public const RFC822_DATE_TIME_FORMAT = 'D, d M y H:i:s O'; - - /** - * {@inheritdoc} - */ - final public function getIterator(): Traversable - { - return new ArrayIterator([$this->getFieldName(), $this->getFieldValue()]); - } - - /** - * {@inheritdoc} - */ - final public function __toString(): string - { - return sprintf('%s: %s', $this->getFieldName(), $this->getFieldValue()); - } - - /** - * Checks if the given string is a token - * - * @param string $token - * - * @return bool - */ - final protected function isToken(string $token): bool - { - return preg_match(self::RFC7230_VALID_TOKEN, $token) === 1; - } - - /** - * Validates the given token(s) - * - * @param string ...$tokens - * - * @return void - * - * @throws InvalidHeaderValueException - * If one of the tokens isn't valid. - */ - final protected function validateToken(string ...$tokens): void - { - $this->validateValueByRegex(self::RFC7230_VALID_TOKEN, ...$tokens); - } - - /** - * Validates the given field value(s) - * - * @param string ...$fieldValues - * - * @return void - * - * @throws InvalidHeaderValueException - * If one of the field values isn't valid. - */ - final protected function validateFieldValue(string ...$fieldValues): void - { - $this->validateValueByRegex(self::RFC7230_VALID_FIELD_VALUE, ...$fieldValues); - } - - /** - * Validates the given quoted string(s) - * - * @param string ...$quotedStrings - * - * @return void - * - * @throws InvalidHeaderValueException - * If one of the quoted strings isn't valid. - */ - final protected function validateQuotedString(string ...$quotedStrings): void - { - $this->validateValueByRegex(self::RFC7230_VALID_QUOTED_STRING, ...$quotedStrings); - } - - /** - * Validates and normalizes the given parameters - * - * @param array $parameters - * - * @return array - * The normalized parameters. - * - * @throws InvalidHeaderValueParameterException - * If one of the parameters isn't valid. - */ - final protected function validateParameters(array $parameters): array - { - return $this->validateParametersByRegex( - $parameters, - self::RFC7230_VALID_TOKEN, - self::RFC7230_VALID_QUOTED_STRING - ); - } - - /** - * Validates the given value(s) by the given regular expression - * - * @param string $regex - * @param string ...$values - * - * @return void - * - * @throws InvalidHeaderValueException - * If one of the values isn't valid. - */ - final protected function validateValueByRegex(string $regex, string ...$values): void - { - foreach ($values as $value) { - if (!preg_match($regex, $value)) { - throw new InvalidHeaderValueException(sprintf( - 'The value "%2$s" for the header "%1$s" is not valid', - $this->getFieldName(), - $value - )); - } - } - } - - /** - * Validates and normalizes the given parameters by the given regular expressions - * - * @param array $parameters - * @param string $nameRegex - * @param string $valueRegex - * - * @return array - * The normalized parameters. - * - * @throws InvalidHeaderValueParameterException - * If one of the parameters isn't valid. - */ - final protected function validateParametersByRegex(array $parameters, string $nameRegex, string $valueRegex): array - { - foreach ($parameters as $name => &$value) { - if (!is_string($name) || !preg_match($nameRegex, $name)) { - throw new InvalidHeaderValueParameterException(sprintf( - 'The parameter name "%2$s" for the header "%1$s" is not valid', - $this->getFieldName(), - (is_string($name) ? $name : ('<' . gettype($name) . '>')) - )); - } - - // e.g. Cache-Control: max-age=31536000 - if (is_int($value)) { - $value = (string) $value; - } - - if (!is_string($value) || !preg_match($valueRegex, $value)) { - throw new InvalidHeaderValueParameterException(sprintf( - 'The parameter value "%2$s" for the header "%1$s" is not valid', - $this->getFieldName(), - (is_string($value) ? $value : ('<' . gettype($value) . '>')) - )); - } - } - - /** @var array $parameters */ - - return $parameters; - } - - /** - * Formats the given date-time object - * - * @link https://tools.ietf.org/html/rfc7230#section-3.2 - * - * @param DateTimeInterface $dateTime - * - * @return string - */ - final protected function formatDateTime(DateTimeInterface $dateTime): string - { - if ($dateTime instanceof DateTime) { - return (clone $dateTime) - ->setTimezone(new DateTimeZone('GMT')) - ->format(self::RFC822_DATE_TIME_FORMAT); - } - - return $dateTime - ->setTimezone(new DateTimeZone('GMT')) - ->format(self::RFC822_DATE_TIME_FORMAT); - } -} diff --git a/src/Header/AccessControlAllowCredentialsHeader.php b/src/Header/AccessControlAllowCredentialsHeader.php deleted file mode 100644 index c96232a..0000000 --- a/src/Header/AccessControlAllowCredentialsHeader.php +++ /dev/null @@ -1,40 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Header; - -/** - * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials - */ -class AccessControlAllowCredentialsHeader extends Header -{ - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Access-Control-Allow-Credentials'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return 'true'; - } -} diff --git a/src/Header/AccessControlAllowHeadersHeader.php b/src/Header/AccessControlAllowHeadersHeader.php deleted file mode 100644 index 70d3d7e..0000000 --- a/src/Header/AccessControlAllowHeadersHeader.php +++ /dev/null @@ -1,68 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; - -/** - * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers - */ -class AccessControlAllowHeadersHeader extends Header -{ - - /** - * @var list - */ - private array $headers; - - /** - * Constructor of the class - * - * @param string ...$headers - * - * @throws InvalidHeaderValueException - * If one of the header names isn't valid. - */ - public function __construct(string ...$headers) - { - /** @var list $headers */ - - $this->validateToken(...$headers); - - $this->headers = $headers; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Access-Control-Allow-Headers'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return implode(', ', $this->headers); - } -} diff --git a/src/Header/AccessControlAllowMethodsHeader.php b/src/Header/AccessControlAllowMethodsHeader.php deleted file mode 100644 index ed8ab4b..0000000 --- a/src/Header/AccessControlAllowMethodsHeader.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; -use function strtoupper; - -/** - * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods - */ -class AccessControlAllowMethodsHeader extends Header -{ - - /** - * @var list - */ - private array $methods = []; - - /** - * Constructor of the class - * - * @param string ...$methods - * - * @throws InvalidHeaderValueException - * If one of the methods isn't valid. - */ - public function __construct(string ...$methods) - { - /** @var list $methods */ - - $this->validateToken(...$methods); - - // normalize the list of methods... - foreach ($methods as $method) { - $this->methods[] = strtoupper($method); - } - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Access-Control-Allow-Methods'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return implode(', ', $this->methods); - } -} diff --git a/src/Header/AccessControlAllowOriginHeader.php b/src/Header/AccessControlAllowOriginHeader.php deleted file mode 100644 index 02defb6..0000000 --- a/src/Header/AccessControlAllowOriginHeader.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Psr\Http\Message\UriInterface; -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Exception\InvalidUriException; -use Sunrise\Http\Message\Header; -use Sunrise\Http\Message\Uri; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin - */ -class AccessControlAllowOriginHeader extends Header -{ - - /** - * @var UriInterface|null - */ - private ?UriInterface $uri = null; - - /** - * Constructor of the class - * - * @param mixed $uri - * - * @throws InvalidUriException - * If the URI isn't valid. - * - * @throws InvalidHeaderValueException - * If the URI isn't valid. - */ - public function __construct($uri = null) - { - if (isset($uri)) { - $uri = Uri::create($uri); - $this->validateUri($uri); - $this->uri = $uri; - } - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Access-Control-Allow-Origin'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - if (!isset($this->uri)) { - return '*'; - } - - $origin = $this->uri->getScheme() . ':'; - $origin .= '//' . $this->uri->getHost(); - - $port = $this->uri->getPort(); - if (isset($port)) { - $origin .= ':' . $port; - } - - return $origin; - } - - /** - * Validates the given URI - * - * @param UriInterface $uri - * - * @return void - * - * @throws InvalidHeaderValueException - * If the URI isn't valid. - */ - private function validateUri(UriInterface $uri): void - { - if ($uri->getScheme() === '' || $uri->getHost() === '') { - throw new InvalidHeaderValueException(sprintf( - 'The URI "%2$s" for the header "%1$s" is not valid', - $this->getFieldName(), - $uri->__toString() - )); - } - } -} diff --git a/src/Header/AccessControlExposeHeadersHeader.php b/src/Header/AccessControlExposeHeadersHeader.php deleted file mode 100644 index 999c974..0000000 --- a/src/Header/AccessControlExposeHeadersHeader.php +++ /dev/null @@ -1,68 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; - -/** - * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers - */ -class AccessControlExposeHeadersHeader extends Header -{ - - /** - * @var list - */ - private array $headers; - - /** - * Constructor of the class - * - * @param string ...$headers - * - * @throws InvalidHeaderValueException - * If one of the header names isn't valid. - */ - public function __construct(string ...$headers) - { - /** @var list $headers */ - - $this->validateToken(...$headers); - - $this->headers = $headers; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Access-Control-Expose-Headers'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return implode(', ', $this->headers); - } -} diff --git a/src/Header/AccessControlMaxAgeHeader.php b/src/Header/AccessControlMaxAgeHeader.php deleted file mode 100644 index fa6d361..0000000 --- a/src/Header/AccessControlMaxAgeHeader.php +++ /dev/null @@ -1,87 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age - */ -class AccessControlMaxAgeHeader extends Header -{ - - /** - * @var int - */ - private int $value; - - /** - * Constructor of the class - * - * @param int $value - * - * @throws InvalidHeaderValueException - * If the value isn't valid. - */ - public function __construct(int $value) - { - $this->validateValue($value); - - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Access-Control-Max-Age'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return sprintf('%d', $this->value); - } - - /** - * Validates the given value - * - * @param int $value - * - * @return void - * - * @throws InvalidHeaderValueException - * If the value isn't valid. - */ - private function validateValue(int $value): void - { - if (! ($value === -1 || $value >= 1)) { - throw new InvalidHeaderValueException(sprintf( - 'The value "%2$d" for the header "%1$s" is not valid.', - $this->getFieldName(), - $value - )); - } - } -} diff --git a/src/Header/AgeHeader.php b/src/Header/AgeHeader.php deleted file mode 100644 index faa4a60..0000000 --- a/src/Header/AgeHeader.php +++ /dev/null @@ -1,87 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.6 - */ -class AgeHeader extends Header -{ - - /** - * @var int - */ - private int $value; - - /** - * Constructor of the class - * - * @param int $value - * - * @throws InvalidHeaderValueException - * If the value isn't valid. - */ - public function __construct(int $value) - { - $this->validateValue($value); - - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Age'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return sprintf('%d', $this->value); - } - - /** - * Validates the given value - * - * @param int $value - * - * @return void - * - * @throws InvalidHeaderValueException - * If the value isn't valid. - */ - private function validateValue(int $value): void - { - if (! ($value >= 0)) { - throw new InvalidHeaderValueException(sprintf( - 'The value "%2$d" for the header "%1$s" is not valid', - $this->getFieldName(), - $value - )); - } - } -} diff --git a/src/Header/AllowHeader.php b/src/Header/AllowHeader.php deleted file mode 100644 index fc943c4..0000000 --- a/src/Header/AllowHeader.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; -use function strtoupper; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.7 - */ -class AllowHeader extends Header -{ - - /** - * @var list - */ - private array $methods = []; - - /** - * Constructor of the class - * - * @param string ...$methods - * - * @throws InvalidHeaderValueException - * If one of the methods isn't valid. - */ - public function __construct(string ...$methods) - { - /** @var list $methods */ - - $this->validateToken(...$methods); - - // normalize the list of methods... - foreach ($methods as $method) { - $this->methods[] = strtoupper($method); - } - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Allow'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return implode(', ', $this->methods); - } -} diff --git a/src/Header/CacheControlHeader.php b/src/Header/CacheControlHeader.php deleted file mode 100644 index 1dfe3e0..0000000 --- a/src/Header/CacheControlHeader.php +++ /dev/null @@ -1,80 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueParameterException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.9 - */ -class CacheControlHeader extends Header -{ - - /** - * @var array - */ - private array $parameters; - - /** - * Constructor of the class - * - * @param array $parameters - * - * @throws InvalidHeaderValueParameterException - * If the parameters aren't valid. - */ - public function __construct(array $parameters) - { - $parameters = $this->validateParameters($parameters); - - $this->parameters = $parameters; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Cache-Control'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - $segments = []; - foreach ($this->parameters as $name => $value) { - // the construction isn't valid... - if ($value === '') { - $segments[] = $name; - continue; - } - - $format = $this->isToken($value) ? '%s=%s' : '%s="%s"'; - - $segments[] = sprintf($format, $name, $value); - } - - return implode(', ', $segments); - } -} diff --git a/src/Header/ClearSiteDataHeader.php b/src/Header/ClearSiteDataHeader.php deleted file mode 100644 index 664f65b..0000000 --- a/src/Header/ClearSiteDataHeader.php +++ /dev/null @@ -1,74 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; -use function sprintf; - -/** - * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data - */ -class ClearSiteDataHeader extends Header -{ - - /** - * @var list - */ - private array $directives; - - /** - * Constructor of the class - * - * @param string ...$directives - * - * @throws InvalidHeaderValueException - * If one of the directives isn't valid. - */ - public function __construct(string ...$directives) - { - /** @var list $directives */ - - $this->validateQuotedString(...$directives); - - $this->directives = $directives; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Clear-Site-Data'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - $segments = []; - foreach ($this->directives as $directive) { - $segments[] = sprintf('"%s"', $directive); - } - - return implode(', ', $segments); - } -} diff --git a/src/Header/ConnectionHeader.php b/src/Header/ConnectionHeader.php deleted file mode 100644 index 171fe8d..0000000 --- a/src/Header/ConnectionHeader.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.10 - */ -class ConnectionHeader extends Header -{ - - /** - * @var string - */ - public const CONNECTION_CLOSE = 'close'; - - /** - * @var string - */ - public const CONNECTION_KEEP_ALIVE = 'keep-alive'; - - /** - * @var string - */ - private string $value; - - /** - * Constructor of the class - * - * @param string $value - * - * @throws InvalidHeaderValueException - * If the value isn't valid. - */ - public function __construct(string $value) - { - $this->validateToken($value); - - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Connection'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return $this->value; - } -} diff --git a/src/Header/ContentDispositionHeader.php b/src/Header/ContentDispositionHeader.php deleted file mode 100644 index 60d5bbf..0000000 --- a/src/Header/ContentDispositionHeader.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Exception\InvalidHeaderValueParameterException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-19.5.1 - */ -class ContentDispositionHeader extends Header -{ - - /** - * @var string - */ - private string $type; - - /** - * @var array - */ - private array $parameters; - - /** - * Constructor of the class - * - * @param string $type - * @param array $parameters - * - * @throws InvalidHeaderValueException - * If the type isn't valid. - * - * @throws InvalidHeaderValueParameterException - * If the parameters aren't valid. - */ - public function __construct(string $type, array $parameters = []) - { - $this->validateToken($type); - - $parameters = $this->validateParameters($parameters); - - $this->type = $type; - $this->parameters = $parameters; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Content-Disposition'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - $v = $this->type; - foreach ($this->parameters as $name => $value) { - $v .= sprintf('; %s="%s"', $name, $value); - } - - return $v; - } -} diff --git a/src/Header/ContentEncodingHeader.php b/src/Header/ContentEncodingHeader.php deleted file mode 100644 index af51152..0000000 --- a/src/Header/ContentEncodingHeader.php +++ /dev/null @@ -1,78 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.11 - */ -class ContentEncodingHeader extends Header -{ - - /** - * Directives - * - * @var string - */ - public const GZIP = 'gzip'; - public const COMPRESS = 'compress'; - public const DEFLATE = 'deflate'; - public const BR = 'br'; - - /** - * @var list - */ - private array $directives; - - /** - * Constructor of the class - * - * @param string ...$directives - * - * @throws InvalidHeaderValueException - * If one of the directives isn't valid. - */ - public function __construct(string ...$directives) - { - /** @var list $directives */ - - $this->validateToken(...$directives); - - $this->directives = $directives; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Content-Encoding'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return implode(', ', $this->directives); - } -} diff --git a/src/Header/ContentLanguageHeader.php b/src/Header/ContentLanguageHeader.php deleted file mode 100644 index f81c33a..0000000 --- a/src/Header/ContentLanguageHeader.php +++ /dev/null @@ -1,77 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.12 - */ -class ContentLanguageHeader extends Header -{ - - /** - * Regular Expression for a language tag validation - * - * @link https://tools.ietf.org/html/rfc2616#section-3.10 - * - * @var string - */ - public const RFC2616_LANGUAGE_TAG = '/^[a-zA-Z]{1,8}(?:\-[a-zA-Z]{1,8})?$/'; - - /** - * @var list - */ - private array $languages; - - /** - * Constructor of the class - * - * @param string ...$languages - * - * @throws InvalidHeaderValueException - * If one of the language codes isn't valid. - */ - public function __construct(string ...$languages) - { - /** @var list $languages */ - - $this->validateValueByRegex(self::RFC2616_LANGUAGE_TAG, ...$languages); - - $this->languages = $languages; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Content-Language'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return implode(', ', $this->languages); - } -} diff --git a/src/Header/ContentLengthHeader.php b/src/Header/ContentLengthHeader.php deleted file mode 100644 index c0a8393..0000000 --- a/src/Header/ContentLengthHeader.php +++ /dev/null @@ -1,87 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.13 - */ -class ContentLengthHeader extends Header -{ - - /** - * @var int - */ - private int $value; - - /** - * Constructor of the class - * - * @param int $value - * - * @throws InvalidHeaderValueException - * If the value isn't valid. - */ - public function __construct(int $value) - { - $this->validateValue($value); - - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Content-Length'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return sprintf('%d', $this->value); - } - - /** - * Validates the given value - * - * @param int $value - * - * @return void - * - * @throws InvalidHeaderValueException - * If the value isn't valid. - */ - private function validateValue(int $value): void - { - if (! ($value >= 0)) { - throw new InvalidHeaderValueException(sprintf( - 'The value "%2$d" for the header "%1$s" is not valid', - $this->getFieldName(), - $value - )); - } - } -} diff --git a/src/Header/ContentLocationHeader.php b/src/Header/ContentLocationHeader.php deleted file mode 100644 index b2fd64e..0000000 --- a/src/Header/ContentLocationHeader.php +++ /dev/null @@ -1,63 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Psr\Http\Message\UriInterface; -use Sunrise\Http\Message\Exception\InvalidUriException; -use Sunrise\Http\Message\Header; -use Sunrise\Http\Message\Uri; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.14 - */ -class ContentLocationHeader extends Header -{ - - /** - * @var UriInterface - */ - private UriInterface $uri; - - /** - * Constructor of the class - * - * @param mixed $uri - * - * @throws InvalidUriException - * If the URI isn't valid. - */ - public function __construct($uri) - { - $uri = Uri::create($uri); - - $this->uri = $uri; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Content-Location'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return $this->uri->__toString(); - } -} diff --git a/src/Header/ContentMD5Header.php b/src/Header/ContentMD5Header.php deleted file mode 100644 index 2ed1133..0000000 --- a/src/Header/ContentMD5Header.php +++ /dev/null @@ -1,70 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.15 - */ -class ContentMD5Header extends Header -{ - - /** - * Regular Expression for a MD5 digest validation - * - * @link https://tools.ietf.org/html/rfc2045#section-6.8 - * - * @var string - */ - public const RFC2045_MD5_DIGEST = '/^[A-Za-z0-9\+\/]+=*$/'; - - /** - * @var string - */ - private string $value; - - /** - * Constructor of the class - * - * @param string $value - * - * @throws InvalidHeaderValueException - * If the value isn't valid. - */ - public function __construct(string $value) - { - $this->validateValueByRegex(self::RFC2045_MD5_DIGEST, $value); - - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Content-MD5'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return $this->value; - } -} diff --git a/src/Header/ContentRangeHeader.php b/src/Header/ContentRangeHeader.php deleted file mode 100644 index 3f6884f..0000000 --- a/src/Header/ContentRangeHeader.php +++ /dev/null @@ -1,114 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.16 - */ -class ContentRangeHeader extends Header -{ - - /** - * @var int - */ - private int $firstBytePosition; - - /** - * @var int - */ - private int $lastBytePosition; - - /** - * @var int - */ - private int $instanceLength; - - /** - * Constructor of the class - * - * @param int $firstBytePosition - * @param int $lastBytePosition - * @param int $instanceLength - * - * @throws InvalidHeaderValueException - * If the range isn't valid. - */ - public function __construct(int $firstBytePosition, int $lastBytePosition, int $instanceLength) - { - $this->validateRange($firstBytePosition, $lastBytePosition, $instanceLength); - - $this->firstBytePosition = $firstBytePosition; - $this->lastBytePosition = $lastBytePosition; - $this->instanceLength = $instanceLength; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Content-Range'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return sprintf( - 'bytes %d-%d/%d', - $this->firstBytePosition, - $this->lastBytePosition, - $this->instanceLength - ); - } - - /** - * Validates the given range - * - * @param int $firstBytePosition - * @param int $lastBytePosition - * @param int $instanceLength - * - * @return void - * - * @throws InvalidHeaderValueException - * If the range isn't valid. - */ - private function validateRange(int $firstBytePosition, int $lastBytePosition, int $instanceLength): void - { - if (! ($firstBytePosition <= $lastBytePosition)) { - throw new InvalidHeaderValueException( - 'The "first-byte-pos" value of the content range ' . - 'must be less than or equal to the "last-byte-pos" value' - ); - } - - if (! ($lastBytePosition < $instanceLength)) { - throw new InvalidHeaderValueException( - 'The "last-byte-pos" value of the content range ' . - 'must be less than the "instance-length" value' - ); - } - } -} diff --git a/src/Header/ContentSecurityPolicyHeader.php b/src/Header/ContentSecurityPolicyHeader.php deleted file mode 100644 index 620bb3f..0000000 --- a/src/Header/ContentSecurityPolicyHeader.php +++ /dev/null @@ -1,101 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueParameterException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; -use function sprintf; - -/** - * @link https://www.w3.org/TR/CSP3/#csp-header - */ -class ContentSecurityPolicyHeader extends Header -{ - - /** - * Regular Expression for a directive name validation - * - * @link https://www.w3.org/TR/CSP3/#framework-directives - * - * @var string - */ - public const VALID_DIRECTIVE_NAME = '/^[0-9A-Za-z\-]+$/'; - - /** - * Regular Expression for a directive value validation - * - * @link https://www.w3.org/TR/CSP3/#framework-directives - * - * @var string - */ - public const VALID_DIRECTIVE_VALUE = '/^[\x09\x20-\x2B\x2D-\x3A\x3C-\x7E]*$/'; - - /** - * @var array - */ - private array $parameters; - - /** - * Constructor of the class - * - * @param array $parameters - * - * @throws InvalidHeaderValueParameterException - * If the parameters aren't valid. - */ - public function __construct(array $parameters = []) - { - $parameters = $this->validateParametersByRegex( - $parameters, - self::VALID_DIRECTIVE_NAME, - self::VALID_DIRECTIVE_VALUE - ); - - $this->parameters = $parameters; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Content-Security-Policy'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - $directives = []; - foreach ($this->parameters as $directive => $value) { - // the directive can be without value... - // e.g. sandbox, upgrade-insecure-requests, etc. - if ($value === '') { - $directives[] = $directive; - continue; - } - - $directives[] = sprintf('%s %s', $directive, $value); - } - - return implode('; ', $directives); - } -} diff --git a/src/Header/ContentSecurityPolicyReportOnlyHeader.php b/src/Header/ContentSecurityPolicyReportOnlyHeader.php deleted file mode 100644 index 3b80446..0000000 --- a/src/Header/ContentSecurityPolicyReportOnlyHeader.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * @link https://www.w3.org/TR/CSP3/#cspro-header - */ -class ContentSecurityPolicyReportOnlyHeader extends ContentSecurityPolicyHeader -{ - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Content-Security-Policy-Report-Only'; - } -} diff --git a/src/Header/ContentTypeHeader.php b/src/Header/ContentTypeHeader.php deleted file mode 100644 index 8964004..0000000 --- a/src/Header/ContentTypeHeader.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Exception\InvalidHeaderValueParameterException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.17 - */ -class ContentTypeHeader extends Header -{ - - /** - * Regular Expression for a content type validation - * - * @link https://tools.ietf.org/html/rfc6838#section-4.2 - * - * @var string - */ - public const RFC6838_CONTENT_TYPE = '/^[\dA-Za-z][\d\w\!#\$&\+\-\.\^]*(?:\/[\dA-Za-z][\d\w\!#\$&\+\-\.\^]*)?$/'; - - /** - * @var string - */ - private string $type; - - /** - * @var array - */ - private array $parameters; - - /** - * Constructor of the class - * - * @param string $type - * @param array $parameters - * - * @throws InvalidHeaderValueException - * If the type isn't valid. - * - * @throws InvalidHeaderValueParameterException - * If the parameters aren't valid. - */ - public function __construct(string $type, array $parameters = []) - { - $this->validateValueByRegex(self::RFC6838_CONTENT_TYPE, $type); - - $parameters = $this->validateParameters($parameters); - - $this->type = $type; - $this->parameters = $parameters; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Content-Type'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - $v = $this->type; - foreach ($this->parameters as $name => $value) { - $v .= sprintf('; %s="%s"', $name, $value); - } - - return $v; - } -} diff --git a/src/Header/CookieHeader.php b/src/Header/CookieHeader.php deleted file mode 100644 index 511255b..0000000 --- a/src/Header/CookieHeader.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function http_build_query; - -/** - * Import constants - */ -use const PHP_QUERY_RFC3986; - -/** - * @link https://tools.ietf.org/html/rfc6265.html#section-5.4 - */ -class CookieHeader extends Header -{ - - /** - * @var array - */ - private array $value; - - /** - * Constructor of the class - * - * @param array $value - */ - public function __construct(array $value = []) - { - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Cookie'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return http_build_query($this->value, '', '; ', PHP_QUERY_RFC3986); - } -} diff --git a/src/Header/DateHeader.php b/src/Header/DateHeader.php deleted file mode 100644 index 1af8b44..0000000 --- a/src/Header/DateHeader.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use DateTimeInterface; -use Sunrise\Http\Message\Header; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.18 - * @link https://tools.ietf.org/html/rfc822#section-5 - */ -class DateHeader extends Header -{ - - /** - * @var DateTimeInterface - */ - private DateTimeInterface $timestamp; - - /** - * Constructor of the class - * - * @param DateTimeInterface $timestamp - */ - public function __construct(DateTimeInterface $timestamp) - { - $this->timestamp = $timestamp; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Date'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return $this->formatDateTime($this->timestamp); - } -} diff --git a/src/Header/EtagHeader.php b/src/Header/EtagHeader.php deleted file mode 100644 index d5d421f..0000000 --- a/src/Header/EtagHeader.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.19 - */ -class EtagHeader extends Header -{ - - /** - * @var string - */ - private string $value; - - /** - * Constructor of the class - * - * @param string $value - * - * @throws InvalidHeaderValueException - * If the value isn't valid. - */ - public function __construct(string $value) - { - $this->validateQuotedString($value); - - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'ETag'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return sprintf('"%s"', $this->value); - } -} diff --git a/src/Header/ExpiresHeader.php b/src/Header/ExpiresHeader.php deleted file mode 100644 index 339b95e..0000000 --- a/src/Header/ExpiresHeader.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use DateTimeInterface; -use Sunrise\Http\Message\Header; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.21 - * @link https://tools.ietf.org/html/rfc822#section-5 - */ -class ExpiresHeader extends Header -{ - - /** - * @var DateTimeInterface - */ - private DateTimeInterface $timestamp; - - /** - * Constructor of the class - * - * @param DateTimeInterface $timestamp - */ - public function __construct(DateTimeInterface $timestamp) - { - $this->timestamp = $timestamp; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Expires'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return $this->formatDateTime($this->timestamp); - } -} diff --git a/src/Header/KeepAliveHeader.php b/src/Header/KeepAliveHeader.php deleted file mode 100644 index fbbc205..0000000 --- a/src/Header/KeepAliveHeader.php +++ /dev/null @@ -1,80 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueParameterException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc2068#section-19.7.1.1 - */ -class KeepAliveHeader extends Header -{ - - /** - * @var array - */ - private array $parameters; - - /** - * Constructor of the class - * - * @param array $parameters - * - * @throws InvalidHeaderValueParameterException - * If the parameters aren't valid. - */ - public function __construct(array $parameters = []) - { - $parameters = $this->validateParameters($parameters); - - $this->parameters = $parameters; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Keep-Alive'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - $segments = []; - foreach ($this->parameters as $name => $value) { - // the construction isn't valid... - if ($value === '') { - $segments[] = $name; - continue; - } - - $format = $this->isToken($value) ? '%s=%s' : '%s="%s"'; - - $segments[] = sprintf($format, $name, $value); - } - - return implode(', ', $segments); - } -} diff --git a/src/Header/LastModifiedHeader.php b/src/Header/LastModifiedHeader.php deleted file mode 100644 index 72c2fbb..0000000 --- a/src/Header/LastModifiedHeader.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use DateTimeInterface; -use Sunrise\Http\Message\Header; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.29 - * @link https://tools.ietf.org/html/rfc822#section-5 - */ -class LastModifiedHeader extends Header -{ - - /** - * @var DateTimeInterface - */ - private DateTimeInterface $timestamp; - - /** - * Constructor of the class - * - * @param DateTimeInterface $timestamp - */ - public function __construct(DateTimeInterface $timestamp) - { - $this->timestamp = $timestamp; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Last-Modified'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return $this->formatDateTime($this->timestamp); - } -} diff --git a/src/Header/LinkHeader.php b/src/Header/LinkHeader.php deleted file mode 100644 index 506f54c..0000000 --- a/src/Header/LinkHeader.php +++ /dev/null @@ -1,86 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Psr\Http\Message\UriInterface; -use Sunrise\Http\Message\Exception\InvalidHeaderValueParameterException; -use Sunrise\Http\Message\Exception\InvalidUriException; -use Sunrise\Http\Message\Header; -use Sunrise\Http\Message\Uri; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc5988 - */ -class LinkHeader extends Header -{ - - /** - * @var UriInterface - */ - private UriInterface $uri; - - /** - * @var array - */ - private array $parameters; - - /** - * Constructor of the class - * - * @param mixed $uri - * @param array $parameters - * - * @throws InvalidUriException - * If the URI isn't valid. - * - * @throws InvalidHeaderValueParameterException - * If the parameters aren't valid. - */ - public function __construct($uri, array $parameters = []) - { - $uri = Uri::create($uri); - - $parameters = $this->validateParameters($parameters); - - $this->uri = $uri; - $this->parameters = $parameters; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Link'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - $v = sprintf('<%s>', $this->uri->__toString()); - foreach ($this->parameters as $name => $value) { - $v .= sprintf('; %s="%s"', $name, $value); - } - - return $v; - } -} diff --git a/src/Header/LocationHeader.php b/src/Header/LocationHeader.php deleted file mode 100644 index 0eef409..0000000 --- a/src/Header/LocationHeader.php +++ /dev/null @@ -1,63 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Psr\Http\Message\UriInterface; -use Sunrise\Http\Message\Exception\InvalidUriException; -use Sunrise\Http\Message\Header; -use Sunrise\Http\Message\Uri; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.30 - */ -class LocationHeader extends Header -{ - - /** - * @var UriInterface - */ - private UriInterface $uri; - - /** - * Constructor of the class - * - * @param mixed $uri - * - * @throws InvalidUriException - * If the URI isn't valid. - */ - public function __construct($uri) - { - $uri = Uri::create($uri); - - $this->uri = $uri; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Location'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return $this->uri->__toString(); - } -} diff --git a/src/Header/RefreshHeader.php b/src/Header/RefreshHeader.php deleted file mode 100644 index 4065b94..0000000 --- a/src/Header/RefreshHeader.php +++ /dev/null @@ -1,102 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Psr\Http\Message\UriInterface; -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Exception\InvalidUriException; -use Sunrise\Http\Message\Header; -use Sunrise\Http\Message\Uri; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://en.wikipedia.org/wiki/Meta_refresh - */ -class RefreshHeader extends Header -{ - - /** - * @var int - */ - private int $delay; - - /** - * @var UriInterface - */ - private UriInterface $uri; - - /** - * Constructor of the class - * - * @param int $delay - * @param mixed $uri - * - * @throws InvalidUriException - * If the URI isn't valid. - * - * @throws InvalidHeaderValueException - * If the delay isn't valid. - */ - public function __construct(int $delay, $uri) - { - $this->validateDelay($delay); - - $uri = Uri::create($uri); - - $this->delay = $delay; - $this->uri = $uri; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Refresh'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return sprintf('%d; url=%s', $this->delay, $this->uri->__toString()); - } - - /** - * Validates the redirection delay - * - * @param int $delay - * - * @return void - * - * @throws InvalidHeaderValueException - * If the delay isn't valid. - */ - private function validateDelay(int $delay): void - { - if (! ($delay >= 0)) { - throw new InvalidHeaderValueException(sprintf( - 'The delay "%2$d" for the header "%1$s" is not valid', - $this->getFieldName(), - $delay - )); - } - } -} diff --git a/src/Header/RetryAfterHeader.php b/src/Header/RetryAfterHeader.php deleted file mode 100644 index 9dd7a20..0000000 --- a/src/Header/RetryAfterHeader.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use DateTimeInterface; -use Sunrise\Http\Message\Header; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.37 - * @link https://tools.ietf.org/html/rfc822#section-5 - */ -class RetryAfterHeader extends Header -{ - - /** - * @var DateTimeInterface - */ - private DateTimeInterface $timestamp; - - /** - * Constructor of the class - * - * @param DateTimeInterface $timestamp - */ - public function __construct(DateTimeInterface $timestamp) - { - $this->timestamp = $timestamp; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Retry-After'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return $this->formatDateTime($this->timestamp); - } -} diff --git a/src/Header/SetCookieHeader.php b/src/Header/SetCookieHeader.php deleted file mode 100644 index cfcc990..0000000 --- a/src/Header/SetCookieHeader.php +++ /dev/null @@ -1,277 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use DateTimeImmutable; -use DateTimeInterface; -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function max; -use function rawurlencode; -use function sprintf; -use function strpbrk; -use function time; - -/** - * @link https://tools.ietf.org/html/rfc6265#section-4.1 - * @link https://github.com/php/php-src/blob/master/ext/standard/head.c - */ -class SetCookieHeader extends Header -{ - - /** - * Cookies are not sent on normal cross-site subrequests, but - * are sent when a user is navigating to the origin site. - * - * This is the default cookie value if SameSite has not been - * explicitly specified in recent browser versions.. - * - * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#lax - * - * @var string - */ - public const SAME_SITE_LAX = 'Lax'; - - /** - * Cookies will only be sent in a first-party context and not - * be sent along with requests initiated by third party websites. - * - * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#strict - * - * @var string - */ - public const SAME_SITE_STRICT = 'Strict'; - - /** - * Cookies will be sent in all contexts, i.e. in responses to - * both first-party and cross-site requests. - * - * If SameSite=None is set, the cookie Secure attribute must - * also be set (or the cookie will be blocked). - * - * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#none - * - * @var string - */ - public const SAME_SITE_NONE = 'None'; - - /** - * Cookie option keys - * - * @var string - */ - public const OPTION_KEY_PATH = 'path'; - public const OPTION_KEY_DOMAIN = 'domain'; - public const OPTION_KEY_SECURE = 'secure'; - public const OPTION_KEY_HTTP_ONLY = 'httpOnly'; - public const OPTION_KEY_SAMESITE = 'sameSite'; - - /** - * Default cookie options - * - * @var array{ - * path?: ?string, - * domain?: ?string, - * secure?: ?bool, - * httpOnly?: ?bool, - * sameSite?: ?string - * } - */ - protected static array $defaultOptions = [ - self::OPTION_KEY_PATH => '/', - self::OPTION_KEY_DOMAIN => null, - self::OPTION_KEY_SECURE => null, - self::OPTION_KEY_HTTP_ONLY => true, - self::OPTION_KEY_SAMESITE => self::SAME_SITE_LAX, - ]; - - /** - * The cookie name - * - * @var string - */ - private string $name; - - /** - * The cookie value - * - * @var string - */ - private string $value; - - /** - * The cookie expiration date - * - * @var DateTimeInterface|null - */ - private ?DateTimeInterface $expires; - - /** - * The cookie options - * - * @var array{ - * path?: ?string, - * domain?: ?string, - * secure?: ?bool, - * httpOnly?: ?bool, - * sameSite?: ?string - * } - */ - private array $options; - - /** - * Constructor of the class - * - * @param string $name - * @param string $value - * @param DateTimeInterface|null $expires - * @param array{path?: ?string, domain?: ?string, secure?: ?bool, httpOnly?: ?bool, sameSite?: ?string} $options - * - * @throws InvalidHeaderValueException - * If one of the parameters isn't valid. - */ - public function __construct(string $name, string $value, ?DateTimeInterface $expires = null, array $options = []) - { - $this->validateCookieName($name); - - if (isset($options[self::OPTION_KEY_PATH])) { - $this->validateCookieOption(self::OPTION_KEY_PATH, $options[self::OPTION_KEY_PATH]); - } - - if (isset($options[self::OPTION_KEY_DOMAIN])) { - $this->validateCookieOption(self::OPTION_KEY_DOMAIN, $options[self::OPTION_KEY_DOMAIN]); - } - - if (isset($options[self::OPTION_KEY_SAMESITE])) { - $this->validateCookieOption(self::OPTION_KEY_SAMESITE, $options[self::OPTION_KEY_SAMESITE]); - } - - if ($value === '') { - $value = 'deleted'; - $expires = new DateTimeImmutable('1 year ago'); - } - - $options += static::$defaultOptions; - - $this->name = $name; - $this->value = $value; - $this->expires = $expires; - $this->options = $options; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Set-Cookie'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - $name = rawurlencode($this->name); - $value = rawurlencode($this->value); - $result = sprintf('%s=%s', $name, $value); - - if (isset($this->expires)) { - $result .= '; Expires=' . $this->formatDateTime($this->expires); - $result .= '; Max-Age=' . max($this->expires->getTimestamp() - time(), 0); - } - - if (isset($this->options[self::OPTION_KEY_PATH])) { - $result .= '; Path=' . $this->options[self::OPTION_KEY_PATH]; - } - - if (isset($this->options[self::OPTION_KEY_DOMAIN])) { - $result .= '; Domain=' . $this->options[self::OPTION_KEY_DOMAIN]; - } - - if (isset($this->options[self::OPTION_KEY_SECURE]) && $this->options[self::OPTION_KEY_SECURE]) { - $result .= '; Secure'; - } - - if (isset($this->options[self::OPTION_KEY_HTTP_ONLY]) && $this->options[self::OPTION_KEY_HTTP_ONLY]) { - $result .= '; HttpOnly'; - } - - if (isset($this->options[self::OPTION_KEY_SAMESITE])) { - $result .= '; SameSite=' . $this->options[self::OPTION_KEY_SAMESITE]; - } - - return $result; - } - - /** - * Validates the given cookie name - * - * @param string $name - * - * @return void - * - * @throws InvalidHeaderValueException - * If the cookie name isn't valid. - */ - private function validateCookieName(string $name): void - { - if ('' === $name) { - throw new InvalidHeaderValueException('Cookie name cannot be empty'); - } - - // https://github.com/php/php-src/blob/02a5335b710aa36cd0c3108bfb9c6f7a57d40000/ext/standard/head.c#L93 - if (strpbrk($name, "=,; \t\r\n\013\014") !== false) { - throw new InvalidHeaderValueException(sprintf( - 'The cookie name "%s" contains prohibited characters', - $name - )); - } - } - - /** - * Validates the given cookie option - * - * @param string $validKey - * @param mixed $value - * - * @return void - * - * @throws InvalidHeaderValueException - * If the cookie option isn't valid. - */ - private function validateCookieOption(string $validKey, $value): void - { - if (!is_string($value)) { - throw new InvalidHeaderValueException(sprintf( - 'The cookie option "%s" must be a string', - $validKey - )); - } - - // https://github.com/php/php-src/blob/02a5335b710aa36cd0c3108bfb9c6f7a57d40000/ext/standard/head.c#L103 - // https://github.com/php/php-src/blob/02a5335b710aa36cd0c3108bfb9c6f7a57d40000/ext/standard/head.c#L108 - if (strpbrk($value, ",; \t\r\n\013\014") !== false) { - throw new InvalidHeaderValueException(sprintf( - 'The cookie option "%s" contains prohibited characters', - $validKey - )); - } - } -} diff --git a/src/Header/SunsetHeader.php b/src/Header/SunsetHeader.php deleted file mode 100644 index b8682ae..0000000 --- a/src/Header/SunsetHeader.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use DateTimeInterface; -use Sunrise\Http\Message\Header; - -/** - * @link https://tools.ietf.org/id/draft-wilde-sunset-header-03.html - * @link https://github.com/sunrise-php/http-header-kit/issues/1#issuecomment-457043527 - */ -class SunsetHeader extends Header -{ - - /** - * @var DateTimeInterface - */ - private DateTimeInterface $timestamp; - - /** - * Constructor of the class - * - * @param DateTimeInterface $timestamp - */ - public function __construct(DateTimeInterface $timestamp) - { - $this->timestamp = $timestamp; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Sunset'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return $this->formatDateTime($this->timestamp); - } -} diff --git a/src/Header/TrailerHeader.php b/src/Header/TrailerHeader.php deleted file mode 100644 index 684621a..0000000 --- a/src/Header/TrailerHeader.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.40 - */ -class TrailerHeader extends Header -{ - - /** - * @var string - */ - private string $value; - - /** - * Constructor of the class - * - * @param string $value - * - * @throws InvalidHeaderValueException - * If the value isn't valid. - */ - public function __construct(string $value) - { - $this->validateToken($value); - - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Trailer'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return $this->value; - } -} diff --git a/src/Header/TransferEncodingHeader.php b/src/Header/TransferEncodingHeader.php deleted file mode 100644 index dabeda2..0000000 --- a/src/Header/TransferEncodingHeader.php +++ /dev/null @@ -1,78 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.41 - */ -class TransferEncodingHeader extends Header -{ - - /** - * Directives - * - * @var string - */ - public const CHUNKED = 'chunked'; - public const COMPRESS = 'compress'; - public const DEFLATE = 'deflate'; - public const GZIP = 'gzip'; - - /** - * @var list - */ - private array $directives; - - /** - * Constructor of the class - * - * @param string ...$directives - * - * @throws InvalidHeaderValueException - * If one of the directives isn't valid. - */ - public function __construct(string ...$directives) - { - /** @var list $directives */ - - $this->validateToken(...$directives); - - $this->directives = $directives; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Transfer-Encoding'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return implode(', ', $this->directives); - } -} diff --git a/src/Header/VaryHeader.php b/src/Header/VaryHeader.php deleted file mode 100644 index dd12ef3..0000000 --- a/src/Header/VaryHeader.php +++ /dev/null @@ -1,68 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.44 - */ -class VaryHeader extends Header -{ - - /** - * @var list - */ - private array $value; - - /** - * Constructor of the class - * - * @param string ...$value - * - * @throws InvalidHeaderValueException - * If one of the values isn't valid. - */ - public function __construct(string ...$value) - { - /** @var list $value */ - - $this->validateToken(...$value); - - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Vary'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - return implode(', ', $this->value); - } -} diff --git a/src/Header/WWWAuthenticateHeader.php b/src/Header/WWWAuthenticateHeader.php deleted file mode 100644 index c6c475b..0000000 --- a/src/Header/WWWAuthenticateHeader.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Exception\InvalidHeaderValueParameterException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function implode; -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc7235#section-4.1 - */ -class WWWAuthenticateHeader extends Header -{ - - /** - * HTTP Authentication Schemes - * - * @link https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml - */ - public const HTTP_AUTHENTICATE_SCHEME_BASIC = 'Basic'; - public const HTTP_AUTHENTICATE_SCHEME_BEARER = 'Bearer'; - public const HTTP_AUTHENTICATE_SCHEME_DIGEST = 'Digest'; - public const HTTP_AUTHENTICATE_SCHEME_HOBA = 'HOBA'; - public const HTTP_AUTHENTICATE_SCHEME_MUTUAL = 'Mutual'; - public const HTTP_AUTHENTICATE_SCHEME_NEGOTIATE = 'Negotiate'; - public const HTTP_AUTHENTICATE_SCHEME_OAUTH = 'OAuth'; - public const HTTP_AUTHENTICATE_SCHEME_SCRAM_SHA_1 = 'SCRAM-SHA-1'; - public const HTTP_AUTHENTICATE_SCHEME_SCRAM_SHA_256 = 'SCRAM-SHA-256'; - public const HTTP_AUTHENTICATE_SCHEME_VAPID = 'vapid'; - - /** - * @var string - */ - private string $scheme; - - /** - * @var array - */ - private array $parameters; - - /** - * Constructor of the class - * - * @param string $scheme - * @param array $parameters - * - * @throws InvalidHeaderValueException - * If the scheme isn't valid. - * - * @throws InvalidHeaderValueParameterException - * If the parameters aren't valid. - */ - public function __construct(string $scheme, array $parameters = []) - { - $this->validateToken($scheme); - - $parameters = $this->validateParameters($parameters); - - $this->scheme = $scheme; - $this->parameters = $parameters; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'WWW-Authenticate'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - $v = $this->scheme; - - $challenge = []; - foreach ($this->parameters as $name => $value) { - $challenge[] = sprintf(' %s="%s"', $name, $value); - } - - if (!empty($challenge)) { - $v .= implode(',', $challenge); - } - - return $v; - } -} diff --git a/src/Header/WarningHeader.php b/src/Header/WarningHeader.php deleted file mode 100644 index 7132def..0000000 --- a/src/Header/WarningHeader.php +++ /dev/null @@ -1,130 +0,0 @@ - - * @copyright Copyright (c) 2018, Anatoly Nekhay - * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE - * @link https://github.com/sunrise-php/http-message - */ - -namespace Sunrise\Http\Message\Header; - -/** - * Import classes - */ -use DateTimeInterface; -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; -use Sunrise\Http\Message\Header; - -/** - * Import functions - */ -use function sprintf; - -/** - * @link https://tools.ietf.org/html/rfc2616#section-14.46 - */ -class WarningHeader extends Header -{ - - /** - * HTTP Warning Codes - * - * @link https://www.iana.org/assignments/http-warn-codes/http-warn-codes.xhtml - */ - public const HTTP_WARNING_CODE_RESPONSE_IS_STALE = 110; - public const HTTP_WARNING_CODE_REVALIDATION_FAILED = 111; - public const HTTP_WARNING_CODE_DISCONNECTED_OPERATION = 112; - public const HTTP_WARNING_CODE_HEURISTIC_EXPIRATION = 113; - public const HTTP_WARNING_CODE_MISCELLANEOUS_WARNING = 199; - public const HTTP_WARNING_CODE_TRANSFORMATION_APPLIED = 214; - public const HTTP_WARNING_CODE_MISCELLANEOUS_PERSISTENT_WARNING = 299; - - /** - * @var int - */ - private int $code; - - /** - * @var string - */ - private string $agent; - - /** - * @var string - */ - private string $text; - - /** - * @var DateTimeInterface|null - */ - private ?DateTimeInterface $date; - - /** - * Constructor of the class - * - * @param int $code - * @param string $agent - * @param string $text - * @param DateTimeInterface|null $date - * - * @throws InvalidHeaderValueException - * If one of parameters isn't valid. - */ - public function __construct(int $code, string $agent, string $text, ?DateTimeInterface $date = null) - { - $this->validateCode($code); - $this->validateToken($agent); - $this->validateQuotedString($text); - - $this->code = $code; - $this->agent = $agent; - $this->text = $text; - $this->date = $date; - } - - /** - * {@inheritdoc} - */ - public function getFieldName(): string - { - return 'Warning'; - } - - /** - * {@inheritdoc} - */ - public function getFieldValue(): string - { - $value = sprintf('%s %s "%s"', $this->code, $this->agent, $this->text); - - if (isset($this->date)) { - $value .= sprintf(' "%s"', $this->formatDateTime($this->date)); - } - - return $value; - } - - /** - * Validates the given code - * - * @param int $code - * - * @return void - * - * @throws InvalidHeaderValueException - * If the code isn't valid. - */ - private function validateCode(int $code): void - { - if (! ($code >= 100 && $code <= 999)) { - throw new InvalidHeaderValueException(sprintf( - 'The code "%2$d" for the header "%1$s" is not valid', - $this->getFieldName(), - $code - )); - } - } -} diff --git a/src/HeaderInterface.php b/src/HeaderInterface.php index 67afa98..ac5cc54 100644 --- a/src/HeaderInterface.php +++ b/src/HeaderInterface.php @@ -17,15 +17,39 @@ use IteratorAggregate; /** - * - * $response->withHeader(...new SetCookieHeader('foo', 'bar')) - * - * - * @template-implements IteratorAggregate + * @extends IteratorAggregate */ interface HeaderInterface extends IteratorAggregate { + /** + * Date format according to RFC-822 + * + * @var string + */ + public const RFC822_DATE_FORMAT = 'D, d M y H:i:s O'; + + /** + * Regular Expression used for a token validation according to RFC-7230 + * + * @var string + */ + public const RFC7230_TOKEN_REGEX = '/^[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]+$/'; + + /** + * Regular Expression used for a field-value validation according to RFC-7230 + * + * @var string + */ + public const RFC7230_FIELD_VALUE_REGEX = '/^[\x09\x20-\x7E\x80-\xFF]*$/'; + + /** + * Regular Expression used for a quoted-string validation according to RFC-7230 + * + * @var string + */ + public const RFC7230_QUOTED_STRING_REGEX = '/^(?:[\x5C][\x22]|[\x09\x20\x21\x23-\x5B\x5D-\x7E\x80-\xFF])*$/'; + /** * Gets the header field name * @@ -41,9 +65,7 @@ public function getFieldName(): string; public function getFieldValue(): string; /** - * Converts the header field to a string - * - * @link http://php.net/manual/en/language.oop5.magic.php#object.tostring + * Converts the header to a field * * @return string */ diff --git a/src/Message.php b/src/Message.php index 443cffc..71fb469 100644 --- a/src/Message.php +++ b/src/Message.php @@ -17,9 +17,6 @@ use Psr\Http\Message\MessageInterface; use Psr\Http\Message\StreamInterface; use Sunrise\Http\Message\Exception\InvalidArgumentException; -use Sunrise\Http\Message\Exception\InvalidHeaderException; -use Sunrise\Http\Message\Exception\InvalidHeaderNameException; -use Sunrise\Http\Message\Exception\InvalidHeaderValueException; use Sunrise\Http\Message\Stream\PhpTempStream; /** @@ -43,18 +40,18 @@ abstract class Message implements MessageInterface { /** - * Default HTTP version + * Allowed HTTP versions * - * @var string + * @var list */ - public const DEFAULT_HTTP_VERSION = '1.1'; + public const ALLOWED_HTTP_VERSIONS = ['1.0', '1.1', '2.0', '2']; /** - * Supported HTTP versions + * Default HTTP version * - * @var list + * @var string */ - public const SUPPORTED_HTTP_VERSIONS = ['1.0', '1.1', '2.0', '2']; + public const DEFAULT_HTTP_VERSION = '1.1'; /** * The message HTTP version @@ -71,7 +68,7 @@ abstract class Message implements MessageInterface private array $headers = []; /** - * Original header names (see $headers) + * Original header names * * @var array */ @@ -137,7 +134,7 @@ public function hasHeader($name): bool } /** - * Gets a header value from the message by the given name + * Gets a header value(s) from the message by the given name * * @param string $name * @@ -145,15 +142,13 @@ public function hasHeader($name): bool */ public function getHeader($name): array { - if (!$this->hasHeader($name)) { + $key = strtolower($name); + + if (!isset($this->headerNames[$key])) { return []; } - $key = strtolower($name); - $originalName = $this->headerNames[$key]; - $value = $this->headers[$originalName]; - - return $value; + return $this->headers[$this->headerNames[$key]]; } /** @@ -165,12 +160,13 @@ public function getHeader($name): array */ public function getHeaderLine($name): string { - $value = $this->getHeader($name); - if ([] === $value) { + $key = strtolower($name); + + if (!isset($this->headerNames[$key])) { return ''; } - return implode(',', $value); + return implode(',', $this->headers[$this->headerNames[$key]]); } /** @@ -181,7 +177,7 @@ public function getHeaderLine($name): string * * @return static * - * @throws InvalidHeaderException + * @throws InvalidArgumentException * If the header isn't valid. */ public function withHeader($name, $value): MessageInterface @@ -200,7 +196,7 @@ public function withHeader($name, $value): MessageInterface * * @return static * - * @throws InvalidHeaderException + * @throws InvalidArgumentException * If the header isn't valid. */ public function withAddedHeader($name, $value): MessageInterface @@ -277,7 +273,7 @@ final protected function setProtocolVersion($protocolVersion): void * * @return void * - * @throws InvalidHeaderException + * @throws InvalidArgumentException * If the header isn't valid. */ final protected function setHeader($name, $value, bool $replace = true): void @@ -298,8 +294,8 @@ final protected function setHeader($name, $value, bool $replace = true): void $this->headerNames[$key] ??= $name; $this->headers[$this->headerNames[$key]] ??= []; - foreach ($value as $subvalue) { - $this->headers[$this->headerNames[$key]][] = $subvalue; + foreach ($value as $item) { + $this->headers[$this->headerNames[$key]][] = $item; } } @@ -310,7 +306,7 @@ final protected function setHeader($name, $value, bool $replace = true): void * * @return void * - * @throws InvalidHeaderException + * @throws InvalidArgumentException * If one of the headers isn't valid. */ final protected function setHeaders(array $headers): void @@ -361,8 +357,8 @@ final protected function setBody(StreamInterface $body): void */ private function validateProtocolVersion($protocolVersion): void { - if (!in_array($protocolVersion, self::SUPPORTED_HTTP_VERSIONS, true)) { - throw new InvalidArgumentException('Invalid or unsupported HTTP version'); + if (!in_array($protocolVersion, self::ALLOWED_HTTP_VERSIONS, true)) { + throw new InvalidArgumentException('Unallowed HTTP version'); } } @@ -373,62 +369,62 @@ private function validateProtocolVersion($protocolVersion): void * * @return void * - * @throws InvalidHeaderNameException + * @throws InvalidArgumentException * If the header name isn't valid. */ private function validateHeaderName($name): void { if ($name === '') { - throw new InvalidHeaderNameException('HTTP header name cannot be an empty'); + throw new InvalidArgumentException('HTTP header name cannot be an empty'); } if (!is_string($name)) { - throw new InvalidHeaderNameException('HTTP header name must be a string'); + throw new InvalidArgumentException('HTTP header name must be a string'); } - if (!preg_match(Header::RFC7230_VALID_TOKEN, $name)) { - throw new InvalidHeaderNameException('HTTP header name is invalid'); + if (!preg_match(HeaderInterface::RFC7230_TOKEN_REGEX, $name)) { + throw new InvalidArgumentException('HTTP header name is invalid'); } } /** * Validates the given header value * - * @param string $validName - * @param array $value + * @param string $name + * @param array $value * * @return void * - * @throws InvalidHeaderValueException + * @throws InvalidArgumentException * If the header value isn't valid. */ - private function validateHeaderValue(string $validName, array $value): void + private function validateHeaderValue(string $name, array $value): void { if ([] === $value) { - throw new InvalidHeaderValueException(sprintf( + throw new InvalidArgumentException(sprintf( 'The "%s" HTTP header value cannot be an empty array', - $validName, + $name, )); } - foreach ($value as $i => $subvalue) { - if ('' === $subvalue) { + foreach ($value as $key => $item) { + if ('' === $item) { continue; } - if (!is_string($subvalue)) { - throw new InvalidHeaderValueException(sprintf( - 'The "%s[%d]" HTTP header value must be a string', - $validName, - $i + if (!is_string($item)) { + throw new InvalidArgumentException(sprintf( + 'The "%s[%s]" HTTP header value must be a string', + $name, + $key )); } - if (!preg_match(Header::RFC7230_VALID_FIELD_VALUE, $subvalue)) { - throw new InvalidHeaderValueException(sprintf( - 'The "%s[%d]" HTTP header value is invalid', - $validName, - $i + if (!preg_match(HeaderInterface::RFC7230_FIELD_VALUE_REGEX, $item)) { + throw new InvalidArgumentException(sprintf( + 'The "%s[%s]" HTTP header value is invalid', + $name, + $key )); } } diff --git a/src/Request.php b/src/Request.php index 54a3751..345d1b9 100644 --- a/src/Request.php +++ b/src/Request.php @@ -37,34 +37,18 @@ class Request extends Message implements RequestInterface, RequestMethodInterfac { /** - * Regular Expression for a request target validation - * - * @link https://tools.ietf.org/html/rfc7230#section-5.3 - * - * @var string - */ - public const RFC7230_VALID_REQUEST_TARGET = '/^[\x21-\x7E\x80-\xFF]+$/'; - - /** - * Default request method - * - * @var string - */ - public const DEFAULT_METHOD = self::METHOD_GET; - - /** - * Default request URI + * Regular Expression used for a request target validation * * @var string */ - public const DEFAULT_URI = '/'; + private const RFC7230_REQUEST_TARGET_REGEX = '/^[\x21-\x7E\x80-\xFF]+$/'; /** * The request method (aka verb) * * @var string */ - private string $method = self::DEFAULT_METHOD; + private string $method = self::METHOD_GET; /** * The request URI @@ -89,7 +73,7 @@ class Request extends Message implements RequestInterface, RequestMethodInterfac * @param StreamInterface|null $body * * @throws InvalidArgumentException - * If one of the parameters isn't valid. + * If one of the arguments isn't valid. */ public function __construct( ?string $method = null, @@ -101,7 +85,7 @@ public function __construct( $this->setMethod($method); } - $this->setUri($uri ?? self::DEFAULT_URI); + $this->setUri($uri ?? '/'); if (isset($headers)) { $this->setHeaders($headers); @@ -304,7 +288,7 @@ private function validateMethod($method): void throw new InvalidArgumentException('HTTP method must be a string'); } - if (!preg_match(Header::RFC7230_VALID_TOKEN, $method)) { + if (!preg_match(HeaderInterface::RFC7230_TOKEN_REGEX, $method)) { throw new InvalidArgumentException('Invalid HTTP method'); } } @@ -329,7 +313,7 @@ private function validateRequestTarget($requestTarget): void throw new InvalidArgumentException('HTTP request target must be a string'); } - if (!preg_match(self::RFC7230_VALID_REQUEST_TARGET, $requestTarget)) { + if (!preg_match(self::RFC7230_REQUEST_TARGET_REGEX, $requestTarget)) { throw new InvalidArgumentException('Invalid HTTP request target'); } } diff --git a/src/Response.php b/src/Response.php index d0c99cd..501cb36 100644 --- a/src/Response.php +++ b/src/Response.php @@ -40,7 +40,7 @@ class Response extends Message implements ResponseInterface, StatusCodeInterface * * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml * - * @var array + * @var array, non-empty-string> */ public const REASON_PHRASES = [ @@ -116,40 +116,19 @@ class Response extends Message implements ResponseInterface, StatusCodeInterface 511 => 'Network Authentication Required', ]; - /** - * Default response status code - * - * @var int - */ - public const DEFAULT_STATUS_CODE = self::STATUS_OK; - - /** - * Default response reason phrase - * - * @var string - */ - public const DEFAULT_REASON_PHRASE = self::REASON_PHRASES[self::DEFAULT_STATUS_CODE]; - - /** - * Reason phrase for unknown status code - * - * @var string - */ - public const UNKNOWN_STATUS_CODE_REASON_PHRASE = 'Unknown Status Code'; - /** * The response's status code * * @var int */ - private int $statusCode = self::DEFAULT_STATUS_CODE; + private int $statusCode = self::STATUS_OK; /** * The response's reason phrase * * @var string */ - private string $reasonPhrase = self::DEFAULT_REASON_PHRASE; + private string $reasonPhrase = self::REASON_PHRASES[self::STATUS_OK]; /** * Constrictor of the class @@ -160,7 +139,7 @@ class Response extends Message implements ResponseInterface, StatusCodeInterface * @param StreamInterface|null $body * * @throws InvalidArgumentException - * If one of the parameters isn't valid. + * If one of the arguments isn't valid. */ public function __construct( ?int $statusCode = null, @@ -237,7 +216,7 @@ final protected function setStatus($statusCode, $reasonPhrase): void $this->validateReasonPhrase($reasonPhrase); if ('' === $reasonPhrase) { - $reasonPhrase = self::REASON_PHRASES[$statusCode] ?? self::UNKNOWN_STATUS_CODE_REASON_PHRASE; + $reasonPhrase = self::REASON_PHRASES[$statusCode] ?? 'Unknown Status Code'; } $this->statusCode = $statusCode; @@ -281,11 +260,15 @@ private function validateStatusCode($statusCode): void */ private function validateReasonPhrase($reasonPhrase): void { + if ('' === $reasonPhrase) { + return; + } + if (!is_string($reasonPhrase)) { throw new InvalidArgumentException('HTTP reason phrase must be a string'); } - if (!preg_match(Header::RFC7230_VALID_FIELD_VALUE, $reasonPhrase)) { + if (!preg_match(HeaderInterface::RFC7230_FIELD_VALUE_REGEX, $reasonPhrase)) { throw new InvalidArgumentException('Invalid HTTP reason phrase'); } } diff --git a/src/Response/HtmlResponse.php b/src/Response/HtmlResponse.php index 1c71b96..3f7cead 100644 --- a/src/Response/HtmlResponse.php +++ b/src/Response/HtmlResponse.php @@ -27,18 +27,11 @@ use function method_exists; /** - * HTML Response + * HTML response */ -class HtmlResponse extends Response +final class HtmlResponse extends Response { - /** - * The response content type - * - * @var string - */ - public const CONTENT_TYPE = 'text/html; charset=utf-8'; - /** * Constructor of the class * @@ -49,22 +42,21 @@ class HtmlResponse extends Response */ public function __construct(int $statusCode, $html) { - $body = $this->createBody($html); + parent::__construct($statusCode); - $headers = ['Content-Type' => self::CONTENT_TYPE]; + $this->setBody($this->createBody($html)); - parent::__construct($statusCode, null, $headers, $body); + $this->setHeader('Content-Type', 'text/html; charset=utf-8'); } /** - * Creates the response body from the given HTML + * Creates the response body from the given HTML data * * @param mixed $html * * @return StreamInterface * * @throws InvalidArgumentException - * If the response body cannot be created from the given HTML. */ private function createBody($html): StreamInterface { @@ -78,7 +70,7 @@ private function createBody($html): StreamInterface } if (!is_string($html)) { - throw new InvalidArgumentException('Unable to create HTML response due to invalid body'); + throw new InvalidArgumentException('Unable to create HTML response due to unexpected HTML data'); } $stream = new PhpTempStream('r+b'); diff --git a/src/Response/JsonResponse.php b/src/Response/JsonResponse.php index 4057f4f..95c01f1 100644 --- a/src/Response/JsonResponse.php +++ b/src/Response/JsonResponse.php @@ -31,35 +31,28 @@ use const JSON_THROW_ON_ERROR; /** - * JSON Response + * JSON response */ -class JsonResponse extends Response +final class JsonResponse extends Response { - /** - * The response content type - * - * @var string - */ - public const CONTENT_TYPE = 'application/json; charset=utf-8'; - /** * Constructor of the class * * @param int $statusCode * @param mixed $data * @param int $flags - * @param int $depth + * @param int<1, max> $depth * * @throws InvalidArgumentException */ public function __construct(int $statusCode, $data, int $flags = 0, int $depth = 512) { - $body = $this->createBody($data, $flags, $depth); + parent::__construct($statusCode); - $headers = ['Content-Type' => self::CONTENT_TYPE]; + $this->setBody($this->createBody($data, $flags, $depth)); - parent::__construct($statusCode, null, $headers, $body); + $this->setHeader('Content-Type', 'application/json; charset=utf-8'); } /** @@ -67,12 +60,11 @@ public function __construct(int $statusCode, $data, int $flags = 0, int $depth = * * @param mixed $data * @param int $flags - * @param int $depth + * @param int<1, max> $depth * * @return StreamInterface * * @throws InvalidArgumentException - * If the response body cannot be created from the given JSON data. */ private function createBody($data, int $flags, int $depth): StreamInterface { @@ -80,10 +72,8 @@ private function createBody($data, int $flags, int $depth): StreamInterface return $data; } - $flags |= JSON_THROW_ON_ERROR; - try { - $payload = json_encode($data, $flags, $depth); + $payload = json_encode($data, $flags | JSON_THROW_ON_ERROR, $depth); } catch (JsonException $e) { throw new InvalidArgumentException(sprintf( 'Unable to create JSON response due to invalid JSON data: %s', diff --git a/src/ServerRequest.php b/src/ServerRequest.php index 0d9503c..4685dd5 100644 --- a/src/ServerRequest.php +++ b/src/ServerRequest.php @@ -38,42 +38,42 @@ class ServerRequest extends Request implements ServerRequestInterface /** * The server parameters * - * @var array + * @var array */ private array $serverParams; /** * The request's query parameters * - * @var array + * @var array */ private array $queryParams; /** * The request's cookie parameters * - * @var array + * @var array */ private array $cookieParams; /** * The request's uploaded files * - * @var array + * @var array */ - private array $uploadedFiles; + private array $uploadedFiles = []; /** * The request's parsed body * - * @var array|object|null + * @var array|object|null */ - private $parsedBody; + private $parsedBody = null; /** * The request attributes * - * @var array + * @var array */ private array $attributes; @@ -86,15 +86,15 @@ class ServerRequest extends Request implements ServerRequestInterface * @param array|null $headers * @param StreamInterface|null $body * - * @param array $serverParams - * @param array $queryParams - * @param array $cookieParams - * @param array $uploadedFiles - * @param array|object|null $parsedBody - * @param array $attributes + * @param array $serverParams + * @param array $queryParams + * @param array $cookieParams + * @param array $uploadedFiles + * @param array|object|null $parsedBody + * @param array $attributes * * @throws InvalidArgumentException - * If one of the parameters isn't valid. + * If one of the arguments isn't valid. */ public function __construct( ?string $protocolVersion = null, @@ -109,24 +109,30 @@ public function __construct( $parsedBody = null, array $attributes = [] ) { + parent::__construct($method, $uri, $headers, $body); + if (isset($protocolVersion)) { $this->setProtocolVersion($protocolVersion); } - parent::__construct($method, $uri, $headers, $body); + if (!empty($uploadedFiles)) { + $this->setUploadedFiles($uploadedFiles); + } + + if (isset($parsedBody)) { + $this->setParsedBody($parsedBody); + } $this->serverParams = $serverParams; $this->queryParams = $queryParams; $this->cookieParams = $cookieParams; - $this->setUploadedFiles($uploadedFiles); - $this->setParsedBody($parsedBody); $this->attributes = $attributes; } /** * Gets the server parameters * - * @return array + * @return array */ public function getServerParams(): array { @@ -136,7 +142,7 @@ public function getServerParams(): array /** * Gets the request's query parameters * - * @return array + * @return array */ public function getQueryParams(): array { @@ -146,7 +152,7 @@ public function getQueryParams(): array /** * Creates a new instance of the request with the given query parameters * - * @param array $query + * @param array $query * * @return static */ @@ -161,7 +167,7 @@ public function withQueryParams(array $query): ServerRequestInterface /** * Gets the request's cookie parameters * - * @return array + * @return array */ public function getCookieParams(): array { @@ -171,7 +177,7 @@ public function getCookieParams(): array /** * Creates a new instance of the request with the given cookie parameters * - * @param array $cookies + * @param array $cookies * * @return static */ @@ -186,7 +192,7 @@ public function withCookieParams(array $cookies): ServerRequestInterface /** * Gets the request's uploaded files * - * @return array + * @return array */ public function getUploadedFiles(): array { @@ -196,7 +202,7 @@ public function getUploadedFiles(): array /** * Creates a new instance of the request with the given uploaded files * - * @param array $uploadedFiles + * @param array $uploadedFiles * * @return static * @@ -214,7 +220,7 @@ public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface /** * Gets the request's parsed body * - * @return array|object|null + * @return array|object|null */ public function getParsedBody() { @@ -224,7 +230,7 @@ public function getParsedBody() /** * Creates a new instance of the request with the given parsed body * - * @param array|object|null $data + * @param array|object|null $data * * @return static * @@ -242,7 +248,7 @@ public function withParsedBody($data): ServerRequestInterface /** * Gets the request attributes * - * @return array + * @return array */ public function getAttributes(): array { @@ -302,7 +308,7 @@ public function withoutAttribute($name): ServerRequestInterface /** * Sets the given uploaded files to the request * - * @param array $files + * @param array $files * * @return void * @@ -319,7 +325,7 @@ final protected function setUploadedFiles(array $files): void /** * Sets the given parsed body to the request * - * @param array|object|null $data + * @param array|object|null $data * * @return void * @@ -336,7 +342,7 @@ final protected function setParsedBody($data): void /** * Validates the given uploaded files * - * @param array $files + * @param array $files * * @return void * @@ -350,17 +356,11 @@ private function validateUploadedFiles(array $files): void } /** - * @param mixed $file - * - * @return void - * - * @throws InvalidArgumentException - * * @psalm-suppress MissingClosureParamType */ array_walk_recursive($files, static function ($file): void { if (! ($file instanceof UploadedFileInterface)) { - throw new InvalidArgumentException('Invalid uploaded files'); + throw new InvalidArgumentException('Invalid uploaded file'); } }); } diff --git a/src/ServerRequestFactory.php b/src/ServerRequestFactory.php index 9d33a51..5b9ed0f 100644 --- a/src/ServerRequestFactory.php +++ b/src/ServerRequestFactory.php @@ -29,11 +29,11 @@ class ServerRequestFactory implements ServerRequestFactoryInterface /** * Creates a new request from superglobals variables * - * @param array|null $serverParams - * @param array|null $queryParams - * @param array|null $cookieParams - * @param array|null $uploadedFiles - * @param array|null $parsedBody + * @param array|null $serverParams + * @param array|null $queryParams + * @param array|null $cookieParams + * @param array|null $uploadedFiles + * @param array|null $parsedBody * * @return ServerRequestInterface * @@ -47,11 +47,11 @@ public static function fromGlobals( ?array $uploadedFiles = null, ?array $parsedBody = null ): ServerRequestInterface { - $serverParams = $serverParams ?? $_SERVER; - $queryParams = $queryParams ?? $_GET; - $cookieParams = $cookieParams ?? $_COOKIE; - $uploadedFiles = $uploadedFiles ?? $_FILES; - $parsedBody = $parsedBody ?? $_POST; + $serverParams ??= $_SERVER; + $queryParams ??= $_GET; + $cookieParams ??= $_COOKIE; + $uploadedFiles ??= $_FILES; + $parsedBody ??= $_POST; return new ServerRequest( server_request_protocol_version($serverParams), @@ -68,7 +68,11 @@ public static function fromGlobals( } /** - * {@inheritdoc} + * Creates a new request + * + * @param string $method + * @param mixed $uri + * @param array $serverParams */ public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface { diff --git a/src/Stream.php b/src/Stream.php index 22a0e5c..7a52a40 100644 --- a/src/Stream.php +++ b/src/Stream.php @@ -15,10 +15,8 @@ * Import classes */ use Psr\Http\Message\StreamInterface; -use Sunrise\Http\Message\Exception\FailedStreamOperationException; use Sunrise\Http\Message\Exception\InvalidArgumentException; -use Sunrise\Http\Message\Exception\InvalidStreamException; -use Sunrise\Http\Message\Exception\InvalidStreamOperationException; +use Sunrise\Http\Message\Exception\RuntimeException; use Throwable; /** @@ -61,7 +59,7 @@ class Stream implements StreamInterface * * @var bool */ - private $autoClose; + private bool $autoClose; /** * Constructor of the class @@ -90,7 +88,7 @@ public function __construct($resource, bool $autoClose = true) * @return StreamInterface * * @throws InvalidArgumentException - * If a stream cannot be created. + * If the stream cannot be initialized with the resource. */ public static function create($resource): StreamInterface { @@ -166,18 +164,17 @@ public function eof(): bool * * @return int * - * @throws InvalidStreamException - * @throws FailedStreamOperationException + * @throws RuntimeException */ public function tell(): int { if (!is_resource($this->resource)) { - throw InvalidStreamException::noResource(); + throw new RuntimeException('Stream has no resource'); } $result = ftell($this->resource); if ($result === false) { - throw new FailedStreamOperationException('Unable to get the stream pointer position'); + throw new RuntimeException('Unable to get the stream pointer position'); } return $result; @@ -205,9 +202,7 @@ public function isSeekable(): bool * * @return void * - * @throws InvalidStreamException - * @throws InvalidStreamOperationException - * @throws FailedStreamOperationException + * @throws RuntimeException */ public function rewind(): void { @@ -224,23 +219,21 @@ public function rewind(): void * * @return void * - * @throws InvalidStreamException - * @throws InvalidStreamOperationException - * @throws FailedStreamOperationException + * @throws RuntimeException */ public function seek($offset, $whence = SEEK_SET): void { if (!is_resource($this->resource)) { - throw InvalidStreamException::noResource(); + throw new RuntimeException('Stream has no resource'); } if (!$this->isSeekable()) { - throw new InvalidStreamOperationException('Stream is not seekable'); + throw new RuntimeException('Stream is not seekable'); } $result = fseek($this->resource, $offset, $whence); if ($result !== 0) { - throw new FailedStreamOperationException('Unable to move the stream pointer position'); + throw new RuntimeException('Unable to move the stream pointer position'); } } @@ -272,23 +265,21 @@ public function isWritable(): bool * * @return int * - * @throws InvalidStreamException - * @throws InvalidStreamOperationException - * @throws FailedStreamOperationException + * @throws RuntimeException */ public function write($string): int { if (!is_resource($this->resource)) { - throw InvalidStreamException::noResource(); + throw new RuntimeException('Stream has no resource'); } if (!$this->isWritable()) { - throw new InvalidStreamOperationException('Stream is not writable'); + throw new RuntimeException('Stream is not writable'); } $result = fwrite($this->resource, $string); if ($result === false) { - throw new FailedStreamOperationException('Unable to write to the stream'); + throw new RuntimeException('Unable to write to the stream'); } return $result; @@ -317,26 +308,26 @@ public function isReadable(): bool * @link http://php.net/manual/en/function.fread.php * * @param int $length + * @psalm-param int $length + * @phpstan-param int<0, max> $length * * @return string * - * @throws InvalidStreamException - * @throws InvalidStreamOperationException - * @throws FailedStreamOperationException + * @throws RuntimeException */ public function read($length): string { if (!is_resource($this->resource)) { - throw InvalidStreamException::noResource(); + throw new RuntimeException('Stream has no resource'); } if (!$this->isReadable()) { - throw new InvalidStreamOperationException('Stream is not readable'); + throw new RuntimeException('Stream is not readable'); } $result = fread($this->resource, $length); if ($result === false) { - throw new FailedStreamOperationException('Unable to read from the stream'); + throw new RuntimeException('Unable to read from the stream'); } return $result; @@ -349,23 +340,21 @@ public function read($length): string * * @return string * - * @throws InvalidStreamException - * @throws InvalidStreamOperationException - * @throws FailedStreamOperationException + * @throws RuntimeException */ public function getContents(): string { if (!is_resource($this->resource)) { - throw InvalidStreamException::noResource(); + throw new RuntimeException('Stream has no resource'); } if (!$this->isReadable()) { - throw new InvalidStreamOperationException('Stream is not readable'); + throw new RuntimeException('Stream is not readable'); } $result = stream_get_contents($this->resource); if ($result === false) { - throw new FailedStreamOperationException('Unable to read the remainder of the stream'); + throw new RuntimeException('Unable to read the remainder of the stream'); } return $result; @@ -397,7 +386,7 @@ public function getMetadata($key = null) /** * Gets the stream size * - * Returns NULL if the stream without a resource, + * Returns NULL if the stream doesn't have a resource, * or if the stream size cannot be determined. * * @link http://php.net/manual/en/function.fstat.php diff --git a/src/Stream/FileStream.php b/src/Stream/FileStream.php index 5e01e62..c3ecac1 100644 --- a/src/Stream/FileStream.php +++ b/src/Stream/FileStream.php @@ -14,10 +14,8 @@ /** * Import classes */ -use Psr\Http\Message\StreamInterface; -use Sunrise\Http\Message\Exception\RuntimeException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; use Sunrise\Http\Message\Stream; -use Throwable; /** * Import functions @@ -25,13 +23,11 @@ use function fopen; use function is_resource; use function sprintf; -use function sys_get_temp_dir; -use function tempnam; /** * FileStream */ -class FileStream extends Stream +final class FileStream extends Stream { /** @@ -40,18 +36,14 @@ class FileStream extends Stream * @param string $filename * @param string $mode * - * @throws RuntimeException + * @throws InvalidArgumentException */ public function __construct(string $filename, string $mode) { - try { - $resource = fopen($filename, $mode); - } catch (Throwable $e) { - $resource = false; - } + $resource = @fopen($filename, $mode); if (!is_resource($resource)) { - throw new RuntimeException(sprintf( + throw new InvalidArgumentException(sprintf( 'Unable to open the file "%s" in the mode "%s"', $filename, $mode @@ -60,18 +52,4 @@ public function __construct(string $filename, string $mode) parent::__construct($resource); } - - /** - * Creates a new temporary file in the temporary directory - * - * @return StreamInterface - * - * @throws RuntimeException - */ - public static function tempFile(): StreamInterface - { - $filename = tempnam(sys_get_temp_dir(), 'sunrisephp'); - - return new self($filename, 'w+b'); - } } diff --git a/src/Stream/PhpInputStream.php b/src/Stream/PhpInputStream.php index 018213b..3f37f88 100644 --- a/src/Stream/PhpInputStream.php +++ b/src/Stream/PhpInputStream.php @@ -25,7 +25,7 @@ /** * @link https://www.php.net/manual/en/wrappers.php.php#wrappers.php.input */ -class PhpInputStream extends Stream +final class PhpInputStream extends Stream { /** @@ -33,12 +33,15 @@ class PhpInputStream extends Stream */ public function __construct() { + /** @var resource */ $input = fopen('php://input', 'rb'); - $resource = fopen('php://temp', 'r+b'); - stream_copy_to_stream($input, $resource); + /** @var resource */ + $handle = fopen('php://temp', 'r+b'); - parent::__construct($resource); + stream_copy_to_stream($input, $handle); + + parent::__construct($handle); $this->rewind(); } diff --git a/src/Stream/PhpMemoryStream.php b/src/Stream/PhpMemoryStream.php index 0ae1b46..67dc1a1 100644 --- a/src/Stream/PhpMemoryStream.php +++ b/src/Stream/PhpMemoryStream.php @@ -24,7 +24,7 @@ /** * @link https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory */ -class PhpMemoryStream extends Stream +final class PhpMemoryStream extends Stream { /** diff --git a/src/Stream/PhpTempStream.php b/src/Stream/PhpTempStream.php index d16b889..74dd59e 100644 --- a/src/Stream/PhpTempStream.php +++ b/src/Stream/PhpTempStream.php @@ -14,7 +14,6 @@ /** * Import classes */ -use Sunrise\Http\Message\Exception\InvalidArgumentException; use Sunrise\Http\Message\Stream; /** @@ -26,23 +25,17 @@ /** * @link https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory */ -class PhpTempStream extends Stream +final class PhpTempStream extends Stream { /** * Constructor of the class * * @param string $mode - * @param int $maxmemory - * - * @throws InvalidArgumentException + * @param int<0, max> $maxmemory */ public function __construct(string $mode = 'r+b', int $maxmemory = 2097152) { - if ($maxmemory < 0) { - throw new InvalidArgumentException('Argument #2 ($maxmemory) must be greater than or equal to 0'); - } - parent::__construct(fopen(sprintf('php://temp/maxmemory:%d', $maxmemory), $mode)); } } diff --git a/src/Stream/TempFileStream.php b/src/Stream/TempFileStream.php new file mode 100644 index 0000000..7de5bb4 --- /dev/null +++ b/src/Stream/TempFileStream.php @@ -0,0 +1,61 @@ + + * @copyright Copyright (c) 2018, Anatoly Nekhay + * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE + * @link https://github.com/sunrise-php/http-message + */ + +namespace Sunrise\Http\Message\Stream; + +/** + * Import classes + */ +use Sunrise\Http\Message\Exception\RuntimeException; +use Sunrise\Http\Message\Stream; + +/** + * Import functions + */ +use function fopen; +use function is_resource; +use function is_writable; +use function sys_get_temp_dir; +use function tempnam; + +/** + * TempFileStream + */ +final class TempFileStream extends Stream +{ + + /** + * Constructor of the class + * + * @param string $prefix + * + * @throws RuntimeException + */ + public function __construct(string $prefix = '') + { + $dirname = sys_get_temp_dir(); + if (!is_writable($dirname)) { + throw new RuntimeException('Temporary files directory is not writable'); + } + + $filename = tempnam($dirname, $prefix); + if ($filename === false) { + throw new RuntimeException('Temporary file name cannot be generated'); + } + + $resource = fopen($filename, 'w+b'); + if (!is_resource($resource)) { + throw new RuntimeException('Temporary file cannot be created or opened'); + } + + parent::__construct($resource); + } +} diff --git a/src/Stream/TmpfileStream.php b/src/Stream/TmpfileStream.php index b6e217b..51f331c 100644 --- a/src/Stream/TmpfileStream.php +++ b/src/Stream/TmpfileStream.php @@ -32,7 +32,7 @@ * * @link https://www.php.net/tmpfile */ -class TmpfileStream extends Stream +final class TmpfileStream extends Stream { /** @@ -42,16 +42,16 @@ class TmpfileStream extends Stream */ public function __construct() { - $tmpdir = sys_get_temp_dir(); - if (!is_writable($tmpdir)) { + $dirname = sys_get_temp_dir(); + if (!is_writable($dirname)) { throw new RuntimeException('Temporary files directory is not writable'); } - $tmpfile = tmpfile(); - if (!is_resource($tmpfile)) { + $resource = tmpfile(); + if (!is_resource($resource)) { throw new RuntimeException('Temporary file cannot be created or opened'); } - parent::__construct($tmpfile); + parent::__construct($resource); } } diff --git a/src/UploadedFile.php b/src/UploadedFile.php index fedaaeb..7be2471 100644 --- a/src/UploadedFile.php +++ b/src/UploadedFile.php @@ -16,9 +16,8 @@ */ use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; -use Sunrise\Http\Message\Exception\FailedUploadedFileOperationException; -use Sunrise\Http\Message\Exception\InvalidUploadedFileException; -use Sunrise\Http\Message\Exception\InvalidUploadedFileOperationException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; +use Sunrise\Http\Message\Exception\RuntimeException; use Sunrise\Http\Message\Stream\FileStream; /** @@ -56,27 +55,19 @@ class UploadedFile implements UploadedFileInterface * * @link https://www.php.net/manual/en/features.file-upload.errors.php * - * @var array + * @var array */ public const UPLOAD_ERRORS = [ UPLOAD_ERR_OK => 'No error', - UPLOAD_ERR_INI_SIZE => 'The uploaded file exceeds the upload_max_filesize directive in php.ini', - UPLOAD_ERR_FORM_SIZE => 'The uploaded file exceeds the MAX_FILE_SIZE directive ' . - 'that was specified in the HTML form', - UPLOAD_ERR_PARTIAL => 'The uploaded file was only partially uploaded', + UPLOAD_ERR_INI_SIZE => 'Uploaded file exceeds the upload_max_filesize directive in the php.ini', + UPLOAD_ERR_FORM_SIZE => 'Uploaded file exceeds the MAX_FILE_SIZE directive in the HTML form', + UPLOAD_ERR_PARTIAL => 'Uploaded file was only partially uploaded', UPLOAD_ERR_NO_FILE => 'No file was uploaded', - UPLOAD_ERR_NO_TMP_DIR => 'Missing a temporary folder', + UPLOAD_ERR_NO_TMP_DIR => 'Missing temporary directory', UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk', - UPLOAD_ERR_EXTENSION => 'File upload stopped by extension', + UPLOAD_ERR_EXTENSION => 'File upload was stopped by a PHP extension', ]; - /** - * Unknown error description - * - * @var string - */ - public const UNKNOWN_ERROR_TEXT = 'Unknown error'; - /** * The file stream * @@ -106,14 +97,14 @@ class UploadedFile implements UploadedFileInterface private string $errorMessage; /** - * The file name + * The client's file name * * @var string|null */ private ?string $clientFilename; /** - * The file type + * The client's file media type * * @var string|null */ @@ -122,28 +113,28 @@ class UploadedFile implements UploadedFileInterface /** * Constructor of the class * - * @param StreamInterface $stream + * @param StreamInterface|null $stream * @param int|null $size * @param int $error * @param string|null $clientFilename * @param string|null $clientMediaType */ public function __construct( - StreamInterface $stream, + ?StreamInterface $stream, ?int $size = null, int $error = UPLOAD_ERR_OK, ?string $clientFilename = null, ?string $clientMediaType = null ) { + // It doesn't make sense to keep the stream + // if the file wasn't successfully uploaded... if (UPLOAD_ERR_OK === $error) { $this->stream = $stream; } - $errorMessage = self::UPLOAD_ERRORS[$error] ?? self::UNKNOWN_ERROR_TEXT; - $this->size = $size; $this->errorCode = $error; - $this->errorMessage = $errorMessage; + $this->errorMessage = self::UPLOAD_ERRORS[$error] ?? 'Unknown error'; $this->clientFilename = $clientFilename; $this->clientMediaType = $clientMediaType; } @@ -153,23 +144,23 @@ public function __construct( * * @return StreamInterface * - * @throws InvalidUploadedFileException - * If the file has no a stream due to an error or - * if the file was already moved. + * @throws RuntimeException + * - If the file has no a stream due to an error; + * - If the file was already moved. */ public function getStream(): StreamInterface { if (UPLOAD_ERR_OK <> $this->errorCode) { - throw new InvalidUploadedFileException(sprintf( - 'The uploaded file has no a stream due to the error #%d (%s)', + throw new RuntimeException(sprintf( + 'Uploaded file has no a stream due to the error #%d (%s)', $this->errorCode, $this->errorMessage )); } if (!isset($this->stream)) { - throw new InvalidUploadedFileException( - 'The uploaded file has no a stream because it was already moved' + throw new RuntimeException( + 'Uploaded file has no a stream because it was already moved' ); } @@ -183,55 +174,51 @@ public function getStream(): StreamInterface * * @return void * - * @throws InvalidUploadedFileException - * If the file has no a stream due to an error or - * if the file was already moved. - * - * @throws InvalidUploadedFileOperationException - * If the file cannot be read. - * - * @throws FailedUploadedFileOperationException + * @throws InvalidArgumentException * If the target path cannot be used. + * + * @throws RuntimeException + * - If the file has no a stream due to an error; + * - If the file was already moved; + * - If the file cannot be read. */ public function moveTo($targetPath): void { if (UPLOAD_ERR_OK <> $this->errorCode) { - throw new InvalidUploadedFileException(sprintf( - 'The uploaded file cannot be moved due to the error #%d (%s)', + throw new RuntimeException(sprintf( + 'Uploaded file cannot be moved due to the error #%d (%s)', $this->errorCode, $this->errorMessage )); } if (!isset($this->stream)) { - throw new InvalidUploadedFileException( - 'The uploaded file cannot be moved because it was already moved' + throw new RuntimeException( + 'Uploaded file cannot be moved because it was already moved' ); } if (!$this->stream->isReadable()) { - throw new InvalidUploadedFileOperationException( - 'The uploaded file cannot be moved because it is not readable' + throw new RuntimeException( + 'Uploaded file cannot be moved because it is not readable' ); } - $targetDir = dirname($targetPath); - if (!is_dir($targetDir) || !is_writable($targetDir)) { - throw new FailedUploadedFileOperationException(sprintf( - 'The uploaded file cannot be moved because the directory "%s" is not writable', - $targetDir + try { + $targetStream = new FileStream($targetPath, 'wb'); + } catch (InvalidArgumentException $e) { + throw new InvalidArgumentException(sprintf( + 'Uploaded file cannot be moved due to the error: %s', + $e->getMessage() )); } - $targetStream = new FileStream($targetPath, 'wb'); - if ($this->stream->isSeekable()) { $this->stream->rewind(); } while (!$this->stream->eof()) { - $piece = $this->stream->read(4096); - $targetStream->write($piece); + $targetStream->write($this->stream->read(4096)); } $targetStream->close(); @@ -271,7 +258,7 @@ public function getError(): int } /** - * Gets the file name + * Gets the client's file name * * @return string|null */ @@ -281,7 +268,7 @@ public function getClientFilename(): ?string } /** - * Gets the file type + * Gets the client's file media type * * @return string|null */ diff --git a/src/Uri.php b/src/Uri.php index 5059c37..f488230 100644 --- a/src/Uri.php +++ b/src/Uri.php @@ -16,8 +16,6 @@ */ use Psr\Http\Message\UriInterface; use Sunrise\Http\Message\Exception\InvalidArgumentException; -use Sunrise\Http\Message\Exception\InvalidUriComponentException; -use Sunrise\Http\Message\Exception\InvalidUriException; use Sunrise\Http\Message\Uri\Component\Fragment; use Sunrise\Http\Message\Uri\Component\Host; use Sunrise\Http\Message\Uri\Component\Path; @@ -97,7 +95,7 @@ class Uri implements UriInterface * * @param string $uri * - * @throws InvalidUriException + * @throws InvalidArgumentException * If the URI isn't valid. */ public function __construct(string $uri = '') @@ -108,7 +106,7 @@ public function __construct(string $uri = '') $components = parse_url($uri); if ($components === false) { - throw new InvalidUriException('Unable to parse URI'); + throw new InvalidArgumentException('Invalid URI'); } if (isset($components['scheme'])) { @@ -151,7 +149,7 @@ public function __construct(string $uri = '') * @return UriInterface * * @throws InvalidArgumentException - * If a URI cannot be created. + * If the URI isn't valid. */ public static function create($uri): UriInterface { @@ -169,7 +167,7 @@ public static function create($uri): UriInterface /** * {@inheritdoc} * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the scheme isn't valid. */ public function withScheme($scheme): UriInterface @@ -183,7 +181,7 @@ public function withScheme($scheme): UriInterface /** * {@inheritdoc} * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the user information isn't valid. */ public function withUserInfo($user, $password = null): UriInterface @@ -197,7 +195,7 @@ public function withUserInfo($user, $password = null): UriInterface /** * {@inheritdoc} * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the host isn't valid. */ public function withHost($host): UriInterface @@ -211,7 +209,7 @@ public function withHost($host): UriInterface /** * {@inheritdoc} * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the port isn't valid. */ public function withPort($port): UriInterface @@ -225,7 +223,7 @@ public function withPort($port): UriInterface /** * {@inheritdoc} * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the path isn't valid. */ public function withPath($path): UriInterface @@ -239,7 +237,7 @@ public function withPath($path): UriInterface /** * {@inheritdoc} * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the query isn't valid. */ public function withQuery($query): UriInterface @@ -253,7 +251,7 @@ public function withQuery($query): UriInterface /** * {@inheritdoc} * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the fragment isn't valid. */ public function withFragment($fragment): UriInterface @@ -419,14 +417,12 @@ public function __toString(): string * * @return void * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the scheme isn't valid. */ final protected function setScheme($scheme): void { - $component = new Scheme($scheme); - - $this->scheme = $component->getValue(); + $this->scheme = (new Scheme($scheme))->getValue(); } /** @@ -437,14 +433,12 @@ final protected function setScheme($scheme): void * * @return void * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the user information isn't valid. */ final protected function setUserInfo($user, $password): void { - $component = new UserInfo($user, $password); - - $this->userInfo = $component->getValue(); + $this->userInfo = (new UserInfo($user, $password))->getValue(); } /** @@ -454,14 +448,12 @@ final protected function setUserInfo($user, $password): void * * @return void * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the host isn't valid. */ final protected function setHost($host): void { - $component = new Host($host); - - $this->host = $component->getValue(); + $this->host = (new Host($host))->getValue(); } /** @@ -471,14 +463,12 @@ final protected function setHost($host): void * * @return void * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the port isn't valid. */ final protected function setPort($port): void { - $component = new Port($port); - - $this->port = $component->getValue(); + $this->port = (new Port($port))->getValue(); } /** @@ -488,14 +478,12 @@ final protected function setPort($port): void * * @return void * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the path isn't valid. */ final protected function setPath($path): void { - $component = new Path($path); - - $this->path = $component->getValue(); + $this->path = (new Path($path))->getValue(); } /** @@ -505,14 +493,12 @@ final protected function setPath($path): void * * @return void * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the query isn't valid. */ final protected function setQuery($query): void { - $component = new Query($query); - - $this->query = $component->getValue(); + $this->query = (new Query($query))->getValue(); } /** @@ -522,13 +508,11 @@ final protected function setQuery($query): void * * @return void * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the fragment isn't valid. */ final protected function setFragment($fragment): void { - $component = new Fragment($fragment); - - $this->fragment = $component->getValue(); + $this->fragment = (new Fragment($fragment))->getValue(); } } diff --git a/src/Uri/Component/Fragment.php b/src/Uri/Component/Fragment.php index 8c89e70..198d45b 100644 --- a/src/Uri/Component/Fragment.php +++ b/src/Uri/Component/Fragment.php @@ -14,7 +14,7 @@ /** * Import classes */ -use Sunrise\Http\Message\Exception\InvalidUriComponentException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; /** * Import functions @@ -32,11 +32,12 @@ final class Fragment implements ComponentInterface { /** - * Regular expression to normalize the component value + * Regular expression used for the component normalization * * @var string */ - private const NORMALIZE_REGEX = '/(?:(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-\._~\!\$&\'\(\)\*\+,;\=\:@\/\?]+)|(.?))/u'; + // phpcs:ignore Generic.Files.LineLength + private const NORMALIZATION_REGEX = '/(?:%[0-9A-Fa-f]{2}|[\x21\x24\x26-\x3b\x3d\x3f-\x5a\x5f\x61-\x7a\x7e])*|(.?)/u'; /** * The component value @@ -50,7 +51,7 @@ final class Fragment implements ComponentInterface * * @param mixed $value * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the component isn't valid. */ public function __construct($value) @@ -60,14 +61,17 @@ public function __construct($value) } if (!is_string($value)) { - throw new InvalidUriComponentException('URI component "fragment" must be a string'); + throw new InvalidArgumentException('URI component "fragment" must be a string'); } - $this->value = preg_replace_callback(self::NORMALIZE_REGEX, function (array $match): string { - /** @var array{0: string, 1?: string} $match */ - - return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; - }, $value); + $this->value = (string) preg_replace_callback( + self::NORMALIZATION_REGEX, + static function (array $match): string { + /** @var array{0: string, 1?: string} $match */ + return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; + }, + $value + ); } /** diff --git a/src/Uri/Component/Host.php b/src/Uri/Component/Host.php index c5b8d69..fefc041 100644 --- a/src/Uri/Component/Host.php +++ b/src/Uri/Component/Host.php @@ -14,7 +14,7 @@ /** * Import classes */ -use Sunrise\Http\Message\Exception\InvalidUriComponentException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; /** * Import functions @@ -33,11 +33,12 @@ final class Host implements ComponentInterface { /** - * Regular expression to normalize the component value + * Regular expression used for the component normalization * * @var string */ - private const NORMALIZE_REGEX = '/(?:(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-\._~\!\$&\'\(\)\*\+,;\=]+)|(.?))/u'; + // phpcs:ignore Generic.Files.LineLength + private const NORMALIZATION_REGEX = '/(?:%[0-9A-Fa-f]{2}|[\x21\x24\x26-\x2e\x30-\x39\x3b\x3d\x41-\x5a\x5f\x61-\x7a\x7e]+)|(.?)/u'; /** * The component value @@ -51,7 +52,7 @@ final class Host implements ComponentInterface * * @param mixed $value * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the component isn't valid. */ public function __construct($value) @@ -61,14 +62,17 @@ public function __construct($value) } if (!is_string($value)) { - throw new InvalidUriComponentException('URI component "host" must be a string'); + throw new InvalidArgumentException('URI component "host" must be a string'); } - $this->value = preg_replace_callback(self::NORMALIZE_REGEX, function (array $match): string { - /** @var array{0: string, 1?: string} $match */ - - return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; - }, $value); + $this->value = (string) preg_replace_callback( + self::NORMALIZATION_REGEX, + static function (array $match): string { + /** @var array{0: string, 1?: string} $match */ + return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; + }, + $value + ); // the component is case-insensitive... $this->value = strtolower($this->value); diff --git a/src/Uri/Component/Password.php b/src/Uri/Component/Password.php index 11be4ea..c2461a0 100644 --- a/src/Uri/Component/Password.php +++ b/src/Uri/Component/Password.php @@ -14,7 +14,7 @@ /** * Import classes */ -use Sunrise\Http\Message\Exception\InvalidUriComponentException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; /** * Import functions @@ -32,11 +32,12 @@ final class Password implements ComponentInterface { /** - * Regular expression to normalize the component value + * Regular expression used for the component normalization * * @var string */ - private const NORMALIZE_REGEX = '/(?:(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-\._~\!\$&\'\(\)\*\+,;\=]+)|(.?))/u'; + // phpcs:ignore Generic.Files.LineLength + private const NORMALIZATION_REGEX = '/(?:%[0-9A-Fa-f]{2}|[\x21\x24\x26-\x2e\x30-\x39\x3b\x3d\x41-\x5a\x5f\x61-\x7a\x7e]+)|(.?)/u'; /** * The component value @@ -50,7 +51,7 @@ final class Password implements ComponentInterface * * @param mixed $value * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the component isn't valid. */ public function __construct($value) @@ -60,14 +61,35 @@ public function __construct($value) } if (!is_string($value)) { - throw new InvalidUriComponentException('URI component "password" must be a string'); + throw new InvalidArgumentException('URI component "password" must be a string'); } - $this->value = preg_replace_callback(self::NORMALIZE_REGEX, function (array $match): string { - /** @var array{0: string, 1?: string} $match */ + $this->value = (string) preg_replace_callback( + self::NORMALIZATION_REGEX, + static function (array $match): string { + /** @var array{0: string, 1?: string} $match */ + return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; + }, + $value + ); + } + + /** + * Creates a password component + * + * @param mixed $password + * + * @return Password + * + * @throws InvalidArgumentException + */ + public static function create($password): Password + { + if ($password instanceof Password) { + return $password; + } - return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; - }, $value); + return new Password($password); } /** diff --git a/src/Uri/Component/Path.php b/src/Uri/Component/Path.php index 5bafae1..dbcf91b 100644 --- a/src/Uri/Component/Path.php +++ b/src/Uri/Component/Path.php @@ -14,7 +14,7 @@ /** * Import classes */ -use Sunrise\Http\Message\Exception\InvalidUriComponentException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; /** * Import functions @@ -32,11 +32,12 @@ final class Path implements ComponentInterface { /** - * Regular expression to normalize the component value + * Regular expression used for the component normalization * * @var string */ - private const NORMALIZE_REGEX = '/(?:(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-\._~\!\$&\'\(\)\*\+,;\=\:@\/]+)|(.?))/u'; + // phpcs:ignore Generic.Files.LineLength + private const NORMALIZATION_REGEX = '/(?:%[0-9A-Fa-f]{2}|[\x21\x24\x26-\x3b\x3d\x40-\x5a\x5f\x61-\x7a\x7e]+)|(.?)/u'; /** * The component value @@ -50,7 +51,7 @@ final class Path implements ComponentInterface * * @param mixed $value * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the component isn't valid. */ public function __construct($value) @@ -60,14 +61,17 @@ public function __construct($value) } if (!is_string($value)) { - throw new InvalidUriComponentException('URI component "path" must be a string'); + throw new InvalidArgumentException('URI component "path" must be a string'); } - $this->value = preg_replace_callback(self::NORMALIZE_REGEX, function (array $match): string { - /** @var array{0: string, 1?: string} $match */ - - return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; - }, $value); + $this->value = (string) preg_replace_callback( + self::NORMALIZATION_REGEX, + static function (array $match): string { + /** @var array{0: string, 1?: string} $match */ + return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; + }, + $value + ); } /** diff --git a/src/Uri/Component/Port.php b/src/Uri/Component/Port.php index d46e981..ec96d9d 100644 --- a/src/Uri/Component/Port.php +++ b/src/Uri/Component/Port.php @@ -14,7 +14,7 @@ /** * Import classes */ -use Sunrise\Http\Message\Exception\InvalidUriComponentException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; /** * Import functions @@ -41,7 +41,7 @@ final class Port implements ComponentInterface * * @param mixed $value * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the component isn't valid. */ public function __construct($value) @@ -54,11 +54,11 @@ public function __construct($value) } if (!is_int($value)) { - throw new InvalidUriComponentException('URI component "port" must be an integer'); + throw new InvalidArgumentException('URI component "port" must be an integer'); } if (!($value >= $min && $value <= $max)) { - throw new InvalidUriComponentException('Invalid URI component "port"'); + throw new InvalidArgumentException('Invalid URI component "port"'); } $this->value = $value; diff --git a/src/Uri/Component/Query.php b/src/Uri/Component/Query.php index 09aeaf3..c7322a3 100644 --- a/src/Uri/Component/Query.php +++ b/src/Uri/Component/Query.php @@ -14,7 +14,7 @@ /** * Import classes */ -use Sunrise\Http\Message\Exception\InvalidUriComponentException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; /** * Import functions @@ -32,11 +32,12 @@ final class Query implements ComponentInterface { /** - * Regular expression to normalize the component value + * Regular expression used for the component normalization * * @var string */ - private const NORMALIZE_REGEX = '/(?:(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-\._~\!\$&\'\(\)\*\+,;\=\:@\/\?]+)|(.?))/u'; + // phpcs:ignore Generic.Files.LineLength + private const NORMALIZATION_REGEX = '/(?:%[0-9A-Fa-f]{2}|[\x21\x24\x26-\x3b\x3d\x3f-\x5a\x5f\x61-\x7a\x7e]+)|(.?)/u'; /** * The component value @@ -50,7 +51,7 @@ final class Query implements ComponentInterface * * @param mixed $value * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the component isn't valid. */ public function __construct($value) @@ -60,14 +61,17 @@ public function __construct($value) } if (!is_string($value)) { - throw new InvalidUriComponentException('URI component "query" must be a string'); + throw new InvalidArgumentException('URI component "query" must be a string'); } - $this->value = preg_replace_callback(self::NORMALIZE_REGEX, function (array $match): string { - /** @var array{0: string, 1?: string} $match */ - - return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; - }, $value); + $this->value = (string) preg_replace_callback( + self::NORMALIZATION_REGEX, + static function (array $match): string { + /** @var array{0: string, 1?: string} $match */ + return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; + }, + $value + ); } /** diff --git a/src/Uri/Component/Scheme.php b/src/Uri/Component/Scheme.php index fb4a24c..abe3aaf 100644 --- a/src/Uri/Component/Scheme.php +++ b/src/Uri/Component/Scheme.php @@ -14,7 +14,7 @@ /** * Import classes */ -use Sunrise\Http\Message\Exception\InvalidUriComponentException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; /** * Import functions @@ -32,11 +32,11 @@ final class Scheme implements ComponentInterface { /** - * Regular expression to validate the component value + * Regular expression used for the component validation * * @var string */ - private const VALIDATE_REGEX = '/^(?:[A-Za-z][0-9A-Za-z\+\-\.]*)?$/'; + private const VALIDATION_REGEX = '/^(?:[A-Za-z][0-9A-Za-z\x2b\x2d\x2e]*)?$/'; /** * The component value @@ -50,7 +50,7 @@ final class Scheme implements ComponentInterface * * @param mixed $value * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the component isn't valid. */ public function __construct($value) @@ -60,11 +60,11 @@ public function __construct($value) } if (!is_string($value)) { - throw new InvalidUriComponentException('URI component "scheme" must be a string'); + throw new InvalidArgumentException('URI component "scheme" must be a string'); } - if (!preg_match(self::VALIDATE_REGEX, $value)) { - throw new InvalidUriComponentException('Invalid URI component "scheme"'); + if (!preg_match(self::VALIDATION_REGEX, $value)) { + throw new InvalidArgumentException('Invalid URI component "scheme"'); } // the component is case-insensitive... diff --git a/src/Uri/Component/User.php b/src/Uri/Component/User.php index 9d84249..8daff17 100644 --- a/src/Uri/Component/User.php +++ b/src/Uri/Component/User.php @@ -14,7 +14,7 @@ /** * Import classes */ -use Sunrise\Http\Message\Exception\InvalidUriComponentException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; /** * Import functions @@ -32,11 +32,12 @@ final class User implements ComponentInterface { /** - * Regular expression to normalize the component value + * Regular expression used for the component normalization * * @var string */ - private const NORMALIZE_REGEX = '/(?:(?:%[0-9A-Fa-f]{2}|[0-9A-Za-z\-\._~\!\$&\'\(\)\*\+,;\=]+)|(.?))/u'; + // phpcs:ignore Generic.Files.LineLength + private const NORMALIZATION_REGEX = '/(?:%[0-9A-Fa-f]{2}|[\x21\x24\x26-\x2e\x30-\x39\x3b\x3d\x41-\x5a\x5f\x61-\x7a\x7e]+)|(.?)/u'; /** * The component value @@ -50,7 +51,7 @@ final class User implements ComponentInterface * * @param mixed $value * - * @throws InvalidUriComponentException + * @throws InvalidArgumentException * If the component isn't valid. */ public function __construct($value) @@ -60,14 +61,35 @@ public function __construct($value) } if (!is_string($value)) { - throw new InvalidUriComponentException('URI component "user" must be a string'); + throw new InvalidArgumentException('URI component "user" must be a string'); } - $this->value = preg_replace_callback(self::NORMALIZE_REGEX, function (array $match): string { - /** @var array{0: string, 1?: string} $match */ + $this->value = (string) preg_replace_callback( + self::NORMALIZATION_REGEX, + static function (array $match): string { + /** @var array{0: string, 1?: string} $match */ + return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; + }, + $value + ); + } + + /** + * Creates a user component + * + * @param mixed $user + * + * @return User + * + * @throws InvalidArgumentException + */ + public static function create($user): User + { + if ($user instanceof User) { + return $user; + } - return isset($match[1]) ? rawurlencode($match[1]) : $match[0]; - }, $value); + return new User($user); } /** diff --git a/src/Uri/Component/UserInfo.php b/src/Uri/Component/UserInfo.php index 1bf6e4d..0bc570a 100644 --- a/src/Uri/Component/UserInfo.php +++ b/src/Uri/Component/UserInfo.php @@ -11,6 +11,11 @@ namespace Sunrise\Http\Message\Uri\Component; +/** + * Import classes + */ +use Sunrise\Http\Message\Exception\InvalidArgumentException; + /** * URI component "User Information" * @@ -38,13 +43,16 @@ final class UserInfo implements ComponentInterface * * @param mixed $user * @param mixed $password + * + * @throws InvalidArgumentException + * If the user or password aren't valid. */ public function __construct($user, $password = null) { - $this->user = $user instanceof User ? $user : new User($user); + $this->user = User::create($user); if (isset($password)) { - $this->password = $password instanceof Password ? $password : new Password($password); + $this->password = Password::create($password); } } diff --git a/tests/BaseMessageTest.php b/tests/BaseMessageTest.php index 2b75e1f..af6d133 100644 --- a/tests/BaseMessageTest.php +++ b/tests/BaseMessageTest.php @@ -70,7 +70,7 @@ public function testSetProtocolVersion($protocolVersion): void public function testSetProtocolVersionAsNull(): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid or unsupported HTTP version'); + $this->expectExceptionMessage('Unallowed HTTP version'); $this->createSubject()->withProtocolVersion(null); } @@ -78,7 +78,7 @@ public function testSetProtocolVersionAsNull(): void public function testSetProtocolVersionAsNumber(): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid or unsupported HTTP version'); + $this->expectExceptionMessage('Unallowed HTTP version'); $this->createSubject()->withProtocolVersion(1.1); } @@ -89,7 +89,7 @@ public function testSetProtocolVersionAsNumber(): void public function testSetInvalidProtocolVersion($protocolVersion): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid or unsupported HTTP version'); + $this->expectExceptionMessage('Unallowed HTTP version'); $this->createSubject()->withProtocolVersion($protocolVersion); } @@ -645,7 +645,7 @@ public function testConstructorWithProtocolVersion(string $protocolVersion): voi public function testConstructorWithInvalidProtocolVersion(string $protocolVersion): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid or unsupported HTTP version'); + $this->expectExceptionMessage('Unallowed HTTP version'); $subject = $this->createSubjectWithProtocolVersion($protocolVersion); diff --git a/tests/BaseRequestTest.php b/tests/BaseRequestTest.php index 326ab3a..8d9f6bf 100644 --- a/tests/BaseRequestTest.php +++ b/tests/BaseRequestTest.php @@ -398,7 +398,7 @@ public function testConstructorWithStringUri(): void public function testConstructorWithInvalidUri(): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Unable to parse URI'); + $this->expectExceptionMessage('Invalid URI'); $subject = $this->createSubjectWithUri(':'); diff --git a/tests/BaseServerRequestTest.php b/tests/BaseServerRequestTest.php index b3304ef..8c87e76 100644 --- a/tests/BaseServerRequestTest.php +++ b/tests/BaseServerRequestTest.php @@ -144,7 +144,7 @@ public function testSetEmptyUploadedFiles(): void public function testSetInvalidUploadedFiles(): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid uploaded files'); + $this->expectExceptionMessage('Invalid uploaded file'); $this->createSubject()->withUploadedFiles(['foo' => 'bar']); } @@ -293,7 +293,7 @@ public function testConstructorWithUploadedFiles(): void public function testConstructorWithInvalidUploadedFiles(): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid uploaded files'); + $this->expectExceptionMessage('Invalid uploaded file'); $subject = $this->createSubjectWithUploadedFiles(['foo' => 'bar']); diff --git a/tests/Header/AccessControlAllowCredentialsHeaderTest.php b/tests/Header/AccessControlAllowCredentialsHeaderTest.php deleted file mode 100644 index b195b5b..0000000 --- a/tests/Header/AccessControlAllowCredentialsHeaderTest.php +++ /dev/null @@ -1,55 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new AccessControlAllowCredentialsHeader(); - - $this->assertSame('Access-Control-Allow-Credentials', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new AccessControlAllowCredentialsHeader(); - - $this->assertSame('true', $header->getFieldValue()); - } - - public function testBuild() - { - $header = new AccessControlAllowCredentialsHeader(); - - $expected = 'Access-Control-Allow-Credentials: true'; - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new AccessControlAllowCredentialsHeader(); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/AccessControlAllowHeadersHeaderTest.php b/tests/Header/AccessControlAllowHeadersHeaderTest.php deleted file mode 100644 index 3881b77..0000000 --- a/tests/Header/AccessControlAllowHeadersHeaderTest.php +++ /dev/null @@ -1,96 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new AccessControlAllowHeadersHeader('x-foo'); - - $this->assertSame('Access-Control-Allow-Headers', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new AccessControlAllowHeadersHeader('x-foo'); - - $this->assertSame('x-foo', $header->getFieldValue()); - } - - public function testSeveralValues() - { - $header = new AccessControlAllowHeadersHeader('x-foo', 'x-bar', 'x-baz'); - - $this->assertSame('x-foo, x-bar, x-baz', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Access-Control-Allow-Headers" is not valid'); - - new AccessControlAllowHeadersHeader(''); - } - - public function testEmptyValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Access-Control-Allow-Headers" is not valid'); - - new AccessControlAllowHeadersHeader('x-foo', '', 'x-bar'); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "x-foo=" for the header "Access-Control-Allow-Headers" is not valid'); - - // a token cannot contain the "=" character... - new AccessControlAllowHeadersHeader('x-foo='); - } - - public function testInvalidValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "x-bar=" for the header "Access-Control-Allow-Headers" is not valid'); - - // a token cannot contain the "=" character... - new AccessControlAllowHeadersHeader('x-foo', 'x-bar=', 'x-bar'); - } - - public function testBuild() - { - $header = new AccessControlAllowHeadersHeader('x-foo'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new AccessControlAllowHeadersHeader('x-foo'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/AccessControlAllowMethodsHeaderTest.php b/tests/Header/AccessControlAllowMethodsHeaderTest.php deleted file mode 100644 index fdb63e4..0000000 --- a/tests/Header/AccessControlAllowMethodsHeaderTest.php +++ /dev/null @@ -1,103 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new AccessControlAllowMethodsHeader('GET'); - - $this->assertSame('Access-Control-Allow-Methods', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new AccessControlAllowMethodsHeader('GET'); - - $this->assertSame('GET', $header->getFieldValue()); - } - - public function testSeveralValues() - { - $header = new AccessControlAllowMethodsHeader('HEAD', 'GET', 'POST'); - - $this->assertSame('HEAD, GET, POST', $header->getFieldValue()); - } - - public function testValueCapitalizing() - { - $header = new AccessControlAllowMethodsHeader('head', 'get', 'post'); - - $this->assertSame('HEAD, GET, POST', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Access-Control-Allow-Methods" is not valid'); - - new AccessControlAllowMethodsHeader(''); - } - - public function testEmptyValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Access-Control-Allow-Methods" is not valid'); - - new AccessControlAllowMethodsHeader('head', '', 'post'); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Access-Control-Allow-Methods" is not valid'); - - // isn't a token... - new AccessControlAllowMethodsHeader('@'); - } - - public function testInvalidValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Access-Control-Allow-Methods" is not valid'); - - // isn't a token... - new AccessControlAllowMethodsHeader('head', '@', 'post'); - } - - public function testBuild() - { - $header = new AccessControlAllowMethodsHeader('GET'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new AccessControlAllowMethodsHeader('GET'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/AccessControlAllowOriginHeaderTest.php b/tests/Header/AccessControlAllowOriginHeaderTest.php deleted file mode 100644 index c75c181..0000000 --- a/tests/Header/AccessControlAllowOriginHeaderTest.php +++ /dev/null @@ -1,106 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $uri = new Uri('http://localhost'); - $header = new AccessControlAllowOriginHeader($uri); - - $this->assertSame('Access-Control-Allow-Origin', $header->getFieldName()); - } - - public function testFieldValue() - { - $uri = new Uri('http://localhost'); - $header = new AccessControlAllowOriginHeader($uri); - - $this->assertSame('http://localhost', $header->getFieldValue()); - } - - public function testFieldValueWithoutUri() - { - $header = new AccessControlAllowOriginHeader(null); - - $this->assertSame('*', $header->getFieldValue()); - } - - public function testIgnoringUnnecessaryUriComponents() - { - $uri = new Uri('http://user:pass@localhost:3000/index.php?q#h'); - $header = new AccessControlAllowOriginHeader($uri); - - $this->assertSame('http://localhost:3000', $header->getFieldValue()); - } - - public function testUriWithPort() - { - $uri = new Uri('http://localhost:3000'); - $header = new AccessControlAllowOriginHeader($uri); - - $this->assertSame('http://localhost:3000', $header->getFieldValue()); - } - - public function testUriWithoutScheme() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The URI "//localhost" for the header "Access-Control-Allow-Origin" is not valid' - ); - - new AccessControlAllowOriginHeader(new Uri('//localhost')); - } - - public function testUriWithoutHost() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The URI "http:" for the header "Access-Control-Allow-Origin" is not valid' - ); - - new AccessControlAllowOriginHeader(new Uri('http:')); - } - - public function testBuild() - { - $uri = new Uri('http://localhost'); - $header = new AccessControlAllowOriginHeader($uri); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $uri = new Uri('http://localhost'); - $header = new AccessControlAllowOriginHeader($uri); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/AccessControlExposeHeadersHeaderTest.php b/tests/Header/AccessControlExposeHeadersHeaderTest.php deleted file mode 100644 index 271a1db..0000000 --- a/tests/Header/AccessControlExposeHeadersHeaderTest.php +++ /dev/null @@ -1,96 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new AccessControlExposeHeadersHeader('x-foo'); - - $this->assertSame('Access-Control-Expose-Headers', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new AccessControlExposeHeadersHeader('x-foo'); - - $this->assertSame('x-foo', $header->getFieldValue()); - } - - public function testSeveralValues() - { - $header = new AccessControlExposeHeadersHeader('x-foo', 'x-bar', 'x-baz'); - - $this->assertSame('x-foo, x-bar, x-baz', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Access-Control-Expose-Headers" is not valid'); - - new AccessControlExposeHeadersHeader(''); - } - - public function testEmptyValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Access-Control-Expose-Headers" is not valid'); - - new AccessControlExposeHeadersHeader('x-foo', '', 'x-baz'); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Access-Control-Expose-Headers" is not valid'); - - // isn't a token... - new AccessControlExposeHeadersHeader('@'); - } - - public function testInvalidValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Access-Control-Expose-Headers" is not valid'); - - // isn't a token... - new AccessControlExposeHeadersHeader('x-foo', '@', 'x-baz'); - } - - public function testBuild() - { - $header = new AccessControlExposeHeadersHeader('x-foo'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new AccessControlExposeHeadersHeader('x-foo'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/AccessControlMaxAgeHeaderTest.php b/tests/Header/AccessControlMaxAgeHeaderTest.php deleted file mode 100644 index 7520624..0000000 --- a/tests/Header/AccessControlMaxAgeHeaderTest.php +++ /dev/null @@ -1,90 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new AccessControlMaxAgeHeader(-1); - - $this->assertSame('Access-Control-Max-Age', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new AccessControlMaxAgeHeader(-1); - - $this->assertSame('-1', $header->getFieldValue()); - } - - /** - * @dataProvider validValueDataProvider - */ - public function testValidValue(int $validValue) - { - $header = new AccessControlMaxAgeHeader($validValue); - - $this->assertEquals($validValue, $header->getFieldValue()); - } - - public function validValueDataProvider(): array - { - return [[-1], [1], [2]]; - } - - /** - * @dataProvider invalidValueDataProvider - */ - public function testInvalidValue(int $invalidValue) - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage(sprintf( - 'The value "%d" for the header "Access-Control-Max-Age" is not valid', - $invalidValue - )); - - new AccessControlMaxAgeHeader($invalidValue); - } - - public function invalidValueDataProvider(): array - { - return [[-3], [-2], [0]]; - } - - public function testBuild() - { - $header = new AccessControlMaxAgeHeader(-1); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new AccessControlMaxAgeHeader(-1); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/AgeHeaderTest.php b/tests/Header/AgeHeaderTest.php deleted file mode 100644 index f3289fb..0000000 --- a/tests/Header/AgeHeaderTest.php +++ /dev/null @@ -1,90 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new AgeHeader(0); - - $this->assertSame('Age', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new AgeHeader(0); - - $this->assertSame('0', $header->getFieldValue()); - } - - /** - * @dataProvider validValueDataProvider - */ - public function testValidValue(int $validValue) - { - $header = new AgeHeader($validValue); - - $this->assertEquals($validValue, $header->getFieldValue()); - } - - public function validValueDataProvider(): array - { - return [[0], [1], [2]]; - } - - /** - * @dataProvider invalidValueDataProvider - */ - public function testInvalidValue(int $invalidValue) - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage(sprintf( - 'The value "%d" for the header "Age" is not valid', - $invalidValue - )); - - new AgeHeader($invalidValue); - } - - public function invalidValueDataProvider(): array - { - return [[-3], [-2], [-1]]; - } - - public function testBuild() - { - $header = new AgeHeader(0); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new AgeHeader(0); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/AllowHeaderTest.php b/tests/Header/AllowHeaderTest.php deleted file mode 100644 index 9c325be..0000000 --- a/tests/Header/AllowHeaderTest.php +++ /dev/null @@ -1,103 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new AllowHeader('GET'); - - $this->assertSame('Allow', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new AllowHeader('GET'); - - $this->assertSame('GET', $header->getFieldValue()); - } - - public function testSeveralValues() - { - $header = new AllowHeader('HEAD', 'GET', 'POST'); - - $this->assertSame('HEAD, GET, POST', $header->getFieldValue()); - } - - public function testValueCapitalizing() - { - $header = new AllowHeader('head', 'get', 'post'); - - $this->assertSame('HEAD, GET, POST', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Allow" is not valid'); - - new AllowHeader(''); - } - - public function testEmptyValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Allow" is not valid'); - - new AllowHeader('head', '', 'post'); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Allow" is not valid'); - - // isn't a token... - new AllowHeader('@'); - } - - public function testInvalidValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Allow" is not valid'); - - // isn't a token... - new AllowHeader('head', '@', 'post'); - } - - public function testBuild() - { - $header = new AllowHeader('GET'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new AllowHeader('GET'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/CacheControlHeaderTest.php b/tests/Header/CacheControlHeaderTest.php deleted file mode 100644 index 7d83961..0000000 --- a/tests/Header/CacheControlHeaderTest.php +++ /dev/null @@ -1,147 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new CacheControlHeader([]); - - $this->assertSame('Cache-Control', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new CacheControlHeader([]); - - $this->assertSame('', $header->getFieldValue()); - } - - public function testParameterWithEmptyValue() - { - $header = new CacheControlHeader([ - 'foo' => '', - ]); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testParameterWithToken() - { - $header = new CacheControlHeader([ - 'foo' => 'token', - ]); - - $this->assertSame('foo=token', $header->getFieldValue()); - } - - public function testParameterWithQuotedString() - { - $header = new CacheControlHeader([ - 'foo' => 'quoted string', - ]); - - $this->assertSame('foo="quoted string"', $header->getFieldValue()); - } - - public function testParameterWithInteger() - { - $header = new CacheControlHeader([ - 'foo' => 1, - ]); - - $this->assertSame('foo=1', $header->getFieldValue()); - } - - public function testSeveralParameters() - { - $header = new CacheControlHeader([ - 'foo' => '', - 'bar' => 'token', - 'baz' => 'quoted string', - 'qux' => 1, - ]); - - $this->assertSame('foo, bar=token, baz="quoted string", qux=1', $header->getFieldValue()); - } - - public function testInvalidParameterName() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "invalid name" for the header "Cache-Control" is not valid' - ); - - new CacheControlHeader(['invalid name' => 'value']); - } - - public function testInvalidParameterValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value ""invalid value"" for the header "Cache-Control" is not valid' - ); - - new CacheControlHeader(['name' => '"invalid value"']); - } - - public function testInvalidParameterNameType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "" for the header "Cache-Control" is not valid' - ); - - new CacheControlHeader([0 => 'value']); - } - - public function testInvalidParameterValueType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value "" for the header "Cache-Control" is not valid' - ); - - new CacheControlHeader(['name' => []]); - } - - public function testBuild() - { - $header = new CacheControlHeader(['foo' => 'bar']); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new CacheControlHeader(['foo' => 'bar']); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ClearSiteDataHeaderTest.php b/tests/Header/ClearSiteDataHeaderTest.php deleted file mode 100644 index 5e7d508..0000000 --- a/tests/Header/ClearSiteDataHeaderTest.php +++ /dev/null @@ -1,94 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ClearSiteDataHeader('foo'); - - $this->assertSame('Clear-Site-Data', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ClearSiteDataHeader('foo'); - - $this->assertSame('"foo"', $header->getFieldValue()); - } - - public function testSeveralValues() - { - $header = new ClearSiteDataHeader('foo', 'bar', 'baz'); - - $this->assertSame('"foo", "bar", "baz"', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $header = new ClearSiteDataHeader(''); - - $this->assertSame('""', $header->getFieldValue()); - } - - public function testEmptyValueAmongOthers() - { - $header = new ClearSiteDataHeader('foo', '', 'baz'); - - $this->assertSame('"foo", "", "baz"', $header->getFieldValue()); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value ""invalid value"" for the header "Clear-Site-Data" is not valid'); - - // cannot contain quotes... - new ClearSiteDataHeader('"invalid value"'); - } - - public function testInvalidValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value ""bar"" for the header "Clear-Site-Data" is not valid'); - - // cannot contain quotes... - new ClearSiteDataHeader('foo', '"bar"', 'baz'); - } - - public function testBuild() - { - $header = new ClearSiteDataHeader('foo'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ClearSiteDataHeader('foo'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ConnectionHeaderTest.php b/tests/Header/ConnectionHeaderTest.php deleted file mode 100644 index 036b9ed..0000000 --- a/tests/Header/ConnectionHeaderTest.php +++ /dev/null @@ -1,78 +0,0 @@ -assertSame('close', ConnectionHeader::CONNECTION_CLOSE); - $this->assertSame('keep-alive', ConnectionHeader::CONNECTION_KEEP_ALIVE); - } - - public function testContracts() - { - $header = new ConnectionHeader('foo'); - - $this->assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ConnectionHeader('foo'); - - $this->assertSame('Connection', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ConnectionHeader('foo'); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Connection" is not valid'); - - new ConnectionHeader(''); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Connection" is not valid'); - - // isn't a token... - new ConnectionHeader('@'); - } - - public function testBuild() - { - $header = new ConnectionHeader('foo'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ConnectionHeader('foo'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ContentDispositionHeaderTest.php b/tests/Header/ContentDispositionHeaderTest.php deleted file mode 100644 index 17ff90f..0000000 --- a/tests/Header/ContentDispositionHeaderTest.php +++ /dev/null @@ -1,166 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ContentDispositionHeader('foo'); - - $this->assertSame('Content-Disposition', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ContentDispositionHeader('foo'); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testParameterWithEmptyValue() - { - $header = new ContentDispositionHeader('foo', [ - 'bar' => '', - ]); - - $this->assertSame('foo; bar=""', $header->getFieldValue()); - } - - public function testParameterWithToken() - { - $header = new ContentDispositionHeader('foo', [ - 'bar' => 'token', - ]); - - $this->assertSame('foo; bar="token"', $header->getFieldValue()); - } - - public function testParameterWithQuotedString() - { - $header = new ContentDispositionHeader('foo', [ - 'bar' => 'quoted string', - ]); - - $this->assertSame('foo; bar="quoted string"', $header->getFieldValue()); - } - - public function testParameterWithInteger() - { - $header = new ContentDispositionHeader('foo', [ - 'bar' => 1, - ]); - - $this->assertSame('foo; bar="1"', $header->getFieldValue()); - } - - public function testSeveralParameters() - { - $header = new ContentDispositionHeader('foo', [ - 'bar' => '', - 'baz' => 'token', - 'bat' => 'quoted string', - 'qux' => 1, - ]); - - $this->assertSame('foo; bar=""; baz="token"; bat="quoted string"; qux="1"', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Content-Disposition" is not valid'); - - new ContentDispositionHeader(''); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Content-Disposition" is not valid'); - - // isn't a token... - new ContentDispositionHeader('@'); - } - - public function testInvalidParameterName() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "invalid name" for the header "Content-Disposition" is not valid' - ); - - // cannot contain spaces... - new ContentDispositionHeader('foo', ['invalid name' => 'value']); - } - - public function testInvalidParameterNameType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "" for the header "Content-Disposition" is not valid' - ); - - new ContentDispositionHeader('foo', [0 => 'value']); - } - - public function testInvalidParameterValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value ""invalid value"" for the header "Content-Disposition" is not valid' - ); - - // cannot contain quotes... - new ContentDispositionHeader('foo', ['name' => '"invalid value"']); - } - - public function testInvalidParameterValueType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value "" for the header "Content-Disposition" is not valid' - ); - - new ContentDispositionHeader('foo', ['name' => []]); - } - - public function testBuild() - { - $header = new ContentDispositionHeader('foo', ['bar' => 'baz']); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ContentDispositionHeader('foo', ['bar' => 'baz']); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ContentEncodingHeaderTest.php b/tests/Header/ContentEncodingHeaderTest.php deleted file mode 100644 index 3325846..0000000 --- a/tests/Header/ContentEncodingHeaderTest.php +++ /dev/null @@ -1,104 +0,0 @@ -assertSame('gzip', ContentEncodingHeader::GZIP); - $this->assertSame('compress', ContentEncodingHeader::COMPRESS); - $this->assertSame('deflate', ContentEncodingHeader::DEFLATE); - $this->assertSame('br', ContentEncodingHeader::BR); - } - - public function testContracts() - { - $header = new ContentEncodingHeader('foo'); - - $this->assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ContentEncodingHeader('foo'); - - $this->assertSame('Content-Encoding', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ContentEncodingHeader('foo'); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testSeveralValues() - { - $header = new ContentEncodingHeader('foo', 'bar', 'baz'); - - $this->assertSame('foo, bar, baz', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Content-Encoding" is not valid'); - - new ContentEncodingHeader(''); - } - - public function testEmptyValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Content-Encoding" is not valid'); - - new ContentEncodingHeader('foo', '', 'bar'); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "foo=" for the header "Content-Encoding" is not valid'); - - // a token cannot contain the "=" character... - new ContentEncodingHeader('foo='); - } - - public function testInvalidValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "bar=" for the header "Content-Encoding" is not valid'); - - // a token cannot contain the "=" character... - new ContentEncodingHeader('foo', 'bar=', 'bar'); - } - - public function testBuild() - { - $header = new ContentEncodingHeader('foo'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ContentEncodingHeader('foo'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ContentLanguageHeaderTest.php b/tests/Header/ContentLanguageHeaderTest.php deleted file mode 100644 index e789827..0000000 --- a/tests/Header/ContentLanguageHeaderTest.php +++ /dev/null @@ -1,114 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ContentLanguageHeader('foo'); - - $this->assertSame('Content-Language', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ContentLanguageHeader('foo'); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testSeveralValues() - { - $header = new ContentLanguageHeader('foo', 'bar', 'baz'); - - $this->assertSame('foo, bar, baz', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Content-Language" is not valid'); - - new ContentLanguageHeader(''); - } - - public function testEmptyValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Content-Language" is not valid'); - - new ContentLanguageHeader('foo', '', 'baz'); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Content-Language" is not valid'); - - // isn't a token... - new ContentLanguageHeader('@'); - } - - public function testInvalidValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Content-Language" is not valid'); - - // isn't a token... - new ContentLanguageHeader('foo', '@', 'baz'); - } - - public function testInvalidValueLength() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "VERYLONGWORD" for the header "Content-Language" is not valid'); - - // isn't a token... - new ContentLanguageHeader('VERYLONGWORD'); - } - - public function testInvalidValueLengthAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "VERYLONGWORD" for the header "Content-Language" is not valid'); - - // isn't a token... - new ContentLanguageHeader('foo', 'VERYLONGWORD', 'baz'); - } - - public function testBuild() - { - $header = new ContentLanguageHeader('foo'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ContentLanguageHeader('foo'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ContentLengthHeaderTest.php b/tests/Header/ContentLengthHeaderTest.php deleted file mode 100644 index 7eb9b1f..0000000 --- a/tests/Header/ContentLengthHeaderTest.php +++ /dev/null @@ -1,63 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ContentLengthHeader(0); - - $this->assertSame('Content-Length', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ContentLengthHeader(0); - - $this->assertSame('0', $header->getFieldValue()); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "-1" for the header "Content-Length" is not valid'); - - new ContentLengthHeader(-1); - } - - public function testBuild() - { - $header = new ContentLengthHeader(0); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ContentLengthHeader(0); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ContentLocationHeaderTest.php b/tests/Header/ContentLocationHeaderTest.php deleted file mode 100644 index 0234399..0000000 --- a/tests/Header/ContentLocationHeaderTest.php +++ /dev/null @@ -1,61 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $uri = new Uri('/'); - $header = new ContentLocationHeader($uri); - - $this->assertSame('Content-Location', $header->getFieldName()); - } - - public function testFieldValue() - { - $uri = new Uri('/'); - $header = new ContentLocationHeader($uri); - - $this->assertSame('/', $header->getFieldValue()); - } - - public function testBuild() - { - $uri = new Uri('/'); - $header = new ContentLocationHeader($uri); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $uri = new Uri('/'); - $header = new ContentLocationHeader($uri); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ContentMD5HeaderTest.php b/tests/Header/ContentMD5HeaderTest.php deleted file mode 100644 index 0bca2d8..0000000 --- a/tests/Header/ContentMD5HeaderTest.php +++ /dev/null @@ -1,79 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ContentMD5Header(self::TEST_MD5_DIGEST); - - $this->assertSame('Content-MD5', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ContentMD5Header(self::TEST_MD5_DIGEST); - - $this->assertSame(self::TEST_MD5_DIGEST, $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The value "" for the header "Content-MD5" is not valid' - ); - - new ContentMD5Header(''); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The value "=invalid md5 digest=" for the header "Content-MD5" is not valid' - ); - - new ContentMD5Header('=invalid md5 digest='); - } - - public function testBuild() - { - $header = new ContentMD5Header(self::TEST_MD5_DIGEST); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ContentMD5Header(self::TEST_MD5_DIGEST); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ContentRangeHeaderTest.php b/tests/Header/ContentRangeHeaderTest.php deleted file mode 100644 index cb04bd5..0000000 --- a/tests/Header/ContentRangeHeaderTest.php +++ /dev/null @@ -1,91 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ContentRangeHeader(0, 1, 2); - - $this->assertSame('Content-Range', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ContentRangeHeader(0, 1, 2); - - $this->assertSame('bytes 0-1/2', $header->getFieldValue()); - } - - public function testInvalidFirstBytePosition() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The "first-byte-pos" value of the content range ' . - 'must be less than or equal to the "last-byte-pos" value' - ); - - new ContentRangeHeader(2, 1, 2); - } - - public function testInvalidLastBytePosition() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The "last-byte-pos" value of the content range ' . - 'must be less than the "instance-length" value' - ); - - new ContentRangeHeader(0, 2, 2); - } - - public function testInvalidInstanceLength() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The "last-byte-pos" value of the content range ' . - 'must be less than the "instance-length" value' - ); - - new ContentRangeHeader(0, 1, 1); - } - - public function testBuild() - { - $header = new ContentRangeHeader(0, 1, 2); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ContentRangeHeader(0, 1, 2); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ContentSecurityPolicyHeaderTest.php b/tests/Header/ContentSecurityPolicyHeaderTest.php deleted file mode 100644 index 44b20d0..0000000 --- a/tests/Header/ContentSecurityPolicyHeaderTest.php +++ /dev/null @@ -1,137 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ContentSecurityPolicyHeader([]); - - $this->assertSame('Content-Security-Policy', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ContentSecurityPolicyHeader([]); - - $this->assertSame('', $header->getFieldValue()); - } - - public function testParameterWithoutValue() - { - $header = new ContentSecurityPolicyHeader([ - 'foo' => '', - ]); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testParameterWithValue() - { - $header = new ContentSecurityPolicyHeader([ - 'foo' => 'bar', - ]); - - $this->assertSame('foo bar', $header->getFieldValue()); - } - - public function testParameterWithInteger() - { - $header = new ContentSecurityPolicyHeader([ - 'foo' => 1, - ]); - - $this->assertSame('foo 1', $header->getFieldValue()); - } - - public function testSeveralParameters() - { - $header = new ContentSecurityPolicyHeader([ - 'foo' => '', - 'bar' => 'bat', - 'baz' => 1, - ]); - - $this->assertSame('foo; bar bat; baz 1', $header->getFieldValue()); - } - - public function testInvalidParameterName() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "name=" for the header "Content-Security-Policy" is not valid' - ); - - new ContentSecurityPolicyHeader(['name=' => 'value']); - } - - public function testInvalidParameterNameType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "" for the header "Content-Security-Policy" is not valid' - ); - - new ContentSecurityPolicyHeader([0 => 'value']); - } - - public function testInvalidParameterValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value ";value" for the header "Content-Security-Policy" is not valid' - ); - - new ContentSecurityPolicyHeader(['name' => ';value']); - } - - public function testInvalidParameterValueType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value "" for the header "Content-Security-Policy" is not valid' - ); - - new ContentSecurityPolicyHeader(['name' => []]); - } - - public function testBuild() - { - $header = new ContentSecurityPolicyHeader(['foo' => 'bar']); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ContentSecurityPolicyHeader(['foo' => 'bar']); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ContentSecurityPolicyReportOnlyHeaderTest.php b/tests/Header/ContentSecurityPolicyReportOnlyHeaderTest.php deleted file mode 100644 index a521715..0000000 --- a/tests/Header/ContentSecurityPolicyReportOnlyHeaderTest.php +++ /dev/null @@ -1,137 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ContentSecurityPolicyReportOnlyHeader([]); - - $this->assertSame('Content-Security-Policy-Report-Only', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ContentSecurityPolicyReportOnlyHeader([]); - - $this->assertSame('', $header->getFieldValue()); - } - - public function testParameterWithoutValue() - { - $header = new ContentSecurityPolicyReportOnlyHeader([ - 'foo' => '', - ]); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testParameterWithValue() - { - $header = new ContentSecurityPolicyReportOnlyHeader([ - 'foo' => 'bar', - ]); - - $this->assertSame('foo bar', $header->getFieldValue()); - } - - public function testParameterWithInteger() - { - $header = new ContentSecurityPolicyReportOnlyHeader([ - 'foo' => 1, - ]); - - $this->assertSame('foo 1', $header->getFieldValue()); - } - - public function testSeveralParameters() - { - $header = new ContentSecurityPolicyReportOnlyHeader([ - 'foo' => '', - 'bar' => 'bat', - 'baz' => 1, - ]); - - $this->assertSame('foo; bar bat; baz 1', $header->getFieldValue()); - } - - public function testInvalidParameterName() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "name=" for the header "Content-Security-Policy-Report-Only" is not valid' - ); - - new ContentSecurityPolicyReportOnlyHeader(['name=' => 'value']); - } - - public function testInvalidParameterNameType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "" for the header "Content-Security-Policy-Report-Only" is not valid' - ); - - new ContentSecurityPolicyReportOnlyHeader([0 => 'value']); - } - - public function testInvalidParameterValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value ";value" for the header "Content-Security-Policy-Report-Only" is not valid' - ); - - new ContentSecurityPolicyReportOnlyHeader(['name' => ';value']); - } - - public function testInvalidParameterValueType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value "" for the header "Content-Security-Policy-Report-Only" is not valid' - ); - - new ContentSecurityPolicyReportOnlyHeader(['name' => []]); - } - - public function testBuild() - { - $header = new ContentSecurityPolicyReportOnlyHeader(['foo' => 'bar']); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ContentSecurityPolicyReportOnlyHeader(['foo' => 'bar']); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ContentTypeHeaderTest.php b/tests/Header/ContentTypeHeaderTest.php deleted file mode 100644 index 3a617e7..0000000 --- a/tests/Header/ContentTypeHeaderTest.php +++ /dev/null @@ -1,168 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new ContentTypeHeader('foo'); - - $this->assertSame('Content-Type', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new ContentTypeHeader('foo'); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testParameterWithEmptyValue() - { - $header = new ContentTypeHeader('foo', [ - 'bar' => '', - ]); - - $this->assertSame('foo; bar=""', $header->getFieldValue()); - } - - public function testParameterWithToken() - { - $header = new ContentTypeHeader('foo', [ - 'bar' => 'token', - ]); - - $this->assertSame('foo; bar="token"', $header->getFieldValue()); - } - - public function testParameterWithQuotedString() - { - $header = new ContentTypeHeader('foo', [ - 'bar' => 'quoted string', - ]); - - $this->assertSame('foo; bar="quoted string"', $header->getFieldValue()); - } - - public function testParameterWithInteger() - { - $header = new ContentTypeHeader('foo', [ - 'bar' => 1, - ]); - - $this->assertSame('foo; bar="1"', $header->getFieldValue()); - } - - public function testSeveralParameters() - { - $header = new ContentTypeHeader('foo', [ - 'bar' => '', - 'baz' => 'token', - 'bat' => 'quoted string', - 'qux' => 1, - ]); - - $this->assertSame('foo; bar=""; baz="token"; bat="quoted string"; qux="1"', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Content-Type" is not valid'); - - new ContentTypeHeader(''); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Content-Type" is not valid'); - - // isn't a token... - new ContentTypeHeader('@'); - } - - public function testInvalidParameterName() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "invalid name" for the header "Content-Type" is not valid' - ); - - // cannot contain spaces... - new ContentTypeHeader('foo', ['invalid name' => 'value']); - } - - public function testInvalidParameterNameType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "" for the header "Content-Type" is not valid' - ); - - // cannot contain spaces... - new ContentTypeHeader('foo', [0 => 'value']); - } - - public function testInvalidParameterValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value ""invalid value"" for the header "Content-Type" is not valid' - ); - - // cannot contain quotes... - new ContentTypeHeader('foo', ['name' => '"invalid value"']); - } - - public function testInvalidParameterValueType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value "" for the header "Content-Type" is not valid' - ); - - // cannot contain quotes... - new ContentTypeHeader('foo', ['name' => []]); - } - - public function testBuild() - { - $header = new ContentTypeHeader('foo', ['bar' => 'baz']); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new ContentTypeHeader('foo', ['bar' => 'baz']); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/CookieHeaderTest.php b/tests/Header/CookieHeaderTest.php deleted file mode 100644 index 870edf4..0000000 --- a/tests/Header/CookieHeaderTest.php +++ /dev/null @@ -1,61 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new CookieHeader(); - - $this->assertSame('Cookie', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new CookieHeader([ - 'foo' => 'bar', - 'bar' => 'baz', - 'baz' => [ - 'qux', - ], - ]); - - $this->assertSame('foo=bar; bar=baz; baz%5B0%5D=qux', $header->getFieldValue()); - } - - public function testBuild() - { - $header = new CookieHeader(['foo' => 'bar']); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new CookieHeader(['foo' => 'bar']); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/DateHeaderTest.php b/tests/Header/DateHeaderTest.php deleted file mode 100644 index 0b95d4c..0000000 --- a/tests/Header/DateHeaderTest.php +++ /dev/null @@ -1,82 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $utc = new \DateTime('utc'); - $header = new DateHeader($utc); - - $this->assertSame('Date', $header->getFieldName()); - } - - public function testFieldValue() - { - $utc = new \DateTime('utc'); - $header = new DateHeader($utc); - - $this->assertSame($utc->format(\DateTime::RFC822), $header->getFieldValue()); - } - - public function testFieldValueWithMutableDateTime() - { - $now = new \DateTime('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTime('now', new \DateTimeZone('UTC')); - - $header = new DateHeader($now); - - $this->assertSame($utc->format(\DateTime::RFC822), $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testFieldValueWithImmutableDateTime() - { - $now = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); - - $header = new DateHeader($now); - - $this->assertSame($utc->format(\DateTimeImmutable::RFC822), $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testBuild() - { - $now = new \DateTime('now'); - $header = new DateHeader($now); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $now = new \DateTime('now'); - $header = new DateHeader($now); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/EtagHeaderTest.php b/tests/Header/EtagHeaderTest.php deleted file mode 100644 index 71fa8b7..0000000 --- a/tests/Header/EtagHeaderTest.php +++ /dev/null @@ -1,71 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new EtagHeader('foo'); - - $this->assertSame('ETag', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new EtagHeader('foo'); - - $this->assertSame('"foo"', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $header = new EtagHeader(''); - - $this->assertSame('""', $header->getFieldValue()); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value ""invalid value"" for the header "ETag" is not valid'); - - // cannot contain quotes... - new EtagHeader('"invalid value"'); - } - - public function testBuild() - { - $header = new EtagHeader('foo'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new EtagHeader('foo'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/ExpiresHeaderTest.php b/tests/Header/ExpiresHeaderTest.php deleted file mode 100644 index f06a795..0000000 --- a/tests/Header/ExpiresHeaderTest.php +++ /dev/null @@ -1,82 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $utc = new \DateTime('utc'); - $header = new ExpiresHeader($utc); - - $this->assertSame('Expires', $header->getFieldName()); - } - - public function testFieldValue() - { - $utc = new \DateTime('utc'); - $header = new ExpiresHeader($utc); - - $this->assertSame($utc->format(\DateTime::RFC822), $header->getFieldValue()); - } - - public function testFieldValueWithMutableDateTime() - { - $now = new \DateTime('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTime('now', new \DateTimeZone('UTC')); - - $header = new ExpiresHeader($now); - - $this->assertSame($utc->format(\DateTime::RFC822), $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testFieldValueWithImmutableDateTime() - { - $now = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); - - $header = new ExpiresHeader($now); - - $this->assertSame($utc->format(\DateTimeImmutable::RFC822), $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testBuild() - { - $now = new \DateTime('now'); - $header = new ExpiresHeader($now); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $now = new \DateTime('now'); - $header = new ExpiresHeader($now); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/KeepAliveHeaderTest.php b/tests/Header/KeepAliveHeaderTest.php deleted file mode 100644 index 2625b47..0000000 --- a/tests/Header/KeepAliveHeaderTest.php +++ /dev/null @@ -1,149 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new KeepAliveHeader(); - - $this->assertSame('Keep-Alive', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new KeepAliveHeader(); - - $this->assertSame('', $header->getFieldValue()); - } - - public function testParameterWithEmptyValue() - { - $header = new KeepAliveHeader([ - 'foo' => '', - ]); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testParameterWithToken() - { - $header = new KeepAliveHeader([ - 'foo' => 'token', - ]); - - $this->assertSame('foo=token', $header->getFieldValue()); - } - - public function testParameterWithQuotedString() - { - $header = new KeepAliveHeader([ - 'foo' => 'quoted string', - ]); - - $this->assertSame('foo="quoted string"', $header->getFieldValue()); - } - - public function testParameterWithInteger() - { - $header = new KeepAliveHeader([ - 'foo' => 1, - ]); - - $this->assertSame('foo=1', $header->getFieldValue()); - } - - public function testSeveralParameters() - { - $header = new KeepAliveHeader([ - 'foo' => '', - 'bar' => 'token', - 'baz' => 'quoted string', - 'qux' => 1, - ]); - - $this->assertSame('foo, bar=token, baz="quoted string", qux=1', $header->getFieldValue()); - } - - public function testInvalidParameterName() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "invalid name" for the header "Keep-Alive" is not valid' - ); - - // cannot contain spaces... - new KeepAliveHeader(['invalid name' => 'value']); - } - - public function testInvalidParameterNameType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "" for the header "Keep-Alive" is not valid' - ); - - new KeepAliveHeader([0 => 'value']); - } - - public function testInvalidParameterValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value ""invalid value"" for the header "Keep-Alive" is not valid' - ); - - // cannot contain quotes... - new KeepAliveHeader(['name' => '"invalid value"']); - } - - public function testInvalidParameterValueType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value "" for the header "Keep-Alive" is not valid' - ); - - new KeepAliveHeader(['name' => []]); - } - - public function testBuild() - { - $header = new KeepAliveHeader(['foo' => 'bar']); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new KeepAliveHeader(['foo' => 'bar']); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/LastModifiedHeaderTest.php b/tests/Header/LastModifiedHeaderTest.php deleted file mode 100644 index a85ec4c..0000000 --- a/tests/Header/LastModifiedHeaderTest.php +++ /dev/null @@ -1,82 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $utc = new \DateTime('utc'); - $header = new LastModifiedHeader($utc); - - $this->assertSame('Last-Modified', $header->getFieldName()); - } - - public function testFieldValue() - { - $utc = new \DateTime('utc'); - $header = new LastModifiedHeader($utc); - - $this->assertSame($utc->format(\DateTime::RFC822), $header->getFieldValue()); - } - - public function testFieldValueWithMutableDateTime() - { - $now = new \DateTime('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTime('now', new \DateTimeZone('UTC')); - - $header = new LastModifiedHeader($now); - - $this->assertSame($utc->format(\DateTime::RFC822), $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testFieldValueWithImmutableDateTime() - { - $now = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); - - $header = new LastModifiedHeader($now); - - $this->assertSame($utc->format(\DateTimeImmutable::RFC822), $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testBuild() - { - $now = new \DateTime('now'); - $header = new LastModifiedHeader($now); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $now = new \DateTime('now'); - $header = new LastModifiedHeader($now); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/LinkHeaderTest.php b/tests/Header/LinkHeaderTest.php deleted file mode 100644 index 57d86aa..0000000 --- a/tests/Header/LinkHeaderTest.php +++ /dev/null @@ -1,174 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $uri = new Uri('/'); - $header = new LinkHeader($uri); - - $this->assertSame('Link', $header->getFieldName()); - } - - public function testFieldValue() - { - $uri = new Uri('/'); - $header = new LinkHeader($uri); - - $this->assertSame('', $header->getFieldValue()); - } - - public function testParameterWithEmptyValue() - { - $uri = new Uri('/'); - - $header = new LinkHeader($uri, [ - 'foo' => '', - ]); - - $this->assertSame('; foo=""', $header->getFieldValue()); - } - - public function testParameterWithToken() - { - $uri = new Uri('/'); - - $header = new LinkHeader($uri, [ - 'foo' => 'token', - ]); - - $this->assertSame('; foo="token"', $header->getFieldValue()); - } - - public function testParameterWithQuotedString() - { - $uri = new Uri('/'); - - $header = new LinkHeader($uri, [ - 'foo' => 'quoted string', - ]); - - $this->assertSame('; foo="quoted string"', $header->getFieldValue()); - } - - public function testParameterWithInteger() - { - $uri = new Uri('/'); - - $header = new LinkHeader($uri, [ - 'foo' => 1, - ]); - - $this->assertSame('; foo="1"', $header->getFieldValue()); - } - - public function testSeveralParameters() - { - $uri = new Uri('/'); - - $header = new LinkHeader($uri, [ - 'foo' => '', - 'bar' => 'token', - 'baz' => 'quoted string', - 'qux' => 1, - ]); - - $this->assertSame('; foo=""; bar="token"; baz="quoted string"; qux="1"', $header->getFieldValue()); - } - - public function testInvalidParameterName() - { - $uri = new Uri('/'); - - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "invalid name" for the header "Link" is not valid' - ); - - // cannot contain spaces... - new LinkHeader($uri, ['invalid name' => 'value']); - } - - public function testInvalidParameterNameType() - { - $uri = new Uri('/'); - - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "" for the header "Link" is not valid' - ); - - new LinkHeader($uri, [0 => 'value']); - } - - public function testInvalidParameterValue() - { - $uri = new Uri('/'); - - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value ""invalid value"" for the header "Link" is not valid' - ); - - // cannot contain quotes... - new LinkHeader($uri, ['name' => '"invalid value"']); - } - - public function testInvalidParameterValueType() - { - $uri = new Uri('/'); - - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value "" for the header "Link" is not valid' - ); - - // cannot contain quotes... - new LinkHeader($uri, ['name' => []]); - } - - public function testBuild() - { - $uri = new Uri('/'); - $header = new LinkHeader($uri, ['foo' => 'bar']); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $uri = new Uri('/'); - $header = new LinkHeader($uri, ['foo' => 'bar']); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/LocationHeaderTest.php b/tests/Header/LocationHeaderTest.php deleted file mode 100644 index c684f26..0000000 --- a/tests/Header/LocationHeaderTest.php +++ /dev/null @@ -1,61 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $uri = new Uri('/'); - $header = new LocationHeader($uri); - - $this->assertSame('Location', $header->getFieldName()); - } - - public function testFieldValue() - { - $uri = new Uri('/'); - $header = new LocationHeader($uri); - - $this->assertSame('/', $header->getFieldValue()); - } - - public function testBuild() - { - $uri = new Uri('/'); - $header = new LocationHeader($uri); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $uri = new Uri('/'); - $header = new LocationHeader($uri); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/RefreshHeaderTest.php b/tests/Header/RefreshHeaderTest.php deleted file mode 100644 index fa9ad0c..0000000 --- a/tests/Header/RefreshHeaderTest.php +++ /dev/null @@ -1,71 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $uri = new Uri('/'); - $header = new RefreshHeader(0, $uri); - - $this->assertSame('Refresh', $header->getFieldName()); - } - - public function testFieldValue() - { - $uri = new Uri('/'); - $header = new RefreshHeader(0, $uri); - - $this->assertSame('0; url=/', $header->getFieldValue()); - } - - public function testInvalidDelay() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The delay "-1" for the header "Refresh" is not valid'); - - $uri = new Uri('/'); - - new RefreshHeader(-1, $uri); - } - - public function testBuild() - { - $uri = new Uri('/'); - $header = new RefreshHeader(0, $uri); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $uri = new Uri('/'); - $header = new RefreshHeader(0, $uri); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/RetryAfterHeaderTest.php b/tests/Header/RetryAfterHeaderTest.php deleted file mode 100644 index 643f180..0000000 --- a/tests/Header/RetryAfterHeaderTest.php +++ /dev/null @@ -1,82 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $utc = new \DateTime('utc'); - $header = new RetryAfterHeader($utc); - - $this->assertSame('Retry-After', $header->getFieldName()); - } - - public function testFieldValue() - { - $utc = new \DateTime('utc'); - $header = new RetryAfterHeader($utc); - - $this->assertSame($utc->format(\DateTime::RFC822), $header->getFieldValue()); - } - - public function testFieldValueWithMutableDateTime() - { - $now = new \DateTime('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTime('now', new \DateTimeZone('UTC')); - - $header = new RetryAfterHeader($now); - - $this->assertSame($utc->format(\DateTime::RFC822), $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testFieldValueWithImmutableDateTime() - { - $now = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); - - $header = new RetryAfterHeader($now); - - $this->assertSame($utc->format(\DateTimeImmutable::RFC822), $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testBuild() - { - $now = new \DateTime('now'); - $header = new RetryAfterHeader($now); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $now = new \DateTime('now'); - $header = new RetryAfterHeader($now); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/SetCookieHeaderTest.php b/tests/Header/SetCookieHeaderTest.php deleted file mode 100644 index 9abfa85..0000000 --- a/tests/Header/SetCookieHeaderTest.php +++ /dev/null @@ -1,257 +0,0 @@ -assertSame('Lax', SetCookieHeader::SAME_SITE_LAX); - $this->assertSame('Strict', SetCookieHeader::SAME_SITE_STRICT); - $this->assertSame('None', SetCookieHeader::SAME_SITE_NONE); - } - - public function testContracts() - { - $header = new SetCookieHeader('name', 'value'); - - $this->assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new SetCookieHeader('name', 'value'); - - $this->assertSame('Set-Cookie', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new SetCookieHeader('name', 'value'); - - $this->assertSame('name=value; Path=/; HttpOnly; SameSite=Lax', $header->getFieldValue()); - } - - public function testEncodingName() - { - $header = new SetCookieHeader('@foo', 'bar'); - - $this->assertSame('%40foo=bar; Path=/; HttpOnly; SameSite=Lax', $header->getFieldValue()); - } - - public function testEncodingValue() - { - $header = new SetCookieHeader('foo', '@bar'); - - $this->assertSame('foo=%40bar; Path=/; HttpOnly; SameSite=Lax', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $dt = new \DateTime('-1 year', new \DateTimeZone('UTC')); - $header = new SetCookieHeader('name', ''); - - $expected = \sprintf( - 'name=deleted; Expires=%s; Max-Age=0; Path=/; HttpOnly; SameSite=Lax', - $dt->format(\DateTime::RFC822) - ); - - $this->assertSame($expected, $header->getFieldValue()); - } - - public function testExpiresWithMutableDateTime() - { - $now = new \DateTime('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTime('now', new \DateTimeZone('UTC')); - - $header = new SetCookieHeader('name', 'value', $now); - - $expected = \sprintf( - 'name=value; Expires=%s; Max-Age=0; Path=/; HttpOnly; SameSite=Lax', - $utc->format(\DateTime::RFC822) - ); - - $this->assertSame($expected, $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testExpiresWithImmutableDateTime() - { - $now = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); - - $header = new SetCookieHeader('name', 'value', $now); - - $expected = \sprintf( - 'name=value; Expires=%s; Max-Age=0; Path=/; HttpOnly; SameSite=Lax', - $utc->format(\DateTimeImmutable::RFC822) - ); - - $this->assertSame($expected, $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testNegativeExpires() - { - $utc = new \DateTime('-30 seconds', new \DateTimeZone('UTC')); - $header = new SetCookieHeader('name', 'value', $utc); - - // the max-age attribute cannot be negative... - $expected = \sprintf( - 'name=value; Expires=%s; Max-Age=0; Path=/; HttpOnly; SameSite=Lax', - $utc->format(\DateTime::RFC822) - ); - - $this->assertSame($expected, $header->getFieldValue()); - } - - public function testPositiveExpires() - { - $utc = new \DateTime('+30 seconds', new \DateTimeZone('UTC')); - $header = new SetCookieHeader('name', 'value', $utc); - - $expected = \sprintf( - 'name=value; Expires=%s; Max-Age=30; Path=/; HttpOnly; SameSite=Lax', - $utc->format(\DateTime::RFC822) - ); - - $this->assertSame($expected, $header->getFieldValue()); - } - - public function testPath() - { - $header = new SetCookieHeader('name', 'value', null, [ - 'path' => '/assets/', - ]); - - $this->assertSame('name=value; Path=/assets/; HttpOnly; SameSite=Lax', $header->getFieldValue()); - } - - public function testDomain() - { - $header = new SetCookieHeader('name', 'value', null, [ - 'domain' => 'acme.com', - ]); - - $this->assertSame('name=value; Path=/; Domain=acme.com; HttpOnly; SameSite=Lax', $header->getFieldValue()); - } - - public function testSecure() - { - $header = new SetCookieHeader('name', 'value', null, [ - 'secure' => true, - ]); - - $this->assertSame('name=value; Path=/; Secure; HttpOnly; SameSite=Lax', $header->getFieldValue()); - } - - public function testHttpOnly() - { - $header = new SetCookieHeader('name', 'value', null, [ - 'httpOnly' => false, - ]); - - $this->assertSame('name=value; Path=/; SameSite=Lax', $header->getFieldValue()); - } - - public function testSameSite() - { - $header = new SetCookieHeader('name', 'value', null, [ - 'sameSite' => 'Strict', - ]); - - $this->assertSame('name=value; Path=/; HttpOnly; SameSite=Strict', $header->getFieldValue()); - } - - public function testEmptyName() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Cookie name cannot be empty'); - - new SetCookieHeader('', 'value'); - } - - public function testInvalidName() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The cookie name "name=" contains prohibited characters'); - - new SetCookieHeader('name=', 'value'); - } - - public function testInvalidPath() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The cookie option "path" contains prohibited characters'); - - new SetCookieHeader('name', 'value', null, ['path' => ';']); - } - - public function testInvalidPathDataType() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The cookie option "path" must be a string'); - - new SetCookieHeader('name', 'value', null, ['path' => []]); - } - - public function testInvalidDomain() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The cookie option "domain" contains prohibited characters'); - - new SetCookieHeader('name', 'value', null, ['domain' => ';']); - } - - public function testInvalidDomainDataType() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The cookie option "domain" must be a string'); - - new SetCookieHeader('name', 'value', null, ['domain' => []]); - } - - public function testInvalidSamesite() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The cookie option "sameSite" contains prohibited characters'); - - new SetCookieHeader('name', 'value', null, ['sameSite' => ';']); - } - - public function testInvalidSamesiteDataType() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The cookie option "sameSite" must be a string'); - - new SetCookieHeader('name', 'value', null, ['sameSite' => []]); - } - - public function testBuild() - { - $header = new SetCookieHeader('name', 'value'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new SetCookieHeader('name', 'value'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/SunsetHeaderTest.php b/tests/Header/SunsetHeaderTest.php deleted file mode 100644 index 02df8bf..0000000 --- a/tests/Header/SunsetHeaderTest.php +++ /dev/null @@ -1,82 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $utc = new \DateTime('utc'); - $header = new SunsetHeader($utc); - - $this->assertSame('Sunset', $header->getFieldName()); - } - - public function testFieldValue() - { - $utc = new \DateTime('utc'); - $header = new SunsetHeader($utc); - - $this->assertSame($utc->format(\DateTime::RFC822), $header->getFieldValue()); - } - - public function testFieldValueWithMutableDateTime() - { - $now = new \DateTime('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTime('now', new \DateTimeZone('UTC')); - - $header = new SunsetHeader($now); - - $this->assertSame($utc->format(\DateTime::RFC822), $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testFieldValueWithImmutableDateTime() - { - $now = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); - - $header = new SunsetHeader($now); - - $this->assertSame($utc->format(\DateTimeImmutable::RFC822), $header->getFieldValue()); - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testBuild() - { - $now = new \DateTime('now'); - $header = new SunsetHeader($now); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $now = new \DateTime('now'); - $header = new SunsetHeader($now); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/TrailerHeaderTest.php b/tests/Header/TrailerHeaderTest.php deleted file mode 100644 index 1614191..0000000 --- a/tests/Header/TrailerHeaderTest.php +++ /dev/null @@ -1,78 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new TrailerHeader('foo'); - - $this->assertSame('Trailer', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new TrailerHeader('foo'); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The value "" for the header "Trailer" is not valid' - ); - - new TrailerHeader(''); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The value "@" for the header "Trailer" is not valid' - ); - - // isn't a token... - new TrailerHeader('@'); - } - - public function testBuild() - { - $header = new TrailerHeader('foo'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new TrailerHeader('foo'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/TransferEncodingHeaderTest.php b/tests/Header/TransferEncodingHeaderTest.php deleted file mode 100644 index b5bd0a4..0000000 --- a/tests/Header/TransferEncodingHeaderTest.php +++ /dev/null @@ -1,104 +0,0 @@ -assertSame('chunked', TransferEncodingHeader::CHUNKED); - $this->assertSame('compress', TransferEncodingHeader::COMPRESS); - $this->assertSame('deflate', TransferEncodingHeader::DEFLATE); - $this->assertSame('gzip', TransferEncodingHeader::GZIP); - } - - public function testContracts() - { - $header = new TransferEncodingHeader('foo'); - - $this->assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new TransferEncodingHeader('foo'); - - $this->assertSame('Transfer-Encoding', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new TransferEncodingHeader('foo'); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testSeveralValues() - { - $header = new TransferEncodingHeader('foo', 'bar', 'baz'); - - $this->assertSame('foo, bar, baz', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Transfer-Encoding" is not valid'); - - new TransferEncodingHeader(''); - } - - public function testEmptyValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Transfer-Encoding" is not valid'); - - new TransferEncodingHeader('foo', '', 'baz'); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Transfer-Encoding" is not valid'); - - // isn't a token... - new TransferEncodingHeader('@'); - } - - public function testInvalidValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Transfer-Encoding" is not valid'); - - // isn't a token... - new TransferEncodingHeader('foo', '@', 'baz'); - } - - public function testBuild() - { - $header = new TransferEncodingHeader('foo'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new TransferEncodingHeader('foo'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/VaryHeaderTest.php b/tests/Header/VaryHeaderTest.php deleted file mode 100644 index 8e37012..0000000 --- a/tests/Header/VaryHeaderTest.php +++ /dev/null @@ -1,96 +0,0 @@ -assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new VaryHeader('foo'); - - $this->assertSame('Vary', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new VaryHeader('foo'); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testSeveralValues() - { - $header = new VaryHeader('foo', 'bar', 'baz'); - - $this->assertSame('foo, bar, baz', $header->getFieldValue()); - } - - public function testEmptyValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Vary" is not valid'); - - new VaryHeader(''); - } - - public function testEmptyValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Vary" is not valid'); - - new VaryHeader('foo', '', 'baz'); - } - - public function testInvalidValue() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Vary" is not valid'); - - // isn't a token... - new VaryHeader('@'); - } - - public function testInvalidValueAmongOthers() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Vary" is not valid'); - - // isn't a token... - new VaryHeader('foo', '@', 'baz'); - } - - public function testBuild() - { - $header = new VaryHeader('foo'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new VaryHeader('foo'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/WWWAuthenticateHeaderTest.php b/tests/Header/WWWAuthenticateHeaderTest.php deleted file mode 100644 index 388dc82..0000000 --- a/tests/Header/WWWAuthenticateHeaderTest.php +++ /dev/null @@ -1,180 +0,0 @@ -assertSame('Basic', WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_BASIC); - $this->assertSame('Bearer', WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_BEARER); - $this->assertSame('Digest', WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_DIGEST); - $this->assertSame('HOBA', WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_HOBA); - $this->assertSame('Mutual', WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_MUTUAL); - $this->assertSame('Negotiate', WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_NEGOTIATE); - $this->assertSame('OAuth', WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_OAUTH); - $this->assertSame('SCRAM-SHA-1', WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_SCRAM_SHA_1); - $this->assertSame('SCRAM-SHA-256', WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_SCRAM_SHA_256); - $this->assertSame('vapid', WWWAuthenticateHeader::HTTP_AUTHENTICATE_SCHEME_VAPID); - } - - public function testContracts() - { - $header = new WWWAuthenticateHeader('foo'); - - $this->assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new WWWAuthenticateHeader('foo'); - - $this->assertSame('WWW-Authenticate', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new WWWAuthenticateHeader('foo'); - - $this->assertSame('foo', $header->getFieldValue()); - } - - public function testParameterWithEmptyValue() - { - $header = new WWWAuthenticateHeader('foo', [ - 'bar' => '', - ]); - - $this->assertSame('foo bar=""', $header->getFieldValue()); - } - - public function testParameterWithToken() - { - $header = new WWWAuthenticateHeader('foo', [ - 'bar' => 'token', - ]); - - $this->assertSame('foo bar="token"', $header->getFieldValue()); - } - - public function testParameterWithQuotedString() - { - $header = new WWWAuthenticateHeader('foo', [ - 'bar' => 'quoted string', - ]); - - $this->assertSame('foo bar="quoted string"', $header->getFieldValue()); - } - - public function testParameterWithInteger() - { - $header = new WWWAuthenticateHeader('foo', [ - 'bar' => 1, - ]); - - $this->assertSame('foo bar="1"', $header->getFieldValue()); - } - - public function testSeveralParameters() - { - $header = new WWWAuthenticateHeader('foo', [ - 'bar' => '', - 'baz' => 'token', - 'bat' => 'quoted string', - 'qux' => 1, - ]); - - $this->assertSame('foo bar="", baz="token", bat="quoted string", qux="1"', $header->getFieldValue()); - } - - public function testEmptyScheme() - { - $this->expectException(\InvalidArgumentException::class); - - new WWWAuthenticateHeader(''); - } - - public function testInvalidScheme() - { - $this->expectException(\InvalidArgumentException::class); - - // isn't a token... - new WWWAuthenticateHeader('@'); - } - - public function testInvalidParameterName() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "invalid name" for the header "WWW-Authenticate" is not valid' - ); - - // cannot contain spaces... - new WWWAuthenticateHeader('foo', ['invalid name' => 'value']); - } - - public function testInvalidParameterNameType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter name "" for the header "WWW-Authenticate" is not valid' - ); - - // cannot contain spaces... - new WWWAuthenticateHeader('foo', [0 => 'value']); - } - - public function testInvalidParameterValue() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value ""invalid value"" for the header "WWW-Authenticate" is not valid' - ); - - // cannot contain quotes... - new WWWAuthenticateHeader('foo', ['name' => '"invalid value"']); - } - - public function testInvalidParameterValueType() - { - $this->expectException(\InvalidArgumentException::class); - - $this->expectExceptionMessage( - 'The parameter value "" for the header "WWW-Authenticate" is not valid' - ); - - // cannot contain quotes... - new WWWAuthenticateHeader('foo', ['name' => []]); - } - - public function testBuild() - { - $header = new WWWAuthenticateHeader('foo', ['bar' => 'baz']); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new WWWAuthenticateHeader('foo', ['bar' => 'baz']); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Header/WarningHeaderTest.php b/tests/Header/WarningHeaderTest.php deleted file mode 100644 index fb884f5..0000000 --- a/tests/Header/WarningHeaderTest.php +++ /dev/null @@ -1,134 +0,0 @@ -assertSame(110, WarningHeader::HTTP_WARNING_CODE_RESPONSE_IS_STALE); - $this->assertSame(111, WarningHeader::HTTP_WARNING_CODE_REVALIDATION_FAILED); - $this->assertSame(112, WarningHeader::HTTP_WARNING_CODE_DISCONNECTED_OPERATION); - $this->assertSame(113, WarningHeader::HTTP_WARNING_CODE_HEURISTIC_EXPIRATION); - $this->assertSame(199, WarningHeader::HTTP_WARNING_CODE_MISCELLANEOUS_WARNING); - $this->assertSame(214, WarningHeader::HTTP_WARNING_CODE_TRANSFORMATION_APPLIED); - $this->assertSame(299, WarningHeader::HTTP_WARNING_CODE_MISCELLANEOUS_PERSISTENT_WARNING); - } - - public function testContracts() - { - $header = new WarningHeader(199, 'agent', 'text'); - - $this->assertInstanceOf(HeaderInterface::class, $header); - } - - public function testFieldName() - { - $header = new WarningHeader(199, 'agent', 'text'); - - $this->assertSame('Warning', $header->getFieldName()); - } - - public function testFieldValue() - { - $header = new WarningHeader(199, 'agent', 'text'); - - $this->assertSame('199 agent "text"', $header->getFieldValue()); - } - - public function testFieldValueWithDate() - { - $now = new \DateTime('now', new \DateTimeZone('Europe/Moscow')); - $utc = new \DateTime('now', new \DateTimeZone('UTC')); - - $header = new WarningHeader(199, 'agent', 'text', $now); - - $this->assertSame( - \sprintf( - '199 agent "text" "%s"', - $utc->format(\DateTime::RFC822) - ), - $header->getFieldValue() - ); - - // cannot be modified... - $this->assertSame('Europe/Moscow', $now->getTimezone()->getName()); - } - - public function testCodeLessThat100() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The code "99" for the header "Warning" is not valid'); - - new WarningHeader(99, 'agent', 'text'); - } - - public function testCodeGreaterThat999() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The code "1000" for the header "Warning" is not valid'); - - new WarningHeader(1000, 'agent', 'text'); - } - - public function testEmptyAgent() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "" for the header "Warning" is not valid'); - - new WarningHeader(199, '', 'text'); - } - - public function testInvalidAgent() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value "@" for the header "Warning" is not valid'); - - // isn't a token... - new WarningHeader(199, '@', 'text'); - } - - public function testEmptyText() - { - $header = new WarningHeader(199, 'agent', ''); - - $this->assertSame('199 agent ""', $header->getFieldValue()); - } - - public function testInvalidText() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The value ""text"" for the header "Warning" is not valid'); - - // cannot contain quotes... - new WarningHeader(199, 'agent', '"text"'); - } - - public function testBuild() - { - $header = new WarningHeader(199, 'agent', 'text'); - - $expected = \sprintf('%s: %s', $header->getFieldName(), $header->getFieldValue()); - - $this->assertSame($expected, $header->__toString()); - } - - public function testIterator() - { - $header = new WarningHeader(199, 'agent', 'text'); - - $this->assertSame( - [ - $header->getFieldName(), - $header->getFieldValue(), - ], - \iterator_to_array($header->getIterator()) - ); - } -} diff --git a/tests/Integration/UploadedFileIntegrationTest.php b/tests/Integration/UploadedFileIntegrationTest.php index 900b3ea..fe5a859 100644 --- a/tests/Integration/UploadedFileIntegrationTest.php +++ b/tests/Integration/UploadedFileIntegrationTest.php @@ -12,6 +12,13 @@ class UploadedFileIntegrationTest extends BaseUploadedFileIntegrationTest { + /** + * {@inheritdoc} + */ + protected $skippedTests = [ + 'testGetSize' => 'The test does not conform to the required behavior described in PSR-7', + ]; + /** * {@inheritdoc} */ diff --git a/tests/RequestFactoryTest.php b/tests/RequestFactoryTest.php index 8672209..c1cde0b 100644 --- a/tests/RequestFactoryTest.php +++ b/tests/RequestFactoryTest.php @@ -70,7 +70,7 @@ public function testCreateRequestWithStringUri(): void public function testCreateRequestWithInvalidUri(): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Unable to parse URI'); + $this->expectExceptionMessage('Invalid URI'); (new RequestFactory)->createRequest('GET', ':'); } diff --git a/tests/Response/HtmlResponseTest.php b/tests/Response/HtmlResponseTest.php index 84a15ba..89cced5 100644 --- a/tests/Response/HtmlResponseTest.php +++ b/tests/Response/HtmlResponseTest.php @@ -39,7 +39,7 @@ public function __toString(): string public function testConstructorWithUnexpectedHtml(): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Unable to create HTML response due to invalid body'); + $this->expectExceptionMessage('Unable to create HTML response due to unexpected HTML data'); new HtmlResponse(200, null); } diff --git a/tests/ServerRequestFactoryTest.php b/tests/ServerRequestFactoryTest.php index c3f2b71..ad89982 100644 --- a/tests/ServerRequestFactoryTest.php +++ b/tests/ServerRequestFactoryTest.php @@ -74,7 +74,7 @@ public function testCreateServerRequestWithStringUri(): void public function testCreateServerRequestWithInvalidUri(): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Unable to parse URI'); + $this->expectExceptionMessage('Invalid URI'); (new ServerRequestFactory)->createServerRequest('GET', ':'); } @@ -101,7 +101,7 @@ public function testCreateServerRequestWithServerParamsWithProtocolVersion( public function testCreateServerRequestWithServerParamsWithUnsupportedProtocolVersion(): void { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid or unsupported HTTP version'); + $this->expectExceptionMessage('Unallowed HTTP version'); (new ServerRequestFactory)->createServerRequest('GET', new Uri(), ['SERVER_PROTOCOL' => 'HTTP/3']); } @@ -195,7 +195,7 @@ public function testCreateServerRequestFromGlobalsWithUnsupportedProtocolVersion $_SERVER = ['SERVER_PROTOCOL' => 'HTTP/3']; $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid or unsupported HTTP version'); + $this->expectExceptionMessage('Unallowed HTTP version'); ServerRequestFactory::fromGlobals(); } @@ -267,7 +267,7 @@ public function testCreateServerRequestFromGlobalsWithInvalidUri(): void $_SERVER = ['HTTP_HOST' => 'localhost:65536']; $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Unable to parse URI'); + $this->expectExceptionMessage('Invalid URI'); ServerRequestFactory::fromGlobals(); } diff --git a/tests/StreamFactoryTest.php b/tests/StreamFactoryTest.php index a9d4e24..78bda08 100644 --- a/tests/StreamFactoryTest.php +++ b/tests/StreamFactoryTest.php @@ -55,7 +55,7 @@ public function testCreateStreamFromFileWithMode(): void public function testCreateStreamFromInvalidFile(): void { - $this->expectException(RuntimeException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage( 'Unable to open the file "/55EF8096-7A6A-4C85-9BCD-6A5958376AB8" in the mode "r"' ); diff --git a/tests/StreamTest.php b/tests/StreamTest.php index 7127f43..f3f968b 100644 --- a/tests/StreamTest.php +++ b/tests/StreamTest.php @@ -6,10 +6,8 @@ use PHPUnit\Framework\TestCase; use Psr\Http\Message\StreamInterface; -use Sunrise\Http\Message\Exception\FailedStreamOperationException; use Sunrise\Http\Message\Exception\InvalidArgumentException; -use Sunrise\Http\Message\Exception\InvalidStreamException; -use Sunrise\Http\Message\Exception\InvalidStreamOperationException; +use Sunrise\Http\Message\Exception\RuntimeException; use Sunrise\Http\Message\Stream; use function fclose; @@ -150,8 +148,8 @@ public function testTellAfterDetach(): void { $this->testStream->detach(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->tell(); } @@ -160,8 +158,8 @@ public function testTellAfterClose(): void { $this->testStream->close(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->tell(); } @@ -170,7 +168,7 @@ public function testFailedTell(): void { $testStream = new Stream(STDIN, false); - $this->expectException(FailedStreamOperationException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Unable to get the stream pointer position'); $testStream->tell(); @@ -211,8 +209,8 @@ public function testRewindAfterDetach(): void { $this->testStream->detach(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->rewind(); } @@ -221,8 +219,8 @@ public function testRewindAfterClose(): void { $this->testStream->close(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->rewind(); } @@ -231,7 +229,7 @@ public function testRewindInUnseekableResource(): void { $testStream = new Stream(STDIN, false); - $this->expectException(InvalidStreamOperationException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Stream is not seekable'); $testStream->rewind(); @@ -248,8 +246,8 @@ public function testSeekAfterDetach(): void { $this->testStream->detach(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->seek(0); } @@ -258,8 +256,8 @@ public function testSeekAfterClose(): void { $this->testStream->close(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->seek(0); } @@ -268,7 +266,7 @@ public function testSeekInUnseekableResource(): void { $testStream = new Stream(STDIN, false); - $this->expectException(InvalidStreamOperationException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Stream is not seekable'); $testStream->seek(0); @@ -276,7 +274,7 @@ public function testSeekInUnseekableResource(): void public function testFailedSeek(): void { - $this->expectException(FailedStreamOperationException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Unable to move the stream pointer position'); $this->testStream->seek(1); @@ -316,8 +314,8 @@ public function testWriteAfterDetach(): void { $this->testStream->detach(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->write('foo'); } @@ -326,8 +324,8 @@ public function testWriteAfterClose(): void { $this->testStream->close(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->write('foo'); } @@ -336,7 +334,7 @@ public function testWriteToUnwritableResource(): void { $testStream = new Stream(STDIN, false); - $this->expectException(InvalidStreamOperationException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Stream is not writable'); $testStream->write('foo'); @@ -376,8 +374,8 @@ public function testReadAfterDetach(): void { $this->testStream->detach(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->read(1); } @@ -386,8 +384,8 @@ public function testReadAfterClose(): void { $this->testStream->close(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->read(1); } @@ -396,7 +394,7 @@ public function testReadFromUnreadableResource(): void { $testStream = new Stream(STDOUT, false); - $this->expectException(InvalidStreamOperationException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Stream is not readable'); $testStream->read(1); @@ -413,8 +411,8 @@ public function testGetContentsAfterDetach(): void { $this->testStream->detach(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->getContents(); } @@ -423,8 +421,8 @@ public function testGetContentsAfterClose(): void { $this->testStream->close(); - $this->expectException(InvalidStreamException::class); - $this->expectExceptionMessage('The stream without a resource so the operation is not possible'); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Stream has no resource'); $this->testStream->getContents(); } @@ -433,7 +431,7 @@ public function testGetContentsFromUnreadableResource(): void { $testStream = new Stream(STDOUT, false); - $this->expectException(InvalidStreamOperationException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Stream is not readable'); $testStream->getContents(); diff --git a/tests/UploadedFileTest.php b/tests/UploadedFileTest.php index ab6f160..1a3adc4 100644 --- a/tests/UploadedFileTest.php +++ b/tests/UploadedFileTest.php @@ -6,11 +6,11 @@ use PHPUnit\Framework\TestCase; use Psr\Http\Message\UploadedFileInterface; -use Sunrise\Http\Message\Exception\FailedUploadedFileOperationException; -use Sunrise\Http\Message\Exception\InvalidUploadedFileException; -use Sunrise\Http\Message\Exception\InvalidUploadedFileOperationException; +use Sunrise\Http\Message\Exception\InvalidArgumentException; +use Sunrise\Http\Message\Exception\RuntimeException; use Sunrise\Http\Message\Stream\FileStream; use Sunrise\Http\Message\Stream\PhpTempStream; +use Sunrise\Http\Message\Stream\TempFileStream; use Sunrise\Http\Message\Stream\TmpfileStream; use Sunrise\Http\Message\UploadedFile; @@ -63,11 +63,11 @@ public function testGetsStreamWithError(int $errorCode): void { $file = new UploadedFile(new PhpTempStream(), null, $errorCode); - $errorMessage = UploadedFile::UPLOAD_ERRORS[$errorCode] ?? UploadedFile::UNKNOWN_ERROR_TEXT; + $errorMessage = UploadedFile::UPLOAD_ERRORS[$errorCode] ?? 'Unknown error'; - $this->expectException(InvalidUploadedFileException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage(sprintf( - 'The uploaded file has no a stream due to the error #%d (%s)', + 'Uploaded file has no a stream due to the error #%d (%s)', $errorCode, $errorMessage )); @@ -82,9 +82,9 @@ public function testGetsStreamAfterMove(): void $file = new UploadedFile(new PhpTempStream()); $file->moveTo($tmpfile->getMetadata('uri')); - $this->expectException(InvalidUploadedFileException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage( - 'The uploaded file has no a stream because it was already moved' + 'Uploaded file has no a stream because it was already moved' ); $file->getStream(); @@ -93,7 +93,7 @@ public function testGetsStreamAfterMove(): void public function testMove(): void { // will be deleted after the move - $srcStream = FileStream::tempFile(); + $srcStream = new TempFileStream(); $srcStream->write('foo'); $srcPath = $srcStream->getMetadata('uri'); @@ -115,11 +115,11 @@ public function testMoveWithError(int $errorCode): void { $file = new UploadedFile(new PhpTempStream(), null, $errorCode); - $errorMessage = UploadedFile::UPLOAD_ERRORS[$errorCode] ?? UploadedFile::UNKNOWN_ERROR_TEXT; + $errorMessage = UploadedFile::UPLOAD_ERRORS[$errorCode] ?? 'Unknown error'; - $this->expectException(InvalidUploadedFileException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage(sprintf( - 'The uploaded file cannot be moved due to the error #%d (%s)', + 'Uploaded file cannot be moved due to the error #%d (%s)', $errorCode, $errorMessage )); @@ -134,9 +134,9 @@ public function testMoveAfterMove(): void $file = new UploadedFile(new PhpTempStream()); $file->moveTo($tmpfile->getMetadata('uri')); - $this->expectException(InvalidUploadedFileException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage( - 'The uploaded file cannot be moved because it was already moved' + 'Uploaded file cannot be moved because it was already moved' ); $file->moveTo('/foo'); @@ -148,9 +148,9 @@ public function testMoveUnreadableFile(): void $file = new UploadedFile(new FileStream($tmpfile->getMetadata('uri'), 'w')); - $this->expectException(InvalidUploadedFileOperationException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage( - 'The uploaded file cannot be moved because it is not readable' + 'Uploaded file cannot be moved because it is not readable' ); $file->moveTo('/foo'); @@ -160,10 +160,10 @@ public function testMoveUnwritableDirectory(): void { $file = new UploadedFile(new PhpTempStream()); - $this->expectException(FailedUploadedFileOperationException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage( - 'The uploaded file cannot be moved because ' . - 'the directory "/4c32dad5-181f-46b7-a86a-15568e11fdf9" is not writable' + 'Uploaded file cannot be moved due to the error: ' . + 'Unable to open the file "/4c32dad5-181f-46b7-a86a-15568e11fdf9/foo" in the mode "wb"' ); $file->moveTo('/4c32dad5-181f-46b7-a86a-15568e11fdf9/foo'); diff --git a/tests/UriTest.php b/tests/UriTest.php index a870730..7cf3461 100644 --- a/tests/UriTest.php +++ b/tests/UriTest.php @@ -7,8 +7,6 @@ use PHPUnit\Framework\TestCase; use Psr\Http\Message\UriInterface; use Sunrise\Http\Message\Exception\InvalidArgumentException; -use Sunrise\Http\Message\Exception\InvalidUriComponentException; -use Sunrise\Http\Message\Exception\InvalidUriException; use Sunrise\Http\Message\Uri; use function strtolower; @@ -49,8 +47,8 @@ public function testConstructorWithEmptyUri(): void public function testConstructorWithInvalidUri(): void { - $this->expectException(InvalidUriException::class); - $this->expectExceptionMessage('Unable to parse URI'); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid URI'); new Uri(':'); } @@ -272,7 +270,7 @@ public function testWithEmptyFragment(): void public function testWithInvalidScheme(): void { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid URI component "scheme"'); (new Uri(self::TEST_URI))->withScheme('scheme:'); @@ -297,7 +295,7 @@ public function testWithInvalidHost(): void public function testWithPortLessThanZero(): void { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid URI component "port"'); (new Uri(self::TEST_URI))->withPort(-1); @@ -305,7 +303,7 @@ public function testWithPortLessThanZero(): void public function testWithPortEqualsZero(): void { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid URI component "port"'); (new Uri(self::TEST_URI))->withPort(0); @@ -313,7 +311,7 @@ public function testWithPortEqualsZero(): void public function testWithPortGreaterThan65535(): void { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid URI component "port"'); (new Uri(self::TEST_URI))->withPort(2 ** 16); @@ -347,7 +345,7 @@ public function testWithInvalidFragment(): void */ public function testWithInvalidDataTypeForScheme($value) { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('URI component "scheme" must be a string'); (new Uri)->withScheme($value); @@ -358,7 +356,7 @@ public function testWithInvalidDataTypeForScheme($value) */ public function testWithInvalidDataTypeForUser($value) { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('URI component "user" must be a string'); (new Uri)->withUserInfo($value); @@ -369,7 +367,7 @@ public function testWithInvalidDataTypeForUser($value) */ public function testWithInvalidDataTypeForPass($value) { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('URI component "password" must be a string'); (new Uri)->withUserInfo('user', $value); @@ -380,7 +378,7 @@ public function testWithInvalidDataTypeForPass($value) */ public function testWithInvalidDataTypeForHost($value) { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('URI component "host" must be a string'); (new Uri)->withHost($value); @@ -391,7 +389,7 @@ public function testWithInvalidDataTypeForHost($value) */ public function testWithInvalidDataTypeForPort($value) { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('URI component "port" must be an integer'); (new Uri)->withPort($value); @@ -402,7 +400,7 @@ public function testWithInvalidDataTypeForPort($value) */ public function testWithInvalidDataTypeForPath($value) { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('URI component "path" must be a string'); (new Uri)->withPath($value); @@ -413,7 +411,7 @@ public function testWithInvalidDataTypeForPath($value) */ public function testWithInvalidDataTypeForQuery($value) { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('URI component "query" must be a string'); (new Uri)->withQuery($value); @@ -424,7 +422,7 @@ public function testWithInvalidDataTypeForQuery($value) */ public function testWithInvalidDataTypeForFragment($value) { - $this->expectException(InvalidUriComponentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('URI component "fragment" must be a string'); (new Uri)->withFragment($value);