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 = ( """