def test_find(self): find_id = random.randint(1, 499) url = URL('http://w3af.org/a/b/foobar.php?foo=123') tag_value = rand_alnum(10) for i in xrange(0, 500): request = HTTPRequest(url, data='a=1') code = 200 if i == find_id: code = 302 hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(code, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(i) h1.response = res if i == find_id: h1.toggle_mark() h1.update_tag(tag_value) h1.save() h2 = HistoryItem() self.assertEqual( len(h2.find([('tag', "%" + tag_value + "%", 'like')])), 1) self.assertEqual(len(h2.find([('code', 302, '=')])), 1) self.assertEqual(len(h2.find([('mark', 1, '=')])), 1) self.assertEqual(len(h2.find([('has_qs', 1, '=')])), 500) self.assertEqual( len(h2.find([('has_qs', 1, '=')], result_limit=10)), 10) results = h2.find( [('has_qs', 1, '=')], result_limit=1, orderData=[('id', 'desc')]) self.assertEqual(results[0].id, 499) search_data = [] search_data.append(('id', find_id + 1, "<")) search_data.append(('id', find_id - 1, ">")) self.assertEqual(len(h2.find(search_data)), 1)
def test_find(self): find_id = random.randint(1, 499) url = URL('http://w3af.org/a/b/foobar.php?foo=123') tag_value = rand_alnum(10) for i in xrange(0, 500): request = HTTPRequest(url, data='a=1') code = 200 if i == find_id: code = 302 hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(code, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(i) h1.response = res if i == find_id: h1.toggle_mark() h1.update_tag(tag_value) h1.save() h2 = HistoryItem() self.assertEqual( len(h2.find([('tag', "%" + tag_value + "%", 'like')])), 1) self.assertEqual(len(h2.find([('code', 302, '=')])), 1) self.assertEqual(len(h2.find([('mark', 1, '=')])), 1) self.assertEqual(len(h2.find([('has_qs', 1, '=')])), 500) self.assertEqual( len(h2.find([('has_qs', 1, '=')], result_limit=10)), 10) results = h2.find( [('has_qs', 1, '=')], result_limit=1, orderData=[('id', 'desc')]) self.assertEqual(results[0].id, 499) search_data = [] search_data.append(('id', find_id + 1, "<")) search_data.append(('id', find_id - 1, ">")) self.assertEqual(len(h2.find(search_data)), 1)
class httpLogTab(RememberingHPaned): """ A tab that shows all HTTP requests and responses made by the framework. :author: Andres Riancho ([email protected]) """ def __init__(self, w3af, padding=10, time_refresh=False): """Init object.""" super(httpLogTab, self).__init__(w3af, "pane-httplogtab", 300) self.w3af = w3af self._padding = padding self._lastId = 0 self._historyItem = HistoryItem() if time_refresh: gobject.timeout_add(1000, self.refresh_results) # Create the main container mainvbox = gtk.VBox() mainvbox.set_spacing(self._padding) # Add the menuHbox, Req/Res viewer and the R/R selector on the bottom self._initSearchBox(mainvbox) self._initFilterBox(mainvbox) self._initReqResViewer(mainvbox) mainvbox.show() # Add everything self.add(mainvbox) self.show() def _initReqResViewer(self, mainvbox): """Create the req/res viewer.""" self._req_res_viewer = ReqResViewer(self.w3af, editableRequest=False, editableResponse=False) self._req_res_viewer.set_sensitive(False) # Create the req/res selector (when a search with more # than one result is done, this window appears) self._sw = gtk.ScrolledWindow() self._sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) self._sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self._lstore = gtk.ListStore(gobject.TYPE_UINT, gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_UINT, gobject.TYPE_STRING, gobject.TYPE_UINT, gobject.TYPE_STRING, gobject.TYPE_FLOAT) # Create tree view self._lstoreTreeview = gtk.TreeView(self._lstore) self._lstoreTreeview.set_rules_hint(True) self._lstoreTreeview.set_search_column(0) self.__add_columns(self._lstoreTreeview) self._lstoreTreeview.show() self._lstoreTreeview.connect('cursor-changed', self._view_in_req_res_viewer) # Popup menu self._rightButtonMenu = None self._lstoreTreeview.connect('button-press-event', self._popupMenu) # # # Selection # treeselection = self._lstoreTreeview.get_selection() treeselection.set_mode(gtk.SELECTION_MULTIPLE) self._sw.add(self._lstoreTreeview) #self._sw.set_sensitive(False) self._sw.show_all() # I want all sections to be resizable self._vpan = RememberingVPaned(self.w3af, "pane-swandrRV", 100) self._vpan.pack1(self._sw) self._vpan.pack2(self._req_res_viewer) self._vpan.show() mainvbox.pack_start(self._vpan) def _popupMenu(self, tv, event): """Generate and show popup menu.""" if event.button != 3: return # creates the whole menu only once if self._rightButtonMenu is None: gm = gtk.Menu() self._rightButtonMenu = gm # the items e = gtk.MenuItem(_("Delete selected items")) e.connect('activate', self._deleteSelected) gm.append(e) gm.show_all() else: gm = self._rightButtonMenu gm.popup(None, None, None, event.button, event.time) return True def _deleteSelected(self, widg=None): """Delete selected transactions.""" ids = [] iters = [] sel = self._lstoreTreeview.get_selection() (model, pathlist) = sel.get_selected_rows() for path in pathlist: iters.append(self._lstore.get_iter(path)) itemNumber = path[0] iid = self._lstore[itemNumber][0] ids.append(iid) for i in iters: self._lstore.remove(i) # TODO Move this action to separate thread for iid in ids: self._historyItem.delete(iid) def _initSearchBox(self, mainvbox): """Init Search box.""" # The search entry self._searchText = gtk.Entry() self._searchText.connect("activate", self.find_request_response) # The button that is used to advanced search filterBtn = gtk.ToggleButton(label=_("_Filter Options")) filterBtn.connect("toggled", self._showHideFilterBox) filterImg = gtk.Image() filterImg.set_from_stock(gtk.STOCK_FIND, gtk.ICON_SIZE_MENU) filterBtn.set_image(filterImg) # Clear button close = gtk.Image() close.set_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_MENU) clearBox = gtk.EventBox() clearBox.add(close) clearBox.connect("button-release-event", self._showAllRequestResponses) # Create the container that has the menu menuHbox = gtk.HBox() menuHbox.set_spacing(self._padding) menuHbox.pack_start(gtk.Label(_("Search:")), False) menuHbox.pack_start(self._searchText) menuHbox.pack_start(clearBox, False) menuHbox.pack_start(filterBtn, False) menuHbox.show_all() mainvbox.pack_start(menuHbox, False, True) def _initFilterBox(self, mainvbox): """Init advanced search options.""" self._advSearchBox = gtk.HBox() self._advSearchBox.set_spacing(self._padding) self.pref = FilterOptions(self) # Filter options self._filterMethods = [ ('GET', 'GET', False), ('POST', 'POST', False), ] filterMethods = OptionList() for method in self._filterMethods: filterMethods.add( opt_factory(method[0], method[2], method[1], "boolean")) self.pref.add_section('methods', _('Request Method'), filterMethods) filterId = OptionList() filterId.add(opt_factory("min", "0", "Min ID", "string")) filterId.add(opt_factory("max", "0", "Max ID", "string")) self.pref.add_section('trans_id', _('Transaction ID'), filterId) filterCodes = OptionList() codes = [ ("1xx", "1xx", False), ("2xx", "2xx", False), ("3xx", "3xx", False), ("4xx", "4xx", False), ("5xx", "5xx", False), ] for code in codes: filterCodes.add(opt_factory(code[0], code[2], code[1], "boolean")) self.pref.add_section('codes', _('Response Code'), filterCodes) filterMisc = OptionList() filterMisc.add(opt_factory("tag", False, "Tag", "boolean")) filterMisc.add( opt_factory("has_qs", False, "Request has Query String", "boolean")) self.pref.add_section('misc', _('Misc'), filterMisc) filterTypes = OptionList() self._filterTypes = [ ('html', 'HTML', False), ('javascript', 'JavaScript', False), ('image', 'Images', False), ('flash', 'Flash', False), ('css', 'CSS', False), ('text', 'Text', False), ] for filterType in self._filterTypes: filterTypes.add( opt_factory(filterType[0], filterType[2], filterType[1], "boolean")) self.pref.add_section('types', _('Response Content Type'), filterTypes) filterSize = OptionList() filterSize.add(opt_factory("resp_size", False, "Not Null", "boolean")) self.pref.add_section('sizes', _('Response Size'), filterSize) self.pref.show() self._advSearchBox.pack_start(self.pref, False, False) self._advSearchBox.hide_all() mainvbox.pack_start(self._advSearchBox, False, False) def __add_columns(self, treeview): """Add columns to main log table.""" model = treeview.get_model() # Column for id's column = gtk.TreeViewColumn(_('ID'), gtk.CellRendererText(), text=0) column.set_sort_column_id(0) treeview.append_column(column) # Column for bookmark #TODO: Find a better way to do this. The "B" and the checkbox aren't nice #what we aim for is something like the stars in gmail. """ renderer = gtk.CellRendererToggle() renderer.set_property('activatable', True) renderer.connect('toggled', self.toggle_bookmark, model) column = gtk.TreeViewColumn(_('B'), renderer) column.add_attribute(renderer, "active", 1) column.set_sort_column_id(1) treeview.append_column(column) """ # Column for METHOD column = gtk.TreeViewColumn(_('Method'), gtk.CellRendererText(), text=2) column.set_sort_column_id(2) treeview.append_column(column) # Column for URI renderer = gtk.CellRendererText() renderer.set_property('ellipsize', pango.ELLIPSIZE_END) column = gtk.TreeViewColumn('URI', renderer, text=3) column.set_sort_column_id(3) column.set_expand(True) column.set_resizable(True) treeview.append_column(column) # Column for Tag renderer = gtk.CellRendererText() #renderer.set_property('ellipsize', pango.ELLIPSIZE_END) renderer.set_property('editable', True) renderer.connect('edited', self.edit_tag, model) column = gtk.TreeViewColumn(_('Tag'), renderer, text=4) column.set_sort_column_id(4) column.set_resizable(True) column.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY) treeview.append_column(column) extColumns = [ (5, _('Code')), (6, _('Message')), (7, _('Content-Length')), (8, _('Content-Type')), (9, _('Time (ms)')), ] for n, title in extColumns: column = gtk.TreeViewColumn(title, gtk.CellRendererText(), text=n) column.set_sort_column_id(n) treeview.append_column(column) def toggle_bookmark(self, cell, path, model): """Toggle bookmark.""" model[path][1] = not model[path][1] historyItem = HistoryItem() historyItem.load(model[path][0]) historyItem.toggle_mark(True) return def edit_tag(self, cell, path, new_text, model): """Edit tag.""" model[path][4] = new_text historyItem = HistoryItem() historyItem.load(model[path][0]) historyItem.update_tag(new_text, True) return def _showHideFilterBox(self, widget): """Show/hide advanced options.""" if not widget.get_active(): self._advSearchBox.hide_all() else: self._advSearchBox.show_all() def _showAllRequestResponses(self, widget=None, event=None): """Show all results.""" self._searchText.set_text("") try: self.find_request_response() except BaseFrameworkException as w3: self._empty_results() return def refresh_results(self): """ TODO: IMPROVEMENT: The find_request_response will read all items from the DB again. If there are no new requests BUT we're already showing 1K of them, all will be read. Not good for performance. """ self.find_request_response(refresh=True) return True def find_request_response(self, widget=None, refresh=False): """Find entries (req/res).""" searchText = self._searchText.get_text() searchText = searchText.strip() search_data = [] # # Search part # if searchText: likePieces = [('url', "%" + searchText + "%", 'like'), ('tag', "%" + searchText + "%", 'like')] search_data.append((likePieces, 'OR')) # # Filter part # # Codes codes = self.pref.get_options('codes') filterCodes = [] for opt in codes: if opt.get_value(): codef = opt.get_name() filterCodes.append(('codef', int(codef[0]), '=')) search_data.append((filterCodes, 'OR')) # IDs try: minId = int(self.pref.get_value('trans_id', 'min')) except: minId = 0 try: maxId = int(self.pref.get_value('trans_id', 'max')) except: maxId = 0 if maxId > 0: search_data.append(('id', maxId, "<")) if minId > 0: search_data.append(('id', minId, ">")) if refresh: search_data.append(('id', self._lastId, ">")) # Sizes if self.pref.get_value('sizes', 'resp_size'): search_data.append(('response_size', 0, ">")) # Tags if self.pref.get_value('misc', 'tag'): search_data.append(('tag', '', "!=")) # has_query_string if self.pref.get_value('misc', 'has_qs'): search_data.append(('has_qs', 0, ">")) # Content type filterTypes = [] for filterType in self._filterTypes: if self.pref.get_value('types', filterType[0]): filterTypes.append( ('content_type', "%" + filterType[0] + "%", 'like')) search_data.append((filterTypes, 'OR')) # Method filterMethods = [] for method in self._filterMethods: if self.pref.get_value('methods', method[0]): filterTypes.append(('method', method[0], '=')) search_data.append((filterMethods, 'OR')) try: # Please see the 5000 below searchResultObjects = self._historyItem.find(search_data, result_limit=5001, order_data=[("id", "") ]) except BaseFrameworkException, w3: self._empty_results() return if len(searchResultObjects) == 0: if not refresh: self._empty_results() return # Please see the 5001 above elif len(searchResultObjects) > 5000: self._empty_results() msg = _('The search you performed returned too many results (') +\ str(len(searchResultObjects)) + ').\n' msg += _('Please refine your search and try again.') self._show_message('Too many results', msg) return else: # show the results in the list view (when first row is selected # that just triggers the req/resp filling. lastItem = searchResultObjects[-1] self._lastId = int(lastItem.id) self._show_list_view(searchResultObjects, appendMode=refresh) self._sw.set_sensitive(True) self._req_res_viewer.set_sensitive(True) if not refresh: self._lstoreTreeview.set_cursor((0, )) return