dev.amp.validator.CdataMatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of validator-java Show documentation
Show all versions of validator-java Show documentation
A Java validator for the AMP Html format.
/*
*
* ====================================================================
* 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.
* ====================================================================
*/
/*
* Changes to the original project are Copyright 2019, Yahoo Inc..
*/
package dev.amp.validator;
import dev.amp.validator.css.CssTokenUtil;
import dev.amp.validator.css.Declaration;
import dev.amp.validator.css.ParsedDocCssSpec;
import dev.amp.validator.exception.TagValidationException;
import com.steadystate.css.parser.Token;
import dev.amp.validator.css.CssParser;
import dev.amp.validator.css.ErrorToken;
import dev.amp.validator.css.CssValidationException;
import dev.amp.validator.css.Stylesheet;
import dev.amp.validator.css.ParsedCssUrl;
import dev.amp.validator.css.CssParsingConfig;
import dev.amp.validator.utils.AttributeSpecUtils;
import dev.amp.validator.utils.ByteUtils;
import dev.amp.validator.utils.CssSpecUtils;
import dev.amp.validator.utils.TagSpecUtils;
import dev.amp.validator.utils.UrlUtils;
import dev.amp.validator.visitor.InvalidDeclVisitor;
import dev.amp.validator.visitor.InvalidRuleVisitor;
import dev.amp.validator.visitor.MediaQueryVisitor;
import dev.amp.validator.visitor.SelectorSpecVisitor;
import org.xml.sax.Locator;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import static dev.amp.validator.utils.TagSpecUtils.getTagDescriptiveName;
/**
* CdataMatcher maintains a constraint to check which an opening tag
* introduces: a tag's cdata matches constraints set by it's cdata
* spec. Unfortunately we need to defer such checking and can't
* handle it while the opening tag is being processed.
*
* @author nhant01
* @author GeorgeLuo
*/
public class CdataMatcher {
/**
* Constructor.
*
* @param parsedTagSpec the ParsedTagSpec.
* @param lineCol a line / column pair.
*/
public CdataMatcher(@Nonnull final ParsedTagSpec parsedTagSpec, @Nonnull final Locator lineCol) {
this.parsedTagSpec = parsedTagSpec;
this.lineCol = lineCol;
}
/**
* Matches the provided cdata against what this CdataMatcher expects.
*
* @param cdata the cdata.
* @param context the context object.
* @param validationResult validation result object.
* @throws TagValidationException the TagValidationException.
* @throws CssValidationException css validation exception.
* @throws IOException IO exception.
*/
public void match(@Nonnull final String cdata, @Nonnull final Context context,
@Nonnull final ValidatorProtos.ValidationResult.Builder validationResult)
throws TagValidationException, CssValidationException, IOException {
final ValidatorProtos.CdataSpec cdataSpec = this.getTagSpec().getCdata();
if (cdataSpec == null) {
return;
}
// Max CDATA Byte Length
if (cdataSpec.hasMaxBytes() && cdataSpec.getMaxBytes() != CDATA_MAX_BYTES
&& cdata.length() > cdataSpec.getMaxBytes()) {
List params = new ArrayList<>();
params.add(String.valueOf(cdata.length()));
params.add(String.valueOf(cdataSpec.getMaxBytes()));
context.addError(
ValidatorProtos.ValidationError.Code.STYLESHEET_TOO_LONG,
context.getLineCol(),
params,
cdataSpec.getMaxBytesSpecUrl(),
validationResult);
return;
}
int urlBytes = 0;
// The mandatory_cdata, cdata_regex, and css_spec fields are treated
// like a oneof, but we're not using oneof because it's a feature
// that was added after protobuf 2.5.0 (which our open-source
// version uses).
// Mandatory CDATA exact match
List params = new ArrayList<>();
params.add(TagSpecUtils.getTagSpecName(this.getTagSpec()));
if (cdataSpec.hasMandatoryCdata()) {
if (!cdataSpec.getMandatoryCdata().equals(cdata)) {
context.addError(
ValidatorProtos.ValidationError.Code.MANDATORY_CDATA_MISSING_OR_INCORRECT,
context.getLineCol(),
params,
TagSpecUtils.getTagSpecUrl(this.getTagSpec()),
validationResult);
}
// We return early if the cdata has an exact match rule. The
// spec shouldn't have an exact match rule that doesn't validate.
return;
} else if (this.getTagSpec().getCdata().hasCdataRegex()) {
if (!context.getRules()
.getFullMatchRegex(this.getTagSpec().getCdata().getCdataRegex())
.matcher(cdata).matches()) {
context.addError(
ValidatorProtos.ValidationError.Code.MANDATORY_CDATA_MISSING_OR_INCORRECT,
context.getLineCol(),
params,
TagSpecUtils.getTagSpecUrl(this.getTagSpec()),
validationResult);
return;
}
} else if (cdataSpec.hasCssSpec()) {
urlBytes = this.matchCss(cdata, cdataSpec.getCssSpec(), context, validationResult);
} else if (cdataSpec.getWhitespaceOnly()) {
if (!(WHITE_SPACE_CHARACTER_PATTERN.matcher(cdata).matches())) {
context.addError(
ValidatorProtos.ValidationError.Code.NON_WHITESPACE_CDATA_ENCOUNTERED,
context.getLineCol(),
params,
TagSpecUtils.getTagSpecUrl(this.getTagSpec()),
validationResult);
}
}
final ParsedDocCssSpec maybeDocCssSpec = context.matchingDocCssSpec();
int adjustedCdataLength = ByteUtils.byteLength(cdata);
if (maybeDocCssSpec != null && !maybeDocCssSpec.getSpec().getUrlBytesIncluded()) {
adjustedCdataLength -= urlBytes;
}
// Record