Source code

Revision control

Copy as Markdown

Other Tools

"""
Server handler for Payment Method Identifier (PMI) endpoints.
Logs incoming request metadata into request.server.stash under `id`.
Supports declarative query parameters:
- `id`: Unique test run token (generated by token() in JS test).
- `redirect_status`: HTTP redirect status code (default 302).
- `num_redirects`: Integer count for multi-hop redirect chains.
- `redirect_location`: Target URL for redirect.
- `status`: HTTP response status code (default 200).
- `link`: Custom Link header value. If omitted, defaults to `<{default_manifest}>; rel="payment-method-manifest"`.
Pass `link=none` to omit the Link header entirely.
Multiple `link` query parameters can be passed to emit multiple Link header lines.
"""
import os
import sys
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
resources_dir = os.path.dirname(__file__)
if resources_dir not in sys.path:
sys.path.insert(0, resources_dir)
from server_constants import STASH_PATH
def main(request, response):
test_id = request.GET.get(b"id")
if not test_id:
response.status = 400
response.headers.set(b"Content-Type", b"text/plain")
response.content = b"Missing required 'id' query parameter"
return
# Record incoming HTTP request metadata into server stash for test verification
stash = request.server.stash
with stash.lock:
logs = stash.take(test_id, path=STASH_PATH) or []
header_dict = {
k.decode("utf-8").lower(): b", ".join(v).decode("utf-8")
for k, v in request.headers.items()
}
logs.append({
"endpoint": "payment-method-identifier",
"step": "payment-method-identifier",
"method": request.method,
"url": request.url,
"headers": header_dict,
})
stash.put(test_id, logs, path=STASH_PATH)
redirect_status = int(request.GET.get(b"redirect_status", b"302"))
# Handle multi-hop redirects
num_redirects_str = request.GET.get(b"num_redirects")
if num_redirects_str is not None:
num_redirects = int(num_redirects_str)
if num_redirects > 0:
parsed = urlparse(request.url)
params = parse_qs(parsed.query)
params["num_redirects"] = [str(num_redirects - 1)]
next_query = urlencode(params, doseq=True)
next_url = urlunparse((
parsed.scheme,
parsed.netloc,
parsed.path,
parsed.params,
next_query,
parsed.fragment,
))
response.status = redirect_status
response.headers.set(b"Location", next_url.encode("utf-8"))
response.content = b"Redirecting..."
return
# Handle explicit redirect_location
redirect_location = request.GET.get(b"redirect_location")
if redirect_location:
response.status = redirect_status
response.headers.set(b"Location", redirect_location)
response.content = b"Redirecting..."
return
# Normal response
status = int(request.GET.get(b"status", b"200"))
response.status = status
response.headers.set(b"Content-Type", b"text/html")
link_params = request.GET.get_list(b"link")
if not link_params:
test_id_str = test_id.decode("utf-8")
default_manifest = f"/payment-method-manifest/resources/payment-method-manifest.py?id={test_id_str}"
response.headers.set(
b"Link",
f'<{default_manifest}>; rel="payment-method-manifest"'.encode(
"utf-8"
),
)
else:
for link in link_params:
if link != b"none":
response.headers.append(b"Link", link)
response.content = b"<!DOCTYPE html><html><body>PMI Endpoint</body></html>"