Skip to content

Commit

Permalink
Improve RFC compliance
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Nov 20, 2024
1 parent 9049e0c commit 930742a
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 55 deletions.
21 changes: 16 additions & 5 deletions src/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public static function fromSapi(array $server = [], string $name = self::SAPI_NA

/**
* Returns an instance from a Header Line and the optional response status code.
*
* Invalid entries will be filtered out according to Structured Field RFC.
*/
public static function fromHttpValue(OuterList|StructuredFieldProvider|Stringable|string $list = '', ?int $statusCode = null): self
{
Expand All @@ -74,12 +76,21 @@ public static function fromHttpValue(OuterList|StructuredFieldProvider|Stringabl
$list = OuterList::fromHttpValue($list);
}

return new self(...$list->map(
fn (Item|InnerList $item, int $offset): HandledRequestCache => match (true) {
$item instanceof Item => HandledRequestCache::fromHttpValue($item, $statusCode),
default => throw new Exception('The list must only contain item structure representing handled request cache.'),
/** @var array<HandledRequestCache> $caches */
$caches = $list->reduce(function (array $filteredCache, Item|InnerList $value, int $offset) use ($statusCode): array { /* @phpstan-ignore-line */
if ($value instanceof InnerList) {
return $filteredCache;
}
));

try {
$filteredCache[] = HandledRequestCache::fromHttpValue($value, $statusCode);
} catch (Exception) {

}
return $filteredCache;
}, []);

return new self(...$caches);
}

/**
Expand Down
95 changes: 95 additions & 0 deletions src/FieldTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

declare(strict_types=1);

namespace Bakame\Http\CacheStatus;

use Bakame\Http\StructuredFields\Token;
use GuzzleHttp\Psr7\HttpFactory;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class FieldTest extends TestCase
{
#[Test]
public function parsing_a_response_header(): void
{
$factory = new HttpFactory();
$response = $factory->createResponse()
->withStatus(302)
->withHeader('cache-status', 'ReverseProxyCache; hit')
->withAddedHeader('Cache-Status', 'ForwardProxyCache; fwd=uri-miss; collapsed; stored')
->withAddedHeader('cache-Status', 'BrowserCache; fwd=uri-miss; key="Hello Boy!"');

$fieldList = Field::fromHttpValue($response->getHeaderLine('cache-Status'), $response->getStatusCode());

self::assertCount(3, $fieldList);

$closestToOrigin = $fieldList->closestToOrigin();
$closestToClient = $fieldList->closestToUser();
$intermediary = $fieldList[1];

self::assertInstanceOf(HandledRequestCache::class, $closestToOrigin);
self::assertInstanceOf(HandledRequestCache::class, $closestToClient);
self::assertSame($fieldList[-1], $closestToClient);
self::assertFalse($fieldList->isEmpty());

self::assertNull($closestToOrigin->forward);

self::assertInstanceOf(Forward::class, $intermediary->forward);
self::assertSame($response->getStatusCode(), $intermediary->forward->statusCode);

self::assertInstanceOf(Forward::class, $closestToClient->forward);
self::assertSame($response->getStatusCode(), $closestToClient->forward->statusCode);
self::assertFalse(isset($fieldList[42]));
self::assertFalse($fieldList->contains('Foobar'));
self::assertTrue($fieldList->contains(Token::fromString('BrowserCache')));
self::assertFalse($fieldList->contains('BrowserCache'));
self::assertSame(2, $fieldList->indexOf(Token::fromString('BrowserCache')));
self::assertNull($fieldList->indexOf('foobar'));
self::assertTrue($closestToOrigin->hit);
self::assertFalse($intermediary->hit);
self::assertFalse($closestToClient->hit);

self::assertNull($closestToOrigin->forward);
self::assertSame(ForwardedReason::UriMiss, $intermediary->forward->reason);
self::assertSame(ForwardedReason::UriMiss, $closestToClient->forward->reason);

self::assertSame('ReverseProxyCache', $closestToOrigin->servedBy());
self::assertSame('ForwardProxyCache', $intermediary->servedBy());
self::assertSame('BrowserCache', $closestToClient->servedBy());
}

#[Test]
public function parsing_a_response_header_with_invalid_members(): void
{
$factory = new HttpFactory();
$response = $factory->createResponse()
->withStatus(302)
->withHeader('cache-status', 'ReverseProxyCache; hit')
->withAddedHeader('Cache-Status', 'ForwardProxyCache; hit; fwd=uri-miss; collapsed; stored')
->withAddedHeader('Cache-Status', '(foo bar "baz")')
->withAddedHeader('cache-Status', 'BrowserCache; fwd=uri-miss; key="Hello Boy!"');

$fieldList = Field::fromHttpValue($response->getHeaderLine('cache-Status'), $response->getStatusCode());

self::assertCount(2, $fieldList);
self::assertFalse($fieldList->contains('ForwardProxyCache'));
}

#[Test]
public function pushing_an_invalid_request_cache_will_fail(): void
{
$this->expectException(Exception::class);

(new Field())->push('ForwardProxyCache; hit; fwd=uri-miss; collapsed; stored');
}

#[Test]
public function creating_a_new_instance_with_an_invalid_request_cache_will_fail(): void
{
$this->expectException(Exception::class);

new Field('ForwardProxyCache; hit; fwd=uri-miss; collapsed; stored');
}
}
50 changes: 0 additions & 50 deletions src/HandledRequestCacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Bakame\Http\StructuredFields\Item;
use Bakame\Http\StructuredFields\Token;
use GuzzleHttp\Psr7\HttpFactory;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

Expand Down Expand Up @@ -63,55 +62,6 @@ public function it_can_create_a_cache_status_progressively(): void
self::assertNull($cacheHit->forward);
}

#[Test]
public function parsing_a_response_header(): void
{
$factory = new HttpFactory();
$response = $factory->createResponse()
->withStatus(302)
->withHeader('cache-status', 'ReverseProxyCache; hit')
->withAddedHeader('Cache-Status', 'ForwardProxyCache; fwd=uri-miss; collapsed; stored')
->withAddedHeader('cache-Status', 'BrowserCache; fwd=uri-miss; key="Hello Boy!"');

$fieldList = Field::fromHttpValue($response->getHeaderLine('cache-Status'), $response->getStatusCode());

self::assertCount(3, $fieldList);

$closestToOrigin = $fieldList->closestToOrigin();
$closestToClient = $fieldList->closestToUser();
$intermediary = $fieldList[1];

self::assertInstanceOf(HandledRequestCache::class, $closestToOrigin);
self::assertInstanceOf(HandledRequestCache::class, $closestToClient);
self::assertSame($fieldList[-1], $closestToClient);
self::assertFalse($fieldList->isEmpty());

self::assertNull($closestToOrigin->forward);

self::assertInstanceOf(Forward::class, $intermediary->forward);
self::assertSame($response->getStatusCode(), $intermediary->forward->statusCode);

self::assertInstanceOf(Forward::class, $closestToClient->forward);
self::assertSame($response->getStatusCode(), $closestToClient->forward->statusCode);
self::assertFalse(isset($fieldList[42]));
self::assertFalse($fieldList->contains('Foobar'));
self::assertTrue($fieldList->contains(Token::fromString('BrowserCache')));
self::assertFalse($fieldList->contains('BrowserCache'));
self::assertSame(2, $fieldList->indexOf(Token::fromString('BrowserCache')));
self::assertNull($fieldList->indexOf('foobar'));
self::assertTrue($closestToOrigin->hit);
self::assertFalse($intermediary->hit);
self::assertFalse($closestToClient->hit);

self::assertNull($closestToOrigin->forward);
self::assertSame(ForwardedReason::UriMiss, $intermediary->forward->reason);
self::assertSame(ForwardedReason::UriMiss, $closestToClient->forward->reason);

self::assertSame('ReverseProxyCache', $closestToOrigin->servedBy());
self::assertSame('ForwardProxyCache', $intermediary->servedBy());
self::assertSame('BrowserCache', $closestToClient->servedBy());
}

#[Test]
public function it_can_update_the_forward_parameters(): void
{
Expand Down

0 comments on commit 930742a

Please sign in to comment.