All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.owasp.html.HtmlChangeReporter Maven / Gradle / Ivy

There is a newer version: 20240325.1
Show newest version
// Copyright (c) 2011, Mike Samuel
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// Neither the name of the OWASP nor the names of its contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package org.owasp.html;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Nullable;

/**
 * Sits between the HTML parser, the policy, and the renderer so that it
 * can report dropped elements and attributes to an {@link HtmlChangeListener}.
 *
 * 
 * HtmlChangeReporter<T> hcr = new HtmlChangeReporter<T>(
 *   renderer, htmlChangeListener, context);
 * hcr.setPolicy(policyFactory.apply(hcr.getWrappedRenderer()));
 * HtmlSanitizer.sanitize(html, hcr.getWrappedPolicy());
 * 
* * The renderer receives events from the policy unchanged, but the reporter * notices differences between the events from the lexer and those from the * policy. * * @param The type of context value passed to the */ public final class HtmlChangeReporter { private final OutputChannel output; private final InputChannel input; /** * @param context forwarded to listener along with any reports. */ public HtmlChangeReporter( HtmlStreamEventReceiver renderer, HtmlChangeListener listener, @Nullable T context) { this.output = new OutputChannel(renderer); this.input = new InputChannel(output, listener, context); } /** * Associates an input channel. {@code this} receives events and forwards * them to input. */ public void setPolicy(HtmlSanitizer.Policy policy) { this.input.policy = policy; } /** * The underlying renderer. */ public HtmlStreamEventReceiver getWrappedRenderer() { return output; } /** * The underlying policy. */ public HtmlSanitizer.Policy getWrappedPolicy() { return input; } private static final class InputChannel implements HtmlSanitizer.Policy { HtmlStreamEventReceiver policy; final OutputChannel output; final T context; final HtmlChangeListener listener; InputChannel( OutputChannel output, HtmlChangeListener listener, @Nullable T context) { this.output = output; this.context = context; this.listener = listener; } public void openDocument() { policy.openDocument(); } public void closeDocument() { policy.closeDocument(); } public void openTag(String elementName, List attrs) { output.expectedElementName = elementName; output.expectedAttrNames.clear(); for (int i = 0, n = attrs.size(); i < n; i += 2) { output.expectedAttrNames.add(attrs.get(i)); } policy.openTag(elementName, attrs); { // Gather the notification details to avoid any problems with the // listener re-entering the stream event receiver. This shouldn't // occur, but if it does it will be a source of subtle confusing bugs. String discardedElementName = output.expectedElementName; output.expectedElementName = null; int nExpected = output.expectedAttrNames.size(); String[] discardedAttrNames = nExpected != 0 && discardedElementName == null ? output.expectedAttrNames.toArray(new String[nExpected]) : ZERO_STRINGS; output.expectedAttrNames.clear(); // Dispatch notifications to the listener. if (discardedElementName != null) { listener.discardedTag(context, discardedElementName); } if (discardedAttrNames.length != 0) { listener.discardedAttributes( context, elementName, discardedAttrNames); } } } public void closeTag(String elementName) { policy.closeTag(elementName); } public void text(String textChunk) { policy.text(textChunk); } private static final String[] ZERO_STRINGS = new String[0]; } private static final class OutputChannel implements HtmlStreamEventReceiver { private final HtmlStreamEventReceiver renderer; String expectedElementName; Set expectedAttrNames = new LinkedHashSet(); OutputChannel(HtmlStreamEventReceiver renderer) { this.renderer = renderer; } public void openDocument() { renderer.openDocument(); } public void closeDocument() { renderer.closeDocument(); } public void openTag(String elementName, List attrs) { if (elementName.equals(expectedElementName)) { expectedElementName = null; } for (int i = 0, n = attrs.size(); i < n; i += 2) { expectedAttrNames.remove(attrs.get(i)); } renderer.openTag(elementName, attrs); } public void closeTag(String elementName) { renderer.closeTag(elementName); } public void text(String text) { renderer.text(text); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy