diff --git a/src/Http/Request.php b/src/Http/Request.php new file mode 100644 index 0000000..55ec066 --- /dev/null +++ b/src/Http/Request.php @@ -0,0 +1,29 @@ + $get + * @param array $post + * @param array> $files + * @param array $cookies + * @param array $server + */ + public function __construct( + public array $get, + public array $post, + public array $files, + public array $cookies, + public array $server, + public string $queryString, + public string $method, + public string $path, + public ?string $contentType, + public string $rawBody, + ) { + } +} diff --git a/src/Http/Response.php b/src/Http/Response.php new file mode 100644 index 0000000..0a3cf56 --- /dev/null +++ b/src/Http/Response.php @@ -0,0 +1,49 @@ + 'nosniff', + 'Referrer-Policy' => 'same-origin', + 'Content-Security-Policy' => "default-src 'self'; img-src 'self' data:; style-src 'self'", + ]; + + /** @param array $headers */ + public function __construct( + public int $status, + public array $headers, + public string $body, + ) { + } + + public static function html(int $status, string $body): self + { + return new self( + $status, + ['Content-Type' => 'text/html; charset=utf-8'] + self::SECURITY_HEADERS, + $body, + ); + } + + public static function json(int $status, mixed $body): self + { + return new self( + $status, + ['Content-Type' => 'application/json; charset=utf-8'] + self::SECURITY_HEADERS, + json_encode($body, JSON_THROW_ON_ERROR), + ); + } + + public static function redirect(string $location, int $status = 303): self + { + return new self( + $status, + ['Location' => $location] + self::SECURITY_HEADERS, + '', + ); + } +} diff --git a/tests/Unit/Http/RequestTest.php b/tests/Unit/Http/RequestTest.php new file mode 100644 index 0000000..1b4a625 --- /dev/null +++ b/tests/Unit/Http/RequestTest.php @@ -0,0 +1,56 @@ + '1'], + post: ['name' => 'alpha'], + files: ['image' => ['name' => 'a.png', 'tmp_name' => '/tmp/x', 'error' => 0, 'size' => 12, 'type' => 'image/png']], + cookies: ['__csrf' => 'cookie-value'], + server: ['HTTP_HOST' => 'localhost'], + queryString: 'q=1', + method: 'POST', + path: '/scenarios/demo/edit/team', + contentType: 'application/x-www-form-urlencoded', + rawBody: '', + ); + + self::assertSame(['q' => '1'], $request->get); + self::assertSame(['name' => 'alpha'], $request->post); + self::assertSame('a.png', $request->files['image']['name']); + self::assertSame('cookie-value', $request->cookies['__csrf']); + self::assertSame('localhost', $request->server['HTTP_HOST']); + self::assertSame('q=1', $request->queryString); + self::assertSame('POST', $request->method); + self::assertSame('/scenarios/demo/edit/team', $request->path); + self::assertSame('application/x-www-form-urlencoded', $request->contentType); + self::assertSame('', $request->rawBody); + } + + public function testItAllowsNullContentType(): void + { + $request = new Request( + get: [], + post: [], + files: [], + cookies: [], + server: [], + queryString: '', + method: 'GET', + path: '/', + contentType: null, + rawBody: '', + ); + + self::assertNull($request->contentType); + } +}