768 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			768 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 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'
 | |
| 
 | |
|         relpath = '/'.join(components)
 | |
|         path = posixpath.join(self.server.root, relpath)
 | |
| 
 | |
|         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):
 | |
|         # If the requested path is outside the root directory, do not open it
 | |
|         rel = os.path.abspath(path)
 | |
|         if not rel.startswith(os.path.abspath(self.server.root)):
 | |
|           return self.send_404()
 | |
|         
 | |
|         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)
 | 
