new: [redis] Store some data in Redis compressed to save memory

pull/8724/head
Jakub Onderka 2022-10-30 16:19:58 +01:00
parent 3deec3e3be
commit 645b11e1b1
4 changed files with 53 additions and 8 deletions

View File

@ -124,7 +124,7 @@ class AppController extends Controller
$this->__cors();
if (Configure::read('Security.check_sec_fetch_site_header')) {
$secFetchSite = $this->request->header('Sec-Fetch-Site');
if ($secFetchSite !== false && $secFetchSite !== 'same-origin' && ($this->request->is('post') || $this->request->is('put') || $this->request->is('ajax'))) {
if ($secFetchSite !== false && $secFetchSite !== 'same-origin' && $this->request->is(['post', 'put', 'ajax'])) {
throw new MethodNotAllowedException("POST, PUT and AJAX requests are allowed just from same origin.");
}
}
@ -1396,8 +1396,7 @@ class AppController extends Controller
}
try {
$redis = $this->User->setupRedisWithException();
return $redis->get('misp:live') !== '0';
return RedisTool::init()->get('misp:live') !== '0';
} catch (Exception $e) {
return true;
}

View File

@ -1,6 +1,10 @@
<?php
class RedisTool
{
const COMPRESS_MIN_LENGTH = 200,
BROTLI_HEADER = "\xce\xb2\xcf\x81",
ZSTD_HEADER = "\x28\xb5\x2f\xfd";
/** @var Redis|null */
private static $connection;
@ -153,4 +157,41 @@ class RedisTool
return JsonTool::decode($string);
}
}
/**
* @param string $data
* @return string
*/
public static function compress($data)
{
if (strlen($data) >= self::COMPRESS_MIN_LENGTH) {
if (function_exists('zstd_compress')) {
return zstd_compress($data, 1);
} elseif (function_exists('brotli_compress')) {
return self::BROTLI_HEADER . brotli_compress($data, 4);
}
}
return $data;
}
/**
* @param string $data
* @return string
*/
public static function decompress($data)
{
$magic = substr($data, 0, 4);
if ($magic === self::ZSTD_HEADER) {
$data = zstd_uncompress($data);
if ($data === false) {
throw new RuntimeException('Could not decompress');
}
} elseif ($magic === self::BROTLI_HEADER) {
$data = brotli_uncompress(substr($data, 4));
if ($data === false) {
throw new RuntimeException('Could not decompress');
}
}
return $data;
}
}

View File

@ -1,9 +1,11 @@
<?php
App::uses('AppModel', 'Model');
// Table `event_locks` is not used anymore
class EventLock extends AppModel
{
// Table `event_locks` is not used anymore
public $useTable = false;
// In seconds
const DEFAULT_TTL = 900,
PREFIX = 'misp:event_lock:';
@ -126,6 +128,8 @@ class EventLock extends AppModel
* @param string $lockId
* @param array $data
* @return bool
* @throws JsonException
* @throws RedisException
*/
private function insertLockToRedis($eventId, $lockId, array $data)
{

View File

@ -816,7 +816,7 @@ class Server extends AppModel
$redis = RedisTool::init();
$indexFromCache = $redis->get("misp:event_index:{$serverSync->serverId()}");
if ($indexFromCache) {
list($etag, $eventIndex) = RedisTool::deserialize($indexFromCache);
list($etag, $eventIndex) = RedisTool::deserialize(RedisTool::decompress($indexFromCache));
} else {
$etag = '""'; // Provide empty ETag, so MISP will compute ETag for returned data
}
@ -835,10 +835,11 @@ class Server extends AppModel
}
// Save to cache for 24 hours if ETag provided
if (isset($response->headers["ETag"])) {
$data = RedisTool::serialize([$response->headers["ETag"], $eventIndex]);
$etag = $response->getHeader('etag');
if ($etag) {
$data = RedisTool::compress(RedisTool::serialize([$etag, $eventIndex]));
$redis->setex("misp:event_index:{$serverSync->serverId()}", 3600 * 24, $data);
} else if ($indexFromCache) {
} elseif ($indexFromCache) {
RedisTool::unlink($redis, "misp:event_index:{$serverSync->serverId()}");
}