mirror of https://github.com/MISP/MISP
chg: [API] Add support for ETag checking
parent
9582d59563
commit
6a3253bd2e
|
@ -601,6 +601,13 @@ class RestResponseComponent extends Component
|
|||
}
|
||||
|
||||
if ($response instanceof TmpFileTool) {
|
||||
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
||||
$etag = '"' . $response->hash('sha1') . '"';
|
||||
if ($_SERVER['HTTP_IF_NONE_MATCH'] === $etag) {
|
||||
return new CakeResponse(['status' => 304]);
|
||||
}
|
||||
$headers['ETag'] = $etag;
|
||||
}
|
||||
if ($this->signContents) {
|
||||
$this->CryptographicKey = ClassRegistry::init('CryptographicKey');
|
||||
$data = $response->intoString();
|
||||
|
@ -612,7 +619,16 @@ class RestResponseComponent extends Component
|
|||
$cakeResponse->file($response);
|
||||
}
|
||||
} else {
|
||||
$cakeResponse = new CakeResponse(array('body' => $response, 'status' => $code, 'type' => $type));
|
||||
// Check if resource was changed when `If-None-Match` header is send and return 304 Not Modified
|
||||
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
||||
$etag = '"' . sha1($response) . '"';
|
||||
if ($_SERVER['HTTP_IF_NONE_MATCH'] === $etag) {
|
||||
return new CakeResponse(['status' => 304]);
|
||||
}
|
||||
// Generate etag just when HTTP_IF_NONE_MATCH is set
|
||||
$headers['ETag'] = $etag;
|
||||
}
|
||||
$cakeResponse = new CakeResponse(['body' => $response, 'status' => $code, 'type' => $type]);
|
||||
if ($this->signContents) {
|
||||
$headers['x-pgp-signature'] = base64_encode($this->CryptographicKey->signWithInstanceKey($response));
|
||||
}
|
||||
|
|
|
@ -192,6 +192,19 @@ class TmpFileTool
|
|||
return fstat($this->tmpfile)['size'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $algo
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function hash($algo)
|
||||
{
|
||||
$this->rewind();
|
||||
$hash = hash_init($algo);
|
||||
hash_update_stream($hash, $this->tmpfile);
|
||||
return hash_final($hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
|
|
|
@ -4,6 +4,7 @@ import json
|
|||
import uuid
|
||||
import subprocess
|
||||
import unittest
|
||||
import requests
|
||||
from xml.etree import ElementTree as ET
|
||||
from io import BytesIO
|
||||
import urllib3 # type: ignore
|
||||
|
@ -746,6 +747,22 @@ class TestComprehensive(unittest.TestCase):
|
|||
self.assertEqual(200, response.status_code, response)
|
||||
response.json()
|
||||
|
||||
def test_etag(self):
|
||||
headers = {
|
||||
'Authorization': self.admin_misp_connector.key,
|
||||
'Accept': 'application/json',
|
||||
'User-Agent': 'PyMISP',
|
||||
'If-None-Match': '',
|
||||
}
|
||||
response = requests.get(self.admin_misp_connector.root_url + '/attributes/describeTypes.json', headers=headers)
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertIn('Etag', response.headers)
|
||||
self.assertTrue(len(response.headers['Etag']) > 0, response.headers['Etag'])
|
||||
|
||||
headers['If-None-Match'] = response.headers['Etag']
|
||||
response = requests.get(self.admin_misp_connector.root_url + '/attributes/describeTypes.json', headers=headers)
|
||||
self.assertEqual(304, response.status_code, response.headers)
|
||||
|
||||
def _search(self, query: dict):
|
||||
response = self.admin_misp_connector._prepare_request('POST', 'events/restSearch', data=query)
|
||||
response = self.admin_misp_connector._check_response(response)
|
||||
|
|
Loading…
Reference in New Issue