mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
feat(rpc): add ETag header with md5 hash content
The ETag header can be used for client-side caching. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
parent
b3b31394e8
commit
6d376fed15
3 changed files with 33 additions and 6 deletions
|
@ -1,8 +1,12 @@
|
||||||
|
import hashlib
|
||||||
|
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
from fastapi import APIRouter, Query, Request
|
import orjson
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Query, Request, Response
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
from aurweb.ratelimit import check_ratelimit
|
from aurweb.ratelimit import check_ratelimit
|
||||||
|
@ -74,4 +78,21 @@ async def rpc(request: Request,
|
||||||
# Prepare list of arguments for input. If 'arg' was given, it'll
|
# Prepare list of arguments for input. If 'arg' was given, it'll
|
||||||
# be a list with one element.
|
# be a list with one element.
|
||||||
arguments = parse_args(request)
|
arguments = parse_args(request)
|
||||||
return JSONResponse(rpc.handle(arguments))
|
data = rpc.handle(arguments)
|
||||||
|
|
||||||
|
# Serialize `data` into JSON in a sorted fashion. This way, our
|
||||||
|
# ETag header produced below will never end up changed.
|
||||||
|
output = orjson.dumps(data, option=orjson.OPT_SORT_KEYS)
|
||||||
|
|
||||||
|
# Produce an md5 hash based on `output`.
|
||||||
|
md5 = hashlib.md5()
|
||||||
|
md5.update(output)
|
||||||
|
etag = md5.hexdigest()
|
||||||
|
|
||||||
|
# Finally, return our JSONResponse with the ETag header.
|
||||||
|
# The ETag header expects quotes to surround any identifier.
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
|
||||||
|
return Response(output.decode(), headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"ETag": f'"{etag}"'
|
||||||
|
})
|
||||||
|
|
|
@ -99,8 +99,7 @@ class RPC:
|
||||||
data: Dict[str, Any]):
|
data: Dict[str, Any]):
|
||||||
# Walk through all related PackageDependencies and produce
|
# Walk through all related PackageDependencies and produce
|
||||||
# the appropriate dict entries.
|
# the appropriate dict entries.
|
||||||
depends = package.package_dependencies
|
for dep in package.package_dependencies:
|
||||||
for dep in depends:
|
|
||||||
if dep.DepTypeID in DEP_TYPES:
|
if dep.DepTypeID in DEP_TYPES:
|
||||||
key = DEP_TYPES.get(dep.DepTypeID)
|
key = DEP_TYPES.get(dep.DepTypeID)
|
||||||
|
|
||||||
|
@ -114,8 +113,7 @@ class RPC:
|
||||||
data: Dict[str, Any]):
|
data: Dict[str, Any]):
|
||||||
# Walk through all related PackageRelations and produce
|
# Walk through all related PackageRelations and produce
|
||||||
# the appropriate dict entries.
|
# the appropriate dict entries.
|
||||||
relations = package.package_relations
|
for rel in package.package_relations:
|
||||||
for rel in relations:
|
|
||||||
if rel.RelTypeID in REL_TYPES:
|
if rel.RelTypeID in REL_TYPES:
|
||||||
key = REL_TYPES.get(rel.RelTypeID)
|
key = REL_TYPES.get(rel.RelTypeID)
|
||||||
|
|
||||||
|
|
|
@ -488,3 +488,11 @@ def test_rpc_ratelimit(getint: mock.MagicMock, pipeline: Pipeline):
|
||||||
# The new first request should be good.
|
# The new first request should be good.
|
||||||
response = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big")
|
response = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big")
|
||||||
assert response.status_code == int(HTTPStatus.OK)
|
assert response.status_code == int(HTTPStatus.OK)
|
||||||
|
|
||||||
|
|
||||||
|
def test_rpc_etag():
|
||||||
|
response1 = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big")
|
||||||
|
response2 = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big")
|
||||||
|
assert response1.headers.get("ETag") is not None
|
||||||
|
assert response1.headers.get("ETag") != str()
|
||||||
|
assert response1.headers.get("ETag") == response2.headers.get("ETag")
|
||||||
|
|
Loading…
Add table
Reference in a new issue