You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2010/08/10 13:32:34 UTC

svn commit: r983934 [4/8] - in /shindig/branches/2.0.x: ./ config/ content/container/ content/samplecontainer/examples/ActivityStreams/ extras/src/main/java/org/apache/shindig/extras/as/core/model/ extras/src/main/java/org/apache/shindig/extras/as/open...

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CssResponseRewriter.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CssResponseRewriter.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CssResponseRewriter.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CssResponseRewriter.java Tue Aug 10 11:32:26 2010
@@ -24,7 +24,7 @@ import org.apache.shindig.gadgets.Gadget
 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.CajaCssLexerParser;
+import org.apache.shindig.gadgets.parse.caja.CajaCssParser;
 import org.apache.shindig.gadgets.uri.ProxyUriManager;
 import org.w3c.dom.Element;
 
@@ -39,6 +39,10 @@ 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;
 
@@ -49,12 +53,12 @@ public class CssResponseRewriter impleme
 
   private static final Logger LOG = Logger.getLogger(CssResponseRewriter.class.getName());
 
-  private final CajaCssLexerParser cssParser;
+  private final CajaCssParser cssParser;
   private final ProxyUriManager proxyUriManager;
   private final ContentRewriterFeature.Factory rewriterFeatureFactory;
 
   @Inject
-  public CssResponseRewriter(CajaCssLexerParser cssParser,
+  public CssResponseRewriter(CajaCssParser cssParser,
       ProxyUriManager proxyUriManager, ContentRewriterFeature.Factory rewriterFeatureFactory) {
     this.cssParser = cssParser;
     this.proxyUriManager = proxyUriManager;
@@ -89,7 +93,7 @@ public class CssResponseRewriter impleme
     try {
       String original = IOUtils.toString(content);
       try {
-        List<Object> stylesheet = cssParser.parse(original);
+        CssTree.StyleSheet stylesheet = cssParser.parseDom(original, source);
         List<String> stringList = rewrite(stylesheet, source, uriMaker, extractImports);
         // Serialize the stylesheet
         cssParser.serialize(stylesheet, writer);
@@ -121,7 +125,8 @@ public class CssResponseRewriter impleme
   public List<String> rewrite(Element styleNode, Uri source,
       UriMaker uriMaker, boolean extractImports) throws RewritingException {
     try {
-      List<Object> stylesheet = cssParser.parse(styleNode.getTextContent());
+      CssTree.StyleSheet stylesheet =
+        cssParser.parseDom(styleNode.getTextContent(), source);
       List<String> imports = rewrite(stylesheet, source, uriMaker, extractImports);
       // Write the rewritten CSS back into the element
       String content = cssParser.serialize(stylesheet);
@@ -152,26 +157,33 @@ public class CssResponseRewriter impleme
    *            referenced URIs.
    * @return Empty list of extracted import URIs.
    */
-  public static List<String> rewrite(List<Object> styleSheet, final Uri source,
+  public static List<String> rewrite(CssTree.StyleSheet styleSheet, final Uri source,
       final UriMaker uriMaker, final boolean extractImports) {
     final List<String> imports = Lists.newLinkedList();
-
-    for (int i = styleSheet.size() - 1; i >= 0; i--) {
-      if (styleSheet.get(i) instanceof CajaCssLexerParser.ImportDecl) {
-        if (extractImports) {
-          imports.add(0, ((CajaCssLexerParser.ImportDecl)styleSheet.get(i)).getUri());
-          styleSheet.remove(i);
-        } else {
-          CajaCssLexerParser.ImportDecl importDecl = (CajaCssLexerParser.ImportDecl) styleSheet
-              .get(i);
-          importDecl.setUri(rewriteUri(uriMaker, importDecl.getUri(), source));
+    final List<CssTree.UriLiteral> 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);
+            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);
+          uriDecl.setValue(rewritten);
         }
-      } else if (styleSheet.get(i) instanceof CajaCssLexerParser.UriDecl) {
-        CajaCssLexerParser.UriDecl uriDecl = (CajaCssLexerParser.UriDecl) styleSheet
-              .get(i);
-          uriDecl.setUri(rewriteUri(uriMaker, uriDecl.getUri(), source));
-      }
-    }
+        return true;
+      }}, null);
+
     return imports;
   }
   

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DomWalker.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DomWalker.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DomWalker.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DomWalker.java Tue Aug 10 11:32:26 2010
@@ -28,9 +28,12 @@ import org.apache.shindig.gadgets.http.H
 import org.apache.shindig.gadgets.http.HttpResponseBuilder;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
 import org.apache.shindig.gadgets.uri.UriCommon.Param;
+import org.apache.commons.lang.StringUtils;
 
+import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
@@ -148,7 +151,13 @@ public final class DomWalker {
       Map<Visitor, List<Node>> reservations = Maps.newHashMap();
         
       LinkedList<Node> toVisit = Lists.newLinkedList();
-      toVisit.add(content.getDocument().getDocumentElement());
+      Document doc = content.getDocument();
+      if (doc == null) {
+        throw new RewritingException("content.getDocument is null. Content: "
+                                     + content.getContent(),
+                                     HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+      }
+      toVisit.add(doc.getDocumentElement());
       boolean mutated = false;
       while (!toVisit.isEmpty()) {
         Node visiting = toVisit.removeFirst();

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/MutableContent.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/MutableContent.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/MutableContent.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/MutableContent.java Tue Aug 10 11:32:26 2010
@@ -17,6 +17,10 @@
  */
 package org.apache.shindig.gadgets.rewrite;
 
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
 import org.apache.commons.io.IOUtils;
 import org.apache.shindig.common.util.CharsetUtil;
 import org.apache.shindig.gadgets.GadgetException;
@@ -28,12 +32,12 @@ import org.w3c.dom.Document;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
 import java.util.Arrays;
 import java.util.Map;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  * Object that maintains a String representation of arbitrary contents
@@ -42,15 +46,23 @@ import com.google.common.collect.Maps;
 public class MutableContent {
   private static final Map<String, Object> EMPTY_MAP = ImmutableMap.of();
 
+  // String representation of contentBytes taking into account the correct
+  // encoding of the content.
   private String content;
   private byte[] contentBytes;
+
+  // Encoding of the content bytes. UTF-8 by default.
+  private Charset contentEncoding;
+
   private HttpResponse contentSource;
+
   private Document document;
   private int numChanges;
   private final GadgetHtmlParser contentParser;
   private Map<String, Object> pipelinedData;
 
   private static final String MUTABLE_CONTENT_LISTENER = "MutableContentListener";
+  private static final Logger logger = Logger.getLogger(MutableContent.class.getName());
 
   public static void notifyEdit(Document doc) {
     MutableContent mc = (MutableContent) doc.getUserData(MUTABLE_CONTENT_LISTENER);
@@ -66,6 +78,7 @@ public class MutableContent {
     this.contentParser = contentParser;
     this.content = content;
     this.numChanges = 0;
+    this.contentEncoding = Charsets.UTF_8;
   }
 
   /**
@@ -75,6 +88,7 @@ public class MutableContent {
   public MutableContent(GadgetHtmlParser contentParser, HttpResponse contentSource) {
     this.contentParser = contentParser;
     this.contentSource = contentSource;
+    this.contentEncoding = contentSource != null ? contentSource.getEncodingCharset() : null;
   }
 
   /**
@@ -98,11 +112,8 @@ public class MutableContent {
       } else if (document != null) {
         content = HtmlSerialization.serialize(document);
       } else if (contentBytes != null) {
-        try {
-          content = new String(contentBytes, "UTF8");
-        } catch (UnsupportedEncodingException e) {
-          // Never happens.
-        }
+        Charset useEncoding = contentEncoding != null ? contentEncoding : Charsets.UTF_8;
+        content = useEncoding.decode(ByteBuffer.wrap(contentBytes)).toString();
       }
     }
     return content;
@@ -136,37 +147,67 @@ public class MutableContent {
     if (contentBytes == null) {
       if (contentSource != null) {
         try {
-          contentBytes = IOUtils.toByteArray(contentSource.getResponse());
+          setContentBytesState(IOUtils.toByteArray(contentSource.getResponse()),
+              contentSource.getEncodingCharset());
           contentSource = null;
         } catch (IOException e) {
           // Doesn't occur; responseBytes wrapped as a ByteArrayInputStream.
         }
       } else if (content != null) {
-        contentBytes = CharsetUtil.getUtf8Bytes(content);
+        // If retrieving a String here, we've already converted to UTF8.
+        // Be sure to reflect this when setting bytes.
+        // In the case of HttpResponseBuilder, this re-sets charset in Content-Type
+        // to UTF-8 rather than whatever it was before. We do this to standardize
+        // on UTF-8 for all String handling.
+        setContentBytesState(CharsetUtil.getUtf8Bytes(content), Charsets.UTF_8);
       } else if (document != null) {
-        contentBytes = CharsetUtil.getUtf8Bytes(HtmlSerialization.serialize(document));
+        setContentBytesState(
+            CharsetUtil.getUtf8Bytes(HtmlSerialization.serialize(document)), Charsets.UTF_8);
       }
     }
     return contentBytes;
   }
 
   /**
-   * Sets the object's contentBytes as the given raw input.
+   * Sets the object's contentBytes as the given raw input. If ever interpreted
+   * as a String, the data will be decoded as the encoding specified.
    * Note, this operation may clear the document if the content has changed.
    * Also note, it's mandated that the new bytes array will NOT be modified
    * by the caller of this API. The array is not copied, for performance reasons.
    * If the caller may modify a byte array, it MUST pass in a new copy.
    * @param newBytes New content.
    */
-  public void setContentBytes(byte[] newBytes) {
+  public void setContentBytes(byte[] newBytes, Charset newEncoding) {
     if (contentBytes == null || !Arrays.equals(contentBytes, newBytes)) {
-      contentBytes = newBytes;
+      setContentBytesState(newBytes, newEncoding);
       document = null;
       contentSource = null;
       content = null;
       incrementNumChanges();
     }
   }
+  
+  /**
+   * Sets content to new byte array, with unspecified charset. It is
+   * recommended to use the {@code setContentBytes(byte[], Charset)} API instead,
+   * where possible.
+   * @param newBytes New content.
+   */
+  public final void setContentBytes(byte[] newBytes) {
+    setContentBytes(newBytes, null);
+  }
+  
+  /**
+   * Sets internal state having to do with content bytes, from the provided
+   * byte array and charset.
+   * This MUST be the only place in which MutableContent's notion of encoding is mutated.
+   * @param newBytes New content.
+   * @param newEncoding Encoding for the bytes, or null for unspecified.
+   */
+  protected void setContentBytesState(byte[] newBytes, Charset newEncoding) {
+    contentBytes = newBytes;
+    contentEncoding = newEncoding;
+  }
 
   /**
    * Notification that the content of the document has changed. Causes the content
@@ -199,7 +240,7 @@ public class MutableContent {
       document = contentParser.parseDom(getContent());
       document.setUserData(MUTABLE_CONTENT_LISTENER, this, null);
     } catch (GadgetException e) {
-      // TODO: emit info message
+      logger.log(Level.WARNING, "Got GadgetException when parsing content", e);
       return null;
     }
     return document;

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitor.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitor.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitor.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingVisitor.java Tue Aug 10 11:32:26 2010
@@ -20,7 +20,6 @@ package org.apache.shindig.gadgets.rewri
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
-
 import org.apache.shindig.common.Pair;
 import org.apache.shindig.common.uri.Uri;
 import org.apache.shindig.common.uri.Uri.UriException;
@@ -33,23 +32,28 @@ import org.w3c.dom.Node;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  * Simple visitor that, when plugged into a DomWalker, rewrites
  * resource links to proxied versions of the same.
  */
 public class ProxyingVisitor implements DomWalker.Visitor {
+  private static final Logger logger = Logger.getLogger(
+      ProxyUriManager.class.getName());
+
   public final static Map<String, String> RESOURCE_TAGS =
     ImmutableMap.of(
+        "body", "background",
         "img", "src",
-        "embed", "src",
+        "input", "src",
         "link", "href",
-        "script", "src",
-        "object", "src");
-  
+        "script", "src");
+
   private final ContentRewriterFeature.Config featureConfig;
   private final ProxyUriManager uriManager;
- 
+
   public ProxyingVisitor(ContentRewriterFeature.Config featureConfig,
                               ProxyUriManager uriManager) {
     this.featureConfig = featureConfig;
@@ -82,7 +86,8 @@ public class ProxyingVisitor implements 
         continue;
       }
       Element element = (Element)proxyPair.one;
-      element.setAttribute(RESOURCE_TAGS.get(element.getNodeName()), proxyPair.two.toString());
+      String nodeName = element.getNodeName().toLowerCase();
+      element.setAttribute(RESOURCE_TAGS.get(nodeName), proxyPair.two.toString());
       mutated = true;
     }
     
@@ -92,15 +97,21 @@ public class ProxyingVisitor implements 
   private List<Pair<Node, Uri>> getProxiedUris(Gadget gadget, List<Node> nodes) {
     List<ProxyUriManager.ProxyUri> reservedUris =
         Lists.newArrayListWithCapacity(nodes.size());
+    List<Node> reservedNodes =
+        Lists.newArrayListWithCapacity(nodes.size());
     
     for (Node node : nodes) {
       Element element = (Element)node;
-      String uriStr = element.getAttribute(RESOURCE_TAGS.get(element.getNodeName()));
+      String nodeName = node.getNodeName().toLowerCase();
+      String uriStr = element.getAttribute(RESOURCE_TAGS.get(nodeName)).trim();
       try {
-        reservedUris.add(new ProxyUriManager.ProxyUri(gadget, Uri.parse(uriStr)));
+        ProxyUriManager.ProxyUri proxiedUri = new ProxyUriManager.ProxyUri(
+            gadget, Uri.parse(uriStr));
+        reservedUris.add(proxiedUri);
+        reservedNodes.add(node);
       } catch (UriException e) {
-        // Uri parse exception, add null.
-        reservedUris.add(null);
+        // Uri parse exception, ignore.
+        logger.log(Level.WARNING, "Uri exception when parsing: " + uriStr, e);
       }
     }
     
@@ -111,7 +122,7 @@ public class ProxyingVisitor implements 
     List<Pair<Node, Uri>> proxiedUris = Lists.newArrayListWithCapacity(nodes.size());
     
     Iterator<Uri> uriIt = resourceUris.iterator();
-    for (Node node : nodes) {
+    for (Node node : reservedNodes) {
       proxiedUris.add(Pair.of(node, uriIt.next()));
     }
     

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java Tue Aug 10 11:32:26 2010
@@ -19,20 +19,18 @@
 package org.apache.shindig.gadgets.rewrite;
 
 import com.google.common.collect.ImmutableList;
-
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 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.old.SanitizingGadgetRewriter;
-import org.apache.shindig.gadgets.render.old.SanitizingRequestRewriter;
+import org.apache.shindig.gadgets.render.SanitizingGadgetRewriter;
+import org.apache.shindig.gadgets.render.SanitizingResponseRewriter;
 import org.apache.shindig.gadgets.rewrite.image.BasicImageRewriter;
-import org.apache.shindig.gadgets.rewrite.old.CssRequestRewriter;
-import org.apache.shindig.gadgets.rewrite.old.HTMLContentRewriter;
 import org.apache.shindig.gadgets.servlet.CajaContentRewriter;
 
 import java.util.List;
@@ -44,6 +42,9 @@ public class RewriteModule extends Abstr
 
   @Override
   protected void configure() {
+    bind(ResponseRewriterRegistry.class)
+        .annotatedWith(Names.named("shindig.accelerate.response.rewriter.registry"))
+        .to(AccelResponseRewriterRegistry.class);
   }
 
   @Provides
@@ -52,13 +53,16 @@ public class RewriteModule extends Abstr
   protected List<GadgetRewriter> provideGadgetRewriters(
       PipelineDataGadgetRewriter pipelineRewriter,
       TemplateRewriter templateRewriter,
-      HTMLContentRewriter optimizingRewriter,
-      CssRequestRewriter cssRewriter,
+      AbsolutePathReferenceRewriter absolutePathRewriter,
+      StyleTagExtractorContentRewriter styleTagExtractorRewriter,
+      StyleAdjacencyContentRewriter styleAdjacencyRewriter,
+      ProxyingContentRewriter proxyingRewriter,
       CajaContentRewriter cajaRewriter,
       SanitizingGadgetRewriter sanitizedRewriter,
       RenderingGadgetRewriter renderingRewriter,
       OpenSocialI18NGadgetRewriter i18nRewriter) {
-    return ImmutableList.of(pipelineRewriter, templateRewriter, optimizingRewriter,
+    return ImmutableList.of(pipelineRewriter, templateRewriter,
+        absolutePathRewriter, styleTagExtractorRewriter, styleAdjacencyRewriter, proxyingRewriter,
         cajaRewriter, sanitizedRewriter, renderingRewriter, i18nRewriter);
   }
 
@@ -93,9 +97,27 @@ public class RewriteModule extends Abstr
   @Provides
   @Singleton
   protected List<ResponseRewriter> provideResponseRewriters(
-      HTMLContentRewriter optimizingRewriter,
-      CssRequestRewriter cssRewriter,
-      SanitizingRequestRewriter sanitizedRewriter) {
-    return ImmutableList.of(optimizingRewriter, cssRewriter, sanitizedRewriter);
+      AbsolutePathReferenceRewriter absolutePathRewriter,
+      StyleTagExtractorContentRewriter styleTagExtractorRewriter,
+      StyleAdjacencyContentRewriter styleAdjacencyRewriter,
+      ProxyingContentRewriter proxyingRewriter,
+      CssResponseRewriter cssRewriter,
+      SanitizingResponseRewriter sanitizedRewriter,
+      CajaResponseRewriter cajaRewriter) {
+    return ImmutableList.of(
+        absolutePathRewriter, styleTagExtractorRewriter, styleAdjacencyRewriter, proxyingRewriter,
+        cssRewriter, sanitizedRewriter, cajaRewriter);
+  }
+
+  @Provides
+  @Singleton
+  @Named("shindig.accelerate.response.rewriters")
+  protected List<ResponseRewriter> provideAccelResponseRewriters(
+      AbsolutePathReferenceRewriter absolutePathReferenceRewriter,
+      StyleTagProxyEmbeddedUrlsRewriter styleTagProxyEmbeddedUrlsRewriter,
+      ProxyingContentRewriter proxyingContentRewriter) {
+    return ImmutableList.of((ResponseRewriter) absolutePathReferenceRewriter,
+        (ResponseRewriter) styleTagProxyEmbeddedUrlsRewriter,
+        (ResponseRewriter) proxyingContentRewriter);
   }
 }

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/image/BaseOptimizer.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/image/BaseOptimizer.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/image/BaseOptimizer.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/image/BaseOptimizer.java Tue Aug 10 11:32:26 2010
@@ -24,6 +24,7 @@ import org.apache.shindig.gadgets.http.H
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
+import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
 
 import java.awt.image.BufferedImage;
@@ -151,7 +152,7 @@ abstract class BaseOptimizer {
     ImageWriteParam writeParam;
     public ImageIOOutputter(ImageWriter writer, ImageWriteParam writeParam) {
       this.writer = writer;
-      this.writeParam = firstNonNull(writeParam, writer.getDefaultWriteParam());
+      this.writeParam = Objects.firstNonNull(writeParam, writer.getDefaultWriteParam());
     }
 
     public byte[] toBytes(BufferedImage image) throws IOException {
@@ -195,7 +196,4 @@ abstract class BaseOptimizer {
       }
     }
   }
-  private static <T> T firstNonNull(T first, T second) {
-    return first != null ? first : Preconditions.checkNotNull(second);
-  }
 }

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/image/BasicImageRewriter.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/image/BasicImageRewriter.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/image/BasicImageRewriter.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/image/BasicImageRewriter.java Tue Aug 10 11:32:26 2010
@@ -145,8 +145,8 @@ public class BasicImageRewriter implemen
       
       boolean noExpand = "1".equals(request.getParam(PARAM_NO_EXPAND));
       if (noExpand &&
-          imageInfo.getHeight() <= requestedHeight &&
-          imageInfo.getWidth() <= requestedWidth) {
+          (requestedHeight == null || imageInfo.getHeight() <= requestedHeight) &&
+          (requestedWidth == null || imageInfo.getWidth() <= requestedWidth)) {
         // Don't do anything, since the current image fits within the bounding area.
         isResizeRequested = false;
       }

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java Tue Aug 10 11:32:26 2010
@@ -19,15 +19,15 @@ package org.apache.shindig.gadgets.servl
 
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
-
+import com.google.inject.name.Named;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.shindig.common.uri.Uri;
-import org.apache.shindig.common.uri.UriBuilder;
 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.ResponseRewriterRegistry;
@@ -37,20 +37,15 @@ import org.apache.shindig.gadgets.uri.Pr
 import org.apache.shindig.gadgets.uri.UriCommon;
 import org.apache.shindig.gadgets.uri.UriUtils;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.util.logging.Logger;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 
 /**
  * Handles requests for accel servlet.
  * The objective is to accelerate web pages.
  */
 @Singleton
-public class AccelHandler extends ProxyBase {
-  private static final Logger logger = Logger.getLogger(ProxyHandler.class.getName());
-
+public class AccelHandler {
   static final String ERROR_FETCHING_DATA = "Error fetching data";
 
   // TODO: parameterize these.
@@ -60,57 +55,64 @@ public class AccelHandler extends ProxyB
   protected final RequestPipeline requestPipeline;
   protected final ResponseRewriterRegistry contentRewriterRegistry;
   protected final AccelUriManager uriManager;
+  protected final boolean remapInternalServerError;
 
   @Inject
   public AccelHandler(RequestPipeline requestPipeline,
+                      @Named("shindig.accelerate.response.rewriter.registry")
                       ResponseRewriterRegistry contentRewriterRegistry,
-                      AccelUriManager accelUriManager) {
+                      AccelUriManager accelUriManager,
+                      @Named("shindig.accelerate.remapInternalServerError")
+                      Boolean remapInternalServerError) {
     this.requestPipeline = requestPipeline;
     this.contentRewriterRegistry = contentRewriterRegistry;
     this.uriManager = accelUriManager;
+    this.remapInternalServerError = remapInternalServerError;
   }
 
-  @Override
-  protected void doFetch(HttpServletRequest request, HttpServletResponse response)
-      throws IOException, GadgetException {
+  protected HttpResponse fetch(HttpRequest request) throws IOException, GadgetException {
     // TODO: Handle if modified since headers.
 
     // Parse and normalize to get a proxied request uri.
-    Uri requestUri = new UriBuilder(request).toUri();
-    ProxyUriManager.ProxyUri proxyUri = getProxyUri(requestUri);
+    ProxyUriManager.ProxyUri proxyUri = getProxyUri(request.getUri());
 
     // Fetch the content of the requested uri.
     HttpRequest req = buildHttpRequest(request, proxyUri);
     HttpResponse results = requestPipeline.execute(req);
 
-    if (!handleErrors(results, response)) {
-      // In case of errors where we want to short circuit the rewriting and
-      // throw appropriate gadget exception.
-      return;
-    }
-
-    // Rewrite the content.
-    try {
-      results = contentRewriterRegistry.rewriteHttpResponse(req, results);
-    } catch (RewritingException e) {
-      if (!isRecoverable(req, results, e)) {
-        throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e,
-                                  e.getHttpStatusCode());
+    HttpResponse errorResponse = handleErrors(results);
+    if (errorResponse == null) {
+      // No error. Lets rewrite the content.
+      try {
+        results = contentRewriterRegistry.rewriteHttpResponse(req, results);
+      } catch (RewritingException e) {
+        if (!isRecoverable(req, results, e)) {
+          throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e,
+                                    e.getHttpStatusCode());
+        }
       }
+    } else {
+      results = errorResponse;
     }
 
     // Copy the response headers and status code to the final http servlet
     // response.
+    HttpResponseBuilder response = new HttpResponseBuilder();
     UriUtils.copyResponseHeadersAndStatusCode(
-        results, response,
-        UriUtils.DisallowedResponseHeaders.OUTPUT_TRANSFER_DIRECTIVES,
-        UriUtils.DisallowedResponseHeaders.CLIENT_STATE_DIRECTIVES);
+        results, response, remapInternalServerError, true,
+        UriUtils.DisallowedHeaders.OUTPUT_TRANSFER_DIRECTIVES,
+        UriUtils.DisallowedHeaders.CLIENT_STATE_DIRECTIVES);
 
     // Override the content type of the final http response if the input request
     // had the rewrite mime type header.
-    rewriteContentType(req, response);
+    UriUtils.maybeRewriteContentType(req, response);
 
-    IOUtils.copy(results.getResponse(), response.getOutputStream());
+    // Copy the content.
+    // TODO: replace this with streaming APIs when ready
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    IOUtils.copy(results.getResponse(), baos);
+    response.setResponseNoCopy(baos.toByteArray());
+    return response.create();
   }
 
   /**
@@ -130,7 +132,7 @@ public class AccelHandler extends ProxyB
     } catch (Uri.UriException e) {
       throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
                                 "Failed to parse uri: " + uriString,
-                                HttpServletResponse.SC_BAD_GATEWAY);
+                                HttpResponse.SC_BAD_GATEWAY);
     }
 
     Gadget gadget = DomWalker.makeGadget(requestUri);
@@ -160,67 +162,56 @@ public class AccelHandler extends ProxyB
   }
 
   /**
-   * Generate a remote content request based on the parameters sent from the client.
+   * Build an HttpRequest object encapsulating the request details as requested
+   * by the user.
    * @param request The http request.
    * @param uriToProxyOrRewrite The parsed uri to proxy or rewrite through
    *   accel servlet.
    * @return Remote content request based on the parameters sent from the client.
    * @throws GadgetException In case the data could not be fetched.
    */
-  protected HttpRequest buildHttpRequest(HttpServletRequest request,
+  protected HttpRequest buildHttpRequest(HttpRequest request,
                                          ProxyUriManager.ProxyUri uriToProxyOrRewrite)
       throws GadgetException {
     Uri tgt = uriToProxyOrRewrite.getResource();
-    validateUrl(tgt);
     HttpRequest req = uriToProxyOrRewrite.makeHttpRequest(tgt);
-    this.setRequestHeaders(request, req);
-
     if (req == null) {
       throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
           "No url parameter in request", HttpResponse.SC_BAD_REQUEST);
     }
-    return req;
-  }
 
-  /**
-   * Rewrite the content type of the final http response if the request has the
-   * rewrite-mime-type param.
-   * @param req The http request.
-   * @param response The final http response to be returned to user.
-   */
-  protected void rewriteContentType(HttpRequest req, HttpServletResponse response) {
-    String contentType = response.getContentType();
-    String requiredType = req.getRewriteMimeType();
-    if (!StringUtils.isEmpty(requiredType)) {
-      if (requiredType.endsWith("/*") && !StringUtils.isEmpty(contentType)) {
-        requiredType = requiredType.substring(0, requiredType.length() - 2);
-      }
-      response.setContentType(requiredType);
-    }
+    // Copy the post body if it exists.
+    UriUtils.copyRequestData(request, req);
+
+    // Set and copy headers.
+    ServletUtil.setXForwardedForHeader(request, req);
+    
+    UriUtils.copyRequestHeaders(
+        request, req,
+        UriUtils.DisallowedHeaders.POST_INCOMPATIBLE_DIRECTIVES);
+
+    req.setFollowRedirects(false);
+    return req;
   }
 
   /**
-   * Process errors when fetching uri using request pipeline by throwing
-   * GadgetException in error cases.
+   * Process errors when fetching uri using request pipeline and return the
+   * error response to be returned to the user if any.
    * @param results The http response returned by request pipeline.
-   * @param response The http servlet response to be returned to the user.
-   * @return True if there is no error, false otherwise.
-   * @throws IOException In case of errors.
+   * @return An HttpResponse instance encapsulating error message and status
+   *   code to be returned to the user in case of errors, null otherwise.
    */
-  protected boolean handleErrors(HttpResponse results, HttpServletResponse response)
-      throws IOException {
+  protected HttpResponse handleErrors(HttpResponse results) {
     if (results == null) {
-      response.sendError(HttpServletResponse.SC_BAD_REQUEST, ERROR_FETCHING_DATA);
-      return false;
+      return new HttpResponseBuilder()
+          .setHttpStatusCode(HttpResponse.SC_NOT_FOUND)
+          .setResponse(ERROR_FETCHING_DATA.getBytes())
+          .create();
     }
-    if (results.getHttpStatusCode() == HttpServletResponse.SC_NOT_FOUND) {
-      response.sendError(HttpServletResponse.SC_NOT_FOUND, ERROR_FETCHING_DATA);
-      return false;
-    } else if (results.isError()) {
-      response.sendError(HttpServletResponse.SC_BAD_GATEWAY, ERROR_FETCHING_DATA);
-      return false;
+    if (results.isError()) {
+      return results;
     }
 
-    return true;
+    return null;
   }
 }

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/CajaContentRewriter.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/CajaContentRewriter.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/CajaContentRewriter.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/CajaContentRewriter.java Tue Aug 10 11:32:26 2010
@@ -18,7 +18,6 @@
  */
 package org.apache.shindig.gadgets.servlet;
 
-import com.google.caja.lexer.CharProducer;
 import com.google.caja.lexer.ExternalReference;
 import com.google.caja.lexer.FetchedData;
 import com.google.caja.lexer.InputSource;

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java Tue Aug 10 11:32:26 2010
@@ -49,17 +49,19 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.regex.Pattern;
 
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 /**
  * Servlet which concatenates the content of several proxied HTTP responses
- *
- * @see org.apache.shindig.gadgets.rewrite.old.HTMLContentRewriter
  */
 public class ConcatProxyServlet extends InjectedServlet {
 
+  private static final long serialVersionUID = -4390212150673709895L;
+
   public static final String JSON_PARAM = Param.JSON.getKey();
   private static final Pattern JSON_PARAM_PATTERN = Pattern.compile("^\\w*$");
   
@@ -70,11 +72,11 @@ public class ConcatProxyServlet extends 
   private static final Logger LOG 
       = Logger.getLogger(ConcatProxyServlet.class.getName());
   
-  private RequestPipeline requestPipeline;
-  private ConcatUriManager concatUriManager;
-  private ResponseRewriterRegistry contentRewriterRegistry;
+  private transient RequestPipeline requestPipeline;
+  private transient ConcatUriManager concatUriManager;
+  private transient ResponseRewriterRegistry contentRewriterRegistry;
 
-  private Executor executor = new Executor() {
+  private transient Executor executor = new Executor() {
     public void execute(Runnable r) {
       // Sequential version of 'execute' by default.
       r.run();
@@ -83,26 +85,35 @@ public class ConcatProxyServlet extends 
 
   @Inject
   public void setRequestPipeline(RequestPipeline requestPipeline) {
+    checkInitialized();
     this.requestPipeline = requestPipeline;
   }
   
   @Inject
   public void setConcatUriManager(ConcatUriManager concatUriManager) {
+    checkInitialized();
     this.concatUriManager = concatUriManager;
   }
 
   @Inject
   public void setContentRewriterRegistry(ResponseRewriterRegistry contentRewriterRegistry) {
+    checkInitialized();
     this.contentRewriterRegistry = contentRewriterRegistry;
   }
   
   @Inject
   public void setExecutor(@Named("shindig.concat.executor") Executor executor) {
+    checkInitialized();
     // Executor is independently named to allow separate configuration of
     // concat fetch parallelism and other Shindig job execution.
     this.executor = executor;
   }
 
+  @Override
+  public void init(ServletConfig config) throws ServletException {
+    super.init(config);
+  }
+
   @SuppressWarnings("boxing")
   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetRenderingServlet.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetRenderingServlet.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetRenderingServlet.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetRenderingServlet.java Tue Aug 10 11:32:26 2010
@@ -26,6 +26,7 @@ import org.apache.shindig.gadgets.render
 import org.apache.shindig.gadgets.render.RenderingResults;
 import org.apache.shindig.gadgets.uri.IframeUriManager;
 import org.apache.shindig.gadgets.uri.UriStatus;
+import org.apache.shindig.gadgets.uri.UriCommon.Param;
 
 import com.google.inject.Inject;
 
@@ -35,6 +36,8 @@ import org.apache.commons.lang.StringUti
 import java.io.IOException;
 import java.util.logging.Logger;
 
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -42,23 +45,53 @@ import javax.servlet.http.HttpServletRes
  * Servlet for rendering Gadgets.
  */
 public class GadgetRenderingServlet extends InjectedServlet {
+
+  private static final long serialVersionUID = -5634040113214794888L;
+
   static final int DEFAULT_CACHE_TTL = 60 * 5;
 
   private static final Logger LOG = Logger.getLogger(GadgetRenderingServlet.class.getName());
 
-  private Renderer renderer;
-  private IframeUriManager iframeUriManager;
+  private transient Renderer renderer;
+  private transient IframeUriManager iframeUriManager;
 
   @Inject
   public void setRenderer(Renderer renderer) {
+    checkInitialized();
     this.renderer = renderer;
   }
   
   @Inject
   public void setIframeUriManager(IframeUriManager iframeUriManager) {
+    checkInitialized();
     this.iframeUriManager = iframeUriManager;
   }
 
+  @Override
+  public void init(ServletConfig config) throws ServletException {
+    super.init(config);
+  }
+
+  @Override
+  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+    // If an If-Modified-Since header is ever provided, we always say
+    // not modified. This is because when there actually is a change,
+    // cache busting should occur.
+    UriStatus urlStatus = getUrlStatus(req);
+    if (req.getHeader("If-Modified-Since") != null &&
+        !"1".equals(req.getParameter("nocache")) &&
+        urlStatus == UriStatus.VALID_VERSIONED) {
+      resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+      return;
+    }
+    render(req, resp, urlStatus);
+  }
+
+  @Override
+  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+    render(req, resp, getUrlStatus(req));
+  }
+
   private void render(HttpServletRequest req, HttpServletResponse resp, UriStatus urlstatus)
       throws IOException {
     if (req.getHeader(HttpRequest.DOS_PREVENTION_HEADER) != null) {
@@ -74,62 +107,111 @@ public class GadgetRenderingServlet exte
 
     GadgetContext context = new HttpGadgetContext(req);
     RenderingResults results = renderer.render(context);
-    switch (results.getStatus()) {
+
+    // process the rendering results
+    postGadgetRendering(new PostGadgetRenderingParams(req, resp, urlstatus, context, results));
+  }
+
+  /**
+   * Implementations that extend this class are strongly discouraged from overriding this method.
+   * To customize the behavior please override the hook methods for each of the
+   * RenderingResults.Status enum values instead. 
+   */
+  protected void postGadgetRendering(PostGadgetRenderingParams params) throws IOException {
+    switch (params.getResults().getStatus()) {
       case OK:
-        if (context.getIgnoreCache() ||
-            urlstatus == UriStatus.INVALID_VERSION) {
-          HttpUtil.setCachingHeaders(resp, 0);
-        } else if (urlstatus == UriStatus.VALID_VERSIONED) {
-          // Versioned files get cached indefinitely
-          HttpUtil.setCachingHeaders(resp, true);
-        } else {
-          // Unversioned files get cached for 5 minutes by default, but this can be overridden
-          // with a query parameter.
-          int ttl = DEFAULT_CACHE_TTL;
-          String ttlStr = req.getParameter(ProxyBase.REFRESH_PARAM);
-          if (!StringUtils.isEmpty(ttlStr)) {
-            try {
-              ttl = Integer.parseInt(ttlStr);
-            } catch (NumberFormatException e) {
-              // Ignore malformed TTL value
-              LOG.info("Bad TTL value '" + ttlStr + "' was ignored");
-            }
-          }
-          HttpUtil.setCachingHeaders(resp, ttl, true);
-        }
-        resp.getWriter().print(results.getContent());
+        onOkRenderingResultsStatus(params);
         break;
       case ERROR:
-        resp.setStatus(results.getHttpStatusCode());
-        resp.getWriter().print(StringEscapeUtils.escapeHtml(results.getErrorMessage()));
+        onErrorRenderingResultsStatus(params);
         break;
       case MUST_REDIRECT:
-        resp.sendRedirect(results.getRedirect().toString());
+        onMustRedirectRenderingResultsStatus(params);
         break;
     }
   }
 
-  @Override
-  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-    // If an If-Modified-Since header is ever provided, we always say
-    // not modified. This is because when there actually is a change,
-    // cache busting should occur.
-    UriStatus urlstatus = getUrlStatus(req);
-    if (req.getHeader("If-Modified-Since") != null &&
-        !"1".equals(req.getParameter("nocache")) &&
-        urlstatus == UriStatus.VALID_VERSIONED) {
-      resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
-      return;
+  protected void onOkRenderingResultsStatus(PostGadgetRenderingParams params)
+      throws IOException {
+    UriStatus urlStatus = params.getUrlStatus();
+    HttpServletResponse resp = params.getResponse();
+    if (params.getContext().getIgnoreCache() ||
+        urlStatus == UriStatus.INVALID_VERSION) {
+      HttpUtil.setCachingHeaders(resp, 0);
+    } else if (urlStatus == UriStatus.VALID_VERSIONED) {
+      // Versioned files get cached indefinitely
+      HttpUtil.setCachingHeaders(resp, true);
+    } else {
+      // Unversioned files get cached for 5 minutes by default, but this can be overridden
+      // with a query parameter.
+      int ttl = DEFAULT_CACHE_TTL;
+      String ttlStr = params.getRequest().getParameter(Param.REFRESH.getKey());
+      if (!StringUtils.isEmpty(ttlStr)) {
+        try {
+          ttl = Integer.parseInt(ttlStr);
+        } catch (NumberFormatException e) {
+          // Ignore malformed TTL value
+          LOG.info("Bad TTL value '" + ttlStr + "' was ignored");
+        }
+      }
+      HttpUtil.setCachingHeaders(resp, ttl, true);
     }
-    render(req, resp, urlstatus);
+    resp.getWriter().print(params.getResults().getContent());
   }
 
-  @Override
-  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-    render(req, resp, getUrlStatus(req));
+  protected void onErrorRenderingResultsStatus(PostGadgetRenderingParams params)
+      throws IOException {
+    HttpServletResponse resp = params.getResponse();
+    resp.setStatus(params.getResults().getHttpStatusCode());
+    resp.getWriter().print(StringEscapeUtils.escapeHtml(params.getResults().getErrorMessage()));
   }
-  
+
+  protected void onMustRedirectRenderingResultsStatus(PostGadgetRenderingParams params)
+      throws IOException {
+     params.getResponse().sendRedirect(params.getResults().getRedirect().toString());
+  }
+
   private UriStatus getUrlStatus(HttpServletRequest req) {
     return iframeUriManager.validateRenderingUri(new UriBuilder(req).toUri());
   }
+
+  /**
+   * Contains the input parameters for post rendering methods.
+   */
+  protected static class PostGadgetRenderingParams {
+    private HttpServletRequest req;
+    private HttpServletResponse resp;
+    private UriStatus urlStatus;
+    private GadgetContext context;
+    private RenderingResults results;
+
+    public PostGadgetRenderingParams (HttpServletRequest req, HttpServletResponse resp,
+      UriStatus urlStatus, GadgetContext context, RenderingResults results) {
+      this.req = req;
+      this.resp = resp;
+      this.urlStatus = urlStatus;
+      this.context = context;
+      this.results = results;
+    }
+
+    public HttpServletRequest getRequest() {
+      return req;
+    }
+
+    public HttpServletResponse getResponse() {
+      return resp;
+    }
+
+    public UriStatus getUrlStatus() {
+      return urlStatus;
+    }
+
+    public GadgetContext getContext() {
+      return context;
+    }
+
+    public RenderingResults getResults() {
+      return results;
+    }
+  }
 }

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java Tue Aug 10 11:32:26 2010
@@ -18,43 +18,62 @@
 package org.apache.shindig.gadgets.servlet;
 
 import com.google.inject.Inject;
-
 import org.apache.shindig.common.servlet.InjectedServlet;
-import org.apache.shindig.gadgets.GadgetContext;
-
-import java.io.IOException;
-import java.util.logging.Logger;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.http.HttpResponse;
 
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  * Handles requests for accel servlet.
  * The objective is to accelerate web pages.
  */
 public class HtmlAccelServlet extends InjectedServlet {
+  private static final long serialVersionUID = -424353123863813052L;
 
-  private AccelHandler accelHandler;
-  private static Logger logger = Logger.getLogger(
+  private static final Logger logger = Logger.getLogger(
       HtmlAccelServlet.class.getName());
-
-  public static final String ACCEL_GADGET_PARAM_NAME = "accelGadget";
-  public static final String ACCEL_GADGET_PARAM_VALUE = "true";
+  private transient AccelHandler accelHandler;
 
   @Inject
   public void setHandler(AccelHandler accelHandler) {
+    checkInitialized();
     this.accelHandler = accelHandler;
   }
 
   @Override
-  protected void doGet(HttpServletRequest request, HttpServletResponse response)
+  public void init(ServletConfig config) throws ServletException {
+    super.init(config);
+  }
+
+  @Override
+  protected void doGet(HttpServletRequest request, HttpServletResponse servletResponse)
       throws IOException {
-    logger.fine("accel request = " + request.toString());
-    accelHandler.fetch(request, response);
+    if (logger.isLoggable(Level.FINE)) {
+      logger.fine("Accel request = " + request.toString());
+    }
+    
+    HttpRequest req = ServletUtil.fromHttpServletRequest(request);
+    HttpResponse response = null;
+    try {
+      response = accelHandler.fetch(req);
+    } catch (GadgetException e) {
+      response = ServletUtil.errorResponse(e);
+    }
+    
+    ServletUtil.copyResponseToServlet(response, servletResponse);
   }
 
-  public static boolean isAccel(GadgetContext context) {
-    return context.getParameter(HtmlAccelServlet.ACCEL_GADGET_PARAM_NAME) ==
-        HtmlAccelServlet.ACCEL_GADGET_PARAM_VALUE;
+  @Override
+  protected void doPost(HttpServletRequest request, HttpServletResponse response)
+      throws IOException {
+    doGet(request, response);
   }
 }

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsServlet.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsServlet.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsServlet.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsServlet.java Tue Aug 10 11:32:26 2010
@@ -29,6 +29,7 @@ import org.apache.shindig.common.servlet
 import org.apache.shindig.common.uri.UriBuilder;
 import org.apache.shindig.config.ContainerConfig;
 import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.RenderingContext;
 import org.apache.shindig.gadgets.config.ConfigContributor;
 import org.apache.shindig.gadgets.features.FeatureRegistry;
@@ -44,6 +45,8 @@ import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -52,6 +55,9 @@ import javax.servlet.http.HttpServletRes
  * Used by type=URL gadgets in loading JavaScript resources.
  */
 public class JsServlet extends InjectedServlet {
+  
+  private static final long serialVersionUID = 6255917470412008175L;
+
   static final String ONLOAD_JS_TPL = "(function() {" +
       "var nm='%s';" +
       "if (typeof window[nm]==='function') {" +
@@ -60,37 +66,53 @@ public class JsServlet extends InjectedS
       "})();";
   private static final Pattern ONLOAD_FN_PATTERN = Pattern.compile("[a-zA-Z0-9_]+");
 
-  private FeatureRegistry registry;
+  private transient FeatureRegistry registry;
+  private transient JsUriManager jsUriManager;
+  private transient ContainerConfig containerConfig;
+  private transient Map<String, ConfigContributor> configContributors;
+
   @Inject
   public void setRegistry(FeatureRegistry registry) {
+    checkInitialized();
     this.registry = registry;
   }
-  
-  private JsUriManager jsUriManager;
+
   @Inject
   public void setUrlGenerator(JsUriManager jsUriManager) {
+    checkInitialized();
     this.jsUriManager = jsUriManager;
   }
 
-  private ContainerConfig containerConfig;
   @Inject
   public void setContainerConfig(ContainerConfig containerConfig) {
+    checkInitialized();
     this.containerConfig = containerConfig;
   }
 
-  private Map<String, ConfigContributor> configContributors;
   @Inject
   public void setConfigContributors(Map<String, ConfigContributor> configContributors) {
+    checkInitialized();
     this.configContributors = configContributors;
   }
 
   @Override
+  public void init(ServletConfig config) throws ServletException {
+    super.init(config);
+  }
+
+  @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
       throws IOException {
     // If an If-Modified-Since header is ever provided, we always say
     // not modified. This is because when there actually is a change,
     // cache busting should occur.
-    UriStatus vstatus = jsUriManager.processExternJsUri(new UriBuilder(req).toUri()).getStatus();
+    UriStatus vstatus;
+    try {
+      vstatus = jsUriManager.processExternJsUri(new UriBuilder(req).toUri()).getStatus();
+    } catch (GadgetException e) {
+      resp.sendError(e.getHttpStatusCode(), e.getMessage());
+      return;
+    }
     if (req.getHeader("If-Modified-Since") != null &&
         vstatus == UriStatus.VALID_VERSIONED) {
       resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
@@ -108,7 +130,7 @@ public class JsServlet extends InjectedS
           0, resourceName.length() - ".js".length());
     }
 
-    Set<String> needed = ImmutableSet.of(StringUtils.split(resourceName, ':'));
+    Set<String> needed = ImmutableSet.copyOf(StringUtils.split(resourceName, ':'));
 
     String debugStr = req.getParameter("debug");
     String containerParam = req.getParameter("container");
@@ -117,7 +139,7 @@ public class JsServlet extends InjectedS
     boolean debug = "1".equals(debugStr);
     final RenderingContext context = "1".equals(containerStr) ?
         RenderingContext.CONTAINER : RenderingContext.GADGET;
-    final String container = 
+    final String container =
         containerParam != null ? containerParam : ContainerConfig.DEFAULT_CONTAINER;
 
     GadgetContext ctx = new GadgetContext() {
@@ -125,7 +147,7 @@ public class JsServlet extends InjectedS
       public RenderingContext getRenderingContext() {
         return context;
       }
-      
+
       @Override
       public String getContainer() {
         return container;
@@ -169,7 +191,7 @@ public class JsServlet extends InjectedS
         jsData.append("gadgets.config.init(").append(JsonSerializer.serialize(config)).append(");\n");
       }
     }
-    
+
     String onloadStr = req.getParameter("onload");
     if (onloadStr != null) {
       if (!ONLOAD_FN_PATTERN.matcher(onloadStr).matches()) {
@@ -178,7 +200,7 @@ public class JsServlet extends InjectedS
       }
       jsData.append(String.format(ONLOAD_JS_TPL, StringEscapeUtils.escapeJavaScript(onloadStr)));
     }
-    
+
     if (jsData.length() == 0) {
       resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
       return;

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java Tue Aug 10 11:32:26 2010
@@ -182,7 +182,7 @@ public class JsonRpcHandler {
         JSONObject userPrefs = new JSONObject();
 
         // User pref specs
-        for (UserPref pref : spec.getUserPrefs()) {
+        for (UserPref pref : spec.getUserPrefs().values()) {
           JSONObject up = new JSONObject()
               .put("displayName", pref.getDisplayName())
               .put("type", pref.getDataType().toString().toLowerCase())

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java Tue Aug 10 11:32:26 2010
@@ -25,8 +25,10 @@ import org.apache.commons.lang.StringUti
 import org.apache.shindig.auth.AuthInfo;
 import org.apache.shindig.auth.SecurityToken;
 import org.apache.shindig.common.JsonSerializer;
+import org.apache.shindig.common.servlet.HttpUtil;
 import org.apache.shindig.common.uri.Uri;
 import org.apache.shindig.common.util.Utf8UrlCoder;
+import org.apache.shindig.config.ContainerConfig;
 import org.apache.shindig.gadgets.AuthType;
 import org.apache.shindig.gadgets.FeedProcessor;
 import org.apache.shindig.gadgets.FetchResponseUtils;
@@ -38,6 +40,8 @@ import org.apache.shindig.gadgets.http.R
 import org.apache.shindig.gadgets.oauth.OAuthArguments;
 import org.apache.shindig.gadgets.rewrite.ResponseRewriterRegistry;
 import org.apache.shindig.gadgets.rewrite.RewritingException;
+import org.apache.shindig.gadgets.uri.UriCommon;
+import org.apache.shindig.gadgets.uri.UriCommon.Param;
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
@@ -53,13 +57,12 @@ import javax.servlet.http.HttpServletRes
  * Unlike ProxyHandler, this may perform operations such as OAuth or signed fetch.
  */
 @Singleton
-public class MakeRequestHandler extends ProxyBase {
+public class MakeRequestHandler {
   // Relaxed visibility for ease of integration. Try to avoid relying on these.
   public static final String UNPARSEABLE_CRUFT = "throw 1; < don't be evil' >";
   public static final String POST_DATA_PARAM = "postData";
   public static final String METHOD_PARAM = "httpMethod";
   public static final String HEADERS_PARAM = "headers";
-  public static final String NOCACHE_PARAM = "nocache";
   public static final String CONTENT_TYPE_PARAM = "contentType";
   public static final String NUM_ENTRIES_PARAM = "numEntries";
   public static final String DEFAULT_NUM_ENTRIES = "3";
@@ -80,8 +83,7 @@ public class MakeRequestHandler extends 
   /**
    * Executes a request, returning the response as JSON to be handled by makeRequest.
    */
-  @Override
-  protected void doFetch(HttpServletRequest request, HttpServletResponse response)
+  public void fetch(HttpServletRequest request, HttpServletResponse response)
       throws GadgetException, IOException {
     HttpRequest rcr = buildHttpRequest(request);
 
@@ -116,18 +118,18 @@ public class MakeRequestHandler extends 
    * @throws GadgetException
    */
   protected HttpRequest buildHttpRequest(HttpServletRequest request) throws GadgetException {
-    String urlStr = request.getParameter(URL_PARAM);
+    String urlStr = request.getParameter(Param.URL.getKey());
     if (urlStr == null) {
       throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
-          URL_PARAM + " parameter is missing.", HttpResponse.SC_BAD_REQUEST);
+          Param.URL.getKey() + " parameter is missing.", HttpResponse.SC_BAD_REQUEST);
     }
     
     Uri url = null;
     try {
-      url = validateUrl(Uri.parse(urlStr));
+      url = ServletUtil.validateUrl(Uri.parse(urlStr));
     } catch (IllegalArgumentException e) {
       throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
-          "Invalid " + URL_PARAM + " parameter", HttpResponse.SC_BAD_REQUEST);
+          "Invalid " + Param.URL.getKey() + " parameter", HttpResponse.SC_BAD_REQUEST);
     }
 
     HttpRequest req = new HttpRequest(url)
@@ -157,18 +159,18 @@ public class MakeRequestHandler extends 
       req.addHeader("Content-Type", "application/x-www-form-urlencoded");
     }
 
-    req.setIgnoreCache("1".equals(request.getParameter(NOCACHE_PARAM)));
+    req.setIgnoreCache("1".equals(request.getParameter(Param.NO_CACHE.getKey())));
 
-    if (request.getParameter(GADGET_PARAM) != null) {
-      req.setGadget(Uri.parse(request.getParameter(GADGET_PARAM)));
+    if (request.getParameter(Param.GADGET.getKey()) != null) {
+      req.setGadget(Uri.parse(request.getParameter(Param.GADGET.getKey())));
     }
 
     // If the proxy request specifies a refresh param then we want to force the min TTL for
     // the retrieved entry in the cache regardless of the headers on the content when it
     // is fetched from the original source.
-    if (request.getParameter(REFRESH_PARAM) != null) {
+    if (request.getParameter(Param.REFRESH.getKey()) != null) {
       try {
-        req.setCacheTtl(Integer.parseInt(request.getParameter(REFRESH_PARAM)));
+        req.setCacheTtl(Integer.parseInt(request.getParameter(Param.REFRESH.getKey())));
       } catch (NumberFormatException nfe) {
         // Ignore
       }
@@ -176,7 +178,7 @@ public class MakeRequestHandler extends 
     // Allow the rewriter to use an externally forced mime type. This is needed
     // allows proper rewriting of <script src="x"/> where x is returned with
     // a content type like text/html which unfortunately happens all too often
-    req.setRewriteMimeType(request.getParameter(REWRITE_MIME_TYPE_PARAM));
+    req.setRewriteMimeType(request.getParameter(Param.REWRITE_MIME_TYPE.getKey()));
 
     // Figure out whether authentication is required
     AuthType auth = AuthType.parse(getParameter(request, AUTHZ_PARAM, null));
@@ -186,7 +188,7 @@ public class MakeRequestHandler extends 
       req.setOAuthArguments(new OAuthArguments(auth, request));
     }
 
-    this.setRequestHeaders(request, req);
+    ServletUtil.setXForwardedForHeader(request, req);
     return req;
   }
 
@@ -220,7 +222,7 @@ public class MakeRequestHandler extends 
       HttpResponse results) throws GadgetException {
     boolean getFullHeaders =
         Boolean.parseBoolean(getParameter(request, GET_FULL_HEADERS_PARAM, "false"));
-    String originalUrl = request.getParameter(ProxyBase.URL_PARAM);
+    String originalUrl = request.getParameter(Param.URL.getKey());
     String body = results.getResponseAsString();
     if (body.length() > 0) {
       if ("FEED".equals(request.getParameter(CONTENT_TYPE_PARAM))) {
@@ -267,4 +269,53 @@ public class MakeRequestHandler extends 
     int numEntries = Integer.parseInt(getParameter(req, NUM_ENTRIES_PARAM, DEFAULT_NUM_ENTRIES));
     return new FeedProcessor().process(url, xml, getSummaries, numEntries).toString();
   }
+  
+  /**
+   * Extracts the container name from the request.
+   */
+  @SuppressWarnings("deprecation")
+  static String getContainer(HttpServletRequest request) {
+    String container = request.getParameter(Param.CONTAINER.getKey());
+    if (container == null) {
+      container = request.getParameter(Param.SYND.getKey());
+    }
+    return container != null ? container : ContainerConfig.DEFAULT_CONTAINER;
+  }
+  
+  /**
+   * getParameter helper method, returning default value if param not present.
+   */
+  static String getParameter(HttpServletRequest request, String key, String defaultValue) {
+    String ret = request.getParameter(key);
+    return ret != null ? ret : defaultValue;
+  }
+  
+  /**
+   * Sets cache control headers for the response.
+   */
+  @SuppressWarnings("boxing")
+  static void setResponseHeaders(HttpServletRequest request,
+      HttpServletResponse response, HttpResponse results) throws GadgetException {
+    int refreshInterval = 0;
+    if (results.isStrictNoCache() || "1".equals(request.getParameter(UriCommon.Param.NO_CACHE.getKey()))) {
+      refreshInterval = 0;
+    } else if (request.getParameter(UriCommon.Param.REFRESH.getKey()) != null) {
+      try {
+        refreshInterval =  Integer.valueOf(request.getParameter(UriCommon.Param.REFRESH.getKey()));
+      } catch (NumberFormatException nfe) {
+        throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
+            "refresh parameter is not a number");
+      }
+    } else {
+      refreshInterval = Math.max(60 * 60, (int)(results.getCacheTtl() / 1000L));
+    }
+    HttpUtil.setCachingHeaders(response, refreshInterval, false);
+    
+    // Always set Content-Disposition header as XSS prevention mechanism.
+    response.setHeader("Content-Disposition", "attachment;filename=p.txt");
+    
+    if (response.getContentType() == null) {
+      response.setContentType("application/octet-stream");
+    }
+  }
 }

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestServlet.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestServlet.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestServlet.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestServlet.java Tue Aug 10 11:32:26 2010
@@ -19,9 +19,12 @@
 package org.apache.shindig.gadgets.servlet;
 
 import org.apache.shindig.common.servlet.InjectedServlet;
+import org.apache.shindig.gadgets.GadgetException;
 
 import java.io.IOException;
 
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -36,17 +39,34 @@ import com.google.inject.Inject;
  * makeRequest and open proxy calls.
  */
 public class MakeRequestServlet extends InjectedServlet {
-  private MakeRequestHandler makeRequestHandler;
+
+  private static final long serialVersionUID = -8298705081500283786L;
+  
+  private transient MakeRequestHandler makeRequestHandler;
 
   @Inject
   public void setMakeRequestHandler(MakeRequestHandler makeRequestHandler) {
+    checkInitialized();
     this.makeRequestHandler = makeRequestHandler;
   }
 
   @Override
+  public void init(ServletConfig config) throws ServletException {
+    super.init(config);
+  }
+
+  @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
       throws IOException {
-    makeRequestHandler.fetch(request, response);
+    try {
+      makeRequestHandler.fetch(request, response);
+    } catch (GadgetException e) {
+      int responseCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+      if (e.getCode() != GadgetException.Code.INTERNAL_SERVER_ERROR) {
+        responseCode = HttpServletResponse.SC_BAD_REQUEST;
+      }
+      response.sendError(responseCode, e.getMessage() != null ? e.getMessage() : "");
+    }
   }
 
   @Override

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/OAuthCallbackServlet.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/OAuthCallbackServlet.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/OAuthCallbackServlet.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/OAuthCallbackServlet.java Tue Aug 10 11:32:26 2010
@@ -32,6 +32,8 @@ import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -50,10 +52,10 @@ import javax.servlet.http.HttpServletRes
  */
 public class OAuthCallbackServlet extends InjectedServlet {
 
-  public static final String CALLBACK_STATE_PARAM = "cs";
+  private static final long serialVersionUID = 7126255229334669172L;
   
+  public static final String CALLBACK_STATE_PARAM = "cs";
   public static final String REAL_DOMAIN_PARAM = "d";
-  
   private static final int ONE_HOUR_IN_SECONDS = 3600;
   
   // This bit of magic passes the entire callback URL into the opening gadget for later use.
@@ -78,15 +80,20 @@ public class OAuthCallbackServlet extend
     "</body>\n" +
     "</html>\n";
 
-  private BlobCrypter stateCrypter;
-  
+  private transient BlobCrypter stateCrypter;
+
   @Inject
-  public void setStateCrypter(
-      @Named(OAuthFetcherConfig.OAUTH_STATE_CRYPTER) BlobCrypter stateCrypter) {
+  public void setStateCrypter(@Named(OAuthFetcherConfig.OAUTH_STATE_CRYPTER) BlobCrypter stateCrypter) {
+    checkInitialized();
     this.stateCrypter = stateCrypter;
   }
 
   @Override
+  public void init(ServletConfig config) throws ServletException {
+    super.init(config);
+  }
+
+  @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
     OAuthCallbackState callbackState = new OAuthCallbackState(stateCrypter,
         req.getParameter(CALLBACK_STATE_PARAM));

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java Tue Aug 10 11:32:26 2010
@@ -23,107 +23,66 @@ import com.google.inject.Singleton;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
-import org.apache.shindig.common.servlet.HttpUtil;
 import org.apache.shindig.common.uri.Uri;
-import org.apache.shindig.common.uri.UriBuilder;
 import org.apache.shindig.gadgets.GadgetException;
-import org.apache.shindig.gadgets.LockedDomainService;
 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.ResponseRewriterRegistry;
 import org.apache.shindig.gadgets.rewrite.RewritingException;
 import org.apache.shindig.gadgets.uri.ProxyUriManager;
+import org.apache.shindig.gadgets.uri.UriUtils;
+import org.apache.shindig.gadgets.uri.UriUtils.DisallowedHeaders;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.util.Map;
-import java.util.logging.Logger;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 
 /**
  * Handles open proxy requests.
  */
 @Singleton
-public class ProxyHandler extends ProxyBase {
-  private static final Logger LOG = Logger.getLogger(ProxyHandler.class.getName());
-
+public class ProxyHandler {
   // TODO: parameterize these.
   static final Integer LONG_LIVED_REFRESH = (365 * 24 * 60 * 60);  // 1 year
   static final Integer DEFAULT_REFRESH = (60 * 60);                // 1 hour
   
   private final RequestPipeline requestPipeline;
-  private final LockedDomainService lockedDomainService;
   private final ResponseRewriterRegistry contentRewriterRegistry;
-  private final ProxyUriManager proxyUriManager;
 
   @Inject
   public ProxyHandler(RequestPipeline requestPipeline,
-                      LockedDomainService lockedDomainService,
-                      ResponseRewriterRegistry contentRewriterRegistry,
-                      ProxyUriManager proxyUriManager) {
+                      ResponseRewriterRegistry contentRewriterRegistry) {
     this.requestPipeline = requestPipeline;
-    this.lockedDomainService = lockedDomainService;
     this.contentRewriterRegistry = contentRewriterRegistry;
-    this.proxyUriManager = proxyUriManager;
   }
 
   /**
    * Generate a remote content request based on the parameters sent from the client.
    */
-  private HttpRequest buildHttpRequest(HttpServletRequest request,
+  private HttpRequest buildHttpRequest(
       ProxyUriManager.ProxyUri uriCtx, Uri tgt) throws GadgetException {
-    validateUrl(tgt);
+    ServletUtil.validateUrl(tgt);
     HttpRequest req = uriCtx.makeHttpRequest(tgt);
-    this.setRequestHeaders(request, req);
+    req.setRewriteMimeType(uriCtx.getRewriteMimeType());
     return req;
   }
 
-  @Override
-  protected void doFetch(HttpServletRequest request, HttpServletResponse response)
+  public HttpResponse fetch(ProxyUriManager.ProxyUri proxyUri)
       throws IOException, GadgetException {
-    if (request.getHeader("If-Modified-Since") != null) {
-      response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
-      return;
-    }
-
-    // TODO: Consider removing due to redundant logic.
-    String host = request.getHeader("Host");
-    if (!lockedDomainService.isSafeForOpenProxy(host)) {
-      // Force embedded images and the like to their own domain to avoid XSS
-      // in gadget domains.
-      String msg = "Embed request for url " + getParameter(request, URL_PARAM, "") +
-          " made to wrong domain " + host;
-      LOG.info(msg);
-      throw new GadgetException(GadgetException.Code.INVALID_PARAMETER, msg,
-          HttpResponse.SC_BAD_REQUEST);
-    }
-    
-    // Parse request uri:
-    ProxyUriManager.ProxyUri proxyUri = proxyUriManager.process(
-        new UriBuilder(request).toUri());
-    
-    try {
-      HttpUtil.setCachingHeaders(response,
-          proxyUri.translateStatusRefresh(LONG_LIVED_REFRESH, DEFAULT_REFRESH), false);
-    } catch (GadgetException gex) {
-      response.sendError(HttpServletResponse.SC_BAD_REQUEST, gex.getMessage());
-      return;
-    }
-
-    HttpRequest rcr = buildHttpRequest(request, proxyUri, proxyUri.getResource());
+    HttpRequest rcr = buildHttpRequest(proxyUri, proxyUri.getResource());
     if (rcr == null) {
       throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
-          "No url paramater in request", HttpResponse.SC_BAD_REQUEST);      
+          "No url parameter in request", HttpResponse.SC_BAD_REQUEST);      
     }
+    
     HttpResponse results = requestPipeline.execute(rcr);
     
     if (results.isError()) {
       // Error: try the fallback. Particularly useful for proxied images.
       Uri fallbackUri = proxyUri.getFallbackUri();
       if (fallbackUri != null) {
-        HttpRequest fallbackRcr = buildHttpRequest(request, proxyUri, fallbackUri);
+        HttpRequest fallbackRcr = buildHttpRequest(proxyUri, fallbackUri);
         results = requestPipeline.execute(fallbackRcr);
       }
     }
@@ -136,42 +95,63 @@ public class ProxyHandler extends ProxyB
             e.getHttpStatusCode());
       }
     }
-
-    for (Map.Entry<String, String> entry : results.getHeaders().entries()) {
-      String name = entry.getKey();
-      if (!DISALLOWED_RESPONSE_HEADERS.contains(name.toLowerCase())) {
-          response.addHeader(name, entry.getValue());
-      }
+    
+    HttpResponseBuilder response = new HttpResponseBuilder(results);
+    
+    try {
+      ServletUtil.setCachingHeaders(response,
+          proxyUri.translateStatusRefresh(LONG_LIVED_REFRESH, DEFAULT_REFRESH), false);
+    } catch (GadgetException gex) {
+      return ServletUtil.errorResponse(gex);
     }
-
-    String responseType = results.getHeader("Content-Type");
+    
+    UriUtils.copyResponseHeadersAndStatusCode(results, response, true, true,
+        DisallowedHeaders.CACHING_DIRECTIVES,  // Proxy sets its own caching headers.
+        DisallowedHeaders.CLIENT_STATE_DIRECTIVES,  // Overridden or irrelevant to proxy.
+        DisallowedHeaders.OUTPUT_TRANSFER_DIRECTIVES
+        );
+    
+    // Set Content-Type and Content-Disposition. Do this after copy results headers,
+    // in order to prevent those from overwriting the correct values.
+    setResponseContentHeaders(response, results);
+    
+    response.setHeader("Content-Type", getContentType(rcr, response));
+    
+    // TODO: replace this with streaming APIs when ready
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    IOUtils.copy(results.getResponse(), baos);
+    response.setResponse(baos.toByteArray());
+    return response.create();
+  }
+  
+  private String getContentType(HttpRequest rcr, HttpResponseBuilder results) {
+    String contentType = results.getHeader("Content-Type");
     if (!StringUtils.isEmpty(rcr.getRewriteMimeType())) {
       String requiredType = rcr.getRewriteMimeType();
       // Use a 'Vary' style check on the response
       if (requiredType.endsWith("/*") &&
-          !StringUtils.isEmpty(responseType)) {
+          !StringUtils.isEmpty(contentType)) {
         requiredType = requiredType.substring(0, requiredType.length() - 2);
-        if (!responseType.toLowerCase().startsWith(requiredType.toLowerCase())) {
-          response.setContentType(requiredType);
-          responseType = requiredType;
+        if (!contentType.toLowerCase().startsWith(requiredType.toLowerCase())) {
+          contentType = requiredType;
         }
       } else {
-        response.setContentType(requiredType);
-        responseType = requiredType;
+        contentType = requiredType;
       }
     }
+    return contentType;
+  }
 
-    setResponseContentHeaders(response, results);
-
-    if (results.getHttpStatusCode() != HttpResponse.SC_OK) {
-      if (results.getHttpStatusCode() == HttpResponse.SC_INTERNAL_SERVER_ERROR) {
-        // External "internal error" should be mapped to gateway error
-        response.sendError(HttpResponse.SC_BAD_GATEWAY);
-      } else {
-        response.sendError(results.getHttpStatusCode());
-      }
+  private void setResponseContentHeaders(HttpResponseBuilder response, HttpResponse results) {
+    // We're skipping the content disposition header for flash due to an issue with Flash player 10
+    // This does make some sites a higher value phishing target, but this can be mitigated by
+    // additional referer checks.
+    if (!"application/x-shockwave-flash".equalsIgnoreCase(results.getHeader("Content-Type")) &&
+        !"application/x-shockwave-flash".equalsIgnoreCase(response.getHeader("Content-Type"))) {
+      response.setHeader("Content-Disposition", "attachment;filename=p.txt");
+    }
+    if (results.getHeader("Content-Type") == null) {
+      response.setHeader("Content-Type", "application/octet-stream");
     }
-
-    IOUtils.copy(results.getResponse(), response.getOutputStream());
   }
 }

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyServlet.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyServlet.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyServlet.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyServlet.java Tue Aug 10 11:32:26 2010
@@ -18,10 +18,20 @@
  */
 package org.apache.shindig.gadgets.servlet;
 
+import com.google.common.base.Preconditions;
 import org.apache.shindig.common.servlet.InjectedServlet;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.uri.UriBuilder;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.LockedDomainService;
+import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
 
 import java.io.IOException;
+import java.util.logging.Logger;
 
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -32,16 +42,70 @@ import com.google.inject.Inject;
  * gadgets.io.getProxyUrl).
  */
 public class ProxyServlet extends InjectedServlet {
-  private ProxyHandler proxyHandler;
+  private static final long serialVersionUID = 9085050443492307723L;
+  
+  private static final Logger LOG = Logger.getLogger(ProxyServlet.class.getName());
+  
+  private transient ProxyUriManager proxyUriManager;
+  private transient LockedDomainService lockedDomainService;
+  private transient ProxyHandler proxyHandler;
 
   @Inject
   public void setProxyHandler(ProxyHandler proxyHandler) {
+    checkInitialized();
     this.proxyHandler = proxyHandler;
   }
+  
+  @Inject
+  public void setProxyUriManager(ProxyUriManager proxyUriManager) {
+    checkInitialized();
+    this.proxyUriManager = proxyUriManager;
+  }
+  
+  @Inject
+  public void setLockedDomainService(LockedDomainService lockedDomainService) {
+    checkInitialized();
+    this.lockedDomainService = lockedDomainService;
+  }
 
   @Override
-  protected void doGet(HttpServletRequest request, HttpServletResponse response)
+  public void init(ServletConfig config) throws ServletException {
+    super.init(config);
+  }
+  
+  @Override
+  protected void doGet(HttpServletRequest request, HttpServletResponse servletResponse)
       throws IOException {
-    proxyHandler.fetch(request, response);
+    if (request.getHeader("If-Modified-Since") != null) {
+      servletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+      return;
+    }
+
+    Uri reqUri = new UriBuilder(request).toUri();
+    HttpResponse response = null;
+    try {
+      // Parse request uri:
+      ProxyUriManager.ProxyUri proxyUri = proxyUriManager.process(reqUri);
+
+      // TODO: Consider removing due to redundant logic.
+      String host = request.getHeader("Host");
+      if (!lockedDomainService.isSafeForOpenProxy(host)) {
+        // Force embedded images and the like to their own domain to avoid XSS
+        // in gadget domains.
+        Uri resourceUri = proxyUri.getResource();
+        String msg = "Embed request for url " +
+            (resourceUri != null ? resourceUri.toString() : "n/a") + " made to wrong domain " + host;
+        LOG.info(msg);
+        throw new GadgetException(GadgetException.Code.INVALID_PARAMETER, msg,
+            HttpResponse.SC_BAD_REQUEST);
+      }
+      
+      response = proxyHandler.fetch(proxyUri);
+    } catch (GadgetException e) {
+      response = ServletUtil.errorResponse(new GadgetException(e.getCode(), e.getMessage(),
+          HttpServletResponse.SC_BAD_REQUEST));
+    }
+    
+    ServletUtil.copyResponseToServlet(response, servletResponse);
   }
 }

Modified: shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/RpcServlet.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/RpcServlet.java?rev=983934&r1=983933&r2=983934&view=diff
==============================================================================
--- shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/RpcServlet.java (original)
+++ shindig/branches/2.0.x/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/RpcServlet.java Tue Aug 10 11:32:26 2010
@@ -18,6 +18,7 @@
  */
 package org.apache.shindig.gadgets.servlet;
 
+import com.google.common.base.Preconditions;
 import org.apache.commons.io.IOUtils;
 import org.apache.shindig.common.servlet.HttpUtil;
 import org.apache.shindig.common.servlet.InjectedServlet;
@@ -26,6 +27,8 @@ import org.json.JSONObject;
 
 import com.google.inject.Inject;
 
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -39,19 +42,28 @@ import java.util.logging.Logger;
  * Handles RPC metadata requests.
  */
 public class RpcServlet extends InjectedServlet {
+  
+  private static final long serialVersionUID = 1382573217773582182L;
+  
   static final String GET_REQUEST_REQ_PARAM = "req";
   static final String GET_REQUEST_CALLBACK_PARAM = "callback";
 
   private static final Logger LOG = Logger.getLogger("org.apache.shindig.gadgets");
 
-  private JsonRpcHandler jsonHandler;
+  private transient JsonRpcHandler jsonHandler;
 
   @Inject
   public void setJsonRpcHandler(JsonRpcHandler jsonHandler) {
+    checkInitialized();
     this.jsonHandler = jsonHandler;
   }
 
   @Override
+  public void init(ServletConfig config) throws ServletException {
+    super.init(config);
+  }
+
+  @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
       throws IOException {
     String reqValue;
@@ -92,9 +104,7 @@ public class RpcServlet extends Injected
   private String validateParameterValue(HttpServletRequest request, String parameter)
       throws IllegalArgumentException {
     String result = request.getParameter(parameter);
-    if (result == null) {
-      throw new IllegalArgumentException("No parameter '" + parameter + "' specified.");
-    }
+    Preconditions.checkArgument(result != null, "No parameter '%s' specified", parameter);
     return result;
   }