You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by jo...@apache.org on 2010/03/09 02:34:47 UTC

svn commit: r920611 - in /shindig/trunk/java/gadgets/src: main/java/org/apache/shindig/gadgets/rewrite/ test/java/org/apache/shindig/gadgets/rewrite/

Author: johnh
Date: Tue Mar  9 01:34:46 2010
New Revision: 920611

URL: http://svn.apache.org/viewvc?rev=920611&view=rev
Log:
Implementation of content reference proxying by way of the DomWalker.Visitor paradigm. Not activated in RewriteModule.


Added:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingContentRewriter.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitor.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingContentRewriterTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitorTest.java

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingContentRewriter.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingContentRewriter.java?rev=920611&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingContentRewriter.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingContentRewriter.java Tue Mar  9 01:34:46 2010
@@ -0,0 +1,48 @@
+/*
+ * 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.inject.Inject;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.rewrite.DomWalker;
+import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ProxyingContentRewriter extends DomWalker.Rewriter {
+  private final ContentRewriterFeature.Factory featureConfigFactory;
+  private final ProxyUriManager proxyUriManager;
+  
+  @Inject
+  public ProxyingContentRewriter(ContentRewriterFeature.Factory featureConfigFactory,
+      ProxyUriManager proxyUriManager) {
+    this.featureConfigFactory = featureConfigFactory;
+    this.proxyUriManager = proxyUriManager;
+  }
+  
+  @Override
+  protected List<Visitor> makeVisitors(Gadget context, Uri gadgetUri) {
+    ContentRewriterFeature.Config config = featureConfigFactory.get(gadgetUri);
+    return Arrays.<Visitor>asList(new ProxyingVisitor(config, proxyUriManager));
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitor.java?rev=920611&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitor.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitor.java Tue Mar  9 01:34:46 2010
@@ -0,0 +1,119 @@
+/*
+ * 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 org.apache.shindig.common.Pair;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Simple visitor that, when plugged into a DomWalker, rewrites
+ * resource links to proxied versions of the same.
+ */
+public class ProxyingVisitor implements DomWalker.Visitor {
+  public final static Map<String, String> RESOURCE_TAGS =
+    ImmutableMap.of(
+        "img", "src",
+        "embed", "src",
+        "link", "href",
+        "script", "src",
+        "object", "src");
+  
+  private final ContentRewriterFeature.Config featureConfig;
+  private final ProxyUriManager uriManager;
+ 
+  public ProxyingVisitor(ContentRewriterFeature.Config featureConfig,
+                              ProxyUriManager uriManager) {
+    this.featureConfig = featureConfig;
+    this.uriManager = uriManager;
+  }
+
+  public VisitStatus visit(Gadget gadget, Node node) throws RewritingException {
+    String nodeName = node.getNodeName().toLowerCase();
+    if (node.getNodeType() == Node.ELEMENT_NODE &&
+        RESOURCE_TAGS.containsKey(nodeName) &&
+        featureConfig.shouldRewriteTag(nodeName)) {
+      Attr attr = (Attr)node.getAttributes().getNamedItem(
+          RESOURCE_TAGS.get(nodeName));
+      if (attr != null) {
+        String urlValue = attr.getValue();
+        if (featureConfig.shouldRewriteURL(urlValue)) {
+          return VisitStatus.RESERVE_NODE;
+        }
+      }
+    }
+    return VisitStatus.BYPASS;
+  }
+
+  public boolean revisit(Gadget gadget, List<Node> nodes) throws RewritingException {
+    List<Pair<Node, Uri>> proxiedUris = getProxiedUris(gadget, nodes);
+    
+    boolean mutated = false;
+    for (Pair<Node, Uri> proxyPair : proxiedUris) {
+      if (proxyPair.two == null) {
+        continue;
+      }
+      Element element = (Element)proxyPair.one;
+      element.setAttribute(RESOURCE_TAGS.get(element.getNodeName()), proxyPair.two.toString());
+      mutated = true;
+    }
+    
+    return mutated;
+  }
+  
+  private List<Pair<Node, Uri>> getProxiedUris(Gadget gadget, List<Node> nodes) {
+    List<ProxyUriManager.ProxyUri> reservedUris =
+        Lists.newArrayListWithCapacity(nodes.size());
+    
+    for (Node node : nodes) {
+      Element element = (Element)node;
+      String uriStr = element.getAttribute(RESOURCE_TAGS.get(element.getNodeName()));
+      try {
+        reservedUris.add(new ProxyUriManager.ProxyUri(gadget, Uri.parse(uriStr)));
+      } catch (Exception e) {
+        // Uri parse exception, add null.
+        reservedUris.add(null);
+      }
+    }
+    
+    List<Uri> resourceUris = uriManager.make(reservedUris, featureConfig.getExpires());
+    
+    // By contract, resourceUris matches by index with inbound Uris. Create an easy-access
+    // List with the results.
+    List<Pair<Node, Uri>> proxiedUris = Lists.newArrayListWithCapacity(nodes.size());
+    
+    Iterator<Uri> uriIt = resourceUris.iterator();
+    for (Node node : nodes) {
+      proxiedUris.add(Pair.of(node, uriIt.next()));
+    }
+    
+    return proxiedUris;
+  }
+}

Added: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingContentRewriterTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingContentRewriterTest.java?rev=920611&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingContentRewriterTest.java (added)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingContentRewriterTest.java Tue Mar  9 01:34:46 2010
@@ -0,0 +1,28 @@
+/*
+ * 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 org.junit.Test;
+
+public class ProxyingContentRewriterTest {
+  @Test
+  public void implementIntegrationTests() throws Exception {
+    // TODO: what the method says
+  }
+}

Added: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitorTest.java?rev=920611&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitorTest.java (added)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitorTest.java Tue Mar  9 01:34:46 2010
@@ -0,0 +1,142 @@
+/*
+ * 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 static org.easymock.classextension.EasyMock.capture;
+import static org.easymock.classextension.EasyMock.createMock;
+import static org.easymock.classextension.EasyMock.expect;
+import static org.easymock.classextension.EasyMock.replay;
+import static org.easymock.classextension.EasyMock.verify;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor.VisitStatus;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+import org.easymock.Capture;
+import org.junit.Test;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Test of proxying rewriter
+ */
+public class ProxyingVisitorTest extends DomWalkerTestBase {
+  private static final String URL_STRING = "http://www.foo.com/";
+  
+  @Test
+  public void imgVisitReserved() throws Exception {
+    checkVisitReserved("img", true);
+  }
+  
+  @Test
+  public void embedVisitReserved() throws Exception {
+    checkVisitReserved("embed", true);
+  }
+  
+  @Test
+  public void linkVisitReserved() throws Exception {
+    checkVisitReserved("link", true);
+  }
+  
+  @Test
+  public void scriptVisitReserved() throws Exception {
+    checkVisitReserved("script", true);
+  }
+  
+  @Test
+  public void objectVisitReserved() throws Exception {
+    checkVisitReserved("object", true);
+  }
+  
+  @Test
+  public void otherVisitNotReserved() throws Exception {
+    checkVisitReserved("other", false);
+  }
+  
+  private void checkVisitReserved(String tag, boolean result) throws Exception {
+    tag = tag.toLowerCase();
+    assertEquals(result, ProxyingVisitor.RESOURCE_TAGS.containsKey(tag));
+    assertEquals(result, getVisitReserved(tag, true, true));
+    assertEquals(result, getVisitReserved(tag.toUpperCase(), true, true));
+    assertFalse(getVisitReserved(tag, false, true));
+    assertFalse(getVisitReserved(tag, true, false));
+    assertFalse(getVisitReserved(tag, false, false));
+  }
+  
+  private boolean getVisitReserved(String tag, boolean resUrl, boolean resTag) throws Exception {
+    // Reserved when lower-case and both URL and Tag reserved.
+    String attrName = ProxyingVisitor.RESOURCE_TAGS.get(tag.toLowerCase());
+    Node node = elem(tag, attrName != null ? attrName : "src", URL_STRING);
+    ContentRewriterFeature.Config config = createMock(ContentRewriterFeature.Config.class);
+    expect(config.shouldRewriteURL(URL_STRING)).andReturn(resUrl).anyTimes();
+    expect(config.shouldRewriteTag(tag.toLowerCase())).andReturn(resTag).anyTimes();
+    replay(config);    
+    
+    ProxyingVisitor rewriter = new ProxyingVisitor(config, null);
+    VisitStatus status = rewriter.visit(null, node);
+    verify(config);
+        
+    return status != VisitStatus.BYPASS;
+  }
+  
+  @Test
+  public void revisitModifyValidSkipInvalid() throws Exception {
+    // Batch test: ensures in-order modification.
+    // Includes one mod and one skip.
+    // No need to test invalid nodes since visit() and DomWalker tests preclude this.
+    String scriptSrc = "http://script.com/foo.js";
+    Element e1 = elem("script", "src", scriptSrc);
+    Element e2 = elem("script", "src", "^!,,|BLARGH");
+    List<Node> nodes = ImmutableList.<Node>of(e1, e2);
+    ProxyUriManager uriManager = createMock(ProxyUriManager.class);
+    Uri rewrittenUri = Uri.parse("http://bar.com/");
+    List<Uri> returned = Lists.newArrayList(rewrittenUri, null);
+    ContentRewriterFeature.Config config = createMock(ContentRewriterFeature.Config.class);
+    Integer expires = new Integer(3);
+    expect(config.getExpires()).andReturn(expires).once();
+    expect(config);
+    Capture<List<ProxyUriManager.ProxyUri>> cap = new Capture<List<ProxyUriManager.ProxyUri>>();
+    Capture<Integer> intCap = new Capture<Integer>();
+    expect(uriManager.make(capture(cap), capture(intCap))).andReturn(returned).once();
+    replay(config, uriManager);
+    Gadget gadget = gadget();
+    
+    ProxyingVisitor rewriter = new ProxyingVisitor(config, uriManager);
+    assertTrue(rewriter.revisit(gadget, nodes));
+    verify(config, uriManager);
+    
+    assertEquals(2, cap.getValue().size());
+    assertEquals(Uri.parse(scriptSrc), cap.getValue().get(0).getResource());
+    assertNull(cap.getValue().get(1));
+    assertSame(expires, intCap.getValue());
+    assertEquals(rewrittenUri.toString(), e1.getAttribute("src"));
+    assertEquals("^!,,|BLARGH", e2.getAttribute("src"));
+  }
+}