private static boolean isInvalidEmptyElementTag(final StartTagType startTagType, final Source source, final int i, final String logType, final String tagName, final int logBegin) { // This checks whether we've found the characters "/>" but it wasn't recognised as the closing delimiter because isClosingSlashIgnored is true. if (startTagType!=StartTagType.NORMAL || !startTagType.atEndOfAttributes(source,i,false)) return false; if (source.logger.isErrorEnabled()) log(source,logType,tagName,logBegin,"contains a '/' character before the closing '>', which is ignored because tags of this name cannot be empty-element tags"); return true; }
/** * Returns the segment between the end of the tag's {@linkplain #getName() name} and the start of its <a href="#EndDelimiter">end delimiter</a>. * <p> * This method is normally only of use for start tags whose content is something other than {@linkplain #getAttributes() attributes}. * <p> * A new {@link Segment} object is created with each call to this method. * * @return the segment between the end of the tag's {@linkplain #getName() name} and the start of the <a href="#EndDelimiter">end delimiter</a>. */ public Segment getTagContent() { return new Segment(source,begin+1+name.length(),end-startTagType.getClosingDelimiter().length()); }
StringBuilder appendDebugTagType(final StringBuilder sb) { if (startTagType!=StartTagType.NORMAL) sb.append('(').append(startTagType.getDescription()).append(") "); return sb; }
/** * Indicates whether a matching end tag is required. * <p> * This property returns <code>true</code> if one of the following conditions is met: * <ul> * <li>The {@linkplain #getStartTagType() type} of this start tag is NOT {@link StartTagType#NORMAL}, but specifies a * {@linkplain StartTagType#getCorrespondingEndTagType() corresponding end tag type}. * <li>The {@linkplain #getName() name} of this start tag indicates it is the start of an * <a href="Element.html#HTML">HTML element</a> whose {@linkplain HTMLElements#getEndTagRequiredElementNames() end tag is required}. * <li>This start tag is NOT {@linkplain #isSyntacticalEmptyElementTag() syntactically an empty-element tag} and its * {@linkplain #getName() name} indicates it is the start of a <a href="HTMLElements.html#NonHTMLElement">non-HTML element</a>. * </ul> * * @return <code>true</code> if a matching end tag is required, otherwise <code>false</code>. */ public boolean isEndTagRequired() { if (getStartTagType()!=StartTagType.NORMAL) return getStartTagType().getCorrespondingEndTagType()!=null; if (HTMLElements.getEndTagRequiredElementNames().contains(name)) return true; if (HTMLElements.getElementNames().contains(name)) return false; return !isSyntacticalEmptyElementTag(); }
/** * Constructs a new <code>StartTagType</code> object with the specified properties. * <br />(<a href="TagType.html#ImplementationAssistance">implementation assistance</a> method) * <p> * As <code>StartTagType</code> is an abstract class, this constructor is only called from sub-class constructors. * * @param description a {@linkplain #getDescription() description} of the new start tag type useful for debugging purposes. * @param startDelimiter the {@linkplain #getStartDelimiter() start delimiter} of the new start tag type. * @param closingDelimiter the {@linkplain #getClosingDelimiter() closing delimiter} of the new start tag type. * @param correspondingEndTagType the {@linkplain #getCorrespondingEndTagType() corresponding end tag type} of the new start tag type. * @param isServerTag indicates whether the new start tag type is a {@linkplain #isServerTag() server tag}. * @param hasAttributes indicates whether the new start tag type {@linkplain #hasAttributes() has attributes}. * @param isNameAfterPrefixRequired indicates whether a {@linkplain #isNameAfterPrefixRequired() name is required after the prefix}. */ protected StartTagType(final String description, final String startDelimiter, final String closingDelimiter, final EndTagType correspondingEndTagType, final boolean isServerTag, final boolean hasAttributes, final boolean isNameAfterPrefixRequired) { super(description,startDelimiter.toLowerCase(),closingDelimiter,isServerTag,START_DELIMITER_PREFIX); if (!getStartDelimiter().startsWith(START_DELIMITER_PREFIX)) throw new IllegalArgumentException("startDelimiter of a start tag must start with \""+START_DELIMITER_PREFIX+'"'); this.correspondingEndTagType=correspondingEndTagType; this.hasAttributes=hasAttributes; this.isNameAfterPrefixRequired=isNameAfterPrefixRequired; }
private static ElementHandler getElementHandler(final Element element) { if (element.getStartTag().getStartTagType().isServerTag()) return RemoveElementHandler.INSTANCE; // hard-coded configuration does not include server tags in child element hierarchy, so this is normally not executed. ElementHandler elementHandler=ELEMENT_HANDLERS.get(element.getName()); return (elementHandler!=null) ? elementHandler : StandardInlineElementHandler.INSTANCE; }
/** * Constructs a {@code PassiveScanThread} with the given data. * * @param passiveScannerList the passive scanners, must not be {@code null}. * @param extHist the extension to obtain the (cached) history references, might be {@code null}. * @param extensionAlert the extension used to raise the alerts, must not be {@code null}. * @param pscanOptions the passive scanner options, must not be {@code null}. * @since 2.6.0 */ public PassiveScanThread (PassiveScannerList passiveScannerList, ExtensionHistory extHist, ExtensionAlert extensionAlert, PassiveScanParam pscanOptions) { super("ZAP-PassiveScanner"); this.setDaemon(true); if (extensionAlert == null) { throw new IllegalArgumentException("Parameter extensionAlert must not be null."); } this.scannerList = passiveScannerList; MicrosoftTagTypes.register(); PHPTagTypes.register(); PHPTagTypes.PHP_SHORT.deregister(); // remove PHP short tags otherwise they override processing instructions MasonTagTypes.register(); extAlert = extensionAlert; this.extHist = extHist; this.pscanOptions = pscanOptions; }
return !StartTagType.SERVER_COMMON_COMMENT.tagEncloses(source,pos);
/** * Indicates whether a matching end tag is forbidden. * <p> * This property returns <code>true</code> if one of the following conditions is met: * <ul> * <li>The {@linkplain #getStartTagType() type} of this start tag does not specify a * {@linkplain StartTagType#getCorrespondingEndTagType() corresponding end tag type}. * <li>The {@linkplain #getName() name} of this start tag indicates it is the start of an * <a href="Element.html#HTML">HTML element</a> whose {@linkplain HTMLElements#getEndTagForbiddenElementNames() end tag is forbidden}. * <li>This start tag is {@linkplain #isSyntacticalEmptyElementTag() syntactically an empty-element tag} and its * {@linkplain #getName() name} indicates it is the start of a <a href="HTMLElements.html#NonHTMLElement">non-HTML element</a>. * </ul> * <p> * If this property returns <code>true</code> then this start tag's {@linkplain #getElement() element} will always be a * <a href="Element.html#SingleTag">single tag element</a>. * * @return <code>true</code> if a matching end tag is forbidden, otherwise <code>false</code>. */ public boolean isEndTagForbidden() { if (getStartTagType()!=StartTagType.NORMAL) return getStartTagType().getCorrespondingEndTagType()==null; if (HTMLElements.getEndTagForbiddenElementNames().contains(name)) return true; if (HTMLElements.getElementNames().contains(name)) return false; return isSyntacticalEmptyElementTag(); }
StringBuilder appendDebugTag(final StringBuilder sb) { if (startTagType==StartTagType.NORMAL && getAttributes().isEmpty()) { sb.append(this); } else { sb.append('<').append(getNameSegment()).append(' '); if (isSyntacticalEmptyElementTag()) sb.append('/'); sb.append(startTagType.getClosingDelimiter()); } return sb; }
if (tag instanceof StartTag) { StartTag startTag=(StartTag)tag; if (startTag.getStartTagType().getCorrespondingEndTagType()==null) continue; if (HTMLElements.getEndTagForbiddenElementNames().contains(startTag.getName())) continue; if (startTag.isEmptyElementTag()) continue;
try { while (!isTerminatingCharacter) { if (i==maxEnd || startTagType.atEndOfAttributes(source,i,isClosingSlashIgnored)) isTerminatingCharacter=true; final char ch=parseText.charAt(i); if (startTagType==StartTagType.NORMAL && startTagType.atEndOfAttributes(source,i,false)) {
/** * Indicates whether the specified source document position is at the end of a tag's {@linkplain Attributes attributes}. * <br />(<a href="TagType.html#DefaultImplementation">default implementation</a> method) * <p> * This method is called internally while parsing {@linkplain Attributes attributes} to detect where they should end. * <p> * It can be assumed that the specified position is not inside a quoted attribute value. * <p> * The default implementation simply compares the {@linkplain ParseText parse text} at the specified * position with the {@linkplain #getClosingDelimiter() closing delimiter}, and is equivalent to:<br /> * <code>source.</code>{@link Source#getParseText() getParseText()}<code>.containsAt(</code>{@link #getClosingDelimiter() getClosingDelimiter()}<code>,pos)</code> * <p> * The <code>isClosingSlashIgnored</code> parameter is only relevant in the {@link #NORMAL} start tag type, * which makes use of it to cater for the '<code>/</code>' character that can occur before the * {@linkplain #getClosingDelimiter() closing delimiter} in {@linkplain StartTag#isEmptyElementTag() empty-element tags}. * It's value is always <code>false</code> when passed to other start tag types. * * @param source the {@link Source} document. * @param pos the character position in the source document. * @param isClosingSlashIgnored indicates whether the {@linkplain StartTag#getName() name} of the {@linkplain StartTag start tag} being tested is incompatible with an {@linkplain StartTag#isEmptyElementTag() empty-element tag}. * @return <code>true</code> if the specified source document position is at the end of a tag's {@linkplain Attributes attributes}, otherwise <code>false</code>. */ public boolean atEndOfAttributes(final Source source, final int pos, final boolean isClosingSlashIgnored) { return source.getParseText().containsAt(getClosingDelimiter(),pos); }
private EndTag getEndTagInternal() { boolean checkForEmptyElementTag=true; final EndTagType endTagType=startTagType.getCorrespondingEndTagType(); if (startTagType==StartTagType.NORMAL) {
/** * Parses the attributes specified in this start tag, regardless of the type of start tag. * This method is only required in the unusual situation where attributes exist in a start tag whose * {@linkplain #getStartTagType() type} doesn't {@linkplain StartTagType#hasAttributes() have attributes}. * <p> * See the documentation of the {@link #parseAttributes()} method for more information. * * @param maxErrorCount the maximum number of minor errors allowed while parsing * @return the attributes specified in this start tag, or <code>null</code> if too many errors occur while parsing. * @see #getAttributes() */ public Attributes parseAttributes(final int maxErrorCount) { if (attributes!=null) return attributes; final int maxEnd=end-startTagType.getClosingDelimiter().length(); int attributesBegin=begin+1+name.length(); // skip any non-name characters directly after the name (which are quite common) while (!isXMLNameStartChar(source.charAt(attributesBegin))) { attributesBegin++; if (attributesBegin==maxEnd) return null; } Attributes attributes=Attributes.construct(source,begin,attributesBegin,maxEnd,startTagType,name,maxErrorCount); if (attributes!=null) attributes.setStartTag(this); return attributes; }
} catch (IOException ex) {throw new RuntimeException(ex);} // never happens if (startTagType==StartTagType.NORMAL && getElement().getEndTag()==null && !HTMLElements.getEndTagOptionalElementNames().contains(name)) sb.append(" /"); sb.append(startTagType.getClosingDelimiter()); return sb.toString();
protected int getEnd(final Source source, final int pos) { // This method needs to be overridden because this tag type shares the same start delimiter as the downlevel hidden conditional comment. // The closing delimiter of the other tag type must not appear inside this tag. // Take the following example: // <!--[if IE]> ... <![endif]--> ... <!--[if !(IE 5)]><!--> ... <!--<![endif]--> // If the default implementation were used, then the parser would recognise the first tag as: // <!--[if IE]> ... <![endif]--> ... <!--[if !(IE 5)]><!--> final int delimiterBegin=source.getParseText().indexOf(MicrosoftConditionalCommentTagTypes.DOWNLEVEL_HIDDEN_IF.getClosingDelimiter(),pos); if (delimiterBegin==-1) return -1; if (source.getParseText().containsAt(getClosingDelimiter(),delimiterBegin)) return delimiterBegin+getClosingDelimiter().length(); // this is a downlevel hidden conditional comment, so fail this tag type silently without displaying a log message return -2; } }