@@ -83,6 +83,7 @@ def deduplicate(seq):
8383
8484
8585class HttpScannerOutput (object ):
86+
8687 def __init__ (self , args ):
8788 # TODO: make separate queues for fast logging
8889 self .args = args
@@ -236,59 +237,63 @@ def write_func(self, worker_id, url, response, exception):
236237 # Acquire lock
237238 self .lock .acquire ()
238239 parsed = self ._parse_response (url , response )
240+ status = parsed ['status' ]
239241
240242 # Calculate progreess
241243 self .urls_scanned += 1
242244 percentage = '{percent:.2%}' .format (percent = float (self .urls_scanned ) / self .args .urls_count )
243245 # TODO: add detailed stats
244246
245247 # Generate and print colored output
246- out = '[%s] [worker:%02i] [%s]\t %s -> %i' % (strnow (), worker_id , percentage , parsed ['url' ], parsed [ ' status' ] )
248+ out = '[%s] [worker:%02i] [%s]\t %s -> %i' % (strnow (), worker_id , percentage , parsed ['url' ], status )
247249 if exception is not None :
248250 out += '(%s)' % str (exception )
249- if parsed [ ' status' ] == 200 :
251+ if status == 200 :
250252 print (Fore .GREEN + out + Fore .RESET )
251- elif 400 <= parsed [ ' status' ] < 500 or parsed [ ' status' ] == - 1 :
253+ elif 400 <= status < 500 or status == - 1 :
252254 print (Fore .RED + out + Fore .RESET )
253255 else :
254256 print (Fore .YELLOW + out + Fore .RESET )
255257
256258 # Write to log file
257259 if self .logger is not None :
258- out = '[worker:%02i] %s %s %i' % (worker_id , url , parsed [ ' status' ] , parsed ['length' ])
260+ out = '[worker:%02i] %s %s %i' % (worker_id , url , status , parsed ['length' ])
259261 if exception is None :
260262 self .logger .info (out )
261263 else :
262264 self .logger .error ("%s %s" % (out , str (exception )))
263265
264266 # Check for exception
265- if exception is not None :
266- self .lock .release ()
267- return
267+ if exception is None :
268+ self ._filter_and_write (url , response , parsed )
269+
270+ # Realse lock
271+ self .lock .release ()
268272
273+ def _filter_and_write (self , url , response , parsed ):
269274 # Filter responses and save responses that are matching ignore, allow rules
270275 if (self .args .allow is None and self .args .ignore is None ) or \
271276 (self .args .allow is not None and parsed ['status' ] in self .args .allow ) or \
272277 (self .args .ignore is not None and parsed ['status' ] not in self .args .ignore ):
278+ self ._write_csv (parsed )
279+ self ._write_json (parsed )
280+ self ._write_dump (url , response )
281+ self ._write_db (parsed )
282+
283+ def _write_csv (self , parsed ):
284+ # Write to CSV file
285+ if self .csv is None :
286+ return
273287
274- # Write to CSV file
275- if self .csv is not None :
276- self .csv .writerow ([parsed ['url' ], parsed ['status' ], parsed ['length' ], parsed ['headers' ]])
277-
278- # Write to JSON file
279- if self .json is not None :
280- self .json .write (unicode (dumps (parsed , ensure_ascii = False )))
281-
282- # Save contents to file
283- if self .dump is not None :
284- self ._write_dump (url , response )
288+ self .csv .writerow ([parsed ['url' ], parsed ['status' ], parsed ['length' ], parsed ['headers' ]])
285289
286- # Write to database
287- if self .engine is not None :
288- self ._write_db (parsed )
290+ def _write_json (self , parsed ):
291+ # Write to JSON file
292+ if self .json is None :
293+ return
289294
290- # Realse lock
291- self .lock . release ( )
295+ # TODO: bugfix appending json
296+ self .json . write ( unicode ( dumps ( parsed , ensure_ascii = False )) )
292297
293298 def _write_dump (self , url , response ):
294299 """
@@ -297,7 +302,7 @@ def _write_dump(self, url, response):
297302 :param response: response
298303 :return: None
299304 """
300- if response is None :
305+ if response is None or self . dump is None :
301306 return
302307
303308 # Generate folder and file path
@@ -322,6 +327,8 @@ def _write_dump(self, url, response):
322327 f .close ()
323328
324329 def _write_db (self , parsed ):
330+ if self .engine is None :
331+ return
325332 # TODO: check if url exists in table
326333 self .scan_table .insert ()
327334 self .engine .execute (self .scan_table .insert ().execution_options (autocommit = True ), parsed )
@@ -556,18 +563,11 @@ def _scan_host(self, worker_id, host):
556563 errors_count += 1
557564
558565 if self .args .skip is not None and errors_count == self .args .skip :
559- self .output .logger . warning ('Errors limit reached on %s Skipping other urls.' % host )
566+ self .output .write_log ('Errors limit reached on %s Skipping other urls.' % host , logging . WARNING )
560567 self .output .urls_scanned += len (self .urls ) - urls_scanned
561568 return
562569
563- def _scan_url (self , worker_id , url , use_head = False ):
564- """
565- Scan specified URL with HTTP GET request
566- :param url: url to scan
567- :return: HTTP response
568- """
569- self .output .write_log ('Scanning %s' % url , logging .DEBUG )
570-
570+ def _fill_headers (self ):
571571 # Fill UserAgent in headers
572572 headers = {}
573573 if self .args .user_agent is not None :
@@ -579,29 +579,39 @@ def _scan_url(self, worker_id, url, use_head=False):
579579 if self .args .referer is not None :
580580 headers ['Referer' ] = self .args .referer
581581
582+ return headers
583+
584+ def _scan_url (self , worker_id , url , use_head = False ):
585+ """
586+ Scan specified URL with HTTP GET request
587+ :param url: url to scan
588+ :return: HTTP response
589+ """
590+ self .output .write_log ('Scanning %s' % url , logging .DEBUG )
591+
582592 # Query URL and handle exceptions
583593 response , exception = None , None
584594 try :
585595 # TODO: add support for user:password in URL
586596 if use_head :
587- response = self .session .head (url , headers = headers , allow_redirects = self .args .allow_redirects )
597+ response = self .session .head (url , headers = self . _fill_headers () , allow_redirects = self .args .allow_redirects )
588598 else :
589- response = self .session .get (url , headers = headers , allow_redirects = self .args .allow_redirects )
590- except ConnectionError as e :
599+ response = self .session .get (url , headers = self . _fill_headers () , allow_redirects = self .args .allow_redirects )
600+ except ConnectionError as ex :
591601 self .output .write_log ('Connection error while quering %s' % url , logging .ERROR )
592- exception = e
593- except HTTPError as e :
602+ exception = ex
603+ except HTTPError as ex :
594604 self .output .write_log ('HTTP error while quering %s' % url , logging .ERROR )
595- exception = e
596- except Timeout as e :
605+ exception = ex
606+ except Timeout as ex :
597607 self .output .write_log ('Timeout while quering %s' % url , logging .ERROR )
598- exception = e
599- except TooManyRedirects as e :
608+ exception = ex
609+ except TooManyRedirects as ex :
600610 self .output .write_log ('Too many redirects while quering %s' % url , logging .ERROR )
601- exception = e
602- except Exception as e :
611+ exception = ex
612+ except Exception as ex :
603613 self .output .write_log ('Unknown exception while quering %s' % url , logging .ERROR )
604- exception = e
614+ exception = ex
605615
606616 self .output .write (worker_id , url , response , exception )
607617 return response if exception is None else None
0 commit comments