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