Skip to content

Commit

Permalink
Handle key being larger than 2048 bytes (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
RikudouSage committed Apr 4, 2022
1 parent 4835c98 commit f9b8211
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 3 deletions.
30 changes: 27 additions & 3 deletions src/DynamoDbCache.php
Expand Up @@ -8,6 +8,7 @@
use AsyncAws\DynamoDb\ValueObject\AttributeValue;
use AsyncAws\DynamoDb\ValueObject\KeysAndAttributes;
use DateInterval;
use LogicException;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Psr\SimpleCache\CacheInterface;
Expand All @@ -23,6 +24,7 @@
final class DynamoDbCache implements CacheItemPoolInterface, CacheInterface
{
private const RESERVED_CHARACTERS = '{}()/\@:';
private const MAX_KEY_LENGTH = 2048;

/**
* @var string
Expand Down Expand Up @@ -107,6 +109,11 @@ public function __construct(
);
}
$this->converter = $converter;
if ($prefix !== null && strlen($prefix) >= self::MAX_KEY_LENGTH) {
throw new LogicException(
sprintf('The prefix cannot be longer or equal to the maximum length: %d bytes', self::MAX_KEY_LENGTH)
);
}
$this->prefix = $prefix;
}

Expand All @@ -123,8 +130,13 @@ public function getItem($key)
throw $exception;
}

$finalKey = $this->getKey($key);
if (strlen($finalKey) > self::MAX_KEY_LENGTH) {
$finalKey = $this->generateCompliantKey($key);
}

try {
$item = $this->getRawItem($this->getKey($key));
$item = $this->getRawItem($finalKey);
if (!isset($item[$this->valueField])) {
throw new CacheItemNotFoundException();
}
Expand All @@ -133,7 +145,7 @@ public function getItem($key)
assert(method_exists($this->clock->now(), 'setTimestamp'));

return new DynamoCacheItem(
$this->getKey($key),
$finalKey,
$data !== null,
$data !== null ? $this->encoder->decode($data) : null,
isset($item[$this->ttlField]) && $item[$this->ttlField]->getN() !== null
Expand All @@ -144,7 +156,7 @@ public function getItem($key)
);
} catch (CacheItemNotFoundException $e) {
return new DynamoCacheItem(
$this->getKey($key),
$finalKey,
false,
null,
null,
Expand Down Expand Up @@ -575,4 +587,16 @@ private function getRawItem(string $key): array

return $item->getItem();
}

private function generateCompliantKey(string $key): string
{
$key = $this->getKey($key);
$suffix = '_trunc_' . md5($key);

return substr(
$this->getKey($key),
0,
self::MAX_KEY_LENGTH - strlen($suffix)
) . $suffix;
}
}
39 changes: 39 additions & 0 deletions tests/DynamoDbCacheTest.php
Expand Up @@ -18,6 +18,7 @@
use DateInterval;
use DateTime;
use DateTimeImmutable;
use LogicException;
use PHPUnit\Framework\TestCase;
use Psr\Cache\CacheItemInterface;
use Psr\Log\NullLogger;
Expand Down Expand Up @@ -287,6 +288,44 @@ public function testGetItemsDefaultFields()
}
}

/**
* @see https://github.com/RikudouSage/DynamoDbCachePsr6/issues/19
*/
public function testGetItemKeyTooLong()
{
$key = bin2hex(random_bytes(1025));

$item = $this->instance->getItem($key);
self::assertNotEquals($key, $item->getKey());
self::assertLessThanOrEqual(2048, strlen($item->getKey()));

$item = $this->instancePrefixed->getItem($key);
self::assertNotEquals($key, $item->getKey());
self::assertNotEquals($this->prefix . $key, $item->getKey());
self::assertStringStartsWith($this->prefix, $item->getKey());
self::assertLessThanOrEqual(2048, strlen($item->getKey()));

$key = bin2hex(random_bytes(1023));

$item = $this->instance->getItem($key);
self::assertEquals($key, $item->getKey());
$item = $this->instancePrefixed->getItem($key);
self::assertNotEquals($key, $item->getKey());

$this->expectException(LogicException::class);
new DynamoDbCache(
'test',
$this->getFakeClient($this->itemPoolPrefixed),
'id',
'ttl',
'value',
null,
null,
null,
bin2hex(random_bytes(1024)),
);
}

public function testGetItemsPrefixed()
{
$result = $this->instancePrefixed->getItems([
Expand Down

0 comments on commit f9b8211

Please sign in to comment.