|
10 | 10 | unsafe_id_value = b"e5p3n<3k0k0s" |
11 | 11 |
|
12 | 12 | def main(request, response): |
13 | | - origin = request.headers.get(b"Origin") |
14 | | - cors_request_headers = request.headers.get(b"Access-Control-Request-Headers") |
15 | | - |
16 | | - # Allow any CORS origin |
17 | | - if origin is not None: |
18 | | - response.headers.set(b"Access-Control-Allow-Origin", origin) |
19 | | - |
20 | | - # Allow any CORS request headers |
21 | | - if cors_request_headers is not None: |
22 | | - response.headers.set(b"Access-Control-Allow-Headers", cors_request_headers) |
23 | | - |
24 | | - # Expect a `token` in the query string |
25 | | - if b"token" not in request.GET: |
26 | | - headers = [(b"Content-Type", b"text/plain")] |
27 | | - return 400, headers, b"ERROR: `token` query parameter!" |
28 | | - |
29 | | - # Expect a `fixture` in the query string |
30 | | - if b"fixture" not in request.GET: |
31 | | - headers = [(b"Content-Type", b"text/plain")] |
32 | | - return 400, headers, b"ERROR: `fixture` query parameter!" |
33 | | - |
34 | | - # Prepare state |
35 | | - fixture = request.GET.first(b"fixture") |
36 | | - token = request.GET.first(b"token") |
37 | | - last_event_id = request.headers.get(b"Last-Event-ID", b"") |
38 | | - expect_preflight = fixture == b"unsafe" or fixture == b"long" |
39 | | - |
40 | | - # Preflight handling |
41 | | - if request.method == u"OPTIONS": |
42 | | - # The first request (without any `Last-Event-ID` header) should _never_ be a |
43 | | - # preflight request, since it should be considered a "safe" request. |
44 | | - # If we _do_ send a preflight for these requests, error early. |
| 13 | + origin = request.headers.get(b"Origin") |
| 14 | + cors_request_headers = request.headers.get(b"Access-Control-Request-Headers") |
| 15 | + |
| 16 | + # Allow any CORS origin |
| 17 | + if origin is not None: |
| 18 | + response.headers.set(b"Access-Control-Allow-Origin", origin) |
| 19 | + |
| 20 | + # Allow any CORS request headers |
| 21 | + if cors_request_headers is not None: |
| 22 | + response.headers.set(b"Access-Control-Allow-Headers", cors_request_headers) |
| 23 | + |
| 24 | + # Expect a `token` in the query string |
| 25 | + if b"token" not in request.GET: |
| 26 | + headers = [(b"Content-Type", b"text/plain")] |
| 27 | + return 400, headers, b"ERROR: `token` query parameter!" |
| 28 | + |
| 29 | + # Expect a `fixture` in the query string |
| 30 | + if b"fixture" not in request.GET: |
| 31 | + headers = [(b"Content-Type", b"text/plain")] |
| 32 | + return 400, headers, b"ERROR: `fixture` query parameter!" |
| 33 | + |
| 34 | + # Prepare state |
| 35 | + fixture = request.GET.first(b"fixture") |
| 36 | + token = request.GET.first(b"token") |
| 37 | + last_event_id = request.headers.get(b"Last-Event-ID", b"") |
| 38 | + expect_preflight = fixture == b"unsafe" or fixture == b"long" |
| 39 | + |
| 40 | + # Preflight handling |
| 41 | + if request.method == u"OPTIONS": |
| 42 | + # The first request (without any `Last-Event-ID` header) should _never_ be a |
| 43 | + # preflight request, since it should be considered a "safe" request. |
| 44 | + # If we _do_ send a preflight for these requests, error early. |
| 45 | + if last_event_id == b"": |
| 46 | + headers = [(b"Content-Type", b"text/plain")] |
| 47 | + return 400, headers, b"ERROR: No Last-Event-ID header in preflight!" |
| 48 | + |
| 49 | + # We keep track of the different "tokens" we see, in order to tell whether or not |
| 50 | + # a client has done a preflight request. If the "stash" does not contain a token, |
| 51 | + # no preflight request was made. |
| 52 | + request.server.stash.put(token, cors_request_headers) |
| 53 | + |
| 54 | + # We can return with an empty body on preflight requests |
| 55 | + return b"" |
| 56 | + |
| 57 | + # This will be a SSE endpoint |
| 58 | + response.headers.set(b"Content-Type", b"text/event-stream") |
| 59 | + response.headers.set(b"Cache-Control", b"no-store") |
| 60 | + |
| 61 | + # If we do not have a `Last-Event-ID` header, we're on the initial request |
| 62 | + # Respond with the fixture corresponding to the `fixture` query parameter |
45 | 63 | if last_event_id == b"": |
46 | | - headers = [(b"Content-Type", b"text/plain")] |
47 | | - return 400, headers, b"ERROR: No Last-Event-ID header in preflight!" |
48 | | - |
49 | | - # We keep track of the different "tokens" we see, in order to tell whether or not |
50 | | - # a client has done a preflight request. If the "stash" does not contain a token, |
51 | | - # no preflight request was made. |
52 | | - request.server.stash.put(token, cors_request_headers) |
53 | | - |
54 | | - # We can return with an empty body on preflight requests |
55 | | - return b"" |
56 | | - |
57 | | - # This will be a SSE endpoint |
58 | | - response.headers.set(b"Content-Type", b"text/event-stream") |
59 | | - response.headers.set(b"Cache-Control", b"no-store") |
60 | | - |
61 | | - # If we do not have a `Last-Event-ID` header, we're on the initial request |
62 | | - # Respond with the fixture corresponding to the `fixture` query parameter |
63 | | - if last_event_id == b"": |
| 64 | + if fixture == b"safe": |
| 65 | + return b"id: " + safe_id_value + b"\nretry: 200\ndata: safe\n\n" |
| 66 | + if fixture == b"unsafe": |
| 67 | + return b"id: " + unsafe_id_value + b"\nretry: 200\ndata: unsafe\n\n" |
| 68 | + if fixture == b"long": |
| 69 | + return b"id: " + long_string + b"\nretry: 200\ndata: long\n\n" |
| 70 | + return b"event: failure\ndata: unknown fixture\n\n" |
| 71 | + |
| 72 | + # If we have a `Last-Event-ID` header, we're on a reconnect. |
| 73 | + # If fixture is "unsafe", eg requires a preflight, check to see that we got one. |
| 74 | + preflight_headers = request.server.stash.take(token) |
| 75 | + saw_preflight = preflight_headers is not None |
| 76 | + if saw_preflight and not expect_preflight: |
| 77 | + return b"event: failure\ndata: saw preflight, did not expect one\n\n" |
| 78 | + elif not saw_preflight and expect_preflight: |
| 79 | + return b"event: failure\ndata: expected preflight, did not get one\n\n" |
| 80 | + |
| 81 | + if saw_preflight and preflight_headers.lower() != b"last-event-id": |
| 82 | + data = b"preflight `access-control-request-headers` was not `last-event-id`" |
| 83 | + return b"event: failure\ndata: " + data + b"\n\n" |
| 84 | + |
| 85 | + # Expect to have the same ID in the header as the one we sent. |
| 86 | + expected = b"<unknown>" |
64 | 87 | if fixture == b"safe": |
65 | | - return b"id: " + safe_id_value + b"\nretry: 200\ndata: safe\n\n" |
66 | | - if fixture == b"unsafe": |
67 | | - return b"id: " + unsafe_id_value + b"\nretry: 200\ndata: unsafe\n\n" |
68 | | - if fixture == b"long": |
69 | | - return b"id: " + long_string + b"\nretry: 200\ndata: long\n\n" |
70 | | - return b"event: failure\ndata: unknown fixture\n\n" |
71 | | - |
72 | | - # If we have a `Last-Event-ID` header, we're on a reconnect. |
73 | | - # If fixture is "unsafe", eg requires a preflight, check to see that we got one. |
74 | | - preflight_headers = request.server.stash.take(token) |
75 | | - saw_preflight = preflight_headers is not None |
76 | | - if saw_preflight and not expect_preflight: |
77 | | - return b"event: failure\ndata: saw preflight, did not expect one\n\n" |
78 | | - elif not saw_preflight and expect_preflight: |
79 | | - return b"event: failure\ndata: expected preflight, did not get one\n\n" |
80 | | - |
81 | | - if saw_preflight and preflight_headers.lower() != b"last-event-id": |
82 | | - data = b"preflight `access-control-request-headers` was not `last-event-id`" |
83 | | - return b"event: failure\ndata: " + data + b"\n\n" |
84 | | - |
85 | | - # Expect to have the same ID in the header as the one we sent. |
86 | | - expected = b"<unknown>" |
87 | | - if fixture == b"safe": |
88 | | - expected = safe_id_value |
89 | | - elif fixture == b"unsafe": |
90 | | - expected = unsafe_id_value |
91 | | - elif fixture == b"long": |
92 | | - expected = long_string |
93 | | - |
94 | | - event = last_event_id == expected and b"success" or b"failure" |
95 | | - data = b"got " + last_event_id + b", expected " + expected |
96 | | - return b"event: " + event + b"\ndata: " + data + b"\n\n" |
| 88 | + expected = safe_id_value |
| 89 | + elif fixture == b"unsafe": |
| 90 | + expected = unsafe_id_value |
| 91 | + elif fixture == b"long": |
| 92 | + expected = long_string |
| 93 | + |
| 94 | + event = last_event_id == expected and b"success" or b"failure" |
| 95 | + data = b"got " + last_event_id + b", expected " + expected |
| 96 | + return b"event: " + event + b"\ndata: " + data + b"\n\n" |
0 commit comments