target.py (3654B)
1 # This endpoint responds to requests for a target of a (possible) LNA request. 2 # 3 # Its behavior can be configured with various search/GET parameters, all of 4 # which are optional: 5 # 6 # - final-headers: Valid values are: 7 # - cors: this endpoint responds with valid CORS headers to CORS-enabled 8 # non-preflight requests. These should be sufficient for non-preflighted 9 # CORS-enabled requests to succeed. 10 # - sw: this endpoint responds with a valid Service-Worker header to allow 11 # for the request to serve as a Service worker script resource. This is 12 # only valid in conjunction with the cors value above. 13 # - unspecified: this endpoint responds with no CORS headers to non-preflight 14 # requests. This should fail CORS-enabled requests, but be sufficient for 15 # no-CORS requests. 16 # 17 # The following parameters only affect non-preflight responses: 18 # 19 # - redirect: If set, the response code is set to 301 and the `Location` 20 # response header is set to this value. 21 # - mime-type: If set, the `Content-Type` response header is set to this value. 22 # - file: Specifies a path (relative to this file's directory) to a file. If 23 # set, the response body is copied from this file. 24 # - random-js-prefix: If set to any value, the response body is prefixed with 25 # a Javascript comment line containing a random value. This is useful in 26 # service worker tests, since service workers are only updated if the new 27 # script is not byte-for-byte identical with the old script. 28 # - body: If set and `file` is not, the response body is set to this value. 29 # 30 31 import os 32 import random 33 34 from wptserve.utils import isomorphic_encode 35 36 _ACAO = ("Access-Control-Allow-Origin", "*") 37 _ACAH = ("Access-Control-Allow-Headers", "Service-Worker") 38 39 def _get_response_headers(method, mode, origin): 40 acam = ("Access-Control-Allow-Methods", method) 41 42 if mode == b"cors": 43 return [acam, _ACAO] 44 45 if mode == b"cors+sw": 46 return [acam, _ACAO, _ACAH] 47 48 if mode == b"navigation": 49 return [ 50 acam, 51 ("Access-Control-Allow-Origin", origin), 52 ("Access-Control-Allow-Credentials", "true"), 53 ] 54 55 return [] 56 57 58 def _is_loaded_in_fenced_frame(request): 59 return request.GET.get(b"is-loaded-in-fenced-frame") 60 61 def _final_response_body(request): 62 file_name = None 63 if file_name is None: 64 file_name = request.GET.get(b"file") 65 if file_name is None: 66 return request.GET.get(b"body") or "success" 67 68 prefix = b"" 69 if request.GET.get(b"random-js-prefix"): 70 value = random.randint(0, 1000000000) 71 prefix = isomorphic_encode("// Random value: {}\n\n".format(value)) 72 73 path = os.path.join(os.path.dirname(isomorphic_encode(__file__)), file_name) 74 with open(path, 'rb') as f: 75 contents = f.read() 76 77 return prefix + contents 78 79 def _handle_final_request(request, response): 80 mode = request.GET.get(b"final-headers") 81 origin = request.headers.get("Origin") 82 headers = _get_response_headers(request.method, mode, origin) 83 84 redirect = request.GET.get(b"redirect") 85 if redirect is not None: 86 headers.append(("Location", redirect)) 87 return (301, headers, b"") 88 89 mime_type = request.GET.get(b"mime-type") 90 if mime_type is not None: 91 headers.append(("Content-Type", mime_type),) 92 93 if _is_loaded_in_fenced_frame(request): 94 headers.append(("Supports-Loading-Mode", "fenced-frame")) 95 96 body = _final_response_body(request) 97 return (headers, body) 98 99 100 def main(request, response): 101 try: 102 return _handle_final_request(request, response) 103 except BaseException as e: 104 # Surface exceptions to the client, where they show up as assertion errors. 105 return (500, [("X-exception", str(e))], "exception: {}".format(e))