#!/usr/bin/env python3
"""HTTP server for the WebXR DOM-Overlay cross-origin POC.

Serves the POC pages plus the generated Mojo JS bindings (under /gen/) and
the Chromium WebXR Test API polyfill (webxr-test.js), so that a fake AR
device can be driven from JavaScript with --enable-blink-features=MojoJS.

Binds to 127.0.0.1:8765. The POC uses two origins that both resolve here:
  origin A = http://localhost:8765   (top frame + inner victim iframe)
  origin B = http://127.0.0.1:8765   (delegated XR subframe / attacker)
"""
import http.server
import os
import sys

PORT = 8765
HERE = os.path.dirname(os.path.abspath(__file__))
SRC  = os.environ.get('CHROMIUM_SRC', '/chromium/chromium/src')
GEN  = os.path.join(SRC, 'out', 'asan', 'gen')
WPT  = os.path.join(SRC, 'third_party', 'blink', 'web_tests', 'external', 'wpt')

ALIASES = {
    '/webxr-test.js':
        os.path.join(WPT, 'resources', 'chromium', 'webxr-test.js'),
    '/webxr-test-math-helper.js':
        os.path.join(WPT, 'resources', 'chromium', 'webxr-test-math-helper.js'),
}


class Handler(http.server.SimpleHTTPRequestHandler):
    extensions_map = dict(http.server.SimpleHTTPRequestHandler.extensions_map)
    extensions_map['.js'] = 'text/javascript'

    def translate_path(self, path):
        p = path.split('?', 1)[0].split('#', 1)[0]
        if p in ALIASES:
            return ALIASES[p]
        if p.startswith('/gen/'):
            rel = os.path.normpath(p[len('/gen/'):])
            if rel.startswith('..'):
                return '/nonexistent'
            return os.path.join(GEN, rel)
        rel = os.path.normpath(p.lstrip('/'))
        if rel.startswith('..'):
            return '/nonexistent'
        return os.path.join(HERE, rel)

    def guess_type(self, path):
        if path.endswith('.js') or path.endswith('.m.js'):
            return 'text/javascript'
        return super().guess_type(path)

    def do_POST(self):
        if self.path == '/log':
            n = int(self.headers.get('Content-Length', '0') or 0)
            body = self.rfile.read(n).decode('utf-8', 'replace')
            print('[PAGE] ' + body, flush=True)
            self.send_response(204)
            self.end_headers()
            return
        self.send_error(404)

    def log_message(self, fmt, *args):
        pass  # quiet


if __name__ == '__main__':
    for f in ALIASES.values():
        if not os.path.exists(f):
            sys.exit('missing: ' + f)
    if not os.path.isdir(GEN):
        sys.exit('missing gen dir: ' + GEN)
    httpd = http.server.ThreadingHTTPServer(('127.0.0.1', PORT), Handler)
    print(f'serving on http://127.0.0.1:{PORT}/ (and http://localhost:{PORT}/)',
          flush=True)
    httpd.serve_forever()
