/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.jmeter.protocol.http.parser; import java.net.URL; import java.nio.charset.Charset; import java.util.ArrayList; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Triple; import org.apache.jmeter.util.JMeterUtils; import org.slf4j.LoggerFactory; import org.slf4j.Logger; import com.github.benmanes.caffeine.cache.CacheLoader; import com.helger.css.ECSSVersion; import com.helger.css.decl.CSSDeclaration; import com.helger.css.decl.CSSExpressionMemberTermURI; import com.helger.css.decl.CSSImportRule; import com.helger.css.decl.CascadingStyleSheet; import com.helger.css.decl.ICSSTopLevelRule; import com.helger.css.decl.visit.CSSVisitor; import com.helger.css.decl.visit.DefaultCSSUrlVisitor; import com.helger.css.reader.CSSReader; import com.helger.css.reader.CSSReaderSettings; import com.helger.css.reader.errorhandler.DoNothingCSSInterpretErrorHandler; import com.helger.css.reader.errorhandler.LoggingCSSParseErrorHandler; public class CssParserCacheLoader implements CacheLoader<Triple<String, URL, Charset>, URLCollection> { private static final Logger LOG = LoggerFactory.getLogger(CssParserCacheLoader.class); private static final boolean IGNORE_ALL_CSS_ERRORS = JMeterUtils .getPropDefault("css.parser.ignore_all_css_errors", true); @Override public URLCollection load(Triple<String, URL, Charset> triple) throws Exception { final String cssContent = triple.getLeft(); final URL baseUrl = triple.getMiddle(); final Charset charset = triple.getRight(); final CSSReaderSettings readerSettings = new CSSReaderSettings() .setBrowserCompliantMode(true) .setFallbackCharset(charset) .setCSSVersion(ECSSVersion.CSS30) .setCustomErrorHandler(new LoggingCSSParseErrorHandler()) .setCustomExceptionHandler( new CSSParseExceptionCallback(baseUrl)); if (IGNORE_ALL_CSS_ERRORS) { readerSettings .setInterpretErrorHandler(new DoNothingCSSInterpretErrorHandler()); } final CascadingStyleSheet aCSS = CSSReader.readFromStringReader( cssContent, readerSettings); final URLCollection urls = new URLCollection(new ArrayList<>()); if (aCSS == null) { LOG.warn("Failed parsing CSS: " + baseUrl + ", got null CascadingStyleSheet"); return urls; } CSSVisitor.visitCSSUrl(aCSS, new DefaultCSSUrlVisitor() { @Override public void onImport(CSSImportRule rule) { final String location = rule.getLocationString(); if (!StringUtils.isEmpty(location)) { urls.addURL(location, baseUrl); } } // Call for URLs outside of URLs @Override public void onUrlDeclaration(final ICSSTopLevelRule aTopLevelRule, final CSSDeclaration aDeclaration, final CSSExpressionMemberTermURI aURITerm) { // NOOP // Browser fetch such urls only when CSS rule matches // so we disable this code } }); return urls; } }