tor-browser

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

python_runner_wsh.py (3006B)


      1 # This Source Code Form is subject to the terms of the Mozilla Public
      2 # License, v. 2.0. If a copy of the MPL was not distributed with this
      3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 
      5 """A pywebsocket3 handler which runs arbitrary Python code and returns the
      6 result.
      7 This is used to test OS specific accessibility APIs which can't be tested in JS.
      8 It is intended to be called from JS browser tests.
      9 """
     10 
     11 import math
     12 import os
     13 import sys
     14 import traceback
     15 
     16 from mod_pywebsocket import msgutil
     17 from mozfile import json
     18 
     19 
     20 def web_socket_do_extra_handshake(request):
     21    pass
     22 
     23 
     24 def web_socket_transfer_data(request):
     25    def send(*args):
     26        """Send a response to the client as a JSON array."""
     27        msgutil.send_message(request, json.dumps(args))
     28 
     29    cleanNamespace = {}
     30    testDir = None
     31    if sys.platform == "win32":
     32        testDir = "windows"
     33    elif sys.platform == "linux":
     34        testDir = "atk"
     35    if testDir:
     36        sys.path.append(
     37            os.path.join(
     38                os.getcwd(), "browser", "accessible", "tests", "browser", testDir
     39            )
     40        )
     41        try:
     42            import a11y_setup
     43 
     44            a11y_setup.setup()
     45            cleanNamespace = a11y_setup.__dict__
     46            setupExc = None
     47        except Exception:
     48            setupExc = traceback.format_exc()
     49        sys.path.pop()
     50 
     51    def info(message):
     52        """Log an info message."""
     53        send("info", str(message))
     54 
     55    cleanNamespace["info"] = info
     56    namespace = cleanNamespace.copy()
     57 
     58    # Keep handling messages until the WebSocket is closed.
     59    while True:
     60        code = msgutil.receive_message(request)
     61        if not code:
     62            return
     63        if code == "__reset__":
     64            namespace = cleanNamespace.copy()
     65            send("return", None)
     66            continue
     67 
     68        if setupExc:
     69            # a11y_setup failed. Report an exception immediately.
     70            send("exception", setupExc)
     71            continue
     72 
     73        # Wrap the code in a function called run(). This allows the code to
     74        # return a result by simply using the return statement.
     75        if "\n" not in code and not code.lstrip().startswith("return "):
     76            # Single line without return. Assume this is an expression. We use
     77            # a lambda to return the result.
     78            code = f"run = lambda: {code}"
     79        else:
     80            lines = ["def run():"]
     81            # Indent each line inside the function.
     82            lines.extend(f"  {line}" for line in code.splitlines())
     83            code = "\n".join(lines)
     84        try:
     85            # Execute this Python code, which will define the run() function.
     86            exec(code, namespace)
     87            # Run the function we just defined.
     88            ret = namespace["run"]()
     89            if isinstance(ret, float) and math.isnan(ret):
     90                # NaN can't be serialized by JSON.
     91                ret = None
     92            send("return", ret)
     93        except Exception:
     94            send("exception", traceback.format_exc())