/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2014 The ZAP Development Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.zaproxy.zap.extension.search;
import java.util.ArrayList;
import java.util.List;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.db.DatabaseException;
import org.parosproxy.paros.model.HistoryReference;
import org.parosproxy.paros.network.HttpMalformedHeaderException;
import org.parosproxy.paros.network.HttpMessage;
import org.zaproxy.zap.extension.httppanel.HttpPanel;
import org.zaproxy.zap.utils.StringUIUtils;
import org.zaproxy.zap.view.table.AbstractCustomColumnHistoryReferencesTableModel;
import org.zaproxy.zap.view.table.AbstractHistoryReferencesTableEntry;
public class SearchResultsTableModel extends
AbstractCustomColumnHistoryReferencesTableModel<SearchResultsTableModel.SearchResultTableEntry> {
private static final long serialVersionUID = 5732679524771190690L;
private static final String MATCH_COLUMN_NAME = Constant.messages.getString("search.results.table.header.match");
private List<SearchResultTableEntry> results = new ArrayList<>();
public SearchResultsTableModel() {
super(new Column[] { Column.HREF_ID, Column.METHOD, Column.URL, Column.CUSTOM });
}
public void addSearchResult(SearchResult sr) {
SearchResultTableEntry previousResult = null;
if (results.size() > 1) {
previousResult = results.get(results.size() - 1);
}
results.add(createSearchResultTableEntry(sr, previousResult));
fireTableRowsInserted(results.size() - 1, results.size() - 1);
}
private static SearchResultTableEntry createSearchResultTableEntry(SearchResult sr, SearchResultTableEntry previousResult) {
HistoryReference hRef = sr.getMessage().getHistoryRef();
Integer historyId = null;
String uri = null;
String stringFound = null;
if (previousResult != null) {
Integer previousId = previousResult.getHistoryId();
if (previousId.intValue() == hRef.getHistoryId()) {
historyId = previousId;
}
if (previousResult.getStringFound().equals(sr.getStringFound())) {
stringFound = previousResult.getStringFound();
}
uri = sr.getMessage().getRequestHeader().getURI().toString();
if (previousResult.getUri().equals(uri)) {
uri = previousResult.getUri();
}
}
if (historyId == null) {
historyId = Integer.valueOf(hRef.getHistoryId());
}
if (stringFound == null) {
stringFound = sr.getStringFound();
}
if (uri == null) {
uri = sr.getMessage().getRequestHeader().getURI().toString();
}
return new SearchResultTableEntry(hRef, historyId, hRef.getMethod(), uri, stringFound, sr);
}
@Override
public void addEntry(SearchResultTableEntry entry) {
}
@Override
public void refreshEntryRow(int historyReferenceId) {
}
@Override
public void removeEntry(int historyReferenceId) {
}
@Override
public SearchResultTableEntry getEntry(int rowIndex) {
return results.get(rowIndex);
}
@Override
public SearchResultTableEntry getEntryWithHistoryId(int historyReferenceId) {
return null;
}
@Override
public int getEntryRowIndex(int historyReferenceId) {
return -1;
}
@Override
public void clear() {
results = new ArrayList<>();
fireTableDataChanged();
}
@Override
public int getRowCount() {
return results.size();
}
@Override
protected Class<?> getColumnClass(Column column) {
return AbstractHistoryReferencesTableEntry.getColumnClass(column);
}
@Override
protected Object getPrototypeValue(Column column) {
return AbstractHistoryReferencesTableEntry.getPrototypeValue(column);
}
@Override
protected Object getCustomValueAt(SearchResultTableEntry entry, int columnIndex) {
return entry.getStringFound();
}
@Override
protected String getCustomColumnName(int columnIndex) {
return MATCH_COLUMN_NAME;
}
@Override
protected Class<String> getCustomColumnClass(int columnIndex) {
return String.class;
}
@Override
protected Object getCustomPrototypeValue(int columnIndex) {
return "A match with some long text";
}
public static class SearchResultTableEntry extends AbstractHistoryReferencesTableEntry {
private static final int MAX_CHARS_FOUND_STRING = 150;
private final Integer historyId;
private final String method;
private final String uri;
private final String stringFound;
private final SearchResult sr;
public SearchResultTableEntry(
HistoryReference historyReference,
Integer historyId,
String method,
String uri,
String stringFound,
SearchResult sr) {
super(historyReference);
this.historyId = historyId;
this.method = method;
this.uri = uri;
String temp;
if (stringFound.length() > MAX_CHARS_FOUND_STRING) {
temp = stringFound.substring(0, MAX_CHARS_FOUND_STRING) + "...";
} else {
temp = stringFound;
}
this.stringFound = StringUIUtils.replaceWithVisibleWhiteSpaceChars(temp);
this.sr = new HistoryReferenceSearchResult(sr, stringFound);
}
@Override
public Integer getHistoryId() {
return historyId;
}
@Override
public String getMethod() {
return method;
}
@Override
public String getUri() {
return uri;
}
public String getStringFound() {
return stringFound;
}
public SearchResult getSearchResult() {
return sr;
}
private class HistoryReferenceSearchResult extends SearchResult {
private List<CachedSearchMatch> matches;
private CachedSearchMatch lastMatch = null;
public HistoryReferenceSearchResult(SearchResult sr, String stringFound) {
super(null, sr.getType(), sr.getRegEx(), stringFound);
matches = new ArrayList<>(1);
matches.add(new CachedSearchMatch(sr.getFirstMatch(null, null)));
}
@Override
public HttpMessage getMessage() {
try {
return getHistoryReference().getHttpMessage();
} catch (DatabaseException | HttpMalformedHeaderException e) {
return null;
}
}
@Override
public SearchMatch getFirstMatch(HttpPanel reqPanel, HttpPanel resPanel) {
if (matches.size() > 0) {
lastMatch = matches.get(0);
return lastMatch;
}
return null;
}
@Override
public SearchMatch getLastMatch(HttpPanel reqPanel, HttpPanel resPanel) {
if (matches.size() > 0) {
lastMatch = matches.get(matches.size() - 1);
return lastMatch;
}
return null;
}
@Override
public SearchMatch getNextMatch() {
if (lastMatch != null) {
int i = matches.indexOf(lastMatch);
if (i >= 0 && i < matches.size() - 1) {
lastMatch = matches.get(i + 1);
return lastMatch;
}
}
return null;
}
@Override
public SearchMatch getPrevMatch() {
if (lastMatch != null) {
int i = matches.indexOf(lastMatch);
if (i >= 1) {
lastMatch = matches.get(i - 1);
return lastMatch;
}
}
return null;
}
}
private class CachedSearchMatch extends SearchMatch {
public CachedSearchMatch(SearchMatch searchMatch) {
super(null, searchMatch.getLocation(), searchMatch.getStart(), searchMatch.getEnd());
}
@Override
public HttpMessage getMessage() {
try {
return getHistoryReference().getHttpMessage();
} catch (DatabaseException | HttpMalformedHeaderException e) {
return null;
}
}
}
}
}