org.apache.shindig.gadgets.rewrite.CssResponseRewriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of shindig-gadgets Show documentation
Show all versions of shindig-gadgets Show documentation
Renders gadgets, provides the gadget metadata service, and serves
all javascript required by the OpenSocial specification.
The newest version!
/*
* 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.shindig.gadgets.rewrite;
import com.google.common.base.Strings;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shindig.common.logging.i18n.MessageKeys;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.gadgets.GadgetContext;
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.http.HttpResponseBuilder;
import org.apache.shindig.gadgets.parse.caja.CajaCssParser;
import org.apache.shindig.gadgets.uri.ProxyUriManager;
import org.w3c.dom.Element;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.caja.lexer.ParseException;
import com.google.caja.parser.AbstractParseTreeNode;
import com.google.caja.parser.AncestorChain;
import com.google.caja.parser.Visitor;
import com.google.caja.parser.css.CssTree;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
/**
* Rewrite links to referenced content in a stylesheet
*
* @since 2.0.0
*/
public class CssResponseRewriter implements ResponseRewriter {
//class name for logging purpose
private static final String classname = CssResponseRewriter.class.getName();
private static final Logger LOG = Logger.getLogger(classname,MessageKeys.MESSAGES);
private final CajaCssParser cssParser;
protected final ProxyUriManager proxyUriManager;
protected final ContentRewriterFeature.Factory rewriterFeatureFactory;
@Inject
public CssResponseRewriter(CajaCssParser cssParser,
ProxyUriManager proxyUriManager, ContentRewriterFeature.Factory rewriterFeatureFactory) {
this.cssParser = cssParser;
this.proxyUriManager = proxyUriManager;
this.rewriterFeatureFactory = rewriterFeatureFactory;
}
public void rewrite(HttpRequest request, HttpResponseBuilder original) throws RewritingException {
ContentRewriterFeature.Config config = rewriterFeatureFactory.get(request);
if (!RewriterUtils.isCss(request, original)) {
return;
}
String css = original.getContent();
StringWriter sw = new StringWriter((css.length() * 110) / 100);
rewrite(new StringReader(css), request.getUri(),
new UriMaker(proxyUriManager, config), sw, false,
DomWalker.makeGadget(request).getContext());
original.setContent(sw.toString());
}
/**
* Rewrite the given CSS content and optionally extract the import references.
* @param content CSS content
* @param source Uri of content
* @param uriMaker a Uri Maker
* @param writer Output
* @param extractImports If true remove the import statements from the output and return their
* referenced URIs.
* @param gadgetContext The gadgetContext
*
* @return Empty list of extracted import URIs.
*/
public List rewrite(Reader content, Uri source, UriMaker uriMaker, Writer writer,
boolean extractImports, GadgetContext gadgetContext) throws RewritingException {
try {
String original = IOUtils.toString(content);
try {
CssTree.StyleSheet stylesheet = cssParser.parseDom(original, source);
List stringList = rewrite(stylesheet, source, uriMaker, extractImports,
gadgetContext);
// Serialize the stylesheet
cssParser.serialize(stylesheet, writer);
return stringList;
} catch (GadgetException ge) {
if (ge.getCause() instanceof ParseException) {
if (LOG.isLoggable(Level.WARNING)) {
LOG.logp(Level.WARNING, classname, "rewrite", MessageKeys.CAJA_CSS_PARSE_FAILURE, new Object[] {ge.getCause().getMessage(),source});
}
writer.write(original);
return Collections.emptyList();
} else {
throw new RewritingException(ge, ge.getHttpStatusCode());
}
}
} catch (IOException ioe) {
throw new RewritingException(ioe, HttpResponse.SC_INTERNAL_SERVER_ERROR);
}
}
/**
* Rewrite the CSS content in a style DOM node.
* @param styleNode Rewrite the CSS content of this node
* @param source Uri of content
* @param uriMaker a UriMaker
* @param extractImports If true remove the import statements from the output and return their
* referenced URIs.
* @param gadgetContext The gadgetContext
* @return Empty list of extracted import URIs.
*/
public List rewrite(Element styleNode, Uri source, UriMaker uriMaker,
boolean extractImports, GadgetContext gadgetContext) throws RewritingException {
try {
CssTree.StyleSheet stylesheet =
cssParser.parseDom(styleNode.getTextContent(), source);
List imports = rewrite(stylesheet, source, uriMaker, extractImports, gadgetContext);
// Write the rewritten CSS back into the element
String content = cssParser.serialize(stylesheet);
if (Strings.isNullOrEmpty(content) || StringUtils.isWhitespace(content)) {
// Remove the owning node
styleNode.getParentNode().removeChild(styleNode);
} else {
styleNode.setTextContent(content);
}
return imports;
} catch (GadgetException ge) {
if (ge.getCause() instanceof ParseException) {
if (LOG.isLoggable(Level.INFO)) {
LOG.logp(Level.WARNING, classname, "rewrite", MessageKeys.CAJA_CSS_PARSE_FAILURE, new Object[] {ge.getCause().getMessage(),source});
}
return Collections.emptyList();
} else {
throw new RewritingException(ge, ge.getHttpStatusCode());
}
}
}
/**
* Rewrite the CSS DOM in place.
* @param styleSheet To rewrite
* @param source Uri of content
* @param uriMaker a UriMaker
* @param extractImports If true remove the import statements from the output and return their
* referenced URIs.
* @return Empty list of extracted import URIs.
*/
public static List rewrite(CssTree.StyleSheet styleSheet, final Uri source,
final UriMaker uriMaker, final boolean extractImports, final GadgetContext gadgetContext) {
final List imports = Lists.newLinkedList();
final List skip = Lists.newLinkedList();
styleSheet.acceptPreOrder(new Visitor() {
public boolean visit(AncestorChain> chain) {
if (chain.node instanceof CssTree.Import) {
CssTree.Import importNode = (CssTree.Import) chain.node;
CssTree.UriLiteral uriLiteral = importNode.getUri();
skip.add(importNode.getUri());
if (extractImports) {
imports.add(uriLiteral.getValue());
((AbstractParseTreeNode) chain.getParentNode()).removeChild(chain.node);
} else {
String rewritten = rewriteUri(uriMaker, uriLiteral.getValue(), source, gadgetContext);
uriLiteral.setValue(rewritten);
}
} else if (chain.node instanceof CssTree.UriLiteral &&
!skip.contains(chain.node)) {
CssTree.UriLiteral uriDecl = (CssTree.UriLiteral) chain.node;
String rewritten = rewriteUri(uriMaker, uriDecl.getValue(), source, gadgetContext);
uriDecl.setValue(rewritten);
}
return true;
}}, null);
return imports;
}
private static String rewriteUri(UriMaker uriMaker, String input, Uri context,
GadgetContext gadgetContext) {
Uri inboundUri;
try {
inboundUri = Uri.parse(input);
} catch (IllegalArgumentException e) {
// Don't rewrite at all.
return input;
}
if (context != null) {
inboundUri = context.resolve(inboundUri);
}
ProxyUriManager.ProxyUri proxyUri =
new ProxyUriManager.ProxyUri(DomWalker.makeGadget(gadgetContext), inboundUri);
return uriMaker.make(proxyUri, context).toString();
}
public static UriMaker uriMaker(ProxyUriManager wrapped, ContentRewriterFeature.Config config) {
return new UriMaker(wrapped, config);
}
public static class UriMaker {
protected final ProxyUriManager wrapped;
protected final ContentRewriterFeature.Config config;
public UriMaker(ProxyUriManager wrapped, ContentRewriterFeature.Config config) {
this.wrapped = wrapped;
this.config = config;
}
public Uri make(ProxyUriManager.ProxyUri uri, Uri context) {
if (config.shouldRewriteURL(uri.getResource().toString())) {
List puris = Lists.newArrayList(uri);
List returned = wrapped.make(puris, null);
return returned.get(0);
}
return context.resolve(uri.getResource());
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy