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/06/18 01:01:12 UTC

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

Author: johnh
Date: Thu Jun 17 23:01:12 2010
New Revision: 955778

URL: http://svn.apache.org/viewvc?rev=955778&view=rev
Log:
Support URI resolution to base URI provided by <base> tag in addition to "current site" URI.

Patch provided by Gagan Singh.


Modified:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceRewriter.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceVisitor.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceVisitorTest.java

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceRewriter.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceRewriter.java?rev=955778&r1=955777&r2=955778&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceRewriter.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceRewriter.java Thu Jun 17 23:01:12 2010
@@ -20,12 +20,6 @@ package org.apache.shindig.gadgets.rewri
 
 import com.google.inject.Inject;
 
-import org.apache.shindig.common.uri.Uri;
-import org.apache.shindig.gadgets.Gadget;
-
-import java.util.Arrays;
-import java.util.List;
-
 /**
  * Rewriter that converts all url's to absolute.
  */

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceVisitor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceVisitor.java?rev=955778&r1=955777&r2=955778&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceVisitor.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceVisitor.java Thu Jun 17 23:01:12 2010
@@ -18,40 +18,81 @@
  */
 package org.apache.shindig.gadgets.rewrite;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableMap;
+import com.google.inject.Inject;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.shindig.common.uri.Uri;
 import org.apache.shindig.gadgets.Gadget;
 import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor;
 import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+/**
+ * Visitor that resolves relative paths relative to the
+ * base tag (only if present) / current page url and marks urls as absolute.
+ */
 public class AbsolutePathReferenceVisitor implements Visitor {
-  public final static Map<String, String> RESOURCE_TAGS =
-    ImmutableMap.<String, String>builder()
-        .put("a", "href")
-        .put("area", "href")
-        .put("q", "cite")
+  public enum Tags {
+    // Resources which would be fetched by the browser when rendering the page.
+    RESOURCES(ImmutableMap.<String, String>builder()
         .put("img", "src")
         .put("input", "src")
         .put("body", "background")
         .put("embed", "src")
         .put("link", "href")
         .put("script", "src")
-        .put("object", "src").build();
+        .put("object", "src").build()),
+
+    // Hyperlinks that the user clicks on to navigate pages.
+    HYPERLINKS(ImmutableMap.<String, String>builder()
+        .put("a", "href")
+        .put("area", "href")
+        .put("q", "cite").build());
+
+    Map<String, String> resourceTags;
+    private Tags(Map<String, String> resourceTags) {
+      this.resourceTags = resourceTags;
+    }
+
+    public Map<String, String> getResourceTags() {
+      return resourceTags;
+    }
+  }
+
+  // Map of tag name -> attribute type describing uris to make absolute.
+  private final Map<String, String> tagsToMakeAbsolute;
+
+  @Inject
+  public AbsolutePathReferenceVisitor(Tags... resourceTags) {
+    Map<String, String> tagsToMakeAbsolute = new HashMap<String, String>();
+    for (Tags r : resourceTags) {
+      tagsToMakeAbsolute.putAll(r.getResourceTags());
+    }
+
+    this.tagsToMakeAbsolute = tagsToMakeAbsolute;
+  }
 
+  // @Override
   public VisitStatus visit(Gadget gadget, Node node) throws RewritingException {
-    Attr nodeAttr = getUriAttributeFromNode(node, RESOURCE_TAGS);
+    Attr nodeAttr = getUriAttributeFromNode(node, tagsToMakeAbsolute);
 
     if (nodeAttr != null) {
       try {
-        Uri prevUri = Uri.parse(nodeAttr.getValue());
-        Uri resolved = gadget.getSpec().getUrl().resolve(prevUri);
-        if (!resolved.equals(prevUri)) {
+        Uri nodeUri = Uri.parse(nodeAttr.getValue());
+        Uri baseUri = getBaseResolutionUri(gadget, node);
+
+        Uri resolved = baseUri.resolve(nodeUri);
+
+        if (!resolved.equals(nodeUri)) {
           nodeAttr.setValue(resolved.toString());
           return VisitStatus.MODIFY;
         }
@@ -62,6 +103,7 @@ public class AbsolutePathReferenceVisito
     return VisitStatus.BYPASS;
   }
 
+  // @Override
   public boolean revisit(Gadget gadget, List<Node> node) throws RewritingException {
     // Modification happens immediately.
     return false;
@@ -90,4 +132,58 @@ public class AbsolutePathReferenceVisito
 
     return null;
   }
+
+  /**
+   * Returns the uri to resolve any relative url on the current page to.
+   * This is equal to the base uri (in case the page has one) or the current
+   * page uri.
+   * @param gadget The gadget (container for page) being processed.
+   * @param node The current node being processed.
+   * @return The uri to resolve non absolute uri's relative to.
+   */
+  private Uri getBaseResolutionUri(Gadget gadget, Node node) {
+    Uri pageUri = gadget.getSpec().getUrl();
+    Uri baseUri = getBaseUri(node.getOwnerDocument());
+    return baseUri != null ? baseUri : pageUri;
+  }
+
+  /**
+   * Returns the base uri of the given document.
+   * Base uri is specified as &lt;base href="..."&gt;
+   * @param doc The document.
+   * @return Base uri of the document.
+   */
+  @VisibleForTesting
+  Uri getBaseUri(Document doc) {
+    String baseHref = getBaseHref(doc);
+    if (baseHref != null) {
+      try {
+        return Uri.parse(baseHref);
+      } catch (Uri.UriException e) {
+        // Ignore.
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * Returns href value of the base tag.
+   * @param doc The document to process.
+   * @return Value of href attribute of the base tag.
+   */
+  @VisibleForTesting
+  String getBaseHref(Document doc) {
+    NodeList list = doc.getElementsByTagName("base");
+    if (list.getLength() == 0) {
+      return null;
+    }
+
+    NamedNodeMap nodeMap = list.item(0).getAttributes();
+    if (nodeMap == null) {
+      return null;
+    }
+    Attr attr = (Attr) nodeMap.getNamedItem("href");
+    return attr != null ? attr.getValue() : null;
+  }
 }

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceVisitorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceVisitorTest.java?rev=955778&r1=955777&r2=955778&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceVisitorTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/AbsolutePathReferenceVisitorTest.java Thu Jun 17 23:01:12 2010
@@ -18,19 +18,20 @@
  */
 package org.apache.shindig.gadgets.rewrite;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
 import org.apache.shindig.common.uri.Uri;
 import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor.VisitStatus;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import org.junit.Test;
-
 import org.w3c.dom.Comment;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.Text;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class AbsolutePathReferenceVisitorTest extends DomWalkerTestBase {
   private static final Uri ABSOLUTE_URI = Uri.parse("http://host.com/path");
   private static final String JS_URI_STR = "javascript:foo();";
@@ -39,51 +40,67 @@ public class AbsolutePathReferenceVisito
   private static final Uri PATH_RELATIVE_URI = Uri.parse("path/relative");
   private static final Uri PATH_RELATIVE_RESOLVED_URI = GADGET_URI.resolve(PATH_RELATIVE_URI);
   private static final String INVALID_URI_STRING = "!^|BAD URI|^!";
-  
+
+  AbsolutePathReferenceVisitor visitorForAllTags() {
+    return new AbsolutePathReferenceVisitor(
+        AbsolutePathReferenceVisitor.Tags.RESOURCES,
+        AbsolutePathReferenceVisitor.Tags.HYPERLINKS);
+  }
+
+  AbsolutePathReferenceVisitor visitorForHyperlinks() {
+    return new AbsolutePathReferenceVisitor(
+        AbsolutePathReferenceVisitor.Tags.HYPERLINKS);
+  }
+
+  AbsolutePathReferenceVisitor visitorForResources() {
+    return new AbsolutePathReferenceVisitor(
+        AbsolutePathReferenceVisitor.Tags.RESOURCES);
+  }
+
   @Test
   public void bypassComment() throws Exception {
     Comment comment = doc.createComment("howdy pardner");
     assertEquals(VisitStatus.BYPASS, getVisitStatus(comment));
   }
-  
+
   @Test
   public void bypassText() throws Exception {
     Text text = doc.createTextNode("back scratchah! get ya back scratcha he'yah!");
     assertEquals(VisitStatus.BYPASS, getVisitStatus(text));
   }
-  
+
   @Test
   public void bypassNonSupportedTag() throws Exception {
     Element div = elem("div", "src", RELATIVE_URI.toString(), "href", RELATIVE_URI.toString());
     assertEquals(VisitStatus.BYPASS, getVisitStatus(div));
   }
-  
+
   @Test
   public void bypassTagWithoutAttrib() throws Exception {
     Element a = elem("a");
     assertEquals(VisitStatus.BYPASS, getVisitStatus(a));
   }
-  
+
   @Test
   public void absolutifyTagA() throws Exception {
     checkAbsolutifyStates("a");
   }
-  
+
   @Test
   public void absolutifyTagImg() throws Exception {
     checkAbsolutifyStates("img");
   }
-  
+
   @Test
   public void absolutifyTagLink() throws Exception {
     checkAbsolutifyStates("link");
   }
-  
+
   @Test
   public void absolutifyTagScript() throws Exception {
     checkAbsolutifyStates("script");
   }
-  
+
   @Test
   public void absolutifyTagObject() throws Exception {
     checkAbsolutifyStates("object");
@@ -91,15 +108,63 @@ public class AbsolutePathReferenceVisito
 
   @Test
   public void revisitDoesNothing() throws Exception {
-    assertFalse(new AbsolutePathReferenceVisitor().revisit(gadget(), null));
+    assertFalse(visitorForAllTags().revisit(gadget(), null));
   }
-  
+
+  @Test
+  public void resolveRelativeToBaseTagIfPresent() throws Exception {
+    Element baseTag = elem("base", "href", "http://www.example.org");
+    Element img = elem("img", "src", RELATIVE_URI.toString());
+    Element html = htmlDoc(null, baseTag, img);
+
+    assertEquals(VisitStatus.BYPASS, getVisitStatus(baseTag));
+    assertEquals(VisitStatus.MODIFY, getVisitStatus(img));
+    assertEquals("http://www.example.org" + RELATIVE_URI.toString(),
+                 img.getAttribute("src"));
+  }
+
+  @Test
+  public void getBaseHrefReturnsNullIfBaseTagWithoutHrefAttribute()
+      throws Exception {
+    Element baseTag = elem("base");
+    Element img = elem("img", "src", RELATIVE_URI.toString());
+    Element html = htmlDoc(null, baseTag, img);
+
+    AbsolutePathReferenceVisitor visitor = visitorForAllTags();
+    assertEquals(VisitStatus.BYPASS, getVisitStatus(baseTag));
+    assertEquals(VisitStatus.MODIFY, getVisitStatus(img));
+    assertEquals(RELATIVE_RESOLVED_URI.toString(), img.getAttribute("src"));
+  }
+
+  @Test
+  public void testGetBaseUri() throws Exception {
+    Element baseTag1 = elem("base", "href", "http://www.example1.org");
+    Element baseTag2 = elem("base", "href", "http://www.example2.org");
+
+    Element img = elem("img", "src", RELATIVE_URI.toString());
+    Element a = elem("a", "href", RELATIVE_URI.toString());
+
+    Node[] headNodes = { baseTag1 };
+    Element html = htmlDoc(headNodes, baseTag2, img, a);
+
+    AbsolutePathReferenceVisitor visitor = visitorForAllTags();
+    assertEquals("http://www.example1.org",
+                 visitor.getBaseHref(html.getOwnerDocument()));
+    assertEquals("http://www.example1.org",
+                 visitor.getBaseUri(html.getOwnerDocument()).toString());
+  }
+
   private void checkAbsolutifyStates(String tagName) throws Exception {
     String lcTag = tagName.toLowerCase();
     String ucTag = tagName.toUpperCase();
-    String validAttr = AbsolutePathReferenceVisitor.RESOURCE_TAGS.get(lcTag);
+    Map<String, String> resourceTags = new HashMap<String, String>();
+    resourceTags.putAll(AbsolutePathReferenceVisitor.Tags
+        .RESOURCES.getResourceTags());
+    resourceTags.putAll(AbsolutePathReferenceVisitor.Tags
+        .HYPERLINKS.getResourceTags());
+    String validAttr = resourceTags.get(lcTag);
     String invalidAttr = validAttr + "whoknows";
-    
+
     // lowercase, correct attrib, relative-possible URL
     Element lcValidRelative = elem(lcTag, validAttr, RELATIVE_URI.toString());
     assertEquals(VisitStatus.MODIFY, getVisitStatus(lcValidRelative));
@@ -142,6 +207,6 @@ public class AbsolutePathReferenceVisito
   }
   
   private VisitStatus getVisitStatus(Node node) throws Exception {
-    return new AbsolutePathReferenceVisitor().visit(gadget(), node);
+    return visitorForAllTags().visit(gadget(), node);
   }
 }