blob: 66bdba8fb84a1e96071a133ccd01bed692f60684 [file] [log] [blame]
/*-
* 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.sling.dynamicinclude;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.sling.SlingFilter;
import org.apache.felix.scr.annotations.sling.SlingFilterScope;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.dynamicinclude.generator.IncludeGenerator;
import org.apache.sling.dynamicinclude.generator.IncludeGeneratorWhiteboard;
import org.apache.sling.dynamicinclude.impl.UrlBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SlingFilter(scope = SlingFilterScope.INCLUDE, order = -500)
public class IncludeTagFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(IncludeTagFilter.class);
private static final String COMMENT = "<!-- SDI include (path: %s, resourceType: %s) -->\n";
@Reference
private ConfigurationWhiteboard configurationWhiteboard;
@Reference
private IncludeGeneratorWhiteboard generatorWhiteboard;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
final String resourceType = slingRequest.getResource().getResourceType();
final Configuration config = configurationWhiteboard.getConfiguration(slingRequest, resourceType);
if (config == null) {
chain.doFilter(request, response);
return;
}
final IncludeGenerator generator = generatorWhiteboard.getGenerator(config.getIncludeTypeName());
if (generator == null) {
LOG.error("Invalid generator: " + config.getIncludeTypeName());
chain.doFilter(request, response);
return;
}
final PrintWriter writer = response.getWriter();
final String url = getUrl(config, slingRequest);
if (url == null) {
chain.doFilter(request, response);
return;
}
if (config.getAddComment()) {
writer.append(String.format(COMMENT, StringEscapeUtils.escapeHtml4(url), resourceType));
}
// Only write the includes markup if the required, configurable request
// header is present
if (shouldWriteIncludes(config, slingRequest)) {
String include = generator.getInclude(url);
LOG.debug(include);
writer.append(include);
} else {
chain.doFilter(request, response);
}
}
private boolean shouldWriteIncludes(Configuration config, SlingHttpServletRequest request) {
if (requestHasParameters(config.getIgnoreUrlParams(), request)) {
return false;
}
final String requiredHeader = config.getRequiredHeader();
return StringUtils.isBlank(requiredHeader) || containsHeader(requiredHeader, request);
}
private boolean requestHasParameters(List<String> ignoreUrlParams, SlingHttpServletRequest request) {
final Enumeration<?> paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
final String paramName = (String) paramNames.nextElement();
if (!ignoreUrlParams.contains(paramName)) {
return true;
}
}
return false;
}
private boolean containsHeader(String requiredHeader, SlingHttpServletRequest request) {
final String name, expectedValue;
if (StringUtils.contains(requiredHeader, '=')) {
final String split[] = StringUtils.split(requiredHeader, '=');
name = split[0];
expectedValue = split[1];
} else {
name = requiredHeader;
expectedValue = null;
}
final String actualValue = request.getHeader(name);
if (actualValue == null) {
return false;
} else if (expectedValue == null) {
return true;
} else {
return actualValue.equalsIgnoreCase(expectedValue);
}
}
private String getUrl(Configuration config, SlingHttpServletRequest request) {
String url = buildUrl(config, request);
if (config.isRewritePath()) {
url = removeQuestionMark(url);
url = request.getResourceResolver().map(request, url);
} else {
url = encodeJcrContentPart(url);
try {
url = new URI(null, null, url, null).toASCIIString();
} catch (URISyntaxException e) {
LOG.error("Include url is in the wrong format", e);
return null;
}
}
return url;
}
private String buildUrl(Configuration config, SlingHttpServletRequest request) {
final Resource resource = request.getResource();
final boolean synthetic = ResourceUtil.isSyntheticResource(request.getResource());
return UrlBuilder.buildUrl(config.getIncludeSelector(), resource.getResourceType(), synthetic, config, request.getRequestPathInfo());
}
private static String sanitize(String path) {
return StringUtils.defaultString(path);
}
private static String encodeJcrContentPart(String url) {
return url.replace("jcr:content", "_jcr_content");
}
private static String removeQuestionMark(String url) {
return url.replaceAll("[?]", "");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}