16bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport BaseHTTPServer
26bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport SimpleHTTPServer
36bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport os
46bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport sys
56bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport urllib, urlparse
66bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport posixpath
76bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport StringIO
86bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport re
96bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport shutil
106bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport threading
116bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport time
126bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport socket
136bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport itertools
146bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
156bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport Reporter
166bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerimport ConfigParser
176bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
186bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker###
196bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker# Various patterns matched or replaced by server.
206bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
216bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkReportFileRE = re.compile('(.*/)?report-(.*)\\.html')
226bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
236bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkBugKeyValueRE = re.compile('<!-- BUG([^ ]*) (.*) -->')
246bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
256bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker#  <!-- REPORTPROBLEM file="crashes/clang_crash_ndSGF9.mi" stderr="crashes/clang_crash_ndSGF9.mi.stderr.txt" info="crashes/clang_crash_ndSGF9.mi.info" -->
266bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
276bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkReportCrashEntryRE = re.compile('<!-- REPORTPROBLEM (.*?)-->')
286bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkReportCrashEntryKeyValueRE = re.compile(' ?([^=]+)="(.*?)"')
296bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
306bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkReportReplacements = []
316bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
326bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker# Add custom javascript.
336bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkReportReplacements.append((re.compile('<!-- SUMMARYENDHEAD -->'), """\
346bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<script language="javascript" type="text/javascript">
356bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerfunction load(url) {
366bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  if (window.XMLHttpRequest) {
376bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    req = new XMLHttpRequest();
386bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  } else if (window.ActiveXObject) {
396bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    req = new ActiveXObject("Microsoft.XMLHTTP");
406bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  }
416bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  if (req != undefined) {
426bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    req.open("GET", url, true);
436bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    req.send("");
446bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  }
456bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker}
466bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</script>"""))
476bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
486bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker# Insert additional columns.
496bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkReportReplacements.append((re.compile('<!-- REPORTBUGCOL -->'),
506bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                            '<td></td><td></td>'))
516bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
526bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker# Insert report bug and open file links.
536bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkReportReplacements.append((re.compile('<!-- REPORTBUG id="report-(.*)\\.html" -->'),
546bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                            ('<td class="Button"><a href="report/\\1">Report Bug</a></td>' +
556bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                             '<td class="Button"><a href="javascript:load(\'open/\\1\')">Open File</a></td>')))
566bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
576bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkReportReplacements.append((re.compile('<!-- REPORTHEADER -->'),
586bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                       '<h3><a href="/">Summary</a> > Report %(report)s</h3>'))
596bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
606bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkReportReplacements.append((re.compile('<!-- REPORTSUMMARYEXTRA -->'),
616bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                            '<td class="Button"><a href="report/%(report)s">Report Bug</a></td>'))
626bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
636bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker# Insert report crashes link.
646bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
656bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker# Disabled for the time being until we decide exactly when this should
666bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker# be enabled. Also the radar reporter needs to be fixed to report
676bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker# multiple files.
686bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
696bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker#kReportReplacements.append((re.compile('<!-- REPORTCRASHES -->'),
706bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker#                            '<br>These files will automatically be attached to ' +
716bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker#                            'reports filed here: <a href="report_crashes">Report Crashes</a>.'))
726bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
736bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker###
746bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker# Other simple parameters
756bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
766bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkShare = posixpath.join(posixpath.dirname(__file__), '../share/scan-view')
776bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerkConfigPath = os.path.expanduser('~/.scanview.cfg')
786bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
796bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker###
806bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
816bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker__version__ = "0.1"
826bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
836bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker__all__ = ["create_server"]
846bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
856bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerclass ReporterThread(threading.Thread):
866bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def __init__(self, report, reporter, parameters, server):
876bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        threading.Thread.__init__(self)
886bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.report = report
896bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.server = server
906bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.reporter = reporter
916bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.parameters = parameters
926bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.success = False
936bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.status = None
946bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
956bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def run(self):
966bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        result = None
976bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
986bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if self.server.options.debug:
996bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                print >>sys.stderr, "%s: SERVER: submitting bug."%(sys.argv[0],)
1006bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.status = self.reporter.fileReport(self.report, self.parameters)
1016bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.success = True
1026bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            time.sleep(3)
1036bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if self.server.options.debug:
1046bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                print >>sys.stderr, "%s: SERVER: submission complete."%(sys.argv[0],)
1056bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except Reporter.ReportFailure,e:
1066bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.status = e.value
1076bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except Exception,e:
1086bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            s = StringIO.StringIO()
1096bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            import traceback
1106bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            print >>s,'<b>Unhandled Exception</b><br><pre>'
1116bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            traceback.print_exc(e,file=s)
1126bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            print >>s,'</pre>'
1136bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.status = s.getvalue()
1146bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1156bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerclass ScanViewServer(BaseHTTPServer.HTTPServer):
1166bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def __init__(self, address, handler, root, reporters, options):
1176bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        BaseHTTPServer.HTTPServer.__init__(self, address, handler)
1186bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.root = root
1196bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.reporters = reporters
1206bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.options = options
1216bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.halted = False
1226bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.config = None
1236bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.load_config()
1246bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1256bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def load_config(self):
1266bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.config = ConfigParser.RawConfigParser()
1276bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1286bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Add defaults
1296bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.config.add_section('ScanView')
1306bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        for r in self.reporters:
1316bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.config.add_section(r.getName())
1326bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            for p in r.getParameters():
1336bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker              if p.saveConfigValue():
1346bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                self.config.set(r.getName(), p.getName(), '')
1356bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1366bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Ignore parse errors
1376bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
1386bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.config.read([kConfigPath])
1396bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except:
1406bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            pass
1416bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1426bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Save on exit
1436bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        import atexit
1446bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        atexit.register(lambda: self.save_config())
1456bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1466bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def save_config(self):
1476bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Ignore errors (only called on exit).
1486bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
1496bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            f = open(kConfigPath,'w')
1506bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.config.write(f)
1516bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            f.close()
1526bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except:
1536bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            pass
1546bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1556bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def halt(self):
1566bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.halted = True
1576bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if self.options.debug:
1586bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            print >>sys.stderr, "%s: SERVER: halting." % (sys.argv[0],)
1596bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1606bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def serve_forever(self):
1616bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        while not self.halted:
1626bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if self.options.debug > 1:
1636bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                print >>sys.stderr, "%s: SERVER: waiting..." % (sys.argv[0],)
1646bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            try:
1656bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                self.handle_request()
1666bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            except OSError,e:
1676bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                print 'OSError',e.errno
1686bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1696bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def finish_request(self, request, client_address):
1706bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if self.options.autoReload:
1716bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            import ScanView
1726bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.RequestHandlerClass = reload(ScanView).ScanViewRequestHandler
1736bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        BaseHTTPServer.HTTPServer.finish_request(self, request, client_address)
1746bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1756bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def handle_error(self, request, client_address):
1766bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Ignore socket errors
1776bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        info = sys.exc_info()
1786bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if info and isinstance(info[1], socket.error):
1796bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if self.options.debug > 1:
1806bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                print >>sys.stderr, "%s: SERVER: ignored socket error." % (sys.argv[0],)
1816bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return
1826bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        BaseHTTPServer.HTTPServer.handle_error(self, request, client_address)
1836bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
1846bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker# Borrowed from Quixote, with simplifications.
1856bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerdef parse_query(qs, fields=None):
1866bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    if fields is None:
1876bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        fields = {}
1886bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    for chunk in filter(None, qs.split('&')):
1896bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if '=' not in chunk:
1906bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            name = chunk
1916bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            value = ''
1926bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        else:
1936bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            name, value = chunk.split('=', 1)
1946bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        name = urllib.unquote(name.replace('+', ' '))
1956bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        value = urllib.unquote(value.replace('+', ' '))
1966bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        item = fields.get(name)
1976bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if item is None:
1986bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            fields[name] = [value]
1996bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        else:
2006bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            item.append(value)
2016bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    return fields
2026bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2036bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerclass ScanViewRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
2046bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    server_version = "ScanViewServer/" + __version__
2056bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    dynamic_mtime = time.time()
2066bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2076bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def do_HEAD(self):
2086bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
2096bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            SimpleHTTPServer.SimpleHTTPRequestHandler.do_HEAD(self)
2106bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except Exception,e:
2116bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.handle_exception(e)
2126bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2136bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def do_GET(self):
2146bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
2156bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
2166bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except Exception,e:
2176bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.handle_exception(e)
2186bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2196bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def do_POST(self):
2206bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        """Serve a POST request."""
2216bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
2226bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            length = self.headers.getheader('content-length') or "0"
2236bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            try:
2246bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                length = int(length)
2256bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            except:
2266bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                length = 0
2276bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            content = self.rfile.read(length)
2286bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            fields = parse_query(content)
2296bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            f = self.send_head(fields)
2306bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if f:
2316bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                self.copyfile(f, self.wfile)
2326bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                f.close()
2336bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except Exception,e:
2346bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.handle_exception(e)
2356bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2366bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def log_message(self, format, *args):
2376bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if self.server.options.debug:
2386bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            sys.stderr.write("%s: SERVER: %s - - [%s] %s\n" %
2396bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                             (sys.argv[0],
2406bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                              self.address_string(),
2416bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                              self.log_date_time_string(),
2426bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                              format%args))
2436bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2446bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def load_report(self, report):
2456bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        path = os.path.join(self.server.root, 'report-%s.html'%report)
2466bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        data = open(path).read()
2476bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        keys = {}
2486bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        for item in kBugKeyValueRE.finditer(data):
2496bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            k,v = item.groups()
2506bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            keys[k] = v
2516bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return keys
2526bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2536bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def load_crashes(self):
2546bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        path = posixpath.join(self.server.root, 'index.html')
2556bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        data = open(path).read()
2566bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        problems = []
2576bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        for item in kReportCrashEntryRE.finditer(data):
2586bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            fieldData = item.group(1)
2596bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            fields = dict([i.groups() for i in
2606bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                           kReportCrashEntryKeyValueRE.finditer(fieldData)])
2616bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            problems.append(fields)
2626bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return problems
2636bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2646bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def handle_exception(self, exc):
2656bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        import traceback
2666bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        s = StringIO.StringIO()
2676bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        print >>s, "INTERNAL ERROR\n"
2686bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        traceback.print_exc(exc, s)
2696bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        f = self.send_string(s.getvalue(), 'text/plain')
2706bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if f:
2716bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.copyfile(f, self.wfile)
2726bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            f.close()
2736bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2746bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def get_scalar_field(self, name):
2756bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if name in self.fields:
2766bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return self.fields[name][0]
2776bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        else:
2786bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return None
2796bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2806bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def submit_bug(self, c):
2816bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        title = self.get_scalar_field('title')
2826bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        description = self.get_scalar_field('description')
2836bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        report = self.get_scalar_field('report')
2846bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        reporterIndex = self.get_scalar_field('reporter')
2856bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        files = []
2866bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        for fileID in self.fields.get('files',[]):
2876bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            try:
2886bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                i = int(fileID)
2896bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            except:
2906bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                i = None
2916bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if i is None or i<0 or i>=len(c.files):
2926bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                return (False, 'Invalid file ID')
2936bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            files.append(c.files[i])
2946bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
2956bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if not title:
2966bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return (False, "Missing title.")
2976bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if not description:
2986bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return (False, "Missing description.")
2996bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
3006bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            reporterIndex = int(reporterIndex)
3016bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except:
3026bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return (False, "Invalid report method.")
3036bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
3046bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Get the reporter and parameters.
3056bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        reporter = self.server.reporters[reporterIndex]
3066bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        parameters = {}
3076bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        for o in reporter.getParameters():
3086bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            name = '%s_%s'%(reporter.getName(),o.getName())
3096bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if name not in self.fields:
3106bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                return (False,
3116bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                        'Missing field "%s" for %s report method.'%(name,
3126bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                                                    reporter.getName()))
3136bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            parameters[o.getName()] = self.get_scalar_field(name)
3146bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
3156bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Update config defaults.
3166bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if report != 'None':
3176bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.server.config.set('ScanView', 'reporter', reporterIndex)
3186bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            for o in reporter.getParameters():
3196bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker              if o.saveConfigValue():
3206bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                name = o.getName()
3216bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                self.server.config.set(reporter.getName(), name, parameters[name])
3226bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
3236bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Create the report.
3246bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        bug = Reporter.BugReport(title, description, files)
3256bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
3266bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Kick off a reporting thread.
3276bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        t = ReporterThread(bug, reporter, parameters, self.server)
3286bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        t.start()
3296bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
3306bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Wait for thread to die...
3316bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        while t.isAlive():
3326bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            time.sleep(.25)
3336bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        submitStatus = t.status
3346bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
3356bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return (t.success, t.status)
3366bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
3376bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def send_report_submit(self):
3386bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        report = self.get_scalar_field('report')
3396bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        c = self.get_report_context(report)
3406bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if c.reportSource is None:
3416bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            reportingFor = "Report Crashes > "
3426bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            fileBug = """\
3436bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<a href="/report_crashes">File Bug</a> > """%locals()
3446bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        else:
3456bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            reportingFor = '<a href="/%s">Report %s</a> > ' % (c.reportSource,
3466bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                                                   report)
3476bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            fileBug = '<a href="/report/%s">File Bug</a> > ' % report
3486bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        title = self.get_scalar_field('title')
3496bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        description = self.get_scalar_field('description')
3506bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
3516bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        res,message = self.submit_bug(c)
3526bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
3536bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if res:
3546bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            statusClass = 'SubmitOk'
3556bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            statusName = 'Succeeded'
3566bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        else:
3576bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            statusClass = 'SubmitFail'
3586bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            statusName = 'Failed'
3596bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
3606bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        result = """
3616bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<head>
3626bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <title>Bug Submission</title>
3636bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <link rel="stylesheet" type="text/css" href="/scanview.css" />
3646bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</head>
3656bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<body>
3666bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<h3>
3676bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<a href="/">Summary</a> >
3686bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%(reportingFor)s
3696bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%(fileBug)s
3706bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerSubmit</h3>
3716bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<form name="form" action="">
3726bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<table class="form">
3736bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<tr><td>
3746bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<table class="form_group">
3756bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<tr>
3766bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_clabel">Title:</td>
3776bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_value">
3786bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    <input type="text" name="title" size="50" value="%(title)s" disabled>
3796bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  </td>
3806bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</tr>
3816bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<tr>
3826bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_label">Description:</td>
3836bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_value">
3846bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<textarea rows="10" cols="80" name="description" disabled>
3856bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%(description)s
3866bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</textarea>
3876bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  </td>
3886bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</table>
3896bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</td></tr>
3906bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</table>
3916bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</form>
3926bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<h1 class="%(statusClass)s">Submission %(statusName)s</h1>
3936bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%(message)s
3946bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<p>
3956bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<hr>
3966bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<a href="/">Return to Summary</a>
3976bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</body>
3986bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</html>"""%locals()
3996bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return self.send_string(result)
4006bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4016bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def send_open_report(self, report):
4026bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
4036bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            keys = self.load_report(report)
4046bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except IOError:
4056bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return self.send_error(400, 'Invalid report.')
4066bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4076bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        file = keys.get('FILE')
4086bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if not file or not posixpath.exists(file):
4096bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return self.send_error(400, 'File does not exist: "%s"' % file)
4106bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4116bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        import startfile
4126bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if self.server.options.debug:
4136bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            print >>sys.stderr, '%s: SERVER: opening "%s"'%(sys.argv[0],
4146bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                                            file)
4156bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4166bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        status = startfile.open(file)
4176bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if status:
4186bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            res = 'Opened: "%s"' % file
4196bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        else:
4206bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            res = 'Open failed: "%s"' % file
4216bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4226bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return self.send_string(res, 'text/plain')
4236bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4246bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def get_report_context(self, report):
4256bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        class Context:
4266bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            pass
4276bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if report is None or report == 'None':
4286bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            data = self.load_crashes()
4296bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            # Don't allow empty reports.
4306bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if not data:
4316bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                raise ValueError, 'No crashes detected!'
4326bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c = Context()
4336bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.title = 'clang static analyzer failures'
4346bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4356bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            stderrSummary = ""
4366bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            for item in data:
4376bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                if 'stderr' in item:
4386bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    path = posixpath.join(self.server.root, item['stderr'])
4396bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    if os.path.exists(path):
4406bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                        lns = itertools.islice(open(path), 0, 10)
4416bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                        stderrSummary += '%s\n--\n%s' % (item.get('src',
4426bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                                                  '<unknown>'),
4436bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                                         ''.join(lns))
4446bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4456bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.description = """\
4466bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerThe clang static analyzer failed on these inputs:
4476bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%s
4486bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4496bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerSTDERR Summary
4506bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker--------------
4516bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%s
4526bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker""" % ('\n'.join([item.get('src','<unknown>') for item in data]),
4536bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker       stderrSummary)
4546bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.reportSource = None
4556bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.navMarkup = "Report Crashes > "
4566bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.files = []
4576bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            for item in data:
4586bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                c.files.append(item.get('src',''))
4596bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                c.files.append(posixpath.join(self.server.root,
4606bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                              item.get('file','')))
4616bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                c.files.append(posixpath.join(self.server.root,
4626bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                              item.get('clangfile','')))
4636bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                c.files.append(posixpath.join(self.server.root,
4646bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                              item.get('stderr','')))
4656bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                c.files.append(posixpath.join(self.server.root,
4666bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                              item.get('info','')))
4676bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            # Just in case something failed, ignore files which don't
4686bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            # exist.
4696bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.files = [f for f in c.files
4706bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                       if os.path.exists(f) and os.path.isfile(f)]
4716bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        else:
4726bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            # Check that this is a valid report.
4736bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            path = posixpath.join(self.server.root, 'report-%s.html' % report)
4746bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if not posixpath.exists(path):
4756bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                raise ValueError, 'Invalid report ID'
4766bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            keys = self.load_report(report)
4776bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c = Context()
4786bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.title = keys.get('DESC','clang error (unrecognized')
4796bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.description = """\
4806bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerBug reported by the clang static analyzer.
4816bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4826bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerDescription: %s
4836bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerFile: %s
4846bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerLine: %s
4856bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker"""%(c.title, keys.get('FILE','<unknown>'), keys.get('LINE', '<unknown>'))
4866bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.reportSource = 'report-%s.html' % report
4876bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.navMarkup = """<a href="/%s">Report %s</a> > """ % (c.reportSource,
4886bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                                                  report)
4896bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4906bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c.files = [path]
4916bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return c
4926bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
4936bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def send_report(self, report, configOverrides=None):
4946bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        def getConfigOption(section, field):
4956bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if (configOverrides is not None and
4966bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                section in configOverrides and
4976bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                field in configOverrides[section]):
4986bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                return configOverrides[section][field]
4996bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return self.server.config.get(section, field)
5006bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
5016bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # report is None is used for crashes
5026bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
5036bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            c = self.get_report_context(report)
5046bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except ValueError, e:
5056bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return self.send_error(400, e.message)
5066bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
5076bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        title = c.title
5086bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        description= c.description
5096bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        reportingFor = c.navMarkup
5106bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if c.reportSource is None:
5116bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            extraIFrame = ""
5126bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        else:
5136bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            extraIFrame = """\
5146bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<iframe src="/%s" width="100%%" height="40%%"
5156bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        scrolling="auto" frameborder="1">
5166bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <a href="/%s">View Bug Report</a>
5176bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</iframe>""" % (c.reportSource, c.reportSource)
5186bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
5196bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        reporterSelections = []
5206bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        reporterOptions = []
5216bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
5226bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
5236bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            active = int(getConfigOption('ScanView','reporter'))
5246bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except:
5256bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            active = 0
5266bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        for i,r in enumerate(self.server.reporters):
5276bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            selected = (i == active)
5286bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if selected:
5296bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                selectedStr = ' selected'
5306bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            else:
5316bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                selectedStr = ''
5326bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            reporterSelections.append('<option value="%d"%s>%s</option>'%(i,selectedStr,r.getName()))
5336bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            options = '\n'.join([ o.getHTML(r,title,getConfigOption) for o in r.getParameters()])
5346bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            display = ('none','')[selected]
5356bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            reporterOptions.append("""\
5366bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<tr id="%sReporterOptions" style="display:%s">
5376bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_label">%s Options</td>
5386bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_value">
5396bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    <table class="form_inner_group">
5406bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%s
5416bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    </table>
5426bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  </td>
5436bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</tr>
5446bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker"""%(r.getName(),display,r.getName(),options))
5456bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        reporterSelections = '\n'.join(reporterSelections)
5466bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        reporterOptionsDivs = '\n'.join(reporterOptions)
5476bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        reportersArray = '[%s]'%(','.join([`r.getName()` for r in self.server.reporters]))
5486bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
5496bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if c.files:
5506bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            fieldSize = min(5, len(c.files))
5516bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            attachFileOptions = '\n'.join(["""\
5526bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<option value="%d" selected>%s</option>""" % (i,v) for i,v in enumerate(c.files)])
5536bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            attachFileRow = """\
5546bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<tr>
5556bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_label">Attach:</td>
5566bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_value">
5576bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<select style="width:100%%" name="files" multiple size=%d>
5586bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%s
5596bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</select>
5606bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  </td>
5616bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</tr>
5626bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker""" % (min(5, len(c.files)), attachFileOptions)
5636bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        else:
5646bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            attachFileRow = ""
5656bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
5666bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        result = """<html>
5676bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<head>
5686bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <title>File Bug</title>
5696bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <link rel="stylesheet" type="text/css" href="/scanview.css" />
5706bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</head>
5716bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<script language="javascript" type="text/javascript">
5726bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickervar reporters = %(reportersArray)s;
5736bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerfunction updateReporterOptions() {
5746bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  index = document.getElementById('reporter').selectedIndex;
5756bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  for (var i=0; i < reporters.length; ++i) {
5766bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    o = document.getElementById(reporters[i] + "ReporterOptions");
5776bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    if (i == index) {
5786bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker      o.style.display = "";
5796bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    } else {
5806bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker      o.style.display = "none";
5816bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    }
5826bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  }
5836bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker}
5846bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</script>
5856bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<body onLoad="updateReporterOptions()">
5866bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<h3>
5876bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<a href="/">Summary</a> >
5886bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%(reportingFor)s
5896bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerFile Bug</h3>
5906bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<form name="form" action="/report_submit" method="post">
5916bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<input type="hidden" name="report" value="%(report)s">
5926bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
5936bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<table class="form">
5946bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<tr><td>
5956bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<table class="form_group">
5966bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<tr>
5976bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_clabel">Title:</td>
5986bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_value">
5996bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    <input type="text" name="title" size="50" value="%(title)s">
6006bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  </td>
6016bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</tr>
6026bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<tr>
6036bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_label">Description:</td>
6046bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_value">
6056bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<textarea rows="10" cols="80" name="description">
6066bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%(description)s
6076bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</textarea>
6086bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  </td>
6096bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</tr>
6106bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6116bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%(attachFileRow)s
6126bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6136bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</table>
6146bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<br>
6156bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<table class="form_group">
6166bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<tr>
6176bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_clabel">Method:</td>
6186bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <td class="form_value">
6196bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    <select id="reporter" name="reporter" onChange="updateReporterOptions()">
6206bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    %(reporterSelections)s
6216bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    </select>
6226bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  </td>
6236bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</tr>
6246bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%(reporterOptionsDivs)s
6256bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</table>
6266bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<br>
6276bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</td></tr>
6286bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker<tr><td class="form_submit">
6296bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker  <input align="right" type="submit" name="Submit" value="Submit">
6306bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</td></tr>
6316bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</table>
6326bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</form>
6336bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6346bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker%(extraIFrame)s
6356bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6366bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</body>
6376bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker</html>"""%locals()
6386bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6396bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return self.send_string(result)
6406bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6416bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def send_head(self, fields=None):
6426bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if (self.server.options.onlyServeLocal and
6436bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.client_address[0] != '127.0.0.1'):
6446bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return self.send_error(401, 'Unauthorized host.')
6456bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6466bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if fields is None:
6476bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            fields = {}
6486bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.fields = fields
6496bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6506bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        o = urlparse.urlparse(self.path)
6516bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.fields = parse_query(o.query, fields)
6526bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        path = posixpath.normpath(urllib.unquote(o.path))
6536bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6546bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Split the components and strip the root prefix.
6556bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        components = path.split('/')[1:]
6566bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6576bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Special case some top-level entries.
6586bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if components:
6596bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            name = components[0]
6606bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if len(components)==2:
6616bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                if name=='report':
6626bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    return self.send_report(components[1])
6636bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                elif name=='open':
6646bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    return self.send_open_report(components[1])
6656bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            elif len(components)==1:
6666bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                if name=='quit':
6676bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    self.server.halt()
6686bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    return self.send_string('Goodbye.', 'text/plain')
6696bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                elif name=='report_submit':
6706bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    return self.send_report_submit()
6716bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                elif name=='report_crashes':
6726bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    overrides = { 'ScanView' : {},
6736bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                  'Radar' : {},
6746bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                  'Email' : {} }
6756bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    for i,r in enumerate(self.server.reporters):
6766bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                        if r.getName() == 'Radar':
6776bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                            overrides['ScanView']['reporter'] = i
6786bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                            break
6796bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    overrides['Radar']['Component'] = 'llvm - checker'
6806bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    overrides['Radar']['Component Version'] = 'X'
6816bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    return self.send_report(None, overrides)
6826bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                elif name=='favicon.ico':
6836bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                    return self.send_path(posixpath.join(kShare,'bugcatcher.ico'))
6846bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6856bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Match directory entries.
6866bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if components[-1] == '':
6876bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            components[-1] = 'index.html'
6886bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6896bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        relpath = '/'.join(components)
6906bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        path = posixpath.join(self.server.root, relpath)
6916bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6926bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if self.server.options.debug > 1:
6936bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            print >>sys.stderr, '%s: SERVER: sending path "%s"'%(sys.argv[0],
6946bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                                                                 path)
6956bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return self.send_path(path)
6966bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
6976bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def send_404(self):
6986bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.send_error(404, "File not found")
6996bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return None
7006bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
7016bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def send_path(self, path):
7026bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # If the requested path is outside the root directory, do not open it
7036bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        rel = os.path.abspath(path)
7046bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if not rel.startswith(os.path.abspath(self.server.root)):
7056bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker          return self.send_404()
7066bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
7076bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        ctype = self.guess_type(path)
7086bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if ctype.startswith('text/'):
7096bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            # Patch file instead
7106bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return self.send_patched_file(path, ctype)
7116bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        else:
7126bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            mode = 'rb'
7136bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
7146bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            f = open(path, mode)
7156bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except IOError:
7166bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return self.send_404()
7176bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return self.send_file(f, ctype)
7186bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
7196bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def send_file(self, f, ctype):
7206bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Patch files to add links, but skip binary files.
7216bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.send_response(200)
7226bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.send_header("Content-type", ctype)
7236bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        fs = os.fstat(f.fileno())
7246bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.send_header("Content-Length", str(fs[6]))
7256bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
7266bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        self.end_headers()
7276bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return f
7286bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
7296bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def send_string(self, s, ctype='text/html', headers=True, mtime=None):
7306bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if headers:
7316bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.send_response(200)
7326bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.send_header("Content-type", ctype)
7336bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.send_header("Content-Length", str(len(s)))
7346bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            if mtime is None:
7356bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                mtime = self.dynamic_mtime
7366bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.send_header("Last-Modified", self.date_time_string(mtime))
7376bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            self.end_headers()
7386bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return StringIO.StringIO(s)
7396bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
7406bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    def send_patched_file(self, path, ctype):
7416bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        # Allow a very limited set of variables. This is pretty gross.
7426bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        variables = {}
7436bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        variables['report'] = ''
7446bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        m = kReportFileRE.match(path)
7456bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        if m:
7466bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            variables['report'] = m.group(2)
7476bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
7486bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        try:
7496bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            f = open(path,'r')
7506bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        except IOError:
7516bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            return self.send_404()
7526bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        fs = os.fstat(f.fileno())
7536bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        data = f.read()
7546bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        for a,b in kReportReplacements:
7556bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker            data = a.sub(b % variables, data)
7566bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker        return self.send_string(data, ctype, mtime=fs.st_mtime)
7576bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
7586bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
7596bdbd720989797e8a53237ef3ef213c4114f869gitbuildkickerdef create_server(address, options, root):
7606bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    import Reporter
7616bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
7626bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    reporters = Reporter.getReporters()
7636bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker
7646bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker    return ScanViewServer(address, ScanViewRequestHandler,
7656bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                          root,
7666bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                          reporters,
7676bdbd720989797e8a53237ef3ef213c4114f869gitbuildkicker                          options)
768