|
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