/* * Created on Jun 17, 2004 * * Paros and its related class files. * * Paros is an HTTP/HTTPS proxy for assessing web application security. * Copyright (C) 2003-2004 Chinotec Technologies Company * * This program is free software; you can redistribute it and/or * modify it under the terms of the Clarified Artistic License * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Clarified Artistic License for more details. * * You should have received a copy of the Clarified Artistic License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // ZAP: 2012/03/15 Changed the method addHistory to use the class StringBuilder // instead of StringBuffer. Added the method getProxyListenerOrder. // ZAP: 2012/04/25 Added @Override annotation to all appropriate methods. // ZAP: 2012/07/29 Issue 43: Cleaned up access to ExtensionHistory UI // ZAP: 2013/01/25 Removed the "(non-Javadoc)" comments. // ZAP: 2013/03/03 Issue 546: Remove all template Javadoc comments // ZAP: 2013/11/16 Issue 869: Differentiate proxied requests from (ZAP) user requests // ZAP: 2015/04/02 Issue 1582: Low memory option // ZAP: 2015/09/07 Issue 1872: EDT accessed in daemon mode // ZAP: 2016/05/30 Issue 2494: ZAP Proxy is not showing the HTTP CONNECT Request in history tab package org.parosproxy.paros.extension.history; import java.awt.EventQueue; import org.apache.log4j.Logger; import org.parosproxy.paros.Constant; import org.parosproxy.paros.core.proxy.ConnectRequestProxyListener; import org.parosproxy.paros.core.proxy.ProxyListener; import org.parosproxy.paros.extension.ViewDelegate; import org.parosproxy.paros.model.HistoryReference; import org.parosproxy.paros.model.Model; import org.parosproxy.paros.network.HttpHeader; import org.parosproxy.paros.network.HttpMessage; import org.parosproxy.paros.network.HttpStatusCode; import org.parosproxy.paros.view.View; import org.zaproxy.zap.model.SessionStructure; public class ProxyListenerLog implements ProxyListener, ConnectRequestProxyListener { // ZAP: Added logger private static final Logger log = Logger.getLogger(ProxyListenerLog.class); // ZAP: Must be the last one of all listeners to be notified, as is the one that saves the HttpMessage // to the DB and must let other listeners change ase' and testthe HttpMessage before saving it. // Note: other listeners can be notified after this one but they shouldn't change the HttpMessage // as that changes will not be saved to the DB. public static final int PROXY_LISTENER_ORDER = 5000; private ViewDelegate view = null; private Model model = null; private boolean isFirstAccess = true; private ExtensionHistory extension = null; public ProxyListenerLog(Model model, ViewDelegate view, ExtensionHistory extension) { this.model = model; this.view = view; this.extension = extension; } // ZAP: Added method. @Override public int getArrangeableListenerOrder() { return PROXY_LISTENER_ORDER; } @Override public boolean onHttpRequestSend(HttpMessage msg) { // if (msg.getRequestHeader().isImage()) { // return; // } HttpMessage existingMsg = model.getSession().getSiteTree().pollPath(msg); // check if a msg of the same type exist if (existingMsg != null && !existingMsg.getResponseHeader().isEmpty()) { if (HttpStatusCode.isSuccess(existingMsg.getResponseHeader().getStatusCode())) { // exist, no modification necessary return true; } } // if not, make sure a new copy will be obtained if (msg.getRequestHeader().getHeader(HttpHeader.IF_MODIFIED_SINCE) != null) { msg.getRequestHeader().setHeader(HttpHeader.IF_MODIFIED_SINCE, null); } if (msg.getRequestHeader().getHeader(HttpHeader.IF_NONE_MATCH) != null) { msg.getRequestHeader().setHeader(HttpHeader.IF_NONE_MATCH, null); } return true; } @Override public boolean onHttpResponseReceive(final HttpMessage msg) { int type = HistoryReference.TYPE_PROXIED; if (isSkipImage(msg.getRequestHeader()) || isSkipImage(msg.getResponseHeader())) { if (msg.getResponseHeader().getStatusCode() == HttpStatusCode.OK) { type = HistoryReference.TYPE_HIDDEN; } else { return true; } } final int finalType = type; Thread t = new Thread(new Runnable() { @Override public void run() { createAndAddMessage(msg, finalType); } }); t.start(); return true; } public boolean isSkipImage(HttpHeader header) { if (header.isImage() && !model.getOptionsParam().getViewParam().isProcessImages()) { return true; } return false; } private void createAndAddMessage(HttpMessage msg, int type) { HistoryReference historyRef = createHistoryReference(msg, type); if (historyRef == null || (type != HistoryReference.TYPE_PROXIED && type != HistoryReference.TYPE_HIDDEN)) { return; } extension.addHistory(historyRef); addToSiteMap(historyRef, msg); } private HistoryReference createHistoryReference(HttpMessage message, int type) { try { return new HistoryReference(model.getSession(), type, message); } catch (Exception e) { // ZAP: Log exceptions log.warn(e.getMessage(), e); } return null; } private void addToSiteMap(final HistoryReference ref, final HttpMessage msg) { if (View.isInitialised() && !EventQueue.isDispatchThread()) { try { EventQueue.invokeAndWait(new Runnable() { @Override public void run() { addToSiteMap(ref, msg); } }); } catch (Exception e) { // ZAP: Log exceptions log.warn(e.getMessage(), e); } return; } SessionStructure.addPath(model.getSession(), ref, msg); if (isFirstAccess && !Constant.isLowMemoryOptionSet()) { isFirstAccess = false; if (View.isInitialised()) { view.getSiteTreePanel().expandRoot(); } } } @Override public void receivedConnectRequest(final HttpMessage connectMessage) { if (!model.getOptionsParam().getViewParam().isShowLocalConnectRequests()) { return; } Thread t = new Thread(new Runnable() { @Override public void run() { HistoryReference historyRef = createHistoryReference(connectMessage, HistoryReference.TYPE_PROXY_CONNECT); if (historyRef != null) { extension.addHistory(historyRef); } } }); t.start(); } }