com.subgraph.vega.impl.scanner.state.PathState.java Source code

Java tutorial

Introduction

Here is the source code for com.subgraph.vega.impl.scanner.state.PathState.java

Source

/*******************************************************************************
 * Copyright (c) 2011 Subgraph.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Subgraph - initial API and implementation
 ******************************************************************************/
package com.subgraph.vega.impl.scanner.state;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpUriRequest;

import com.subgraph.vega.api.analysis.IContentAnalyzer;
import com.subgraph.vega.api.analysis.IContentAnalyzerResult;
import com.subgraph.vega.api.analysis.MimeType;
import com.subgraph.vega.api.crawler.ICrawlerResponseProcessor;
import com.subgraph.vega.api.http.requests.IHttpResponse;
import com.subgraph.vega.api.http.requests.IPageFingerprint;
import com.subgraph.vega.api.model.web.IWebPath;
import com.subgraph.vega.api.model.web.IWebPath.PathType;
import com.subgraph.vega.api.scanner.IInjectionModuleContext;
import com.subgraph.vega.api.scanner.IPathState;
import com.subgraph.vega.api.scanner.modules.IBasicModuleScript;
import com.subgraph.vega.impl.scanner.requests.BasicRequestBuilder;
import com.subgraph.vega.impl.scanner.requests.GetParameterRequestBuilder;
import com.subgraph.vega.impl.scanner.requests.IRequestBuilder;
import com.subgraph.vega.impl.scanner.requests.PostParameterRequestBuilder;

public class PathState implements IPathState {

    public static PathState createBasicPathState(ICrawlerResponseProcessor fetchProcessor,
            PathStateManager stateManager, PathState parentState, IWebPath path) {
        final IRequestBuilder rb = new BasicRequestBuilder(path);
        final PathState st = new PathState(fetchProcessor, stateManager, parentState, path, rb);
        if (parentState != null)
            parentState.addChildState(st, true);
        else {
            st.setLocked();
            st.performInitialFetch();
        }
        return st;
    }

    public static PathState createParameterPathState(ICrawlerResponseProcessor fetchProcessor,
            PathState parentState, List<NameValuePair> parameters, int fuzzIndex) {
        if (parentState == null)
            throw new IllegalArgumentException("Parent of parameter path cannot be null");
        final IRequestBuilder rb = new GetParameterRequestBuilder(parentState.getPath(), parameters, fuzzIndex);
        final PathState st = new PathState(fetchProcessor, parentState.getPathStateManager(), parentState,
                parentState.getPath(), rb);
        parentState.addChildState(st, false);
        return st;
    }

    public static PathState createPostParameterPathState(ICrawlerResponseProcessor fetchProcessor,
            PathState parentState, List<NameValuePair> parameters, int fuzzIndex) {
        if (parentState == null)
            throw new IllegalArgumentException("Parent of parameter path cannot be null");
        final IRequestBuilder rb = new PostParameterRequestBuilder(parentState.getPath(), parameters, fuzzIndex);
        final PathState st = new PathState(fetchProcessor, parentState.getPathStateManager(), parentState,
                parentState.getPath(), rb);
        parentState.addChildState(st, false);
        return st;
    }

    private final PathStateManager pathStateManager;
    private final IWebPath path;
    private final PathState parentState;
    private final List<PathState> childStates = new ArrayList<PathState>();
    private final IRequestBuilder requestBuilder;
    private final PathState404 state404;
    private final ICrawlerResponseProcessor initialFetchProcessor;

    private IHttpResponse response;
    private IPageFingerprint pathFingerprint;
    private IPageFingerprint unknownFingerprint;

    private boolean isDone;
    private boolean hasFailed404;
    private boolean hasBadParent;
    private boolean ipsDetected;

    private boolean isSureDirectory;
    private boolean isPageMissing;
    private boolean isBogusParameter;
    private boolean responseVaries;
    private boolean lockedFlag;
    private PathStateParameterManager parameterManager;

    private final Object childCountLock = new Object();
    private int descendantCount = 0;
    private int childCount = 0;

    private PathState(ICrawlerResponseProcessor fetchProcessor, PathStateManager stateManager,
            PathState parentState, IWebPath path, IRequestBuilder requestBuilder) {
        this.initialFetchProcessor = fetchProcessor;
        this.pathStateManager = stateManager;
        this.path = path;
        this.parentState = parentState;
        this.requestBuilder = requestBuilder;
        this.state404 = new PathState404(this);
    }

    @Override
    public PathState getParentState() {
        return parentState;
    }

    private void addChildState(PathState state, boolean checkDup) {
        synchronized (childStates) {
            if (checkDup) {
                for (IPathState cs : childStates) {
                    if (cs.getPath().equals(state.getPath()))
                        return;
                }
            }
            childStates.add(state);
            if (lockedFlag)
                state.setLocked();
            else
                state.performInitialFetch();

            synchronized (childCountLock) {
                childCount += 1;
                incrementDescendants();
            }
        }
    }

    private void incrementDescendants() {
        synchronized (childCountLock) {
            descendantCount += 1;
            if (parentState != null) {
                parentState.incrementDescendants();
            }
        }
    }

    public int getDescendantCount() {
        return descendantCount;
    }

    public int getChildCount() {
        return childCount;
    }

    public synchronized int getDepth() {
        if (parentState == null) {
            return 1;
        } else {
            return 1 + parentState.getDepth();
        }
    }

    public PathStateManager getPathStateManager() {
        return pathStateManager;
    }

    @Override
    public boolean isParametric() {
        return requestBuilder.isFuzzable();
    }

    @Override
    public boolean isDone() {
        return isDone;
    }

    @Override
    public void setDone() {
        isDone = true;
        response = null;
    }

    private void setLocked() {
        lockedFlag = true;
    }

    private void performInitialFetch() {
        final IInjectionModuleContext ctx = new ModuleContext(pathStateManager, requestBuilder, this, 0);
        final HttpUriRequest req = createRequest();

        if (response != null) {
            initialFetchProcessor.processResponse(pathStateManager.getCrawler(), req, response, ctx);
        } else {
            submitRequest(req, initialFetchProcessor, ctx);
        }
    }

    @Override
    public void setBogusParameter() {
        isBogusParameter = true;
    }

    @Override
    public boolean isBogusParameter() {
        return isBogusParameter;
    }

    @Override
    public IWebPath getPath() {
        return path;
    }

    @Override
    public void setUnknownFingerprint(IPageFingerprint fp) {
        unknownFingerprint = fp;
    }

    @Override
    public IPageFingerprint getUnknownFingerprint() {
        return unknownFingerprint;
    }

    public void submitRequest(ICrawlerResponseProcessor callback) {
        final HttpUriRequest req = requestBuilder.createBasicRequest();
        final IInjectionModuleContext ctx = createModuleContext();
        submitRequest(req, callback, ctx);
    }

    public void submitRequest(HttpUriRequest request, ICrawlerResponseProcessor callback) {
        final IInjectionModuleContext ctx = createModuleContext();
        submitRequest(request, callback, ctx);
    }

    public void submitRequest(HttpUriRequest request, ICrawlerResponseProcessor callback,
            IInjectionModuleContext ctx) {
        pathStateManager.getCrawler().submitTask(request, getWrappedCallback(callback), ctx);
    }

    private ICrawlerResponseProcessor getWrappedCallback(ICrawlerResponseProcessor callback) {
        if (pathStateManager.requestLoggingEnabled())
            return CrawlerCallbackWrapper.createLogging(pathStateManager.getRequestLog(), callback);
        else
            return CrawlerCallbackWrapper.create(callback);
    }

    @Override
    public HttpUriRequest createRequest() {
        return requestBuilder.createBasicRequest();
    }

    @Override
    public HttpUriRequest createAlteredRequest(String value, boolean append) {
        return requestBuilder.createAlteredRequest(value, append);
    }

    public boolean hasMaximum404Fingerprints() {
        return state404.hasMaximum404Fingerprints();
    }

    @Override
    public boolean add404Fingerprint(IPageFingerprint fp) {
        return state404.add404Fingerprint(fp);
    }

    @Override
    public boolean isRootPath() {
        return path.getParentPath() == null;
    }

    @Override
    public boolean has404Fingerprints() {
        return state404.has404Fingerprints();
    }

    @Override
    public IPathState get404Parent() {
        return state404.get404Parent();
    }

    @Override
    public boolean has404FingerprintMatching(IPageFingerprint fp) {
        return state404.has404FingerprintMatching(fp);
    }

    @Override
    public boolean hasParent404Fingerprint(IPageFingerprint fp) {
        return state404.hasParent404Fingerprint(fp);
    }

    public void dump404Fingerprints() {
        state404.dumpFingerprints();
    }

    @Override
    public boolean hasParent404FingerprintMatchingThis() {
        return state404.hasParent404Fingerprint(pathFingerprint);
    }

    @Override
    public void setSureDirectory() {
        isSureDirectory = true;
    }

    @Override
    public void clear404Fingerprints() {
        state404.clear404Fingerprints();
    }

    public void setSkip404() {
        state404.setSkip404();
    }

    public boolean getSkip404() {
        return state404.getSkip404();
    }

    @Override
    public boolean isSureDirectory() {
        return isSureDirectory;
    }

    @Override
    public void setResponse(IHttpResponse response) {
        this.response = response;
        if (response != null) {
            this.pathFingerprint = response.getPageFingerprint();
        } else {
            this.pathFingerprint = null;
            return;
        }

        if (response.getResponseCode() == 200) {
            addWebResponseToPath(response);
        }
    }

    private void addWebResponseToPath(IHttpResponse response) {
        final IContentAnalyzer contentAnalyzer = pathStateManager.getContentAnalyzer();
        final IContentAnalyzerResult result = contentAnalyzer.processResponse(response, false, false);
        final URI uri = createRequest().getURI();
        path.addGetResponse(uri.getQuery(), contentAnalyzerResultToMimeString(result));
    }

    private String contentAnalyzerResultToMimeString(IContentAnalyzerResult result) {
        if (result.getSniffedMimeType() != MimeType.MIME_NONE)
            return result.getSniffedMimeType().getCanonicalName();
        else if (result.getDeclaredMimeType() != MimeType.MIME_NONE)
            return result.getDeclaredMimeType().getCanonicalName();
        else
            return null;
    }

    @Override
    public IHttpResponse getResponse() {
        return response;
    }

    public boolean isPageMissing() {
        return isPageMissing;
    }

    @Override
    public void setPageMissing() {
        isPageMissing = true;
    }

    @Override
    public void setResponseVaries() {
        responseVaries = true;
    }

    @Override
    public boolean getResponseVaries() {
        return responseVaries;
    }

    public void debug(String msg) {
        pathStateManager.debug("[" + path.getUri() + "] " + msg);
    }

    @Override
    public IPageFingerprint getPathFingerprint() {
        return pathFingerprint;
    }

    @Override
    public boolean matchesPathFingerprint(IPageFingerprint fp) {
        if (pathFingerprint == null) {
            debug("Whoops no path fingerprint for " + path.getUri() + " : " + this);
            return false;
        }
        return pathFingerprint.isSame(fp);
    }

    @Override
    public int allocateXssId() {
        return pathStateManager.allocateXssId();
    }

    @Override
    public String createXssTag(int xssId) {
        return pathStateManager.createXssTag(xssId);
    }

    @Override
    public String createXssTag(String prefix, int xssId) {
        return pathStateManager.createXssTag(prefix, xssId);
    }

    @Override
    public void registerXssRequest(HttpUriRequest request, int xssId) {
        pathStateManager.registerXssRequest(request, xssId);
    }

    @Override
    public HttpUriRequest getXssRequest(int xssId, int scanId) {
        return pathStateManager.getXssRequest(xssId, scanId);
    }

    @Override
    public NameValuePair getFuzzableParameter() {
        return requestBuilder.getFuzzableParameter();
    }

    @Override
    public void maybeAddParameters(List<NameValuePair> parameters) {
        final PathStateParameterManager pm = getParameterManager();
        synchronized (pm) {
            if (parameters.size() > pathStateManager.getMaxParameterCount()) {
                return;
            } else if (pm.hasParameterList(parameters)) {
                return;
            } else if (pathStateManager.hasExceededLimits(this)) {
                return;
            } else {
                pm.addParameterList(parameters);
            }
        }
    }

    @Override
    public void maybeAddPostParameters(List<NameValuePair> parameters) {
        final PathStateParameterManager pm = getParameterManager();
        synchronized (pm) {
            if (parameters.size() > pathStateManager.getMaxParameterCount()) {
                return;
            }
            if (!pm.hasPostParameterList(parameters))
                pm.addPostParameterList(parameters);
        }
    }

    private synchronized PathStateParameterManager getParameterManager() {
        if (parameterManager == null) {
            parameterManager = new PathStateParameterManager(this);
        }
        return parameterManager;
    }

    @Override
    public void unlockChildren() {
        synchronized (childStates) {
            if (!lockedFlag)
                return;
            lockedFlag = false;
            for (PathState c : childStates) {
                c.performInitialFetch();
            }
        }
    }

    @Override
    public String toString() {
        return "STATE: [" + requestBuilder + "]";
    }

    @Override
    public IInjectionModuleContext createModuleContext() {
        return new ModuleContext(pathStateManager, requestBuilder, this);
    }

    @Override
    public void setFailed404Detection() {
        hasFailed404 = true;
    }

    @Override
    public boolean hasFailed404Detection() {
        return hasFailed404;
    }

    @Override
    public void setBadParentDirectory() {
        hasBadParent = true;
    }

    @Override
    public boolean hasBadParentDirectory() {
        return hasBadParent;
    }

    @Override
    public boolean isIPSDetected() {
        return ipsDetected;
    }

    @Override
    public void setIPSDetected() {
        ipsDetected = true;
    }

    @Override
    public boolean doInjectionChecks() {
        if (isParametric())
            return true;
        else if (path.getPathType() == PathType.PATH_DIRECTORY)
            return pathStateManager.getDirectoryInjectionChecksFlag();
        else
            return pathStateManager.getNonParameterFileInjectionChecksFlag();
    }

    @Override
    public List<IBasicModuleScript> getInjectionModules() {
        return pathStateManager.getInjectionModules();
    }
}