org.zaproxy.zap.scan.BaseScannerThread Maven / Gradle / Ivy
Show all versions of zap Show documentation
/*
* 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.scan;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* The base implementation that needs to be extended for a thread that is used to run a Scan.
*
* This abstract implementation handles common elements that correspond to all scans (scan
* progress, scan maximum progress, running/paused state, start options), but should be extended to
* take into consideration particular needs of the scan.
*
*
An important characteristic of the scanner threads is that they are based on a set of start
* options ({@link ScanStartOptions}) that should be used for fully specifying the configuration for
* a particular scan. The scan options should be provided to the Scanner Thread before being started
* via the {@link #setStartOptions(ScanStartOptions)} method. Examples of configuration required
* might include: context and/or site node to scan, user to scan as, policy etc.
*
*
The most important method that needs to be implemented is {@link #scan()}, but other common
* methods should be implemented as well, calling the {@code super} implementation:
*
*
* - {@link #pauseScan()}
*
- {@link #resumeScan()}
*
- {@link #startScan()}
*
- {@link #stopScan()}
*
*
* @param the type of the start scan options
* @see ScanStartOptions
* @see ScannerThreadManager
*/
public abstract class BaseScannerThread extends Thread {
private StartOptions startOptions;
private int progress = 0;
private int maximumProgress = 100;
private boolean paused;
private boolean running;
/** The pause lock, used for locking access to the "paused" variable. */
private ReentrantLock pauseLock = new ReentrantLock();
/**
* The condition that is used to wait on, when the scan is paused. When the scan is resumed, all
* the waiting threads are awakened.
*/
private Condition pausedCondition = pauseLock.newCondition();
/**
* Gets the start options.
*
* @return the start options
*/
public StartOptions getStartOptions() {
return startOptions;
}
/**
* Sets the start options.
*
* @param startOptions the new start options
*/
public void setStartOptions(StartOptions startOptions) {
this.startOptions = startOptions;
}
/**
* Gets the scan's progress, on a scale from 0 to {@link #getScanMaximumProgress()}.
*
* @return the scan progress
*/
public int getScanProgress() {
return progress;
}
/**
* Sets the scan's progress, on a scale from 0 to {@link #getScanMaximumProgress()}.
*
* @param progress the new scan progress
*/
public void setScanProgress(int progress) {
this.progress = progress;
}
/**
* Sets the scan's maximum progress.
*
* @param maximumProgress the new scan maximum progress
*/
public void setScanMaximumProgress(int maximumProgress) {
this.maximumProgress = maximumProgress;
}
/**
* Gets the scan's maximum progress.
*
* @return the scan maximum progress
*/
public int getScanMaximumProgress() {
return maximumProgress;
}
/**
* Checks if is paused.
*
* @return true, if is paused
*/
public boolean isPaused() {
return paused;
}
/**
* Checks if is running.
*
* @return true, if is running
*/
public boolean isRunning() {
return running;
}
/**
* Sets the paused state of the thread and, if the thread needs to be resumed and was paused and
* sleeping, it gets signaled.
*
* @param paused whether the thread should be paused or not
* @see #checkPausedAndWait()
*/
public void setPaused(boolean paused) {
// Make use of a lock when modifying the paused variable to avoid any race conditions
pauseLock.lock();
this.paused = paused;
// Wake up all threads that are currently paused
if (!this.paused) pausedCondition.signalAll();
pauseLock.unlock();
}
/**
* Checks whether the scan is paused and, if it is, sleeps until it's resumed. Internally, this
* method makes use of threading synchronization features ({@link ReentrantLock} and {@link
* Condition}) to cause the calling thread to wait, if needed. Thus, it is mandatory to
* eventually call {@link #setPaused(boolean) setPaused(false)} from another thread to wake the
* calling thread.
*
* @see #setPaused(boolean)
*/
protected void checkPausedAndWait() {
pauseLock.lock();
// While the status is paused, keep waiting
while (paused) {
try {
pausedCondition.await();
} catch (InterruptedException e) {
}
}
pauseLock.unlock();
}
/**
* Sets the running state of the thread.
*
* @param running whether the thread is running or not
*/
public void setRunningState(boolean running) {
this.running = running;
}
/**
* Checks if the scanner thread has already run/been started. Useful as a Java Thread cannot be
* restarted.
*
* @return true, if successful
*/
public boolean hasRun() {
return getState() != State.NEW;
}
@Override
public void run() {
this.startScan();
}
/**
* Method called when the scan is paused. The base implementation handles the update of the
* thread's paused state, but should be overridden if necessary.
*
* Note: Implementations must be careful to make sure the scan actually gets paused (either
* by overriding this method or by constantly checking the {@link #isPaused()} status or using
* the {@link #checkPausedAndWait()} method in the {@link #scan()} method).
*
*
Note: This method is not always run on the scanner thread.
*
* @see #setPaused(boolean)
*/
public void pauseScan() {
setPaused(true);
}
/**
* Method called when the scan is resumed. The base implementation handles the update of the
* thread's paused state, but should be overridden if necessary.
*
*
Note: Implementations must be careful to make sure the scan actually gets paused (either
* by overriding this method or by constantly checking the {@link #isPaused()} status or using
* the {@link #checkPausedAndWait()} method in the {@link #scan()} method).
*
*
Note: This method is not always run on the scanner thread.
*
* @see #setPaused(boolean)
*/
public void resumeScan() {
setPaused(false);
}
/**
* Method called when the scan is stopped before it finished. The base implementation handles
* the update of the thread's running state, but should be overridden if necessary. If the
* thread is now stopped, also updates the paused state to {@code false}, to make sure that, if
* the thread was sleeping, it gets awakened.
*
*
Note: Implementations must be careful to make sure the scan is stopped and the thread
* finishes (either by overriding this method or by constantly checking the {@link #isRunning()}
* status in the {@link #scan()} method).
*
*
Note: This method is not always run on the scanner thread.
*/
public void stopScan() {
setPaused(false);
setRunningState(false);
}
/**
* Method called when the scan is started. The base implementation handles the update of the
* thread's running state and calls the {@link #scan()} method.
*
*
Note: This method is being run on the scanner thread.
*/
public void startScan() {
setRunningState(true);
this.scan();
}
@Override
public synchronized void start() {
// Make sure start options have been set.
if (startOptions == null) {
throw new IllegalStateException(
"No scan start options have been set for the Scanner thread.");
}
super.start();
}
/** Method called on the scanner thread in order to perform the work required by the scan. */
protected abstract void scan();
}