diff --git a/packages/http-client/src/Driver/Psr18Driver.php b/packages/http-client/src/Driver/Psr18Driver.php index af7ecad268..134ff029ec 100644 --- a/packages/http-client/src/Driver/Psr18Driver.php +++ b/packages/http-client/src/Driver/Psr18Driver.php @@ -44,7 +44,7 @@ private function convertTempestRequestToPsrRequest(Request $tempestRequest): Req $request = $this->requestFactory->createRequest( method: $tempestRequest->method->value, uri: $this->uriFactory->createUri( - $tempestRequest->uri, + $tempestRequest->uri->toString(), ), ); diff --git a/packages/http/src/IsRequest.php b/packages/http/src/IsRequest.php index e4e7f227bd..cedbc94f12 100644 --- a/packages/http/src/IsRequest.php +++ b/packages/http/src/IsRequest.php @@ -17,8 +17,6 @@ /** * @phpstan-require-implements \Tempest\Http\Request - * - * @mago-expect lint:too-many-properties */ trait IsRequest { @@ -26,7 +24,7 @@ trait IsRequest private(set) Method $method; #[SkipValidation] - private(set) string $uri; + private(set) Uri $uri; #[SkipValidation] private(set) ?string $raw = null; @@ -37,12 +35,6 @@ trait IsRequest #[SkipValidation] private(set) RequestHeaders $headers; - #[SkipValidation] - private(set) string $path; - - #[SkipValidation] - private(set) array $query; - /** @var array */ #[SkipValidation] private(set) array $files; @@ -60,7 +52,7 @@ trait IsRequest public function __construct( Method $method, - string $uri, + Uri|string $uri, array $body = [], array $headers = [], array $files = [], @@ -68,23 +60,22 @@ public function __construct( IpAddress|string|null $ip = null, ) { $this->method = $method; - $this->uri = $uri; + $this->uri = $uri instanceof Uri ? $uri : Uri::from($uri); $this->body = $body; $this->headers = RequestHeaders::normalizeFromArray($headers); $this->files = $files; $this->raw = $raw; $this->ip = IpAddress::tryFrom($ip); - if ($this->method === Method::CONNECT) { - $this->path ??= ''; - $this->query ??= []; - - return; - } - - $uri = Uri::from($this->uri); - $this->path ??= rawurldecode($uri->path ?? ''); - $this->query ??= $uri->query; + // if ($this->method === Method::CONNECT) { + // $this->path ??= ''; + // $this->query ??= []; + // + // return; + // } + // + // $this->path ??= rawurldecode($uri->path ?? ''); + // $this->query ??= $uri->query; } public function get(string $key, mixed $default = null): mixed @@ -93,8 +84,8 @@ public function get(string $key, mixed $default = null): mixed return get_by_key($this->body, $key); } - if (array_key_exists($key, $this->query)) { - return get_by_key($this->query, $key); + if (array_key_exists($key, $this->uri->query)) { + return get_by_key($this->uri->query, $key); } return $default; @@ -133,7 +124,7 @@ public function hasBody(?string $key = null): bool public function hasQuery(string $key): bool { - return has_key($this->query, $key); + return has_key($this->uri->query, $key); } public function accepts(ContentType ...$contentTypes): bool diff --git a/packages/http/src/Mappers/PsrRequestToGenericRequestMapper.php b/packages/http/src/Mappers/PsrRequestToGenericRequestMapper.php index 38b12f1521..dd580d5070 100644 --- a/packages/http/src/Mappers/PsrRequestToGenericRequestMapper.php +++ b/packages/http/src/Mappers/PsrRequestToGenericRequestMapper.php @@ -17,6 +17,7 @@ use Tempest\Http\Upload; use Tempest\Mapper\Mapper; use Tempest\Support\Arr; +use Tempest\Support\Uri\Uri; use Throwable; use function Tempest\Mapper\map; @@ -53,18 +54,23 @@ public function map(mixed $from, mixed $to): GenericRequest $headers = RequestHeaders::normalizeFromArray($headersAsString); - parse_str($from->getUri()->getQuery(), $query); - $uploads = $this->createUploads($from->getUploadedFiles()); + $uri = $from->getUri(); + return map([ 'method' => $this->requestMethod($from, $data), - 'uri' => (string) $from->getUri(), + 'uri' => new Uri( + scheme: $uri->getScheme(), + host: $uri->getHost(), + port: $uri->getPort(), + path: $uri->getPath(), + queryString: $uri->getQuery(), + fragment: $uri->getFragment(), + ), 'raw' => $raw, 'body' => $data, 'headers' => $headers, - 'path' => $from->getUri()->getPath(), - 'query' => $query, 'files' => $uploads, 'ip' => $this->clientIpResolver->resolve($from->getServerParams()['REMOTE_ADDR'] ?? null, $headers), 'cookies' => Arr\filter(Arr\map( diff --git a/packages/http/src/Mappers/RequestToObjectMapper.php b/packages/http/src/Mappers/RequestToObjectMapper.php index 36db970a7a..d1c706daaa 100644 --- a/packages/http/src/Mappers/RequestToObjectMapper.php +++ b/packages/http/src/Mappers/RequestToObjectMapper.php @@ -29,7 +29,7 @@ public function canMap(mixed $from, mixed $to): bool public function map(mixed $from, mixed $to): array|object { /** @var Request $from */ - $data = [...$from->files, ...$from->body, ...$from->query]; + $data = [...$from->files, ...$from->body, ...$from->uri->query]; if (is_a($to, Request::class, true)) { $invalidReservedProperties = arr(new ClassReflector(Request::class)->getProperties()) @@ -46,8 +46,6 @@ public function map(mixed $from, mixed $to): array|object 'uri' => $from->uri, 'body' => $from->body, 'headers' => $from->headers, - 'path' => $from->path, - 'query' => $from->query, 'files' => $from->files, 'cookies' => $from->cookies, 'ip' => $from->ip, diff --git a/packages/http/src/Mappers/RequestToPsrRequestMapper.php b/packages/http/src/Mappers/RequestToPsrRequestMapper.php index 83134a17d7..c809b13817 100644 --- a/packages/http/src/Mappers/RequestToPsrRequestMapper.php +++ b/packages/http/src/Mappers/RequestToPsrRequestMapper.php @@ -23,11 +23,11 @@ public function map(mixed $from, mixed $to): PsrRequest $request = new ServerRequest( serverParams: $from->ip === null ? [] : ['REMOTE_ADDR' => $from->ip->toString()], uploadedFiles: $from->files, - uri: $from->uri, + uri: $from->uri->toString(), method: $from->method->value, headers: $from->headers->toArray(), cookieParams: $from->cookies, - queryParams: $from->query, + queryParams: $from->uri->query, parsedBody: $from->body, ); diff --git a/packages/http/src/Request.php b/packages/http/src/Request.php index bbd5373908..a8c2c81bcd 100644 --- a/packages/http/src/Request.php +++ b/packages/http/src/Request.php @@ -6,12 +6,13 @@ use Tempest\Http\Cookie\Cookie; use Tempest\Support\Ip\IpAddress; +use Tempest\Support\Uri\Uri; interface Request { public Method $method { get; } - public string $uri { get; } + public Uri $uri { get; } public ?string $raw { get; } @@ -19,10 +20,6 @@ interface Request public RequestHeaders $headers { get; } - public string $path { get; } - - public array $query { get; } - /** @var array $files */ public array $files { get; } diff --git a/packages/http/src/Session/PreviousUrl.php b/packages/http/src/Session/PreviousUrl.php index 9fe22a66eb..676824f49a 100644 --- a/packages/http/src/Session/PreviousUrl.php +++ b/packages/http/src/Session/PreviousUrl.php @@ -29,7 +29,8 @@ public function track(Request $request): void return; } - $this->session->set(self::PREVIOUS_URL_SESSION_KEY, $request->uri); + // TODO(neoisrecursive): figure out if a full uri is OK here + $this->session->set(self::PREVIOUS_URL_SESSION_KEY, $request->uri->toString()); } /** diff --git a/packages/http/tests/GenericRequestTest.php b/packages/http/tests/GenericRequestTest.php index 3a3d8b7cf2..37ad428209 100644 --- a/packages/http/tests/GenericRequestTest.php +++ b/packages/http/tests/GenericRequestTest.php @@ -187,9 +187,8 @@ public function connect_requests_skip_uri_parsing(string $uri): void uri: $uri, ); - $this->assertSame($uri, $request->uri); - $this->assertSame('', $request->path); - $this->assertSame([], $request->query); + $this->assertSame($uri, $request->uri->path); + $this->assertSame([], $request->uri->query); } #[Test] diff --git a/packages/idempotency/src/Fingerprint/RequestFingerprintGenerator.php b/packages/idempotency/src/Fingerprint/RequestFingerprintGenerator.php index 6267df8e75..c437008d1c 100644 --- a/packages/idempotency/src/Fingerprint/RequestFingerprintGenerator.php +++ b/packages/idempotency/src/Fingerprint/RequestFingerprintGenerator.php @@ -14,8 +14,8 @@ public function generate(Request $request): string { $payload = [ 'method' => $request->method->value, - 'path' => $request->path, - 'query' => $this->normalize($request->query), + 'path' => $request->uri->path, + 'query' => $this->normalize($request->uri->query), 'body' => $request->raw ?? $this->normalize($request->body), ]; diff --git a/packages/mcp/src/McpHttpController.php b/packages/mcp/src/McpHttpController.php index f08316a088..854764099d 100644 --- a/packages/mcp/src/McpHttpController.php +++ b/packages/mcp/src/McpHttpController.php @@ -24,7 +24,7 @@ public function __construct( public function __invoke(Request $request): Response { - $server = $this->config->getServerByPath($request->path); + $server = $this->config->getServerByPath($request->uri->path); if (! $server instanceof McpServerDefinition) { return new NotFound(); diff --git a/packages/router/src/Routing/Matching/GenericRouteMatcher.php b/packages/router/src/Routing/Matching/GenericRouteMatcher.php index ba52658592..9c6ba039d8 100644 --- a/packages/router/src/Routing/Matching/GenericRouteMatcher.php +++ b/packages/router/src/Routing/Matching/GenericRouteMatcher.php @@ -29,7 +29,7 @@ public function match(Request $request): ?MatchedRoute private function matchStaticRoute(Request $request): ?MatchedRoute { - $staticRoute = $this->routeConfig->staticRoutes[$request->method->value][$request->path] ?? null; + $staticRoute = $this->routeConfig->staticRoutes[$request->method->value][$request->uri->path] ?? null; if ($staticRoute === null) { return null; @@ -50,7 +50,7 @@ private function matchDynamicRoute(Request $request): ?MatchedRoute $matchingRegexForMethod = $this->routeConfig->matchingRegexes[$request->method->value]; // Then we'll use this regex to see whether we have a match or not - $matchResult = $matchingRegexForMethod->match($request->path); + $matchResult = $matchingRegexForMethod->match($request->uri->path ?? ''); if ($matchResult === null) { return null; diff --git a/packages/router/src/UriGenerator.php b/packages/router/src/UriGenerator.php index 5fa8630e33..4e3abf69e9 100644 --- a/packages/router/src/UriGenerator.php +++ b/packages/router/src/UriGenerator.php @@ -48,7 +48,7 @@ public function hasValidSignature(Request $request): bool } return $this->signer->verify( - data: $this->createUri($request->path, ...Arr\remove_keys($request->query, 'signature')), + data: $this->createUri($request->uri->path, ...Arr\remove_keys($request->uri->query, 'signature')), signature: Signature::from($signature), ); }