1*f4a2713aSLionel Sambucimport BaseHTTPServer 2*f4a2713aSLionel Sambucimport SimpleHTTPServer 3*f4a2713aSLionel Sambucimport os 4*f4a2713aSLionel Sambucimport sys 5*f4a2713aSLionel Sambucimport urllib, urlparse 6*f4a2713aSLionel Sambucimport posixpath 7*f4a2713aSLionel Sambucimport StringIO 8*f4a2713aSLionel Sambucimport re 9*f4a2713aSLionel Sambucimport shutil 10*f4a2713aSLionel Sambucimport threading 11*f4a2713aSLionel Sambucimport time 12*f4a2713aSLionel Sambucimport socket 13*f4a2713aSLionel Sambucimport itertools 14*f4a2713aSLionel Sambuc 15*f4a2713aSLionel Sambucimport Reporter 16*f4a2713aSLionel Sambucimport ConfigParser 17*f4a2713aSLionel Sambuc 18*f4a2713aSLionel Sambuc### 19*f4a2713aSLionel Sambuc# Various patterns matched or replaced by server. 20*f4a2713aSLionel Sambuc 21*f4a2713aSLionel SambuckReportFileRE = re.compile('(.*/)?report-(.*)\\.html') 22*f4a2713aSLionel Sambuc 23*f4a2713aSLionel SambuckBugKeyValueRE = re.compile('<!-- BUG([^ ]*) (.*) -->') 24*f4a2713aSLionel Sambuc 25*f4a2713aSLionel Sambuc# <!-- REPORTPROBLEM file="crashes/clang_crash_ndSGF9.mi" stderr="crashes/clang_crash_ndSGF9.mi.stderr.txt" info="crashes/clang_crash_ndSGF9.mi.info" --> 26*f4a2713aSLionel Sambuc 27*f4a2713aSLionel SambuckReportCrashEntryRE = re.compile('<!-- REPORTPROBLEM (.*?)-->') 28*f4a2713aSLionel SambuckReportCrashEntryKeyValueRE = re.compile(' ?([^=]+)="(.*?)"') 29*f4a2713aSLionel Sambuc 30*f4a2713aSLionel SambuckReportReplacements = [] 31*f4a2713aSLionel Sambuc 32*f4a2713aSLionel Sambuc# Add custom javascript. 33*f4a2713aSLionel SambuckReportReplacements.append((re.compile('<!-- SUMMARYENDHEAD -->'), """\ 34*f4a2713aSLionel Sambuc<script language="javascript" type="text/javascript"> 35*f4a2713aSLionel Sambucfunction load(url) { 36*f4a2713aSLionel Sambuc if (window.XMLHttpRequest) { 37*f4a2713aSLionel Sambuc req = new XMLHttpRequest(); 38*f4a2713aSLionel Sambuc } else if (window.ActiveXObject) { 39*f4a2713aSLionel Sambuc req = new ActiveXObject("Microsoft.XMLHTTP"); 40*f4a2713aSLionel Sambuc } 41*f4a2713aSLionel Sambuc if (req != undefined) { 42*f4a2713aSLionel Sambuc req.open("GET", url, true); 43*f4a2713aSLionel Sambuc req.send(""); 44*f4a2713aSLionel Sambuc } 45*f4a2713aSLionel Sambuc} 46*f4a2713aSLionel Sambuc</script>""")) 47*f4a2713aSLionel Sambuc 48*f4a2713aSLionel Sambuc# Insert additional columns. 49*f4a2713aSLionel SambuckReportReplacements.append((re.compile('<!-- REPORTBUGCOL -->'), 50*f4a2713aSLionel Sambuc '<td></td><td></td>')) 51*f4a2713aSLionel Sambuc 52*f4a2713aSLionel Sambuc# Insert report bug and open file links. 53*f4a2713aSLionel SambuckReportReplacements.append((re.compile('<!-- REPORTBUG id="report-(.*)\\.html" -->'), 54*f4a2713aSLionel Sambuc ('<td class="Button"><a href="report/\\1">Report Bug</a></td>' + 55*f4a2713aSLionel Sambuc '<td class="Button"><a href="javascript:load(\'open/\\1\')">Open File</a></td>'))) 56*f4a2713aSLionel Sambuc 57*f4a2713aSLionel SambuckReportReplacements.append((re.compile('<!-- REPORTHEADER -->'), 58*f4a2713aSLionel Sambuc '<h3><a href="/">Summary</a> > Report %(report)s</h3>')) 59*f4a2713aSLionel Sambuc 60*f4a2713aSLionel SambuckReportReplacements.append((re.compile('<!-- REPORTSUMMARYEXTRA -->'), 61*f4a2713aSLionel Sambuc '<td class="Button"><a href="report/%(report)s">Report Bug</a></td>')) 62*f4a2713aSLionel Sambuc 63*f4a2713aSLionel Sambuc# Insert report crashes link. 64*f4a2713aSLionel Sambuc 65*f4a2713aSLionel Sambuc# Disabled for the time being until we decide exactly when this should 66*f4a2713aSLionel Sambuc# be enabled. Also the radar reporter needs to be fixed to report 67*f4a2713aSLionel Sambuc# multiple files. 68*f4a2713aSLionel Sambuc 69*f4a2713aSLionel Sambuc#kReportReplacements.append((re.compile('<!-- REPORTCRASHES -->'), 70*f4a2713aSLionel Sambuc# '<br>These files will automatically be attached to ' + 71*f4a2713aSLionel Sambuc# 'reports filed here: <a href="report_crashes">Report Crashes</a>.')) 72*f4a2713aSLionel Sambuc 73*f4a2713aSLionel Sambuc### 74*f4a2713aSLionel Sambuc# Other simple parameters 75*f4a2713aSLionel Sambuc 76*f4a2713aSLionel SambuckResources = posixpath.join(posixpath.dirname(__file__), 'Resources') 77*f4a2713aSLionel SambuckConfigPath = os.path.expanduser('~/.scanview.cfg') 78*f4a2713aSLionel Sambuc 79*f4a2713aSLionel Sambuc### 80*f4a2713aSLionel Sambuc 81*f4a2713aSLionel Sambuc__version__ = "0.1" 82*f4a2713aSLionel Sambuc 83*f4a2713aSLionel Sambuc__all__ = ["create_server"] 84*f4a2713aSLionel Sambuc 85*f4a2713aSLionel Sambucclass ReporterThread(threading.Thread): 86*f4a2713aSLionel Sambuc def __init__(self, report, reporter, parameters, server): 87*f4a2713aSLionel Sambuc threading.Thread.__init__(self) 88*f4a2713aSLionel Sambuc self.report = report 89*f4a2713aSLionel Sambuc self.server = server 90*f4a2713aSLionel Sambuc self.reporter = reporter 91*f4a2713aSLionel Sambuc self.parameters = parameters 92*f4a2713aSLionel Sambuc self.success = False 93*f4a2713aSLionel Sambuc self.status = None 94*f4a2713aSLionel Sambuc 95*f4a2713aSLionel Sambuc def run(self): 96*f4a2713aSLionel Sambuc result = None 97*f4a2713aSLionel Sambuc try: 98*f4a2713aSLionel Sambuc if self.server.options.debug: 99*f4a2713aSLionel Sambuc print >>sys.stderr, "%s: SERVER: submitting bug."%(sys.argv[0],) 100*f4a2713aSLionel Sambuc self.status = self.reporter.fileReport(self.report, self.parameters) 101*f4a2713aSLionel Sambuc self.success = True 102*f4a2713aSLionel Sambuc time.sleep(3) 103*f4a2713aSLionel Sambuc if self.server.options.debug: 104*f4a2713aSLionel Sambuc print >>sys.stderr, "%s: SERVER: submission complete."%(sys.argv[0],) 105*f4a2713aSLionel Sambuc except Reporter.ReportFailure,e: 106*f4a2713aSLionel Sambuc self.status = e.value 107*f4a2713aSLionel Sambuc except Exception,e: 108*f4a2713aSLionel Sambuc s = StringIO.StringIO() 109*f4a2713aSLionel Sambuc import traceback 110*f4a2713aSLionel Sambuc print >>s,'<b>Unhandled Exception</b><br><pre>' 111*f4a2713aSLionel Sambuc traceback.print_exc(e,file=s) 112*f4a2713aSLionel Sambuc print >>s,'</pre>' 113*f4a2713aSLionel Sambuc self.status = s.getvalue() 114*f4a2713aSLionel Sambuc 115*f4a2713aSLionel Sambucclass ScanViewServer(BaseHTTPServer.HTTPServer): 116*f4a2713aSLionel Sambuc def __init__(self, address, handler, root, reporters, options): 117*f4a2713aSLionel Sambuc BaseHTTPServer.HTTPServer.__init__(self, address, handler) 118*f4a2713aSLionel Sambuc self.root = root 119*f4a2713aSLionel Sambuc self.reporters = reporters 120*f4a2713aSLionel Sambuc self.options = options 121*f4a2713aSLionel Sambuc self.halted = False 122*f4a2713aSLionel Sambuc self.config = None 123*f4a2713aSLionel Sambuc self.load_config() 124*f4a2713aSLionel Sambuc 125*f4a2713aSLionel Sambuc def load_config(self): 126*f4a2713aSLionel Sambuc self.config = ConfigParser.RawConfigParser() 127*f4a2713aSLionel Sambuc 128*f4a2713aSLionel Sambuc # Add defaults 129*f4a2713aSLionel Sambuc self.config.add_section('ScanView') 130*f4a2713aSLionel Sambuc for r in self.reporters: 131*f4a2713aSLionel Sambuc self.config.add_section(r.getName()) 132*f4a2713aSLionel Sambuc for p in r.getParameters(): 133*f4a2713aSLionel Sambuc if p.saveConfigValue(): 134*f4a2713aSLionel Sambuc self.config.set(r.getName(), p.getName(), '') 135*f4a2713aSLionel Sambuc 136*f4a2713aSLionel Sambuc # Ignore parse errors 137*f4a2713aSLionel Sambuc try: 138*f4a2713aSLionel Sambuc self.config.read([kConfigPath]) 139*f4a2713aSLionel Sambuc except: 140*f4a2713aSLionel Sambuc pass 141*f4a2713aSLionel Sambuc 142*f4a2713aSLionel Sambuc # Save on exit 143*f4a2713aSLionel Sambuc import atexit 144*f4a2713aSLionel Sambuc atexit.register(lambda: self.save_config()) 145*f4a2713aSLionel Sambuc 146*f4a2713aSLionel Sambuc def save_config(self): 147*f4a2713aSLionel Sambuc # Ignore errors (only called on exit). 148*f4a2713aSLionel Sambuc try: 149*f4a2713aSLionel Sambuc f = open(kConfigPath,'w') 150*f4a2713aSLionel Sambuc self.config.write(f) 151*f4a2713aSLionel Sambuc f.close() 152*f4a2713aSLionel Sambuc except: 153*f4a2713aSLionel Sambuc pass 154*f4a2713aSLionel Sambuc 155*f4a2713aSLionel Sambuc def halt(self): 156*f4a2713aSLionel Sambuc self.halted = True 157*f4a2713aSLionel Sambuc if self.options.debug: 158*f4a2713aSLionel Sambuc print >>sys.stderr, "%s: SERVER: halting." % (sys.argv[0],) 159*f4a2713aSLionel Sambuc 160*f4a2713aSLionel Sambuc def serve_forever(self): 161*f4a2713aSLionel Sambuc while not self.halted: 162*f4a2713aSLionel Sambuc if self.options.debug > 1: 163*f4a2713aSLionel Sambuc print >>sys.stderr, "%s: SERVER: waiting..." % (sys.argv[0],) 164*f4a2713aSLionel Sambuc try: 165*f4a2713aSLionel Sambuc self.handle_request() 166*f4a2713aSLionel Sambuc except OSError,e: 167*f4a2713aSLionel Sambuc print 'OSError',e.errno 168*f4a2713aSLionel Sambuc 169*f4a2713aSLionel Sambuc def finish_request(self, request, client_address): 170*f4a2713aSLionel Sambuc if self.options.autoReload: 171*f4a2713aSLionel Sambuc import ScanView 172*f4a2713aSLionel Sambuc self.RequestHandlerClass = reload(ScanView).ScanViewRequestHandler 173*f4a2713aSLionel Sambuc BaseHTTPServer.HTTPServer.finish_request(self, request, client_address) 174*f4a2713aSLionel Sambuc 175*f4a2713aSLionel Sambuc def handle_error(self, request, client_address): 176*f4a2713aSLionel Sambuc # Ignore socket errors 177*f4a2713aSLionel Sambuc info = sys.exc_info() 178*f4a2713aSLionel Sambuc if info and isinstance(info[1], socket.error): 179*f4a2713aSLionel Sambuc if self.options.debug > 1: 180*f4a2713aSLionel Sambuc print >>sys.stderr, "%s: SERVER: ignored socket error." % (sys.argv[0],) 181*f4a2713aSLionel Sambuc return 182*f4a2713aSLionel Sambuc BaseHTTPServer.HTTPServer.handle_error(self, request, client_address) 183*f4a2713aSLionel Sambuc 184*f4a2713aSLionel Sambuc# Borrowed from Quixote, with simplifications. 185*f4a2713aSLionel Sambucdef parse_query(qs, fields=None): 186*f4a2713aSLionel Sambuc if fields is None: 187*f4a2713aSLionel Sambuc fields = {} 188*f4a2713aSLionel Sambuc for chunk in filter(None, qs.split('&')): 189*f4a2713aSLionel Sambuc if '=' not in chunk: 190*f4a2713aSLionel Sambuc name = chunk 191*f4a2713aSLionel Sambuc value = '' 192*f4a2713aSLionel Sambuc else: 193*f4a2713aSLionel Sambuc name, value = chunk.split('=', 1) 194*f4a2713aSLionel Sambuc name = urllib.unquote(name.replace('+', ' ')) 195*f4a2713aSLionel Sambuc value = urllib.unquote(value.replace('+', ' ')) 196*f4a2713aSLionel Sambuc item = fields.get(name) 197*f4a2713aSLionel Sambuc if item is None: 198*f4a2713aSLionel Sambuc fields[name] = [value] 199*f4a2713aSLionel Sambuc else: 200*f4a2713aSLionel Sambuc item.append(value) 201*f4a2713aSLionel Sambuc return fields 202*f4a2713aSLionel Sambuc 203*f4a2713aSLionel Sambucclass ScanViewRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 204*f4a2713aSLionel Sambuc server_version = "ScanViewServer/" + __version__ 205*f4a2713aSLionel Sambuc dynamic_mtime = time.time() 206*f4a2713aSLionel Sambuc 207*f4a2713aSLionel Sambuc def do_HEAD(self): 208*f4a2713aSLionel Sambuc try: 209*f4a2713aSLionel Sambuc SimpleHTTPServer.SimpleHTTPRequestHandler.do_HEAD(self) 210*f4a2713aSLionel Sambuc except Exception,e: 211*f4a2713aSLionel Sambuc self.handle_exception(e) 212*f4a2713aSLionel Sambuc 213*f4a2713aSLionel Sambuc def do_GET(self): 214*f4a2713aSLionel Sambuc try: 215*f4a2713aSLionel Sambuc SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) 216*f4a2713aSLionel Sambuc except Exception,e: 217*f4a2713aSLionel Sambuc self.handle_exception(e) 218*f4a2713aSLionel Sambuc 219*f4a2713aSLionel Sambuc def do_POST(self): 220*f4a2713aSLionel Sambuc """Serve a POST request.""" 221*f4a2713aSLionel Sambuc try: 222*f4a2713aSLionel Sambuc length = self.headers.getheader('content-length') or "0" 223*f4a2713aSLionel Sambuc try: 224*f4a2713aSLionel Sambuc length = int(length) 225*f4a2713aSLionel Sambuc except: 226*f4a2713aSLionel Sambuc length = 0 227*f4a2713aSLionel Sambuc content = self.rfile.read(length) 228*f4a2713aSLionel Sambuc fields = parse_query(content) 229*f4a2713aSLionel Sambuc f = self.send_head(fields) 230*f4a2713aSLionel Sambuc if f: 231*f4a2713aSLionel Sambuc self.copyfile(f, self.wfile) 232*f4a2713aSLionel Sambuc f.close() 233*f4a2713aSLionel Sambuc except Exception,e: 234*f4a2713aSLionel Sambuc self.handle_exception(e) 235*f4a2713aSLionel Sambuc 236*f4a2713aSLionel Sambuc def log_message(self, format, *args): 237*f4a2713aSLionel Sambuc if self.server.options.debug: 238*f4a2713aSLionel Sambuc sys.stderr.write("%s: SERVER: %s - - [%s] %s\n" % 239*f4a2713aSLionel Sambuc (sys.argv[0], 240*f4a2713aSLionel Sambuc self.address_string(), 241*f4a2713aSLionel Sambuc self.log_date_time_string(), 242*f4a2713aSLionel Sambuc format%args)) 243*f4a2713aSLionel Sambuc 244*f4a2713aSLionel Sambuc def load_report(self, report): 245*f4a2713aSLionel Sambuc path = os.path.join(self.server.root, 'report-%s.html'%report) 246*f4a2713aSLionel Sambuc data = open(path).read() 247*f4a2713aSLionel Sambuc keys = {} 248*f4a2713aSLionel Sambuc for item in kBugKeyValueRE.finditer(data): 249*f4a2713aSLionel Sambuc k,v = item.groups() 250*f4a2713aSLionel Sambuc keys[k] = v 251*f4a2713aSLionel Sambuc return keys 252*f4a2713aSLionel Sambuc 253*f4a2713aSLionel Sambuc def load_crashes(self): 254*f4a2713aSLionel Sambuc path = posixpath.join(self.server.root, 'index.html') 255*f4a2713aSLionel Sambuc data = open(path).read() 256*f4a2713aSLionel Sambuc problems = [] 257*f4a2713aSLionel Sambuc for item in kReportCrashEntryRE.finditer(data): 258*f4a2713aSLionel Sambuc fieldData = item.group(1) 259*f4a2713aSLionel Sambuc fields = dict([i.groups() for i in 260*f4a2713aSLionel Sambuc kReportCrashEntryKeyValueRE.finditer(fieldData)]) 261*f4a2713aSLionel Sambuc problems.append(fields) 262*f4a2713aSLionel Sambuc return problems 263*f4a2713aSLionel Sambuc 264*f4a2713aSLionel Sambuc def handle_exception(self, exc): 265*f4a2713aSLionel Sambuc import traceback 266*f4a2713aSLionel Sambuc s = StringIO.StringIO() 267*f4a2713aSLionel Sambuc print >>s, "INTERNAL ERROR\n" 268*f4a2713aSLionel Sambuc traceback.print_exc(exc, s) 269*f4a2713aSLionel Sambuc f = self.send_string(s.getvalue(), 'text/plain') 270*f4a2713aSLionel Sambuc if f: 271*f4a2713aSLionel Sambuc self.copyfile(f, self.wfile) 272*f4a2713aSLionel Sambuc f.close() 273*f4a2713aSLionel Sambuc 274*f4a2713aSLionel Sambuc def get_scalar_field(self, name): 275*f4a2713aSLionel Sambuc if name in self.fields: 276*f4a2713aSLionel Sambuc return self.fields[name][0] 277*f4a2713aSLionel Sambuc else: 278*f4a2713aSLionel Sambuc return None 279*f4a2713aSLionel Sambuc 280*f4a2713aSLionel Sambuc def submit_bug(self, c): 281*f4a2713aSLionel Sambuc title = self.get_scalar_field('title') 282*f4a2713aSLionel Sambuc description = self.get_scalar_field('description') 283*f4a2713aSLionel Sambuc report = self.get_scalar_field('report') 284*f4a2713aSLionel Sambuc reporterIndex = self.get_scalar_field('reporter') 285*f4a2713aSLionel Sambuc files = [] 286*f4a2713aSLionel Sambuc for fileID in self.fields.get('files',[]): 287*f4a2713aSLionel Sambuc try: 288*f4a2713aSLionel Sambuc i = int(fileID) 289*f4a2713aSLionel Sambuc except: 290*f4a2713aSLionel Sambuc i = None 291*f4a2713aSLionel Sambuc if i is None or i<0 or i>=len(c.files): 292*f4a2713aSLionel Sambuc return (False, 'Invalid file ID') 293*f4a2713aSLionel Sambuc files.append(c.files[i]) 294*f4a2713aSLionel Sambuc 295*f4a2713aSLionel Sambuc if not title: 296*f4a2713aSLionel Sambuc return (False, "Missing title.") 297*f4a2713aSLionel Sambuc if not description: 298*f4a2713aSLionel Sambuc return (False, "Missing description.") 299*f4a2713aSLionel Sambuc try: 300*f4a2713aSLionel Sambuc reporterIndex = int(reporterIndex) 301*f4a2713aSLionel Sambuc except: 302*f4a2713aSLionel Sambuc return (False, "Invalid report method.") 303*f4a2713aSLionel Sambuc 304*f4a2713aSLionel Sambuc # Get the reporter and parameters. 305*f4a2713aSLionel Sambuc reporter = self.server.reporters[reporterIndex] 306*f4a2713aSLionel Sambuc parameters = {} 307*f4a2713aSLionel Sambuc for o in reporter.getParameters(): 308*f4a2713aSLionel Sambuc name = '%s_%s'%(reporter.getName(),o.getName()) 309*f4a2713aSLionel Sambuc if name not in self.fields: 310*f4a2713aSLionel Sambuc return (False, 311*f4a2713aSLionel Sambuc 'Missing field "%s" for %s report method.'%(name, 312*f4a2713aSLionel Sambuc reporter.getName())) 313*f4a2713aSLionel Sambuc parameters[o.getName()] = self.get_scalar_field(name) 314*f4a2713aSLionel Sambuc 315*f4a2713aSLionel Sambuc # Update config defaults. 316*f4a2713aSLionel Sambuc if report != 'None': 317*f4a2713aSLionel Sambuc self.server.config.set('ScanView', 'reporter', reporterIndex) 318*f4a2713aSLionel Sambuc for o in reporter.getParameters(): 319*f4a2713aSLionel Sambuc if o.saveConfigValue(): 320*f4a2713aSLionel Sambuc name = o.getName() 321*f4a2713aSLionel Sambuc self.server.config.set(reporter.getName(), name, parameters[name]) 322*f4a2713aSLionel Sambuc 323*f4a2713aSLionel Sambuc # Create the report. 324*f4a2713aSLionel Sambuc bug = Reporter.BugReport(title, description, files) 325*f4a2713aSLionel Sambuc 326*f4a2713aSLionel Sambuc # Kick off a reporting thread. 327*f4a2713aSLionel Sambuc t = ReporterThread(bug, reporter, parameters, self.server) 328*f4a2713aSLionel Sambuc t.start() 329*f4a2713aSLionel Sambuc 330*f4a2713aSLionel Sambuc # Wait for thread to die... 331*f4a2713aSLionel Sambuc while t.isAlive(): 332*f4a2713aSLionel Sambuc time.sleep(.25) 333*f4a2713aSLionel Sambuc submitStatus = t.status 334*f4a2713aSLionel Sambuc 335*f4a2713aSLionel Sambuc return (t.success, t.status) 336*f4a2713aSLionel Sambuc 337*f4a2713aSLionel Sambuc def send_report_submit(self): 338*f4a2713aSLionel Sambuc report = self.get_scalar_field('report') 339*f4a2713aSLionel Sambuc c = self.get_report_context(report) 340*f4a2713aSLionel Sambuc if c.reportSource is None: 341*f4a2713aSLionel Sambuc reportingFor = "Report Crashes > " 342*f4a2713aSLionel Sambuc fileBug = """\ 343*f4a2713aSLionel Sambuc<a href="/report_crashes">File Bug</a> > """%locals() 344*f4a2713aSLionel Sambuc else: 345*f4a2713aSLionel Sambuc reportingFor = '<a href="/%s">Report %s</a> > ' % (c.reportSource, 346*f4a2713aSLionel Sambuc report) 347*f4a2713aSLionel Sambuc fileBug = '<a href="/report/%s">File Bug</a> > ' % report 348*f4a2713aSLionel Sambuc title = self.get_scalar_field('title') 349*f4a2713aSLionel Sambuc description = self.get_scalar_field('description') 350*f4a2713aSLionel Sambuc 351*f4a2713aSLionel Sambuc res,message = self.submit_bug(c) 352*f4a2713aSLionel Sambuc 353*f4a2713aSLionel Sambuc if res: 354*f4a2713aSLionel Sambuc statusClass = 'SubmitOk' 355*f4a2713aSLionel Sambuc statusName = 'Succeeded' 356*f4a2713aSLionel Sambuc else: 357*f4a2713aSLionel Sambuc statusClass = 'SubmitFail' 358*f4a2713aSLionel Sambuc statusName = 'Failed' 359*f4a2713aSLionel Sambuc 360*f4a2713aSLionel Sambuc result = """ 361*f4a2713aSLionel Sambuc<head> 362*f4a2713aSLionel Sambuc <title>Bug Submission</title> 363*f4a2713aSLionel Sambuc <link rel="stylesheet" type="text/css" href="/scanview.css" /> 364*f4a2713aSLionel Sambuc</head> 365*f4a2713aSLionel Sambuc<body> 366*f4a2713aSLionel Sambuc<h3> 367*f4a2713aSLionel Sambuc<a href="/">Summary</a> > 368*f4a2713aSLionel Sambuc%(reportingFor)s 369*f4a2713aSLionel Sambuc%(fileBug)s 370*f4a2713aSLionel SambucSubmit</h3> 371*f4a2713aSLionel Sambuc<form name="form" action=""> 372*f4a2713aSLionel Sambuc<table class="form"> 373*f4a2713aSLionel Sambuc<tr><td> 374*f4a2713aSLionel Sambuc<table class="form_group"> 375*f4a2713aSLionel Sambuc<tr> 376*f4a2713aSLionel Sambuc <td class="form_clabel">Title:</td> 377*f4a2713aSLionel Sambuc <td class="form_value"> 378*f4a2713aSLionel Sambuc <input type="text" name="title" size="50" value="%(title)s" disabled> 379*f4a2713aSLionel Sambuc </td> 380*f4a2713aSLionel Sambuc</tr> 381*f4a2713aSLionel Sambuc<tr> 382*f4a2713aSLionel Sambuc <td class="form_label">Description:</td> 383*f4a2713aSLionel Sambuc <td class="form_value"> 384*f4a2713aSLionel Sambuc<textarea rows="10" cols="80" name="description" disabled> 385*f4a2713aSLionel Sambuc%(description)s 386*f4a2713aSLionel Sambuc</textarea> 387*f4a2713aSLionel Sambuc </td> 388*f4a2713aSLionel Sambuc</table> 389*f4a2713aSLionel Sambuc</td></tr> 390*f4a2713aSLionel Sambuc</table> 391*f4a2713aSLionel Sambuc</form> 392*f4a2713aSLionel Sambuc<h1 class="%(statusClass)s">Submission %(statusName)s</h1> 393*f4a2713aSLionel Sambuc%(message)s 394*f4a2713aSLionel Sambuc<p> 395*f4a2713aSLionel Sambuc<hr> 396*f4a2713aSLionel Sambuc<a href="/">Return to Summary</a> 397*f4a2713aSLionel Sambuc</body> 398*f4a2713aSLionel Sambuc</html>"""%locals() 399*f4a2713aSLionel Sambuc return self.send_string(result) 400*f4a2713aSLionel Sambuc 401*f4a2713aSLionel Sambuc def send_open_report(self, report): 402*f4a2713aSLionel Sambuc try: 403*f4a2713aSLionel Sambuc keys = self.load_report(report) 404*f4a2713aSLionel Sambuc except IOError: 405*f4a2713aSLionel Sambuc return self.send_error(400, 'Invalid report.') 406*f4a2713aSLionel Sambuc 407*f4a2713aSLionel Sambuc file = keys.get('FILE') 408*f4a2713aSLionel Sambuc if not file or not posixpath.exists(file): 409*f4a2713aSLionel Sambuc return self.send_error(400, 'File does not exist: "%s"' % file) 410*f4a2713aSLionel Sambuc 411*f4a2713aSLionel Sambuc import startfile 412*f4a2713aSLionel Sambuc if self.server.options.debug: 413*f4a2713aSLionel Sambuc print >>sys.stderr, '%s: SERVER: opening "%s"'%(sys.argv[0], 414*f4a2713aSLionel Sambuc file) 415*f4a2713aSLionel Sambuc 416*f4a2713aSLionel Sambuc status = startfile.open(file) 417*f4a2713aSLionel Sambuc if status: 418*f4a2713aSLionel Sambuc res = 'Opened: "%s"' % file 419*f4a2713aSLionel Sambuc else: 420*f4a2713aSLionel Sambuc res = 'Open failed: "%s"' % file 421*f4a2713aSLionel Sambuc 422*f4a2713aSLionel Sambuc return self.send_string(res, 'text/plain') 423*f4a2713aSLionel Sambuc 424*f4a2713aSLionel Sambuc def get_report_context(self, report): 425*f4a2713aSLionel Sambuc class Context: 426*f4a2713aSLionel Sambuc pass 427*f4a2713aSLionel Sambuc if report is None or report == 'None': 428*f4a2713aSLionel Sambuc data = self.load_crashes() 429*f4a2713aSLionel Sambuc # Don't allow empty reports. 430*f4a2713aSLionel Sambuc if not data: 431*f4a2713aSLionel Sambuc raise ValueError, 'No crashes detected!' 432*f4a2713aSLionel Sambuc c = Context() 433*f4a2713aSLionel Sambuc c.title = 'clang static analyzer failures' 434*f4a2713aSLionel Sambuc 435*f4a2713aSLionel Sambuc stderrSummary = "" 436*f4a2713aSLionel Sambuc for item in data: 437*f4a2713aSLionel Sambuc if 'stderr' in item: 438*f4a2713aSLionel Sambuc path = posixpath.join(self.server.root, item['stderr']) 439*f4a2713aSLionel Sambuc if os.path.exists(path): 440*f4a2713aSLionel Sambuc lns = itertools.islice(open(path), 0, 10) 441*f4a2713aSLionel Sambuc stderrSummary += '%s\n--\n%s' % (item.get('src', 442*f4a2713aSLionel Sambuc '<unknown>'), 443*f4a2713aSLionel Sambuc ''.join(lns)) 444*f4a2713aSLionel Sambuc 445*f4a2713aSLionel Sambuc c.description = """\ 446*f4a2713aSLionel SambucThe clang static analyzer failed on these inputs: 447*f4a2713aSLionel Sambuc%s 448*f4a2713aSLionel Sambuc 449*f4a2713aSLionel SambucSTDERR Summary 450*f4a2713aSLionel Sambuc-------------- 451*f4a2713aSLionel Sambuc%s 452*f4a2713aSLionel Sambuc""" % ('\n'.join([item.get('src','<unknown>') for item in data]), 453*f4a2713aSLionel Sambuc stderrSummary) 454*f4a2713aSLionel Sambuc c.reportSource = None 455*f4a2713aSLionel Sambuc c.navMarkup = "Report Crashes > " 456*f4a2713aSLionel Sambuc c.files = [] 457*f4a2713aSLionel Sambuc for item in data: 458*f4a2713aSLionel Sambuc c.files.append(item.get('src','')) 459*f4a2713aSLionel Sambuc c.files.append(posixpath.join(self.server.root, 460*f4a2713aSLionel Sambuc item.get('file',''))) 461*f4a2713aSLionel Sambuc c.files.append(posixpath.join(self.server.root, 462*f4a2713aSLionel Sambuc item.get('clangfile',''))) 463*f4a2713aSLionel Sambuc c.files.append(posixpath.join(self.server.root, 464*f4a2713aSLionel Sambuc item.get('stderr',''))) 465*f4a2713aSLionel Sambuc c.files.append(posixpath.join(self.server.root, 466*f4a2713aSLionel Sambuc item.get('info',''))) 467*f4a2713aSLionel Sambuc # Just in case something failed, ignore files which don't 468*f4a2713aSLionel Sambuc # exist. 469*f4a2713aSLionel Sambuc c.files = [f for f in c.files 470*f4a2713aSLionel Sambuc if os.path.exists(f) and os.path.isfile(f)] 471*f4a2713aSLionel Sambuc else: 472*f4a2713aSLionel Sambuc # Check that this is a valid report. 473*f4a2713aSLionel Sambuc path = posixpath.join(self.server.root, 'report-%s.html' % report) 474*f4a2713aSLionel Sambuc if not posixpath.exists(path): 475*f4a2713aSLionel Sambuc raise ValueError, 'Invalid report ID' 476*f4a2713aSLionel Sambuc keys = self.load_report(report) 477*f4a2713aSLionel Sambuc c = Context() 478*f4a2713aSLionel Sambuc c.title = keys.get('DESC','clang error (unrecognized') 479*f4a2713aSLionel Sambuc c.description = """\ 480*f4a2713aSLionel SambucBug reported by the clang static analyzer. 481*f4a2713aSLionel Sambuc 482*f4a2713aSLionel SambucDescription: %s 483*f4a2713aSLionel SambucFile: %s 484*f4a2713aSLionel SambucLine: %s 485*f4a2713aSLionel Sambuc"""%(c.title, keys.get('FILE','<unknown>'), keys.get('LINE', '<unknown>')) 486*f4a2713aSLionel Sambuc c.reportSource = 'report-%s.html' % report 487*f4a2713aSLionel Sambuc c.navMarkup = """<a href="/%s">Report %s</a> > """ % (c.reportSource, 488*f4a2713aSLionel Sambuc report) 489*f4a2713aSLionel Sambuc 490*f4a2713aSLionel Sambuc c.files = [path] 491*f4a2713aSLionel Sambuc return c 492*f4a2713aSLionel Sambuc 493*f4a2713aSLionel Sambuc def send_report(self, report, configOverrides=None): 494*f4a2713aSLionel Sambuc def getConfigOption(section, field): 495*f4a2713aSLionel Sambuc if (configOverrides is not None and 496*f4a2713aSLionel Sambuc section in configOverrides and 497*f4a2713aSLionel Sambuc field in configOverrides[section]): 498*f4a2713aSLionel Sambuc return configOverrides[section][field] 499*f4a2713aSLionel Sambuc return self.server.config.get(section, field) 500*f4a2713aSLionel Sambuc 501*f4a2713aSLionel Sambuc # report is None is used for crashes 502*f4a2713aSLionel Sambuc try: 503*f4a2713aSLionel Sambuc c = self.get_report_context(report) 504*f4a2713aSLionel Sambuc except ValueError, e: 505*f4a2713aSLionel Sambuc return self.send_error(400, e.message) 506*f4a2713aSLionel Sambuc 507*f4a2713aSLionel Sambuc title = c.title 508*f4a2713aSLionel Sambuc description= c.description 509*f4a2713aSLionel Sambuc reportingFor = c.navMarkup 510*f4a2713aSLionel Sambuc if c.reportSource is None: 511*f4a2713aSLionel Sambuc extraIFrame = "" 512*f4a2713aSLionel Sambuc else: 513*f4a2713aSLionel Sambuc extraIFrame = """\ 514*f4a2713aSLionel Sambuc<iframe src="/%s" width="100%%" height="40%%" 515*f4a2713aSLionel Sambuc scrolling="auto" frameborder="1"> 516*f4a2713aSLionel Sambuc <a href="/%s">View Bug Report</a> 517*f4a2713aSLionel Sambuc</iframe>""" % (c.reportSource, c.reportSource) 518*f4a2713aSLionel Sambuc 519*f4a2713aSLionel Sambuc reporterSelections = [] 520*f4a2713aSLionel Sambuc reporterOptions = [] 521*f4a2713aSLionel Sambuc 522*f4a2713aSLionel Sambuc try: 523*f4a2713aSLionel Sambuc active = int(getConfigOption('ScanView','reporter')) 524*f4a2713aSLionel Sambuc except: 525*f4a2713aSLionel Sambuc active = 0 526*f4a2713aSLionel Sambuc for i,r in enumerate(self.server.reporters): 527*f4a2713aSLionel Sambuc selected = (i == active) 528*f4a2713aSLionel Sambuc if selected: 529*f4a2713aSLionel Sambuc selectedStr = ' selected' 530*f4a2713aSLionel Sambuc else: 531*f4a2713aSLionel Sambuc selectedStr = '' 532*f4a2713aSLionel Sambuc reporterSelections.append('<option value="%d"%s>%s</option>'%(i,selectedStr,r.getName())) 533*f4a2713aSLionel Sambuc options = '\n'.join([ o.getHTML(r,title,getConfigOption) for o in r.getParameters()]) 534*f4a2713aSLionel Sambuc display = ('none','')[selected] 535*f4a2713aSLionel Sambuc reporterOptions.append("""\ 536*f4a2713aSLionel Sambuc<tr id="%sReporterOptions" style="display:%s"> 537*f4a2713aSLionel Sambuc <td class="form_label">%s Options</td> 538*f4a2713aSLionel Sambuc <td class="form_value"> 539*f4a2713aSLionel Sambuc <table class="form_inner_group"> 540*f4a2713aSLionel Sambuc%s 541*f4a2713aSLionel Sambuc </table> 542*f4a2713aSLionel Sambuc </td> 543*f4a2713aSLionel Sambuc</tr> 544*f4a2713aSLionel Sambuc"""%(r.getName(),display,r.getName(),options)) 545*f4a2713aSLionel Sambuc reporterSelections = '\n'.join(reporterSelections) 546*f4a2713aSLionel Sambuc reporterOptionsDivs = '\n'.join(reporterOptions) 547*f4a2713aSLionel Sambuc reportersArray = '[%s]'%(','.join([`r.getName()` for r in self.server.reporters])) 548*f4a2713aSLionel Sambuc 549*f4a2713aSLionel Sambuc if c.files: 550*f4a2713aSLionel Sambuc fieldSize = min(5, len(c.files)) 551*f4a2713aSLionel Sambuc attachFileOptions = '\n'.join(["""\ 552*f4a2713aSLionel Sambuc<option value="%d" selected>%s</option>""" % (i,v) for i,v in enumerate(c.files)]) 553*f4a2713aSLionel Sambuc attachFileRow = """\ 554*f4a2713aSLionel Sambuc<tr> 555*f4a2713aSLionel Sambuc <td class="form_label">Attach:</td> 556*f4a2713aSLionel Sambuc <td class="form_value"> 557*f4a2713aSLionel Sambuc<select style="width:100%%" name="files" multiple size=%d> 558*f4a2713aSLionel Sambuc%s 559*f4a2713aSLionel Sambuc</select> 560*f4a2713aSLionel Sambuc </td> 561*f4a2713aSLionel Sambuc</tr> 562*f4a2713aSLionel Sambuc""" % (min(5, len(c.files)), attachFileOptions) 563*f4a2713aSLionel Sambuc else: 564*f4a2713aSLionel Sambuc attachFileRow = "" 565*f4a2713aSLionel Sambuc 566*f4a2713aSLionel Sambuc result = """<html> 567*f4a2713aSLionel Sambuc<head> 568*f4a2713aSLionel Sambuc <title>File Bug</title> 569*f4a2713aSLionel Sambuc <link rel="stylesheet" type="text/css" href="/scanview.css" /> 570*f4a2713aSLionel Sambuc</head> 571*f4a2713aSLionel Sambuc<script language="javascript" type="text/javascript"> 572*f4a2713aSLionel Sambucvar reporters = %(reportersArray)s; 573*f4a2713aSLionel Sambucfunction updateReporterOptions() { 574*f4a2713aSLionel Sambuc index = document.getElementById('reporter').selectedIndex; 575*f4a2713aSLionel Sambuc for (var i=0; i < reporters.length; ++i) { 576*f4a2713aSLionel Sambuc o = document.getElementById(reporters[i] + "ReporterOptions"); 577*f4a2713aSLionel Sambuc if (i == index) { 578*f4a2713aSLionel Sambuc o.style.display = ""; 579*f4a2713aSLionel Sambuc } else { 580*f4a2713aSLionel Sambuc o.style.display = "none"; 581*f4a2713aSLionel Sambuc } 582*f4a2713aSLionel Sambuc } 583*f4a2713aSLionel Sambuc} 584*f4a2713aSLionel Sambuc</script> 585*f4a2713aSLionel Sambuc<body onLoad="updateReporterOptions()"> 586*f4a2713aSLionel Sambuc<h3> 587*f4a2713aSLionel Sambuc<a href="/">Summary</a> > 588*f4a2713aSLionel Sambuc%(reportingFor)s 589*f4a2713aSLionel SambucFile Bug</h3> 590*f4a2713aSLionel Sambuc<form name="form" action="/report_submit" method="post"> 591*f4a2713aSLionel Sambuc<input type="hidden" name="report" value="%(report)s"> 592*f4a2713aSLionel Sambuc 593*f4a2713aSLionel Sambuc<table class="form"> 594*f4a2713aSLionel Sambuc<tr><td> 595*f4a2713aSLionel Sambuc<table class="form_group"> 596*f4a2713aSLionel Sambuc<tr> 597*f4a2713aSLionel Sambuc <td class="form_clabel">Title:</td> 598*f4a2713aSLionel Sambuc <td class="form_value"> 599*f4a2713aSLionel Sambuc <input type="text" name="title" size="50" value="%(title)s"> 600*f4a2713aSLionel Sambuc </td> 601*f4a2713aSLionel Sambuc</tr> 602*f4a2713aSLionel Sambuc<tr> 603*f4a2713aSLionel Sambuc <td class="form_label">Description:</td> 604*f4a2713aSLionel Sambuc <td class="form_value"> 605*f4a2713aSLionel Sambuc<textarea rows="10" cols="80" name="description"> 606*f4a2713aSLionel Sambuc%(description)s 607*f4a2713aSLionel Sambuc</textarea> 608*f4a2713aSLionel Sambuc </td> 609*f4a2713aSLionel Sambuc</tr> 610*f4a2713aSLionel Sambuc 611*f4a2713aSLionel Sambuc%(attachFileRow)s 612*f4a2713aSLionel Sambuc 613*f4a2713aSLionel Sambuc</table> 614*f4a2713aSLionel Sambuc<br> 615*f4a2713aSLionel Sambuc<table class="form_group"> 616*f4a2713aSLionel Sambuc<tr> 617*f4a2713aSLionel Sambuc <td class="form_clabel">Method:</td> 618*f4a2713aSLionel Sambuc <td class="form_value"> 619*f4a2713aSLionel Sambuc <select id="reporter" name="reporter" onChange="updateReporterOptions()"> 620*f4a2713aSLionel Sambuc %(reporterSelections)s 621*f4a2713aSLionel Sambuc </select> 622*f4a2713aSLionel Sambuc </td> 623*f4a2713aSLionel Sambuc</tr> 624*f4a2713aSLionel Sambuc%(reporterOptionsDivs)s 625*f4a2713aSLionel Sambuc</table> 626*f4a2713aSLionel Sambuc<br> 627*f4a2713aSLionel Sambuc</td></tr> 628*f4a2713aSLionel Sambuc<tr><td class="form_submit"> 629*f4a2713aSLionel Sambuc <input align="right" type="submit" name="Submit" value="Submit"> 630*f4a2713aSLionel Sambuc</td></tr> 631*f4a2713aSLionel Sambuc</table> 632*f4a2713aSLionel Sambuc</form> 633*f4a2713aSLionel Sambuc 634*f4a2713aSLionel Sambuc%(extraIFrame)s 635*f4a2713aSLionel Sambuc 636*f4a2713aSLionel Sambuc</body> 637*f4a2713aSLionel Sambuc</html>"""%locals() 638*f4a2713aSLionel Sambuc 639*f4a2713aSLionel Sambuc return self.send_string(result) 640*f4a2713aSLionel Sambuc 641*f4a2713aSLionel Sambuc def send_head(self, fields=None): 642*f4a2713aSLionel Sambuc if (self.server.options.onlyServeLocal and 643*f4a2713aSLionel Sambuc self.client_address[0] != '127.0.0.1'): 644*f4a2713aSLionel Sambuc return self.send_error(401, 'Unauthorized host.') 645*f4a2713aSLionel Sambuc 646*f4a2713aSLionel Sambuc if fields is None: 647*f4a2713aSLionel Sambuc fields = {} 648*f4a2713aSLionel Sambuc self.fields = fields 649*f4a2713aSLionel Sambuc 650*f4a2713aSLionel Sambuc o = urlparse.urlparse(self.path) 651*f4a2713aSLionel Sambuc self.fields = parse_query(o.query, fields) 652*f4a2713aSLionel Sambuc path = posixpath.normpath(urllib.unquote(o.path)) 653*f4a2713aSLionel Sambuc 654*f4a2713aSLionel Sambuc # Split the components and strip the root prefix. 655*f4a2713aSLionel Sambuc components = path.split('/')[1:] 656*f4a2713aSLionel Sambuc 657*f4a2713aSLionel Sambuc # Special case some top-level entries. 658*f4a2713aSLionel Sambuc if components: 659*f4a2713aSLionel Sambuc name = components[0] 660*f4a2713aSLionel Sambuc if len(components)==2: 661*f4a2713aSLionel Sambuc if name=='report': 662*f4a2713aSLionel Sambuc return self.send_report(components[1]) 663*f4a2713aSLionel Sambuc elif name=='open': 664*f4a2713aSLionel Sambuc return self.send_open_report(components[1]) 665*f4a2713aSLionel Sambuc elif len(components)==1: 666*f4a2713aSLionel Sambuc if name=='quit': 667*f4a2713aSLionel Sambuc self.server.halt() 668*f4a2713aSLionel Sambuc return self.send_string('Goodbye.', 'text/plain') 669*f4a2713aSLionel Sambuc elif name=='report_submit': 670*f4a2713aSLionel Sambuc return self.send_report_submit() 671*f4a2713aSLionel Sambuc elif name=='report_crashes': 672*f4a2713aSLionel Sambuc overrides = { 'ScanView' : {}, 673*f4a2713aSLionel Sambuc 'Radar' : {}, 674*f4a2713aSLionel Sambuc 'Email' : {} } 675*f4a2713aSLionel Sambuc for i,r in enumerate(self.server.reporters): 676*f4a2713aSLionel Sambuc if r.getName() == 'Radar': 677*f4a2713aSLionel Sambuc overrides['ScanView']['reporter'] = i 678*f4a2713aSLionel Sambuc break 679*f4a2713aSLionel Sambuc overrides['Radar']['Component'] = 'llvm - checker' 680*f4a2713aSLionel Sambuc overrides['Radar']['Component Version'] = 'X' 681*f4a2713aSLionel Sambuc return self.send_report(None, overrides) 682*f4a2713aSLionel Sambuc elif name=='favicon.ico': 683*f4a2713aSLionel Sambuc return self.send_path(posixpath.join(kResources,'bugcatcher.ico')) 684*f4a2713aSLionel Sambuc 685*f4a2713aSLionel Sambuc # Match directory entries. 686*f4a2713aSLionel Sambuc if components[-1] == '': 687*f4a2713aSLionel Sambuc components[-1] = 'index.html' 688*f4a2713aSLionel Sambuc 689*f4a2713aSLionel Sambuc relpath = '/'.join(components) 690*f4a2713aSLionel Sambuc path = posixpath.join(self.server.root, relpath) 691*f4a2713aSLionel Sambuc 692*f4a2713aSLionel Sambuc if self.server.options.debug > 1: 693*f4a2713aSLionel Sambuc print >>sys.stderr, '%s: SERVER: sending path "%s"'%(sys.argv[0], 694*f4a2713aSLionel Sambuc path) 695*f4a2713aSLionel Sambuc return self.send_path(path) 696*f4a2713aSLionel Sambuc 697*f4a2713aSLionel Sambuc def send_404(self): 698*f4a2713aSLionel Sambuc self.send_error(404, "File not found") 699*f4a2713aSLionel Sambuc return None 700*f4a2713aSLionel Sambuc 701*f4a2713aSLionel Sambuc def send_path(self, path): 702*f4a2713aSLionel Sambuc # If the requested path is outside the root directory, do not open it 703*f4a2713aSLionel Sambuc rel = os.path.abspath(path) 704*f4a2713aSLionel Sambuc if not rel.startswith(os.path.abspath(self.server.root)): 705*f4a2713aSLionel Sambuc return self.send_404() 706*f4a2713aSLionel Sambuc 707*f4a2713aSLionel Sambuc ctype = self.guess_type(path) 708*f4a2713aSLionel Sambuc if ctype.startswith('text/'): 709*f4a2713aSLionel Sambuc # Patch file instead 710*f4a2713aSLionel Sambuc return self.send_patched_file(path, ctype) 711*f4a2713aSLionel Sambuc else: 712*f4a2713aSLionel Sambuc mode = 'rb' 713*f4a2713aSLionel Sambuc try: 714*f4a2713aSLionel Sambuc f = open(path, mode) 715*f4a2713aSLionel Sambuc except IOError: 716*f4a2713aSLionel Sambuc return self.send_404() 717*f4a2713aSLionel Sambuc return self.send_file(f, ctype) 718*f4a2713aSLionel Sambuc 719*f4a2713aSLionel Sambuc def send_file(self, f, ctype): 720*f4a2713aSLionel Sambuc # Patch files to add links, but skip binary files. 721*f4a2713aSLionel Sambuc self.send_response(200) 722*f4a2713aSLionel Sambuc self.send_header("Content-type", ctype) 723*f4a2713aSLionel Sambuc fs = os.fstat(f.fileno()) 724*f4a2713aSLionel Sambuc self.send_header("Content-Length", str(fs[6])) 725*f4a2713aSLionel Sambuc self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) 726*f4a2713aSLionel Sambuc self.end_headers() 727*f4a2713aSLionel Sambuc return f 728*f4a2713aSLionel Sambuc 729*f4a2713aSLionel Sambuc def send_string(self, s, ctype='text/html', headers=True, mtime=None): 730*f4a2713aSLionel Sambuc if headers: 731*f4a2713aSLionel Sambuc self.send_response(200) 732*f4a2713aSLionel Sambuc self.send_header("Content-type", ctype) 733*f4a2713aSLionel Sambuc self.send_header("Content-Length", str(len(s))) 734*f4a2713aSLionel Sambuc if mtime is None: 735*f4a2713aSLionel Sambuc mtime = self.dynamic_mtime 736*f4a2713aSLionel Sambuc self.send_header("Last-Modified", self.date_time_string(mtime)) 737*f4a2713aSLionel Sambuc self.end_headers() 738*f4a2713aSLionel Sambuc return StringIO.StringIO(s) 739*f4a2713aSLionel Sambuc 740*f4a2713aSLionel Sambuc def send_patched_file(self, path, ctype): 741*f4a2713aSLionel Sambuc # Allow a very limited set of variables. This is pretty gross. 742*f4a2713aSLionel Sambuc variables = {} 743*f4a2713aSLionel Sambuc variables['report'] = '' 744*f4a2713aSLionel Sambuc m = kReportFileRE.match(path) 745*f4a2713aSLionel Sambuc if m: 746*f4a2713aSLionel Sambuc variables['report'] = m.group(2) 747*f4a2713aSLionel Sambuc 748*f4a2713aSLionel Sambuc try: 749*f4a2713aSLionel Sambuc f = open(path,'r') 750*f4a2713aSLionel Sambuc except IOError: 751*f4a2713aSLionel Sambuc return self.send_404() 752*f4a2713aSLionel Sambuc fs = os.fstat(f.fileno()) 753*f4a2713aSLionel Sambuc data = f.read() 754*f4a2713aSLionel Sambuc for a,b in kReportReplacements: 755*f4a2713aSLionel Sambuc data = a.sub(b % variables, data) 756*f4a2713aSLionel Sambuc return self.send_string(data, ctype, mtime=fs.st_mtime) 757*f4a2713aSLionel Sambuc 758*f4a2713aSLionel Sambuc 759*f4a2713aSLionel Sambucdef create_server(address, options, root): 760*f4a2713aSLionel Sambuc import Reporter 761*f4a2713aSLionel Sambuc 762*f4a2713aSLionel Sambuc reporters = Reporter.getReporters() 763*f4a2713aSLionel Sambuc 764*f4a2713aSLionel Sambuc return ScanViewServer(address, ScanViewRequestHandler, 765*f4a2713aSLionel Sambuc root, 766*f4a2713aSLionel Sambuc reporters, 767*f4a2713aSLionel Sambuc options) 768