Package Peach :: Package Engine :: Module webwatcher
[hide private]

Source Code for Module Peach.Engine.webwatcher

  1  ''' 
  2  An embeded web server that displays fuzzing status. 
  3   
  4  @authors: Michael Eddington (mike@phed.org) 
  5                    Blake Frantz (blakefrantz@gmail.org) 
  6   
  7  @version: $Id: webwatcher.py 863 2008-05-11 10:25:32Z meddingt $ 
  8  ''' 
  9   
 10  # 
 11  # Copyright (c) 2007-2008 Michael Eddington 
 12  # 
 13  # Permission is hereby granted, free of charge, to any person obtaining a copy  
 14  # of this software and associated documentation files (the "Software"), to deal 
 15  # in the Software without restriction, including without limitation the rights  
 16  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
 17  # copies of the Software, and to permit persons to whom the Software is  
 18  # furnished to do so, subject to the following conditions: 
 19  # 
 20  # The above copyright notice and this permission notice shall be included in     
 21  # all copies or substantial portions of the Software. 
 22  # 
 23  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
 24  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
 25  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
 26  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
 27  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 28  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 29  # SOFTWARE. 
 30  # 
 31   
 32  # Authors: 
 33  #   Michael Eddington (mike@phed.org) 
 34  #       Blake Frantz(blakefrantz@gmail.com) 
 35  # 
 36  # $Id: webwatcher.py 863 2008-05-11 10:25:32Z meddingt $ 
 37   
 38   
 39  import sys, os, time, threading 
 40  from parser import * 
 41  from dom import DomPrint 
 42  from engine import * 
 43  import engine 
 44   
 45  from twisted.web import server, resource, static 
 46  from twisted.internet import reactor 
 47   
48 -class WebHandler(resource.Resource):
49 50 gadgetData = "%RUN_NAME%,%TEST_NAME%,%TEST_COUNT%,%TEST_TOTALCOUNT%,%FAULT_COUNT%" 51 52 html = """ 53 54 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> 55 <html> 56 <head> 57 <meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/> 58 <meta http-equiv="refresh" content="10" /> 59 <title>Peach Run Monitor</title> 60 <style> 61 /*############################################################# 62 Name: Indigo 63 Description: A lightweight (7kb images), simple and professional design. 64 Date: 2006-07-27 65 Author: Viktor Persson 66 URL: http://arcsin.se 67 68 Feel free to use and modify but please provide credits. 69 #############################################################*/ 70 71 /* standard elements */ 72 * { 73 margin: 0; 74 padding: 0; 75 } 76 a { 77 color: #F70; 78 } 79 a:hover { 80 color: #C60; 81 } 82 body { 83 background: #0094D6 url(img/bg.gif) repeat-x; 84 color: #466; 85 font: normal 62.5% "Lucida Sans Unicode",sans-serif; 86 margin: 0; 87 } 88 input { 89 color: #555; 90 font: normal 1.1em "Lucida Sans Unicode",sans-serif; 91 } 92 p,cite,code,ul { 93 font-size: 1.2em; 94 padding-bottom: 1.2em; 95 } 96 h1 { 97 font-size: 1.4em; 98 margin-bottom: 4px; 99 } 100 code { 101 background: url(img/bgcode.gif); 102 border: 1px solid #F0F0F0; 103 border-left: 6px solid #39F; 104 color: #555; 105 display: block; 106 font: normal 1.1em "Lucida Sans Unicode",serif; 107 margin-bottom: 12px; 108 padding: 8px 10px; 109 white-space: pre; 110 } 111 cite { 112 background: url(img/quote.gif) no-repeat; 113 color: #666; 114 display: block; 115 font: normal 1.3em "Lucida Sans Unicode",serif; 116 padding-left: 28px; 117 } 118 h1,h2,h3 { 119 color: #06C; 120 padding-top: 6px; 121 } 122 /* misc */ 123 .clearer { 124 clear: both; 125 } 126 127 /* structure */ 128 .container { 129 background: url(img/topleft.png) no-repeat; 130 } 131 132 .header { 133 height: 92px; 134 } 135 136 /* title */ 137 .title { 138 float: left; 139 padding: 28px 0 0 76px; 140 } 141 .title h1 { 142 color: #FFF; 143 font: normal 2em Verdana,sans-serif; 144 } 145 /* navigation */ 146 .navigation { 147 float: left; 148 height: 92px; 149 margin-left: 24px; 150 padding: 0 16px; 151 } 152 .navigation a { 153 color: #FFF; 154 float: left; 155 font: bold 1.2em "Trebuchet MS",sans-serif; 156 margin-top: 56px; 157 padding: 8px 18px; 158 text-align: center; 159 text-decoration: none; 160 } 161 .navigation a:hover { 162 background-color: #4A91C3; 163 color: #FFF; 164 } 165 166 /* main */ 167 .main { 168 background: #FFF url(img/bgmain.gif) no-repeat; 169 clear: both; 170 padding: 12px 12px 0 52px; 171 } 172 173 /* main left */ 174 .sidenav { 175 float: left; 176 width: 24%; 177 } 178 .sidenav h1 { 179 border-bottom: 1px dashed #DDD; 180 color: #E73; 181 font-size: 1.2em; 182 height: 20px; 183 margin-top: 1.2em; 184 } 185 .sidenav ul { 186 margin: 0; 187 padding: 0; 188 } 189 .sidenav li { 190 border-bottom: 1px dashed #EEE; 191 list-style: none; 192 margin: 0; 193 } 194 .sidenav li a { 195 color: #777; 196 display: block; 197 font-size: 0.9em; 198 padding: 3px 6px 3px 18px; 199 text-decoration: none; 200 } 201 .sidenav li a:hover { 202 color: #111; 203 background: url(img/nav_li.gif) no-repeat; 204 } 205 206 /* content */ 207 .content { 208 float: left; 209 margin-right: 4%; 210 width: 69%; 211 } 212 .content .descr { 213 color: #C60; 214 margin-bottom: 6px; 215 } 216 .content li { 217 list-style: url(img/li.gif); 218 margin-left: 18px; 219 } 220 221 /* search form */ 222 .styled { 223 border: 3px double #E5E5E5; 224 padding: 2px 3px; 225 } 226 .button { 227 border: 1px solid #AAA; 228 margin-left: 5px; 229 padding: 2px 3px; 230 } 231 232 /* footer */ 233 .footer { 234 background: #0094D6 url(img/bgfooter.gif) repeat-x; 235 color: #C1DEF0; 236 font-size: 1.1em; 237 line-height: 40px; 238 text-align: center; 239 } 240 .footer a { 241 color: #FFF; 242 text-decoration: none; 243 } 244 .footer a:hover { 245 color: #FFF; 246 text-decoration: underline; 247 } 248 </style> 249 </head> 250 <body> 251 <div class="container"> 252 <div class="header"> 253 <div class="title"> 254 <h1>Peach Run Monitor</h1> 255 </div> 256 </div> 257 <div class="main"> 258 <div class="content"> 259 <h1>%RUN_NAME% -- %TEST_NAME%</h1> 260 <div class="descr">%TEST_COUNT% of %TEST_TOTALCOUNT% <b>/</b> %FAULT_COUNT% faults detected</div> 261 <p></p> 262 263 <b>Current test case:</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br> 264 <!-- <b>Length</b>: %TEST_VALUE_LENGTH%<br /> --> 265 %TEST_VALUE% 266 267 <br /><br /><br /><br /><br /><br /><br /> 268 <br /><br /><br /><br /><br /><br /><br /> 269 <br /><br /><br /><br /><br /><br /><br /> 270 271 <br /> 272 <br /> 273 <p> 274 </p> 275 </div> 276 <div class="sidenav"> 277 <br /> 278 %FAULTS% 279 <!-- <br /> 280 <p> 281 Fault detected on test case #47<br /> 282 <ul> 283 <li><a href="">Data.txt</a></li> 284 <li><a href="">Debugger.txt</a></li> 285 <li><a href="">Network.pcap</a></li> 286 </ul> 287 </p> --> 288 </div> 289 <div class="clearer"><span> </span></div> 290 </div> 291 </div> 292 <div class="footer">&nbsp;</div> 293 </body> 294 </html>""" 295 296 isLeaf = True 297 298 #def getChild(self, name, request): 299 # if name == '': 300 # return self 301 # 302 # return Resource.getChild(self, name, request) 303 304 ret = "" 305 306 dataUri = re.compile(r"^/stuff/(\d+)_(\d+)_(.*)$") 307 308 #vista gadget uri 309 gadgetDataUri = re.compile(r"^/\?gadgetData") 310
311 - def render_GET(self, request):
312 313 self.parent._lock.acquire() 314 315 try: 316 317 #print repr(request) 318 #print "Uri: " + request.uri 319 m = self.dataUri.search(request.uri) 320 if m != None: 321 # feed back our run data 322 faultIndex = int(m.group(1)) 323 faultKey = m.group(3) 324 325 if faultKey[-3:] == "txt": 326 return "<body><pre>" + self.parent._faultData[faultIndex][1][faultKey] + "</pre></body>" 327 328 else: 329 ret = self.parent._faultData[faultIndex][1][faultKey] 330 331 self.parent._lock.release() 332 return ret 333 334 # support for Vista Gadget 335 m = self.gadgetDataUri.search(request.uri) 336 337 if m != None: 338 ret = self.gadgetData 339 else: 340 ret = self.html 341 342 # swap in values 343 if self.parent._run != None: 344 ret = ret.replace("%RUN_NAME%", self.parent._run.name) 345 else: 346 ret = ret.replace("%RUN_NAME%", "") 347 if self.parent._test != None: 348 ret = ret.replace("%TEST_NAME%", self.parent._test.name) 349 else: 350 ret = ret.replace("%TEST_NAME%", "") 351 if self.parent._variationCount != None: 352 ret = ret.replace("%TEST_COUNT%", str(self.parent._variationCount)) 353 else: 354 ret = ret.replace("%TEST_COUNT%", "") 355 if self.parent._totalVariations!= None: 356 ret = ret.replace("%TEST_TOTALCOUNT%", str(self.parent._totalVariations)) 357 else: 358 ret = ret.replace("%TEST_TOTALCOUNT%", "") 359 if self.parent._value != None: 360 361 buff = "" 362 for value in self.parent._value: 363 if len(value) < 3: 364 continue 365 366 buff += "<b>%s: %s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;length: %d</b><br/><textarea rows=\"20\" cols=\"60\" readonly=\"true\">%s</textarea><br/>" % (value[1], value[0], len(value[2]), repr(value[2])) 367 368 ret = ret.replace("%TEST_VALUE%", buff) 369 else: 370 ret = ret.replace("%TEST_VALUE%", "") 371 372 ret = ret.replace("%FAULT_COUNT%", str(self.parent._faultCount)) 373 374 faultHtml = '' 375 if self.parent._faultCount > 0: 376 # build a fault block 377 378 for i in range(len(self.parent._faultData)): 379 fault = self.parent._faultData[i] 380 381 faultHtml += '<br /><p>Fault detected on test case #' + str(fault[0]) + '<br /><ul>' 382 383 for key in fault[1].keys(): 384 faultHtml += '<li><a href="/stuff/%d_%d_%s">%s</a></li>' % (i, fault[0], key, key) 385 386 faultHtml += '</ul></p>' 387 388 ret = ret.replace("%FAULTS%", faultHtml) 389 390 finally: 391 self.parent._lock.release() 392 393 return str(ret)
394
395 -class PeachWebWatcher(threading.Thread):
396 ''' 397 Base for a class that receives callback when events occur 398 in the Peach Engine. 399 ''' 400
401 - def __init__(self, port = 9001):
402 threading.Thread.__init__(self) 403 404 self._port = port 405 self._run = None 406 self._test = None 407 self._totalVariations = 0 408 self._variationCount = 0 409 self._value = None 410 self._exception = None 411 self._isFinished = False 412 self._lock = threading.Lock() 413 self._faultCount = 0 414 self._faultData = [] 415 416 self.start() 417 418 # This will never work on Liunx/OS X :) 419 try: 420 params = [ 'explorer', "http://127.0.0.1:"+str(self._port)] 421 ret = os.spawnv(os.P_NOWAIT, "c:/windows/explorer.exe", params ) 422 except: 423 pass
424
425 - def run(self):
426 if engine.__file__[1] != ':': 427 imgPath = os.path.dirname(os.path.join(os.getcwd(), engine.__file__)) 428 else: 429 imgPath = os.path.dirname(engine.__file__) 430 imgPath = os.path.join(imgPath, 'img') 431 432 res = static.File(imgPath) 433 handler = WebHandler() 434 435 res.putChild('img', static.File(imgPath)) 436 res.putChild('', handler) 437 res.putChild('stuff', handler) 438 439 #self._site = server.Site(handler) 440 self._site = server.Site(res) 441 handler.parent = self 442 reactor.listenTCP(9001, self._site) 443 print "Listening on port 9001." 444 reactor.run(installSignalHandlers=0)
445
446 - def setTotalVariations(self, totalVariations):
447 self._lock.acquire() 448 self._totalVariations = totalVariations 449 self._lock.release()
450
451 - def OnRunStarting(self, run):
452 self._lock.acquire() 453 self._run = run 454 self._lock.release()
455
456 - def OnRunFinished(self, run):
457 self._lock.acquire() 458 self._isFinished = True 459 self._lock.release() 460 461 print "\n\n --- Type CTRL-BREAK To End Peach Web Server --- \n"
462
463 - def OnTestStarting(self, run, test, totalVariations):
464 self._lock.acquire() 465 self._test = test 466 self._totalVariations = totalVariations 467 self._lock.release()
468
469 - def OnTestFinished(self, run, test):
470 self._lock.acquire() 471 self._test = None 472 self._lock.release()
473
474 - def OnTestCaseStarting(self, run, test, variationCount):
475 pass
476
477 - def OnTestCaseReceived(self, run, test, variationCount, value):
478 pass
479
480 - def OnTestCaseException(self, run, test, variationCount, exception):
481 self._lock.acquire() 482 self._exception = exception 483 self._lock.release()
484
485 - def OnTestCaseFinished(self, run, test, variationCount, actionValues):
486 self._lock.acquire() 487 self._variationCount = variationCount 488 self._value = actionValues 489 self._lock.release()
490
491 - def OnFault(self, run, test, variationCount, monitorData, value):
492 self._faultCount += 1 493 self._faultData.append((variationCount, monitorData))
494 495 496 # end 497