from __future__ import print_function try: from http.server import HTTPServer, SimpleHTTPRequestHandler except ImportError: from BaseHTTPServer import HTTPServer from SimpleHTTPServer import SimpleHTTPRequestHandler import os import sys try: from urlparse import urlparse from urllib import unquote except ImportError: from urllib.parse import urlparse, unquote import posixpath if sys.version_info.major >= 3: from io import StringIO, BytesIO else: from io import BytesIO, BytesIO as StringIO import re import shutil import threading import time import socket import itertools import Reporter try: import configparser except ImportError: import ConfigParser as configparser ### # Various patterns matched or replaced by server. kReportFileRE = re.compile("(.*/)?report-(.*)\\.html") kBugKeyValueRE = re.compile("") # kReportCrashEntryRE = re.compile("") kReportCrashEntryKeyValueRE = re.compile(' ?([^=]+)="(.*?)"') kReportReplacements = [] # Add custom javascript. kReportReplacements.append( ( re.compile(""), """\ """, ) ) # Insert additional columns. kReportReplacements.append((re.compile(""), "
", file=s)
traceback.print_exc(file=s)
print("", file=s)
self.status = s.getvalue()
class ScanViewServer(HTTPServer):
def __init__(self, address, handler, root, reporters, options):
HTTPServer.__init__(self, address, handler)
self.root = root
self.reporters = reporters
self.options = options
self.halted = False
self.config = None
self.load_config()
def load_config(self):
self.config = configparser.RawConfigParser()
# Add defaults
self.config.add_section("ScanView")
for r in self.reporters:
self.config.add_section(r.getName())
for p in r.getParameters():
if p.saveConfigValue():
self.config.set(r.getName(), p.getName(), "")
# Ignore parse errors
try:
self.config.read([kConfigPath])
except:
pass
# Save on exit
import atexit
atexit.register(lambda: self.save_config())
def save_config(self):
# Ignore errors (only called on exit).
try:
f = open(kConfigPath, "w")
self.config.write(f)
f.close()
except:
pass
def halt(self):
self.halted = True
if self.options.debug:
print("%s: SERVER: halting." % (sys.argv[0],), file=sys.stderr)
def serve_forever(self):
while not self.halted:
if self.options.debug > 1:
print("%s: SERVER: waiting..." % (sys.argv[0],), file=sys.stderr)
try:
self.handle_request()
except OSError as e:
print("OSError", e.errno)
def finish_request(self, request, client_address):
if self.options.autoReload:
import ScanView
self.RequestHandlerClass = reload(ScanView).ScanViewRequestHandler
HTTPServer.finish_request(self, request, client_address)
def handle_error(self, request, client_address):
# Ignore socket errors
info = sys.exc_info()
if info and isinstance(info[1], socket.error):
if self.options.debug > 1:
print(
"%s: SERVER: ignored socket error." % (sys.argv[0],),
file=sys.stderr,
)
return
HTTPServer.handle_error(self, request, client_address)
# Borrowed from Quixote, with simplifications.
def parse_query(qs, fields=None):
if fields is None:
fields = {}
for chunk in (_f for _f in qs.split("&") if _f):
if "=" not in chunk:
name = chunk
value = ""
else:
name, value = chunk.split("=", 1)
name = unquote(name.replace("+", " "))
value = unquote(value.replace("+", " "))
item = fields.get(name)
if item is None:
fields[name] = [value]
else:
item.append(value)
return fields
class ScanViewRequestHandler(SimpleHTTPRequestHandler):
server_version = "ScanViewServer/" + __version__
dynamic_mtime = time.time()
def do_HEAD(self):
try:
SimpleHTTPRequestHandler.do_HEAD(self)
except Exception as e:
self.handle_exception(e)
def do_GET(self):
try:
SimpleHTTPRequestHandler.do_GET(self)
except Exception as e:
self.handle_exception(e)
def do_POST(self):
"""Serve a POST request."""
try:
length = self.headers.getheader("content-length") or "0"
try:
length = int(length)
except:
length = 0
content = self.rfile.read(length)
fields = parse_query(content)
f = self.send_head(fields)
if f:
self.copyfile(f, self.wfile)
f.close()
except Exception as e:
self.handle_exception(e)
def log_message(self, format, *args):
if self.server.options.debug:
sys.stderr.write(
"%s: SERVER: %s - - [%s] %s\n"
% (
sys.argv[0],
self.address_string(),
self.log_date_time_string(),
format % args,
)
)
def load_report(self, report):
path = os.path.join(self.server.root, "report-%s.html" % report)
data = open(path).read()
keys = {}
for item in kBugKeyValueRE.finditer(data):
k, v = item.groups()
keys[k] = v
return keys
def load_crashes(self):
path = posixpath.join(self.server.root, "index.html")
data = open(path).read()
problems = []
for item in kReportCrashEntryRE.finditer(data):
fieldData = item.group(1)
fields = dict(
[i.groups() for i in kReportCrashEntryKeyValueRE.finditer(fieldData)]
)
problems.append(fields)
return problems
def handle_exception(self, exc):
import traceback
s = StringIO()
print("INTERNAL ERROR\n", file=s)
traceback.print_exc(file=s)
f = self.send_string(s.getvalue(), "text/plain")
if f:
self.copyfile(f, self.wfile)
f.close()
def get_scalar_field(self, name):
if name in self.fields:
return self.fields[name][0]
else:
return None
def submit_bug(self, c):
title = self.get_scalar_field("title")
description = self.get_scalar_field("description")
report = self.get_scalar_field("report")
reporterIndex = self.get_scalar_field("reporter")
files = []
for fileID in self.fields.get("files", []):
try:
i = int(fileID)
except:
i = None
if i is None or i < 0 or i >= len(c.files):
return (False, "Invalid file ID")
files.append(c.files[i])
if not title:
return (False, "Missing title.")
if not description:
return (False, "Missing description.")
try:
reporterIndex = int(reporterIndex)
except:
return (False, "Invalid report method.")
# Get the reporter and parameters.
reporter = self.server.reporters[reporterIndex]
parameters = {}
for o in reporter.getParameters():
name = "%s_%s" % (reporter.getName(), o.getName())
if name not in self.fields:
return (
False,
'Missing field "%s" for %s report method.'
% (name, reporter.getName()),
)
parameters[o.getName()] = self.get_scalar_field(name)
# Update config defaults.
if report != "None":
self.server.config.set("ScanView", "reporter", reporterIndex)
for o in reporter.getParameters():
if o.saveConfigValue():
name = o.getName()
self.server.config.set(reporter.getName(), name, parameters[name])
# Create the report.
bug = Reporter.BugReport(title, description, files)
# Kick off a reporting thread.
t = ReporterThread(bug, reporter, parameters, self.server)
t.start()
# Wait for thread to die...
while t.isAlive():
time.sleep(0.25)
submitStatus = t.status
return (t.success, t.status)
def send_report_submit(self):
report = self.get_scalar_field("report")
c = self.get_report_context(report)
if c.reportSource is None:
reportingFor = "Report Crashes > "
fileBug = (
"""\
File Bug > """
% locals()
)
else:
reportingFor = 'Report %s > ' % (c.reportSource, report)
fileBug = 'File Bug > ' % report
title = self.get_scalar_field("title")
description = self.get_scalar_field("description")
res, message = self.submit_bug(c)
if res:
statusClass = "SubmitOk"
statusName = "Succeeded"
else:
statusClass = "SubmitFail"
statusName = "Failed"
result = (
"""