| """Methods for the report-shared-storage and report-protected-audience endpoints (including debug endpoints)""" |
| import json |
| from typing import List, Optional, Tuple, Union |
| 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" |
| |
| CLEAR_STASH_AS_BYTES = isomorphic_encode("clear_stash") |
| |
| Header = Tuple[str, str] |
| Status = Union[int, 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. |
| """ |
| if request.GET.get(CLEAR_STASH_AS_BYTES): |
| clear_stash(request.server.stash) |
| return 200, [], "Stash successfully cleared." |
| |
| 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 clear_stash(stash: Stash) -> None: |
| "Clears the stash." |
| stash.take(REPORTS_KEY) |
| 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." |
| }) |