#!/usr/bin/env python3
"""HTTP server for the cross-origin TouchEvent intervention-report POC.

Serves attacker.html and victim.html on a single port. Chrome is launched with
--host-resolver-rules so that a.example.com and b.example.com both resolve to
127.0.0.1; the two hosts are same-site / cross-origin and therefore share a
renderer process under default Site Isolation.
"""
import http.server
import json
import os
import socketserver
import sys

PORT = 8080
ROOT = os.path.dirname(os.path.abspath(__file__))


class Handler(http.server.BaseHTTPRequestHandler):
    def _serve(self, path, extra_headers=None):
        try:
            with open(os.path.join(ROOT, path), 'rb') as f:
                body = f.read()
        except FileNotFoundError:
            self.send_error(404)
            return
        self.send_response(200)
        self.send_header('Content-Type', 'text/html; charset=utf-8')
        self.send_header('Cache-Control', 'no-store')
        for k, v in (extra_headers or {}).items():
            self.send_header(k, v)
        self.send_header('Content-Length', str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def do_GET(self):
        if self.path.startswith('/attacker.html'):
            self._serve('attacker.html')
        elif self.path.startswith('/victim.html'):
            # Victim configures a Reporting-API endpoint named "default".
            self._serve('victim.html', {
                'Reporting-Endpoints': 'default="http://b.example.com:8080/reports"',
            })
        else:
            self.send_error(404)

    def do_POST(self):
        if self.path.startswith('/reports'):
            length = int(self.headers.get('Content-Length', '0'))
            body = self.rfile.read(length)
            host = self.headers.get('Host', '?')
            sys.stderr.write(
                '\n[SERVER] Reporting-API POST received on host %r:\n' % host)
            try:
                sys.stderr.write(
                    json.dumps(json.loads(body), indent=2) + '\n')
            except Exception:
                sys.stderr.write(repr(body) + '\n')
            sys.stderr.flush()
            self.send_response(200)
            self.end_headers()
        else:
            self.send_error(404)

    def log_message(self, fmt, *args):
        sys.stderr.write('[SERVER] ' + (fmt % args) + '\n')


class ReusableTCPServer(socketserver.TCPServer):
    allow_reuse_address = True


if __name__ == '__main__':
    os.chdir(ROOT)
    with ReusableTCPServer(('0.0.0.0', PORT), Handler) as httpd:
        sys.stderr.write('[SERVER] listening on 0.0.0.0:%d\n' % PORT)
        sys.stderr.flush()
        httpd.serve_forever()
