You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by ch...@apache.org on 2010/08/07 02:17:49 UTC
svn commit: r983148 - in /shindig/trunk/java/gadgets/src:
main/java/org/apache/shindig/gadgets/http/
main/java/org/apache/shindig/gadgets/render/
main/java/org/apache/shindig/gadgets/rewrite/
main/java/org/apache/shindig/gadgets/uri/ test/java/org/apac...
Author: chirag
Date: Sat Aug 7 00:17:49 2010
New Revision: 983148
URL: http://svn.apache.org/viewvc?rev=983148&view=rev
Log:
Cajole proxied javascript responses with CajaResponseRewriter
Code Review: http://codereview.appspot.com/1847052/show
Added:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/CajaResponseRewriter.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/CajaResponseRewriterTest.java
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriCommon.java
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java?rev=983148&r1=983147&r2=983148&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java Sat Aug 7 00:17:49 2010
@@ -69,6 +69,9 @@ public class HttpRequest {
// Sanitization
private boolean sanitizationRequested;
+ // Caja
+ private boolean cajaRequested;
+
// Whether to follow redirects
private boolean followRedirects = true;
@@ -220,6 +223,18 @@ public class HttpRequest {
this.sanitizationRequested = sanitizationRequested;
}
+ /**
+ * Should content fetched in response to this request
+ * be sanitized based on the specified mime-type
+ */
+ public boolean isCajaRequested() {
+ return cajaRequested;
+ }
+
+ public void setCajaRequested(boolean cajaRequested) {
+ this.cajaRequested = cajaRequested;
+ }
+
/**
* @param cacheTtl The amount of time to cache the result object for, in seconds. If set to -1,
* HTTP cache control headers will be honored. Otherwise objects will be cached for the time
Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/CajaResponseRewriter.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/CajaResponseRewriter.java?rev=983148&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/CajaResponseRewriter.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/CajaResponseRewriter.java Sat Aug 7 00:17:49 2010
@@ -0,0 +1,197 @@
+/*
+ * 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.render;
+
+import com.google.caja.lexer.CharProducer;
+import com.google.caja.lexer.ExternalReference;
+import com.google.caja.lexer.FetchedData;
+import com.google.caja.lexer.InputSource;
+import com.google.caja.lexer.JsLexer;
+import com.google.caja.lexer.JsTokenQueue;
+import com.google.caja.lexer.ParseException;
+import com.google.caja.lexer.TokenConsumer;
+
+import com.google.caja.parser.AncestorChain;
+import com.google.caja.parser.ParseTreeNode;
+import com.google.caja.parser.js.CajoledModule;
+import com.google.caja.parser.js.Parser;
+import com.google.caja.plugin.PipelineMaker;
+import com.google.caja.plugin.PluginCompiler;
+import com.google.caja.plugin.PluginMeta;
+import com.google.caja.plugin.UriFetcher;
+import com.google.caja.plugin.UriPolicy;
+import com.google.caja.render.Concatenator;
+import com.google.caja.render.JsMinimalPrinter;
+import com.google.caja.render.JsPrettyPrinter;
+import com.google.caja.reporting.BuildInfo;
+import com.google.caja.reporting.MessageContext;
+import com.google.caja.reporting.MessageQueue;
+import com.google.caja.reporting.RenderContext;
+import com.google.caja.reporting.SimpleMessageQueue;
+import com.google.inject.Inject;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.Gadget;
+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.http.RequestPipeline;
+import org.apache.shindig.gadgets.rewrite.DomWalker;
+import org.apache.shindig.gadgets.rewrite.ResponseRewriter;
+import org.apache.shindig.gadgets.rewrite.RewriterUtils;
+import org.apache.shindig.gadgets.rewrite.RewritingException;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * Rewriter that cajoles Javascript.
+ */
+public class CajaResponseRewriter implements ResponseRewriter {
+ private static final Logger LOG = Logger.getLogger(CajaResponseRewriter.class.getName());
+
+ private final RequestPipeline requestPipeline;
+
+ @Inject
+ public CajaResponseRewriter(RequestPipeline requestPipeline) {
+ this.requestPipeline = requestPipeline;
+ }
+
+ public void rewrite(HttpRequest req, HttpResponseBuilder resp) throws RewritingException {
+ if (!req.isCajaRequested()) { return; }
+
+ // Only accept Javascript for now
+ if (!RewriterUtils.isJavascript(req, resp)) {
+ resp.setContent("");
+ resp.setHttpStatusCode(HttpResponse.SC_BAD_REQUEST);
+ return;
+ }
+
+ boolean passed = false;
+
+ MessageQueue mq = new SimpleMessageQueue();
+ MessageContext mc = new MessageContext();
+ Uri contextUri = req.getUri();
+ InputSource is = new InputSource(contextUri.toJavaUri());
+
+ PluginMeta pluginMeta = new PluginMeta(
+ proxyFetcher(req, contextUri), proxyUriPolicy(contextUri));
+ PluginCompiler compiler = new PluginCompiler(BuildInfo.getInstance(),
+ pluginMeta, mq);
+ compiler.setMessageContext(mc);
+
+ // Parse the javascript
+ try {
+ StringReader strReader = new StringReader(resp.getContent());
+ CharProducer cp = CharProducer.Factory.create(strReader, is);
+ JsTokenQueue tq = new JsTokenQueue(new JsLexer(cp), is);
+ ParseTreeNode input = new Parser(tq, mq).parse();
+ tq.expectEmpty();
+
+ compiler.addInput(AncestorChain.instance(input), contextUri.toJavaUri());
+ } catch (ParseException e) {
+ // Don't bother continuing.
+ resp.setContent("");
+ return;
+ }
+
+ try {
+ if (RewriterUtils.isJavascript(req, resp)) {
+ compiler.setGoals(
+ compiler.getGoals().without(PipelineMaker.HTML_SAFE_STATIC));
+ }
+ passed = compiler.run();
+
+ CajoledModule outputJs = passed ? compiler.getJavascript() : null;
+
+ StringBuilder jsOut = new StringBuilder();
+ TokenConsumer printer;
+ if ("1".equals(req.getParam("debug"))) {
+ printer = new JsPrettyPrinter(new Concatenator(jsOut));
+ } else {
+ printer = new JsMinimalPrinter(new Concatenator(jsOut));
+ }
+
+ RenderContext renderContext = new RenderContext(printer).withEmbeddable(true);
+
+ if (outputJs != null) {
+ outputJs.render(renderContext);
+ }
+
+ renderContext.getOut().noMoreTokens();
+ resp.setContent(jsOut.toString());
+ } finally {
+ if (!passed) {
+ resp.setContent("");
+ }
+ }
+ }
+
+ private UriPolicy proxyUriPolicy(final Uri contextUri) {
+ final Gadget stubGadget = DomWalker.makeGadget(contextUri);
+
+ return new UriPolicy() {
+ public String rewriteUri(ExternalReference ref, UriEffect effect,
+ LoaderType loader, Map<String, ?> hints) {
+
+ Uri resourceUri = Uri.fromJavaUri(ref.getUri());
+ if (contextUri != null) {
+ resourceUri = contextUri.resolve(resourceUri);
+ }
+
+ ProxyUriManager.ProxyUri proxyUri = new ProxyUriManager.ProxyUri(
+ stubGadget, resourceUri);
+ return proxyUri.getResource().toString();
+ }
+ };
+ }
+
+ private UriFetcher proxyFetcher(final HttpRequest req, final Uri contextUri) {
+ return new UriFetcher() {
+ public FetchedData fetch(ExternalReference ref, String mimeType) throws UriFetchException {
+ Uri resourceUri = Uri.fromJavaUri(ref.getUri());
+ if (contextUri != null) {
+ resourceUri = contextUri.resolve(resourceUri);
+ }
+
+ HttpRequest request = new HttpRequest(resourceUri)
+ .setContainer(req.getContainer())
+ .setGadget(req.getGadget());
+
+ try {
+ HttpResponse response = requestPipeline.execute(request);
+ byte[] responseBytes = IOUtils.toByteArray(response.getResponse());
+ return FetchedData.fromBytes(responseBytes, mimeType, response.getEncoding(),
+ new InputSource(ref.getUri()));
+ } catch (GadgetException e) {
+ LOG.info("Failed to retrieve: " + ref.toString());
+ return null;
+ } catch (IOException e) {
+ LOG.info("Failed to read: " + ref.toString());
+ return null;
+ }
+ }
+ };
+ }
+}
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java?rev=983148&r1=983147&r2=983148&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java Sat Aug 7 00:17:49 2010
@@ -25,6 +25,7 @@ import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
+import org.apache.shindig.gadgets.render.CajaResponseRewriter;
import org.apache.shindig.gadgets.render.OpenSocialI18NGadgetRewriter;
import org.apache.shindig.gadgets.render.RenderingGadgetRewriter;
import org.apache.shindig.gadgets.render.SanitizingGadgetRewriter;
@@ -101,10 +102,11 @@ public class RewriteModule extends Abstr
StyleAdjacencyContentRewriter styleAdjacencyRewriter,
ProxyingContentRewriter proxyingRewriter,
CssResponseRewriter cssRewriter,
- SanitizingResponseRewriter sanitizedRewriter) {
+ SanitizingResponseRewriter sanitizedRewriter,
+ CajaResponseRewriter cajaRewriter) {
return ImmutableList.of(
absolutePathRewriter, styleTagExtractorRewriter, styleAdjacencyRewriter, proxyingRewriter,
- cssRewriter, sanitizedRewriter);
+ cssRewriter, sanitizedRewriter, cajaRewriter);
}
@Provides
@@ -115,7 +117,7 @@ public class RewriteModule extends Abstr
StyleTagProxyEmbeddedUrlsRewriter styleTagProxyEmbeddedUrlsRewriter,
ProxyingContentRewriter proxyingContentRewriter) {
return ImmutableList.of((ResponseRewriter) absolutePathReferenceRewriter,
- (ResponseRewriter) styleTagProxyEmbeddedUrlsRewriter,
- (ResponseRewriter) proxyingContentRewriter);
+ (ResponseRewriter) styleTagProxyEmbeddedUrlsRewriter,
+ (ResponseRewriter) proxyingContentRewriter);
}
}
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java?rev=983148&r1=983147&r2=983148&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java Sat Aug 7 00:17:49 2010
@@ -39,6 +39,7 @@ public class ProxyUriBase {
private String gadget = null;
private String rewriteMimeType = null;
private boolean sanitizeContent = false;
+ private boolean cajoleContent = false;
protected ProxyUriBase(Gadget gadget) {
this(null, // Meaningless in "context" mode. translateStatusRefresh invalid here.
@@ -83,6 +84,7 @@ public class ProxyUriBase {
gadget = uri.getQueryParameter(Param.GADGET.getKey());
rewriteMimeType = uri.getQueryParameter(Param.REWRITE_MIME_TYPE.getKey());
sanitizeContent = getBooleanValue(uri.getQueryParameter(Param.SANITIZE.getKey()));
+ cajoleContent = getBooleanValue(uri.getQueryParameter(Param.CAJOLE.getKey()));
}
}
@@ -102,13 +104,15 @@ public class ProxyUriBase {
&& Objects.equal(this.rewriteMimeType, objUri.rewriteMimeType)
&& this.noCache == objUri.noCache
&& this.debug == objUri.debug
- && this.sanitizeContent == objUri.sanitizeContent);
+ && this.sanitizeContent == objUri.sanitizeContent
+ && this.cajoleContent == objUri.cajoleContent);
+
}
@Override
public int hashCode() {
return Objects.hashCode(status, refresh, container, gadget, rewriteMimeType,
- noCache, debug, sanitizeContent);
+ noCache, debug, sanitizeContent, cajoleContent);
}
public ProxyUriBase setRewriteMimeType(String type) {
@@ -120,6 +124,11 @@ public class ProxyUriBase {
this.sanitizeContent = sanitize;
return this;
}
+
+ public ProxyUriBase setCajoleContent(boolean cajole) {
+ this.cajoleContent = cajole;
+ return this;
+ }
public UriStatus getStatus() {
return status;
@@ -153,6 +162,10 @@ public class ProxyUriBase {
return sanitizeContent;
}
+ public boolean cajoleContent() {
+ return cajoleContent;
+ }
+
public HttpRequest makeHttpRequest(Uri targetUri) throws GadgetException {
HttpRequest req = new HttpRequest(targetUri)
.setIgnoreCache(isNoCache())
@@ -177,6 +190,7 @@ public class ProxyUriBase {
req.setRewriteMimeType(getRewriteMimeType());
}
req.setSanitizationRequested(sanitizeContent());
+ req.setCajaRequested(cajoleContent());
return req;
}
@@ -213,6 +227,9 @@ public class ProxyUriBase {
if (sanitizeContent) {
queryBuilder.addQueryParameter(Param.SANITIZE.getKey(), "1");
}
+ if (cajoleContent) {
+ queryBuilder.addQueryParameter(Param.CAJOLE.getKey(), "1");
+ }
return queryBuilder;
}
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriCommon.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriCommon.java?rev=983148&r1=983147&r2=983148&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriCommon.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriCommon.java Sat Aug 7 00:17:49 2010
@@ -39,6 +39,7 @@ public interface UriCommon {
TYPE("type"),
REWRITE_MIME_TYPE("rewriteMime"),
SANITIZE("sanitize"),
+ CAJOLE("cajole"),
CONTAINER_MODE("c"),
// Proxy resize params:
Added: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/CajaResponseRewriterTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/CajaResponseRewriterTest.java?rev=983148&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/CajaResponseRewriterTest.java (added)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/CajaResponseRewriterTest.java Sat Aug 7 00:17:49 2010
@@ -0,0 +1,84 @@
+/*
+ * 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.render;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.shindig.common.uri.Uri;
+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.http.RequestPipeline;
+import org.apache.shindig.gadgets.rewrite.RewriterTestBase;
+import org.apache.shindig.gadgets.rewrite.ResponseRewriter;
+import org.junit.Test;
+
+public class CajaResponseRewriterTest extends RewriterTestBase {
+ private static final Uri CONTENT_URI = Uri.parse("http://www.example.org/content");
+
+ private String rewrite(HttpRequest request, HttpResponse response) throws Exception {
+ request.setSanitizationRequested(true);
+ ResponseRewriter rewriter = createRewriter();
+
+ HttpResponseBuilder hrb = new HttpResponseBuilder(parser, response);
+ rewriter.rewrite(request, hrb);
+ return hrb.getContent();
+ }
+
+ private ResponseRewriter createRewriter() {
+ return new CajaResponseRewriter(new RequestPipeline() {
+ public HttpResponse execute(HttpRequest request) {
+ return null;
+ }
+ });
+ }
+
+ @Test
+ public void testJs() throws Exception {
+ HttpRequest req = new HttpRequest(CONTENT_URI);
+ req.setRewriteMimeType("text/javascript");
+ req.setCajaRequested(true);
+ HttpResponse response = new HttpResponseBuilder().setResponseString("var a;").create();
+ String sanitized = "$v.initOuter('a');";
+
+ assertTrue(rewrite(req, response).contains(sanitized));
+ }
+
+ @Test
+ public void testJsWithoutCaja() throws Exception {
+ HttpRequest req = new HttpRequest(CONTENT_URI);
+ req.setRewriteMimeType("text/javascript");
+ req.setCajaRequested(false);
+ HttpResponse response = new HttpResponseBuilder().setResponseString("var a;").create();
+ String sanitized = "var a;";
+
+ assertTrue(rewrite(req, response).contains(sanitized));
+ }
+
+ @Test
+ public void testNonJs() throws Exception {
+ HttpRequest req = new HttpRequest(CONTENT_URI);
+ req.setRewriteMimeType("text/html");
+ req.setCajaRequested(true);
+ HttpResponse response = new HttpResponseBuilder().setResponseString("<html></html>").create();
+
+ assertEquals("", rewrite(req, response));
+ }
+}