tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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))