diff --git a/src/JsonLd/Dereferencer/CachingDereferencer.php b/src/JsonLd/Dereferencer/CachingDereferencer.php index b6e1933..73fd2c0 100644 --- a/src/JsonLd/Dereferencer/CachingDereferencer.php +++ b/src/JsonLd/Dereferencer/CachingDereferencer.php @@ -4,6 +4,7 @@ namespace ActivityPub\JsonLd\Dereferencer; use ActivityPub\Crypto\HttpSignatureService; use ActivityPub\JsonLd\Exceptions\NodeNotFoundException; +use ActivityPub\Utils\DateTimeProvider; use ActivityPub\Utils\Util; use DateTime; use DateTimeZone; @@ -44,6 +45,11 @@ class CachingDereferencer implements DereferencerInterface */ private $httpSignatureService; + /** + * @var DateTimeProvider + */ + private $dateTimeProvider; + /** * The keyId for signing requests, if there is one. * @var null|string @@ -58,9 +64,11 @@ class CachingDereferencer implements DereferencerInterface /** * CachingDereferencer constructor. + * @param LoggerInterface $logger * @param CacheItemPoolInterface $cache * @param Client $httpClient * @param HttpSignatureService $httpSignatureService + * @param DateTimeProvider $dateTimeProvider * @param null|string $keyId * @param null|string $privateKey */ @@ -68,6 +76,7 @@ class CachingDereferencer implements DereferencerInterface CacheItemPoolInterface $cache, Client $httpClient, HttpSignatureService $httpSignatureService, + DateTimeProvider $dateTimeProvider, $keyId = null, $privateKey = null ) { @@ -75,6 +84,7 @@ class CachingDereferencer implements DereferencerInterface $this->cache = $cache; $this->httpClient = $httpClient; $this->httpSignatureService = $httpSignatureService; + $this->dateTimeProvider = $dateTimeProvider; $this->keyId = $keyId; $this->privateKey = $privateKey; } @@ -113,7 +123,7 @@ class CachingDereferencer implements DereferencerInterface $signature = $this->httpSignatureService->sign( $request, $this->privateKey, $this->keyId ); $request = $request->withHeader( 'Signature', $signature ); } - $response = $this->httpClient->send( $request ); + $response = $this->httpClient->send( $request, array( 'http_errors' => false ) ); if ( $response->getStatusCode() >= 400 ) { $statusCode = $response->getStatusCode(); $this->logger->error( @@ -154,7 +164,8 @@ class CachingDereferencer implements DereferencerInterface private function getNowRFC1123() { - $now = new DateTime( 'now', new DateTimeZone( 'GMT' ) ); + $now = $this->dateTimeProvider->getTime( 'caching-dereferencer.dereference' ); + $now->setTimezone( new DateTimeZone( 'GMT' ) ); return $now->format( 'D, d M Y H:i:s T' ); } } \ No newline at end of file diff --git a/test/JsonLd/Dereferencer/CachingDereferencerTest.php b/test/JsonLd/Dereferencer/CachingDereferencerTest.php new file mode 100644 index 0000000..727ceee --- /dev/null +++ b/test/JsonLd/Dereferencer/CachingDereferencerTest.php @@ -0,0 +1,141 @@ + 'https://example.com/sally', + 'type' => 'Person', + ), + array( + new Request( + 'GET', + 'https://example.com/sally', + array( + 'Host' => 'example.com', + 'Accept' => 'application/ld+json', + 'Date' => 'Sun, 05 Jan 2014 21:31:40 GMT', + ) + ), + ), + array( + new Response( 200, array(), json_encode( + (object) array( + 'id' => 'https://example.com/sally', + 'type' => 'Person', + ) + )), + ), + ), + array( + 'https://example.com/sally', + (object) array( + 'id' => 'https://example.com/sally', + 'type' => 'Person', + ), + array( + new Request( + 'GET', + 'https://example.com/sally', + array( + 'Host' => 'example.com', + 'Accept' => 'application/ld+json', + 'Date' => 'Sun, 05 Jan 2014 21:31:40 GMT', + 'Signature' => 'keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date",signature="PXfYgMWE1CpS7DDuo8iB7Sj3qCBuN8bDuND3mQBU06rh7EMfWqisB0USH0DWFbZVcbsHr/YnKJlcmbWG5mpU6Kf0B4SAoMKGHCUNT1i55uw5XLPSZfrd2c38md2Pv8Dt0lO7cFP8SeiTlBM3gTmpvnuKn+AxpR9jpvwAQT8riQw="', + ) + ), + ), + array( + new Response( 200, array(), json_encode( + (object) array( + 'id' => 'https://example.com/sally', + 'type' => 'Person', + ) + )), + ), + 'Test', + "-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDCFENGw33yGihy92pDjZQhl0C36rPJj+CvfSC8+q28hxA161QF +NUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6Z4UMR7EOcpfdUE9Hf3m/hs+F +UR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJwoYi+1hqp1fIekaxsyQIDAQAB +AoGBAJR8ZkCUvx5kzv+utdl7T5MnordT1TvoXXJGXK7ZZ+UuvMNUCdN2QPc4sBiA +QWvLw1cSKt5DsKZ8UETpYPy8pPYnnDEz2dDYiaew9+xEpubyeW2oH4Zx71wqBtOK +kqwrXa/pzdpiucRRjk6vE6YY7EBBs/g7uanVpGibOVAEsqH1AkEA7DkjVH28WDUg +f1nqvfn2Kj6CT7nIcE3jGJsZZ7zlZmBmHFDONMLUrXR/Zm3pR5m0tCmBqa5RK95u +412jt1dPIwJBANJT3v8pnkth48bQo/fKel6uEYyboRtA5/uHuHkZ6FQF7OUkGogc +mSJluOdc5t6hI1VsLn0QZEjQZMEOWr+wKSMCQQCC4kXJEsHAve77oP6HtG/IiEn7 +kpyUXRNvFsDE0czpJJBvL/aRFUJxuRK91jhjC68sA7NsKMGg5OXb5I5Jj36xAkEA +gIT7aFOYBFwGgQAQkWNKLvySgKbAZRTeLBacpHMuQdl1DfdntvAyqpAZ0lY0RKmW +G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI +7U1yQXnTAEFYM560yJlzUpOb1V4cScGd365tiSMvxLOvTA== +-----END RSA PRIVATE KEY-----", + ), + ); + } + + /** + * @dataProvider provideForItCaches + */ + public function testItCaches( $iri, + $expectedJsonObj, + $expectedRequestHistory = array(), + $mockResponses = array(), + $keyId = null, + $privateKey = null ) + { + $logger = new Logger(); + $cache = new ArrayCachePool(); + $dateTimeProvider = new TestDateTimeProvider( array ( + 'caching-dereferencer.dereference' => DateTime::createFromFormat( + DateTime::RFC2822, 'Sun, 05 Jan 2014 21:31:40 GMT' + ), + ) ); + $sigService = new HttpSignatureService( $dateTimeProvider ); + + $mock = new MockHandler( $mockResponses ); + $handler = HandlerStack::create( $mock ); + $historyContainer = array(); + $history = Middleware::history( $historyContainer ); + $handler->push( $history ); + $client = new Client( array( 'handler' => $handler ) ); + + $dereferencer = new CachingDereferencer( + $logger, $cache, $client, $sigService, $dateTimeProvider, $keyId, $privateKey + ); + + $jsonObj = $dereferencer->dereference( $iri ); + $this->assertEquals( $expectedJsonObj, $jsonObj ); + + $cachedObj = $dereferencer->dereference( $iri ); + $this->assertEquals( $expectedJsonObj, $cachedObj ); + + $this->assertEquals( count( $expectedRequestHistory ), count( $historyContainer ) ); + for ( $i = 0; $i < count( $expectedRequestHistory ); $i += 1 ) { + $expectedRequest = $expectedRequestHistory[$i]; + $actualRequest = $historyContainer[$i]['request']; + foreach ( $expectedRequest->getHeaders() as $name => $expectedHeaders ) { + $this->assertEquals( $expectedHeaders, $actualRequest->getHeader( $name ) ); + } + } + } +} \ No newline at end of file