diff --git a/testing/web-platform/tests/.well-known/private-aggregation/debug/report-shared-storage b/testing/web-platform/tests/.well-known/private-aggregation/debug/report-shared-storage new file mode 100644 index 000000000000..7ffdb70773d4 --- /dev/null +++ b/testing/web-platform/tests/.well-known/private-aggregation/debug/report-shared-storage @@ -0,0 +1,7 @@ +"""Endpoint to receive and return aggregatable reports.""" +from importlib import import_module + +reports = import_module('private-aggregation.resources.reports') + +def main(request, response): + return reports.handle_request(request) diff --git a/testing/web-platform/tests/.well-known/private-aggregation/report-shared-storage b/testing/web-platform/tests/.well-known/private-aggregation/report-shared-storage new file mode 100644 index 000000000000..7ffdb70773d4 --- /dev/null +++ b/testing/web-platform/tests/.well-known/private-aggregation/report-shared-storage @@ -0,0 +1,7 @@ +"""Endpoint to receive and return aggregatable reports.""" +from importlib import import_module + +reports = import_module('private-aggregation.resources.reports') + +def main(request, response): + return reports.handle_request(request) diff --git a/testing/web-platform/tests/private-aggregation/resources/reports.py b/testing/web-platform/tests/private-aggregation/resources/reports.py new file mode 100644 index 000000000000..fc6260c784d5 --- /dev/null +++ b/testing/web-platform/tests/private-aggregation/resources/reports.py @@ -0,0 +1,77 @@ +"""Methods for the report-shared-storage and report-protected-audience endpoints (including debug endpoints)""" +import json +from typing import List, Optional, Tuple, TypedDict +import urllib.parse + +from wptserve.request import Request +from wptserve.stash import Stash +from wptserve.utils import isomorphic_decode, isomorphic_encode + +# Arbitrary key used to access the reports in the stash. +REPORTS_KEY = "9d285691-4386-45ad-9a79-d2ec29557bfe" + +Header = Tuple[str, str] +Status = Tuple[int, str] +Response = Tuple[Status, List[Header], str] + +def get_request_origin(request: Request) -> str: + return "%s://%s" % (request.url_parts.scheme, + request.url_parts.netloc) + +def handle_post_request(request: Request) -> Response: + """Handles POST request for reports. + + Retrieves the report from the request body and stores the report in the + stash. If clear_stash is specified in the query params, clears the stash. + """ + store_report(request.server.stash, get_request_origin(request), + request.body.decode("utf-8")) + return 200, [], "" + + +def handle_get_request(request: Request) -> Response: + """Handles GET request for reports. + + Retrieves and returns all reports from the stash. + """ + headers = [("Content-Type", "application/json")] + reports = take_reports(request.server.stash, get_request_origin(request)) + headers.append(("Access-Control-Allow-Origin", "*")) + return 200, headers, json.dumps(reports) + + +def store_report(stash: Stash, origin: str, report: str) -> None: + """Stores the report in the stash. Report here is a JSON.""" + with stash.lock: + reports_dict = stash.take(REPORTS_KEY) + if not reports_dict: + reports_dict = {} + reports = reports_dict.get(origin, []) + reports.append(report) + reports_dict[origin] = reports + stash.put(REPORTS_KEY, reports_dict) + return None + +def take_reports(stash: Stash, origin: str) -> List[str]: + """Takes all the reports from the stash and returns them.""" + with stash.lock: + reports_dict = stash.take(REPORTS_KEY) + if not reports_dict: + reports_dict = {} + + reports = reports_dict.pop(origin, []) + stash.put(REPORTS_KEY, reports_dict) + return reports + + +def handle_request(request: Request) -> Response: + """Handles request to get or store reports.""" + if request.method == "POST": + return handle_post_request(request) + if request.method == "GET": + return handle_get_request(request) + + return (405, "Method Not Allowed"), [("Content-Type", "application/json")], json.dumps({ + "code": 405, + "message": "Only GET or POST methods are supported." + })