| import BaseHTTPServer | 
 | import SimpleHTTPServer | 
 | import os | 
 | import sys | 
 | import urllib, urlparse | 
 | import posixpath | 
 | import StringIO | 
 | import re | 
 | import shutil | 
 | import threading | 
 | import time | 
 | import socket | 
 | import itertools | 
 |  | 
 | import Reporter | 
 | import ConfigParser | 
 |  | 
 | ### | 
 | # Various patterns matched or replaced by server. | 
 |  | 
 | kReportFileRE = re.compile('(.*/)?report-(.*)\\.html') | 
 |  | 
 | kBugKeyValueRE = re.compile('<!-- BUG([^ ]*) (.*) -->') | 
 |  | 
 | #  <!-- REPORTPROBLEM file="crashes/clang_crash_ndSGF9.mi" stderr="crashes/clang_crash_ndSGF9.mi.stderr.txt" info="crashes/clang_crash_ndSGF9.mi.info" --> | 
 |  | 
 | kReportCrashEntryRE = re.compile('<!-- REPORTPROBLEM (.*?)-->') | 
 | kReportCrashEntryKeyValueRE = re.compile(' ?([^=]+)="(.*?)"') | 
 |  | 
 | kReportReplacements = [] | 
 |  | 
 | # Add custom javascript. | 
 | kReportReplacements.append((re.compile('<!-- SUMMARYENDHEAD -->'), """\ | 
 | <script language="javascript" type="text/javascript"> | 
 | function load(url) { | 
 |   if (window.XMLHttpRequest) { | 
 |     req = new XMLHttpRequest(); | 
 |   } else if (window.ActiveXObject) { | 
 |     req = new ActiveXObject("Microsoft.XMLHTTP"); | 
 |   } | 
 |   if (req != undefined) { | 
 |     req.open("GET", url, true); | 
 |     req.send(""); | 
 |   } | 
 | } | 
 | </script>""")) | 
 |  | 
 | # Insert additional columns. | 
 | kReportReplacements.append((re.compile('<!-- REPORTBUGCOL -->'),  | 
 |                             '<td></td><td></td>')) | 
 |  | 
 | # Insert report bug and open file links. | 
 | kReportReplacements.append((re.compile('<!-- REPORTBUG id="report-(.*)\\.html" -->'), | 
 |                             ('<td class="Button"><a href="report/\\1">Report Bug</a></td>' +  | 
 |                              '<td class="Button"><a href="javascript:load(\'open/\\1\')">Open File</a></td>'))) | 
 |  | 
 | kReportReplacements.append((re.compile('<!-- REPORTHEADER -->'), | 
 |                                        '<h3><a href="/">Summary</a> > Report %(report)s</h3>')) | 
 |  | 
 | kReportReplacements.append((re.compile('<!-- REPORTSUMMARYEXTRA -->'), | 
 |                             '<td class="Button"><a href="report/%(report)s">Report Bug</a></td>')) | 
 |  | 
 | # Insert report crashes link. | 
 |  | 
 | # Disabled for the time being until we decide exactly when this should | 
 | # be enabled. Also the radar reporter needs to be fixed to report | 
 | # multiple files. | 
 |  | 
 | #kReportReplacements.append((re.compile('<!-- REPORTCRASHES -->'), | 
 | #                            '<br>These files will automatically be attached to ' + | 
 | #                            'reports filed here: <a href="report_crashes">Report Crashes</a>.')) | 
 |  | 
 | ### | 
 | # Other simple parameters | 
 |  | 
 | kResources = posixpath.join(posixpath.dirname(__file__), 'Resources') | 
 | kConfigPath = os.path.expanduser('~/.scanview.cfg') | 
 |  | 
 | ### | 
 |  | 
 | __version__ = "0.1" | 
 |  | 
 | __all__ = ["create_server"] | 
 |  | 
 | class ReporterThread(threading.Thread): | 
 |     def __init__(self, report, reporter, parameters, server): | 
 |         threading.Thread.__init__(self) | 
 |         self.report = report | 
 |         self.server = server | 
 |         self.reporter = reporter | 
 |         self.parameters = parameters | 
 |         self.success = False | 
 |         self.status = None | 
 |  | 
 |     def run(self): | 
 |         result = None | 
 |         try: | 
 |             if self.server.options.debug: | 
 |                 print >>sys.stderr, "%s: SERVER: submitting bug."%(sys.argv[0],) | 
 |             self.status = self.reporter.fileReport(self.report, self.parameters) | 
 |             self.success = True | 
 |             time.sleep(3) | 
 |             if self.server.options.debug: | 
 |                 print >>sys.stderr, "%s: SERVER: submission complete."%(sys.argv[0],) | 
 |         except Reporter.ReportFailure,e: | 
 |             self.status = e.value | 
 |         except Exception,e: | 
 |             s = StringIO.StringIO() | 
 |             import traceback | 
 |             print >>s,'<b>Unhandled Exception</b><br><pre>' | 
 |             traceback.print_exc(e,file=s) | 
 |             print >>s,'</pre>' | 
 |             self.status = s.getvalue() | 
 |  | 
 | class ScanViewServer(BaseHTTPServer.HTTPServer): | 
 |     def __init__(self, address, handler, root, reporters, options): | 
 |         BaseHTTPServer.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 >>sys.stderr, "%s: SERVER: halting." % (sys.argv[0],) | 
 |  | 
 |     def serve_forever(self): | 
 |         while not self.halted: | 
 |             if self.options.debug > 1: | 
 |                 print >>sys.stderr, "%s: SERVER: waiting..." % (sys.argv[0],) | 
 |             try: | 
 |                 self.handle_request() | 
 |             except OSError,e: | 
 |                 print 'OSError',e.errno | 
 |  | 
 |     def finish_request(self, request, client_address): | 
 |         if self.options.autoReload: | 
 |             import ScanView | 
 |             self.RequestHandlerClass = reload(ScanView).ScanViewRequestHandler | 
 |         BaseHTTPServer.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 >>sys.stderr, "%s: SERVER: ignored socket error." % (sys.argv[0],) | 
 |             return | 
 |         BaseHTTPServer.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 filter(None, qs.split('&')): | 
 |         if '=' not in chunk: | 
 |             name = chunk | 
 |             value = '' | 
 |         else: | 
 |             name, value = chunk.split('=', 1) | 
 |         name = urllib.unquote(name.replace('+', ' ')) | 
 |         value = urllib.unquote(value.replace('+', ' ')) | 
 |         item = fields.get(name) | 
 |         if item is None: | 
 |             fields[name] = [value] | 
 |         else: | 
 |             item.append(value) | 
 |     return fields | 
 |  | 
 | class ScanViewRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): | 
 |     server_version = "ScanViewServer/" + __version__ | 
 |     dynamic_mtime = time.time() | 
 |  | 
 |     def do_HEAD(self): | 
 |         try: | 
 |             SimpleHTTPServer.SimpleHTTPRequestHandler.do_HEAD(self) | 
 |         except Exception,e: | 
 |             self.handle_exception(e) | 
 |              | 
 |     def do_GET(self): | 
 |         try: | 
 |             SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) | 
 |         except Exception,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,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.StringIO() | 
 |         print >>s, "INTERNAL ERROR\n" | 
 |         traceback.print_exc(exc, 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 = """\ | 
 | <a href="/report_crashes">File Bug</a> > """%locals() | 
 |         else: | 
 |             reportingFor = '<a href="/%s">Report %s</a> > ' % (c.reportSource,  | 
 |                                                                    report) | 
 |             fileBug = '<a href="/report/%s">File Bug</a> > ' % 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 = """ | 
 | <head> | 
 |   <title>Bug Submission</title> | 
 |   <link rel="stylesheet" type="text/css" href="/scanview.css" /> | 
 | </head> | 
 | <body> | 
 | <h3> | 
 | <a href="/">Summary</a> >  | 
 | %(reportingFor)s | 
 | %(fileBug)s | 
 | Submit</h3> | 
 | <form name="form" action=""> | 
 | <table class="form"> | 
 | <tr><td> | 
 | <table class="form_group"> | 
 | <tr> | 
 |   <td class="form_clabel">Title:</td> | 
 |   <td class="form_value"> | 
 |     <input type="text" name="title" size="50" value="%(title)s" disabled> | 
 |   </td> | 
 | </tr> | 
 | <tr> | 
 |   <td class="form_label">Description:</td> | 
 |   <td class="form_value"> | 
 | <textarea rows="10" cols="80" name="description" disabled> | 
 | %(description)s | 
 | </textarea> | 
 |   </td> | 
 | </table> | 
 | </td></tr> | 
 | </table> | 
 | </form> | 
 | <h1 class="%(statusClass)s">Submission %(statusName)s</h1> | 
 | %(message)s | 
 | <p> | 
 | <hr> | 
 | <a href="/">Return to Summary</a> | 
 | </body> | 
 | </html>"""%locals() | 
 |         return self.send_string(result) | 
 |  | 
 |     def send_open_report(self, report): | 
 |         try: | 
 |             keys = self.load_report(report) | 
 |         except IOError: | 
 |             return self.send_error(400, 'Invalid report.') | 
 |  | 
 |         file = keys.get('FILE') | 
 |         if not file or not posixpath.exists(file): | 
 |             return self.send_error(400, 'File does not exist: "%s"' % file) | 
 |  | 
 |         import startfile | 
 |         if self.server.options.debug: | 
 |             print >>sys.stderr, '%s: SERVER: opening "%s"'%(sys.argv[0], | 
 |                                                             file) | 
 |  | 
 |         status = startfile.open(file) | 
 |         if status: | 
 |             res = 'Opened: "%s"' % file | 
 |         else: | 
 |             res = 'Open failed: "%s"' % file | 
 |  | 
 |         return self.send_string(res, 'text/plain') | 
 |  | 
 |     def get_report_context(self, report): | 
 |         class Context: | 
 |             pass | 
 |         if report is None or report == 'None': | 
 |             data = self.load_crashes() | 
 |             # Don't allow empty reports. | 
 |             if not data: | 
 |                 raise ValueError, 'No crashes detected!' | 
 |             c = Context() | 
 |             c.title = 'clang static analyzer failures' | 
 |  | 
 |             stderrSummary = "" | 
 |             for item in data: | 
 |                 if 'stderr' in item: | 
 |                     path = posixpath.join(self.server.root, item['stderr']) | 
 |                     if os.path.exists(path): | 
 |                         lns = itertools.islice(open(path), 0, 10) | 
 |                         stderrSummary += '%s\n--\n%s' % (item.get('src',  | 
 |                                                                   '<unknown>'), | 
 |                                                          ''.join(lns)) | 
 |  | 
 |             c.description = """\ | 
 | The clang static analyzer failed on these inputs: | 
 | %s | 
 |  | 
 | STDERR Summary | 
 | -------------- | 
 | %s | 
 | """ % ('\n'.join([item.get('src','<unknown>') for item in data]), | 
 |        stderrSummary) | 
 |             c.reportSource = None | 
 |             c.navMarkup = "Report Crashes > " | 
 |             c.files = [] | 
 |             for item in data:                 | 
 |                 c.files.append(item.get('src','')) | 
 |                 c.files.append(posixpath.join(self.server.root, | 
 |                                               item.get('file',''))) | 
 |                 c.files.append(posixpath.join(self.server.root, | 
 |                                               item.get('clangfile',''))) | 
 |                 c.files.append(posixpath.join(self.server.root, | 
 |                                               item.get('stderr',''))) | 
 |                 c.files.append(posixpath.join(self.server.root, | 
 |                                               item.get('info',''))) | 
 |             # Just in case something failed, ignore files which don't | 
 |             # exist. | 
 |             c.files = [f for f in c.files | 
 |                        if os.path.exists(f) and os.path.isfile(f)] | 
 |         else: | 
 |             # Check that this is a valid report.             | 
 |             path = posixpath.join(self.server.root, 'report-%s.html' % report) | 
 |             if not posixpath.exists(path): | 
 |                 raise ValueError, 'Invalid report ID' | 
 |             keys = self.load_report(report) | 
 |             c = Context() | 
 |             c.title = keys.get('DESC','clang error (unrecognized') | 
 |             c.description = """\ | 
 | Bug reported by the clang static analyzer. | 
 |  | 
 | Description: %s | 
 | File: %s | 
 | Line: %s | 
 | """%(c.title, keys.get('FILE','<unknown>'), keys.get('LINE', '<unknown>')) | 
 |             c.reportSource = 'report-%s.html' % report | 
 |             c.navMarkup = """<a href="/%s">Report %s</a> > """ % (c.reportSource, | 
 |                                                                   report) | 
 |  | 
 |             c.files = [path] | 
 |         return c | 
 |  | 
 |     def send_report(self, report, configOverrides=None): | 
 |         def getConfigOption(section, field):             | 
 |             if (configOverrides is not None and | 
 |                 section in configOverrides and | 
 |                 field in configOverrides[section]): | 
 |                 return configOverrides[section][field] | 
 |             return self.server.config.get(section, field) | 
 |  | 
 |         # report is None is used for crashes | 
 |         try: | 
 |             c = self.get_report_context(report) | 
 |         except ValueError, e: | 
 |             return self.send_error(400, e.message) | 
 |  | 
 |         title = c.title | 
 |         description= c.description | 
 |         reportingFor = c.navMarkup | 
 |         if c.reportSource is None: | 
 |             extraIFrame = "" | 
 |         else: | 
 |             extraIFrame = """\ | 
 | <iframe src="/%s" width="100%%" height="40%%" | 
 |         scrolling="auto" frameborder="1"> | 
 |   <a href="/%s">View Bug Report</a> | 
 | </iframe>""" % (c.reportSource, c.reportSource) | 
 |  | 
 |         reporterSelections = [] | 
 |         reporterOptions = [] | 
 |  | 
 |         try: | 
 |             active = int(getConfigOption('ScanView','reporter')) | 
 |         except: | 
 |             active = 0 | 
 |         for i,r in enumerate(self.server.reporters): | 
 |             selected = (i == active) | 
 |             if selected: | 
 |                 selectedStr = ' selected' | 
 |             else: | 
 |                 selectedStr = '' | 
 |             reporterSelections.append('<option value="%d"%s>%s</option>'%(i,selectedStr,r.getName())) | 
 |             options = '\n'.join([ o.getHTML(r,title,getConfigOption) for o in r.getParameters()]) | 
 |             display = ('none','')[selected] | 
 |             reporterOptions.append("""\ | 
 | <tr id="%sReporterOptions" style="display:%s"> | 
 |   <td class="form_label">%s Options</td> | 
 |   <td class="form_value"> | 
 |     <table class="form_inner_group"> | 
 | %s | 
 |     </table> | 
 |   </td> | 
 | </tr> | 
 | """%(r.getName(),display,r.getName(),options)) | 
 |         reporterSelections = '\n'.join(reporterSelections) | 
 |         reporterOptionsDivs = '\n'.join(reporterOptions) | 
 |         reportersArray = '[%s]'%(','.join([`r.getName()` for r in self.server.reporters])) | 
 |  | 
 |         if c.files: | 
 |             fieldSize = min(5, len(c.files)) | 
 |             attachFileOptions = '\n'.join(["""\ | 
 | <option value="%d" selected>%s</option>""" % (i,v) for i,v in enumerate(c.files)]) | 
 |             attachFileRow = """\ | 
 | <tr> | 
 |   <td class="form_label">Attach:</td> | 
 |   <td class="form_value"> | 
 | <select style="width:100%%" name="files" multiple size=%d> | 
 | %s | 
 | </select> | 
 |   </td> | 
 | </tr> | 
 | """ % (min(5, len(c.files)), attachFileOptions) | 
 |         else: | 
 |             attachFileRow = "" | 
 |  | 
 |         result = """<html> | 
 | <head> | 
 |   <title>File Bug</title> | 
 |   <link rel="stylesheet" type="text/css" href="/scanview.css" /> | 
 | </head> | 
 | <script language="javascript" type="text/javascript"> | 
 | var reporters = %(reportersArray)s; | 
 | function updateReporterOptions() { | 
 |   index = document.getElementById('reporter').selectedIndex; | 
 |   for (var i=0; i < reporters.length; ++i) { | 
 |     o = document.getElementById(reporters[i] + "ReporterOptions"); | 
 |     if (i == index) { | 
 |       o.style.display = ""; | 
 |     } else { | 
 |       o.style.display = "none"; | 
 |     } | 
 |   } | 
 | } | 
 | </script> | 
 | <body onLoad="updateReporterOptions()"> | 
 | <h3> | 
 | <a href="/">Summary</a> >  | 
 | %(reportingFor)s | 
 | File Bug</h3> | 
 | <form name="form" action="/report_submit" method="post"> | 
 | <input type="hidden" name="report" value="%(report)s"> | 
 |  | 
 | <table class="form"> | 
 | <tr><td> | 
 | <table class="form_group"> | 
 | <tr> | 
 |   <td class="form_clabel">Title:</td> | 
 |   <td class="form_value"> | 
 |     <input type="text" name="title" size="50" value="%(title)s"> | 
 |   </td> | 
 | </tr> | 
 | <tr> | 
 |   <td class="form_label">Description:</td> | 
 |   <td class="form_value"> | 
 | <textarea rows="10" cols="80" name="description"> | 
 | %(description)s | 
 | </textarea> | 
 |   </td> | 
 | </tr> | 
 |  | 
 | %(attachFileRow)s | 
 |  | 
 | </table> | 
 | <br> | 
 | <table class="form_group"> | 
 | <tr> | 
 |   <td class="form_clabel">Method:</td> | 
 |   <td class="form_value"> | 
 |     <select id="reporter" name="reporter" onChange="updateReporterOptions()"> | 
 |     %(reporterSelections)s | 
 |     </select> | 
 |   </td> | 
 | </tr> | 
 | %(reporterOptionsDivs)s | 
 | </table> | 
 | <br> | 
 | </td></tr> | 
 | <tr><td class="form_submit"> | 
 |   <input align="right" type="submit" name="Submit" value="Submit"> | 
 | </td></tr> | 
 | </table> | 
 | </form> | 
 |  | 
 | %(extraIFrame)s | 
 |  | 
 | </body> | 
 | </html>"""%locals() | 
 |  | 
 |         return self.send_string(result) | 
 |  | 
 |     def send_head(self, fields=None): | 
 |         if (self.server.options.onlyServeLocal and | 
 |             self.client_address[0] != '127.0.0.1'): | 
 |             return self.send_error('401', 'Unauthorized host.') | 
 |  | 
 |         if fields is None: | 
 |             fields = {} | 
 |         self.fields = fields | 
 |  | 
 |         o = urlparse.urlparse(self.path) | 
 |         self.fields = parse_query(o.query, fields) | 
 |         path = posixpath.normpath(urllib.unquote(o.path)) | 
 |  | 
 |         # Split the components and strip the root prefix. | 
 |         components = path.split('/')[1:] | 
 |          | 
 |         # Special case some top-level entries. | 
 |         if components: | 
 |             name = components[0] | 
 |             if len(components)==2: | 
 |                 if name=='report': | 
 |                     return self.send_report(components[1]) | 
 |                 elif name=='open': | 
 |                     return self.send_open_report(components[1]) | 
 |             elif len(components)==1: | 
 |                 if name=='quit': | 
 |                     self.server.halt() | 
 |                     return self.send_string('Goodbye.', 'text/plain') | 
 |                 elif name=='report_submit': | 
 |                     return self.send_report_submit() | 
 |                 elif name=='report_crashes': | 
 |                     overrides = { 'ScanView' : {}, | 
 |                                   'Radar' : {}, | 
 |                                   'Email' : {} } | 
 |                     for i,r in enumerate(self.server.reporters): | 
 |                         if r.getName() == 'Radar': | 
 |                             overrides['ScanView']['reporter'] = i | 
 |                             break | 
 |                     overrides['Radar']['Component'] = 'llvm - checker' | 
 |                     overrides['Radar']['Component Version'] = 'X' | 
 |                     return self.send_report(None, overrides) | 
 |                 elif name=='favicon.ico': | 
 |                     return self.send_path(posixpath.join(kResources,'bugcatcher.ico')) | 
 |          | 
 |         # Match directory entries. | 
 |         if components[-1] == '': | 
 |             components[-1] = 'index.html' | 
 |  | 
 |         suffix = '/'.join(components) | 
 |  | 
 |         # The summary may reference source files on disk using rooted | 
 |         # paths. Make sure these resolve correctly for now. | 
 |         # FIXME: This isn't a very good idea... we should probably | 
 |         # mark rooted paths somehow.         | 
 |         if os.path.exists(posixpath.join('/', suffix)): | 
 |             path = posixpath.join('/', suffix) | 
 |         else: | 
 |             path = posixpath.join(self.server.root, suffix) | 
 |  | 
 |         if self.server.options.debug > 1: | 
 |             print >>sys.stderr, '%s: SERVER: sending path "%s"'%(sys.argv[0], | 
 |                                                                  path) | 
 |         return self.send_path(path) | 
 |  | 
 |     def send_404(self): | 
 |         self.send_error(404, "File not found") | 
 |         return None | 
 |  | 
 |     def send_path(self, path): | 
 |         ctype = self.guess_type(path) | 
 |         if ctype.startswith('text/'): | 
 |             # Patch file instead | 
 |             return self.send_patched_file(path, ctype) | 
 |         else: | 
 |             mode = 'rb' | 
 |         try: | 
 |             f = open(path, mode) | 
 |         except IOError: | 
 |             return self.send_404() | 
 |         return self.send_file(f, ctype) | 
 |  | 
 |     def send_file(self, f, ctype): | 
 |         # Patch files to add links, but skip binary files. | 
 |         self.send_response(200) | 
 |         self.send_header("Content-type", ctype) | 
 |         fs = os.fstat(f.fileno()) | 
 |         self.send_header("Content-Length", str(fs[6])) | 
 |         self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) | 
 |         self.end_headers() | 
 |         return f | 
 |  | 
 |     def send_string(self, s, ctype='text/html', headers=True, mtime=None): | 
 |         if headers: | 
 |             self.send_response(200) | 
 |             self.send_header("Content-type", ctype) | 
 |             self.send_header("Content-Length", str(len(s))) | 
 |             if mtime is None: | 
 |                 mtime = self.dynamic_mtime | 
 |             self.send_header("Last-Modified", self.date_time_string(mtime)) | 
 |             self.end_headers() | 
 |         return StringIO.StringIO(s) | 
 |  | 
 |     def send_patched_file(self, path, ctype): | 
 |         # Allow a very limited set of variables. This is pretty gross. | 
 |         variables = {} | 
 |         variables['report'] = '' | 
 |         m = kReportFileRE.match(path) | 
 |         if m: | 
 |             variables['report'] = m.group(2) | 
 |  | 
 |         try: | 
 |             f = open(path,'r') | 
 |         except IOError: | 
 |             return self.send_404() | 
 |         fs = os.fstat(f.fileno()) | 
 |         data = f.read() | 
 |         for a,b in kReportReplacements: | 
 |             data = a.sub(b % variables, data) | 
 |         return self.send_string(data, ctype, mtime=fs.st_mtime) | 
 |  | 
 |  | 
 | def create_server(address, options, root): | 
 |     import Reporter | 
 |  | 
 |     reporters = Reporter.getReporters() | 
 |  | 
 |     return ScanViewServer(address, ScanViewRequestHandler, | 
 |                           root, | 
 |                           reporters, | 
 |                           options) |