1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
import json
from wptserve.utils import isomorphic_decode
def main(request, response):
"""Helper handler for Beacon tests.
It handles two forms of requests:
STORE:
A URL with a query string of the form 'cmd=store&id=<token>'.
Stores the receipt of a sendBeacon() request along with its validation
result, returning HTTP 200 OK.
if "preflightExpected" exists in the query, this handler responds to
CORS preflights.
STAT:
A URL with a query string of the form 'cmd=stat&id=<token>'.
Retrieves the results of test for the given id and returns them as a
JSON array and HTTP 200 OK status code. Due to the eventual read-once
nature of the stash, results for a given test are only guaranteed to be
returned once, though they may be returned multiple times.
An entry may contain following members.
- error: An error string. null if there is no error.
- type: The content-type header of the request "(missing)" if there
is no content-type header in the request.
Example response bodies:
- [{error: null, type: "text/plain;charset=UTF8"}]
- [{error: "some validation details"}]
- []
Common parameters:
cmd - the command, 'store' or 'stat'.
id - the unique identifier of the test.
"""
id = request.GET.first(b"id")
command = request.GET.first(b"cmd").lower()
# Append CORS headers if needed.
if b"origin" in request.GET:
response.headers.set(b"Access-Control-Allow-Origin",
request.GET.first(b"origin"))
if b"credentials" in request.GET:
response.headers.set(b"Access-Control-Allow-Credentials",
request.GET.first(b"credentials"))
# Handle the 'store' and 'stat' commands.
if command == b"store":
error = None
# Only store the actual POST requests, not any preflight/OPTIONS
# requests we may get.
if request.method == u"POST":
payload = b""
contentType = request.headers[b"Content-Type"] \
if b"Content-Type" in request.headers else b"(missing)"
if b"form-data" in contentType:
if b"payload" in request.POST:
# The payload was sent as a FormData.
payload = request.POST.first(b"payload")
else:
# A FormData was sent with an empty payload.
pass
else:
# The payload was sent as either a string, Blob, or BufferSource.
payload = request.body
payload_parts = list(filter(None, payload.split(b":")))
if len(payload_parts) > 0:
payload_size = int(payload_parts[0])
# Confirm the payload size sent matches with the number of
# characters sent.
if payload_size != len(payload):
error = u"expected %d characters but got %d" % (
payload_size, len(payload))
else:
# Confirm the payload contains the correct characters.
for i in range(len(payload)):
if i <= len(payload_parts[0]):
continue
c = payload[i:i+1]
if c != b"*":
error = u"expected '*' at index %d but got '%s''" % (
i, isomorphic_decode(c))
break
# Store the result in the stash so that it can be retrieved
# later with a 'stat' command.
request.server.stash.put(id, {
u"error": error,
u"type": isomorphic_decode(contentType)
})
elif request.method == u"OPTIONS":
# If we expect a preflight, then add the cors headers we expect,
# otherwise log an error as we shouldn't send a preflight for all
# requests.
if b"preflightExpected" in request.GET:
response.headers.set(b"Access-Control-Allow-Headers",
b"content-type")
response.headers.set(b"Access-Control-Allow-Methods", b"POST")
else:
error = u"Preflight not expected."
request.server.stash.put(id, {u"error": error})
elif command == b"stat":
test_data = request.server.stash.take(id)
results = [test_data] if test_data else []
response.headers.set(b"Content-Type", b"text/plain")
response.content = json.dumps(results)
else:
response.status = 400 # BadRequest
|