Source code

Revision control

Other Tools

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# This module contains code for running an HTTP server to view build info.
import http.server
import json
import os
import requests
class HTTPHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
s = self.server.wrapper
p = self.path
if p == "/build_resources.json":
self.send_response(200)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.end_headers()
keys = sorted(s.json_files.keys())
s = json.dumps({"files": ["resources/%s" % k for k in keys]})
self.wfile.write(s.encode("utf-8"))
return
if p.startswith("/resources/"):
key = p[len("/resources/") :]
if key not in s.json_files:
self.send_error(404)
return
self.send_response(200)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.end_headers()
self.wfile.write(s.json_files[key])
return
if p == "/":
p = "/build_resources.html"
self.serve_docroot(s.doc_root, p[1:])
def do_POST(self):
if self.path == "/shutdown":
self.server.wrapper.do_shutdown = True
self.send_response(200)
return
self.send_error(404)
def serve_docroot(self, root, path):
local_path = os.path.normpath(os.path.join(root, path))
# Cheap security. This doesn't resolve symlinks, etc. But, it should be
# acceptable since this server only runs locally.
if not local_path.startswith(root):
self.send_error(404)
if not os.path.exists(local_path):
self.send_error(404)
return
if os.path.isdir(local_path):
self.send_error(500)
return
self.send_response(200)
ct = "text/plain"
if path.endswith(".html"):
ct = "text/html"
self.send_header("Content-Type", ct)
self.end_headers()
with open(local_path, "rb") as fh:
self.wfile.write(fh.read())
class BuildViewerServer(object):
def __init__(self, address="localhost", port=0):
# TODO use pkg_resources to obtain HTML resources.
pkg_dir = os.path.dirname(os.path.abspath(__file__))
doc_root = os.path.join(pkg_dir, "resources", "html-build-viewer")
assert os.path.isdir(doc_root)
self.doc_root = doc_root
self.json_files = {}
self.server = http.server.HTTPServer((address, port), HTTPHandler)
self.server.wrapper = self
self.do_shutdown = False
@property
def url(self):
hostname, port = self.server.server_address
return "http://%s:%d/" % (hostname, port)
def add_resource_json_file(self, key, path):
"""Register a resource JSON file with the server.
The file will be made available under the name/key specified."""
with open(path, "rb") as fh:
self.json_files[key] = fh.read()
def add_resource_json_url(self, key, url):
"""Register a resource JSON file at a URL."""
r = requests.get(url)
if r.status_code != 200:
raise Exception("Non-200 HTTP response code")
self.json_files[key] = r.text
def run(self):
while not self.do_shutdown:
self.server.handle_request()