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 2009/11/05 20:03:06 UTC

svn commit: r833128 [1/2] - in /incubator/shindig/trunk/java: common/conf/ gadgets/src/main/java/org/apache/shindig/gadgets/render/ gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ gadg...

Author: lindner
Date: Thu Nov  5 19:03:04 2009
New Revision: 833128

URL: http://svn.apache.org/viewvc?rev=833128&view=rev
Log:
SHINDIG-1192 | Patch from Jon Weygandt | ontent-rewrite is not compliant with Open Social v0.9, plus some bugs

Added:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/DefaultSanitizingProxyingLinkRewriterFactory.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingProxyingLinkRewriter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingProxyingLinkRewriterFactory.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ConcatLinkRewriter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ConcatLinkRewriterFactory.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultConcatLinkRewriterFactory.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultProxyingLinkRewriterFactory.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriterFactory.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureTestCaseOS9.java
Modified:
    incubator/shindig/trunk/java/common/conf/shindig.properties
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingGadgetRewriter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingRequestRewriter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureFactory.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CssRequestRewriter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/HTMLContentRewriter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyBase.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Feature.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizingGadgetRewriterTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizingRequestRewriterTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/BaseRewriterTestCase.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureTestCase.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/CssRequestRewriterTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/HTMLContentRewriterTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriterTest.java
    incubator/shindig/trunk/java/gadgets/src/test/resources/org/apache/shindig/gadgets/rewrite/rewritebasic-expected.css
    incubator/shindig/trunk/java/gadgets/src/test/resources/org/apache/shindig/gadgets/rewrite/rewritescriptbasic.html
    incubator/shindig/trunk/java/gadgets/src/test/resources/org/apache/shindig/gadgets/rewrite/rewritestyle2-expected.html

Modified: incubator/shindig/trunk/java/common/conf/shindig.properties
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/conf/shindig.properties?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/common/conf/shindig.properties (original)
+++ incubator/shindig/trunk/java/common/conf/shindig.properties Thu Nov  5 19:03:04 2009
@@ -43,6 +43,7 @@
 shindig.locked-domain.enabled=false
 
 # TODO: This needs to be moved to container configuration.
+shindig.content-rewrite.only-allow-excludes=false
 shindig.content-rewrite.include-urls=.*
 shindig.content-rewrite.exclude-urls=
 shindig.content-rewrite.include-tags=link,script,embed,img,style

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/DefaultSanitizingProxyingLinkRewriterFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/DefaultSanitizingProxyingLinkRewriterFactory.java?rev=833128&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/DefaultSanitizingProxyingLinkRewriterFactory.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/DefaultSanitizingProxyingLinkRewriterFactory.java Thu Nov  5 19:03:04 2009
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.render;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.rewrite.ContentRewriterFeature;
+import org.apache.shindig.gadgets.rewrite.ContentRewriterUris;
+
+/**
+ * @author <a href="mailto:jweygandt@ebay.com">Jon Weygandt</a>
+ * @version $Id: $
+ */
+@Singleton
+public class DefaultSanitizingProxyingLinkRewriterFactory implements
+    SanitizingProxyingLinkRewriterFactory {
+
+  private final ContentRewriterUris rewriterUris;
+
+  @Inject
+  public DefaultSanitizingProxyingLinkRewriterFactory(
+      ContentRewriterUris rewriterUris) {
+    this.rewriterUris = rewriterUris;
+  }
+
+  public SanitizingProxyingLinkRewriter create(Uri gadgetUri,
+      ContentRewriterFeature rewriterFeature, String container,
+      String expectedMime, boolean debug, boolean nocache) {
+    return new SanitizingProxyingLinkRewriter(rewriterUris, gadgetUri,
+        rewriterFeature, container, expectedMime, debug, nocache);
+  }
+
+}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingGadgetRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingGadgetRewriter.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingGadgetRewriter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingGadgetRewriter.java Thu Nov  5 19:03:04 2009
@@ -23,12 +23,9 @@
 import org.apache.shindig.gadgets.parse.caja.CajaCssSanitizer;
 import org.apache.shindig.gadgets.rewrite.ContentRewriterFeature;
 import org.apache.shindig.gadgets.rewrite.ContentRewriterFeatureFactory;
-import org.apache.shindig.gadgets.rewrite.ContentRewriterUris;
 import org.apache.shindig.gadgets.rewrite.GadgetRewriter;
 import org.apache.shindig.gadgets.rewrite.LinkRewriter;
 import org.apache.shindig.gadgets.rewrite.MutableContent;
-import org.apache.shindig.gadgets.rewrite.ProxyingLinkRewriter;
-import org.apache.shindig.gadgets.servlet.ProxyBase;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
@@ -103,19 +100,19 @@
   private final Set<String> allowedAttributes;
   private final CajaCssSanitizer cssSanitizer;
   private final ContentRewriterFeatureFactory rewriterFeatureFactory;
-  private final ContentRewriterUris rewriterUris;
+  private final SanitizingProxyingLinkRewriterFactory sanitizingProxyingLinkRewriterFactory;
 
   @Inject
   public SanitizingGadgetRewriter(@AllowedTags Set<String> allowedTags,
       @AllowedAttributes Set<String> allowedAttributes,
       ContentRewriterFeatureFactory rewriterFeatureFactory,
-      ContentRewriterUris rewriterUris,
-      CajaCssSanitizer cssSanitizer) {
+      CajaCssSanitizer cssSanitizer,
+      SanitizingProxyingLinkRewriterFactory sanitizingProxyingLinkRewriterFactory) {
     this.allowedTags = allowedTags;
     this.allowedAttributes = allowedAttributes;
-    this.rewriterUris = rewriterUris;
     this.cssSanitizer = cssSanitizer;
     this.rewriterFeatureFactory = rewriterFeatureFactory;
+    this.sanitizingProxyingLinkRewriterFactory = sanitizingProxyingLinkRewriterFactory;
   }
 
 
@@ -148,11 +145,14 @@
       ContentRewriterFeature rewriterFeature =
           rewriterFeatureFactory.createRewriteAllFeature(expires == null ? -1 : expires);
 
-      String proxyBaseNoGadget = rewriterUris.getProxyBase(gadget.getContext().getContainer());
-      LinkRewriter cssImportRewriter = new SanitizingProxyingLinkRewriter(gadget.getSpec().getUrl(),
-          rewriterFeature, proxyBaseNoGadget, "text/css");
-      LinkRewriter imageRewriter = new SanitizingProxyingLinkRewriter(gadget.getSpec().getUrl(),
-          rewriterFeature, proxyBaseNoGadget, "image/*");
+      SanitizingProxyingLinkRewriter cssImportRewriter = sanitizingProxyingLinkRewriterFactory
+          .create(gadget.getSpec().getUrl(), rewriterFeature, gadget
+              .getContext().getContainer(), "text/css", gadget.getContext()
+              .getDebug(), gadget.getContext().getIgnoreCache());
+      SanitizingProxyingLinkRewriter imageRewriter = sanitizingProxyingLinkRewriterFactory
+          .create(gadget.getSpec().getUrl(), rewriterFeature, gadget
+              .getContext().getContainer(), "image/*", gadget.getContext()
+              .getDebug(), gadget.getContext().getIgnoreCache());
 
       // Create the set of filters to process in order.
       filters = ImmutableList.of(
@@ -434,35 +434,6 @@
     }
   }
 
-  /**
-   * Forcible rewrite the link through the proxy and force sanitization with
-   * an expected mime type
-   */
-  static class SanitizingProxyingLinkRewriter extends ProxyingLinkRewriter {
-
-    private final String expectedMime;
-
-    SanitizingProxyingLinkRewriter(Uri gadgetUri, ContentRewriterFeature rewriterFeature,
-        String prefix, String expectedMime) {
-      super(gadgetUri, rewriterFeature, prefix);
-      this.expectedMime = expectedMime;
-    }
-
-    @Override
-    public String rewrite(String link, Uri context) {
-      try {
-        Uri.parse(link);
-      } catch (RuntimeException re) {
-        // Any failure in parse
-        return "about:blank";
-      }
-      String rewritten = super.rewrite(link, context);
-      rewritten += '&' + ProxyBase.SANITIZE_CONTENT_PARAM + "=1";
-      rewritten += '&' + ProxyBase.REWRITE_MIME_TYPE_PARAM + '=' + expectedMime;
-      return rewritten;
-    }
-  }
-
   @Retention(RetentionPolicy.RUNTIME)
   @Target(ElementType.PARAMETER)
   @BindingAnnotation

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingProxyingLinkRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingProxyingLinkRewriter.java?rev=833128&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingProxyingLinkRewriter.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingProxyingLinkRewriter.java Thu Nov  5 19:03:04 2009
@@ -0,0 +1,37 @@
+package org.apache.shindig.gadgets.render;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.rewrite.ContentRewriterFeature;
+import org.apache.shindig.gadgets.rewrite.ContentRewriterUris;
+import org.apache.shindig.gadgets.rewrite.ProxyingLinkRewriter;
+import org.apache.shindig.gadgets.servlet.ProxyBase;
+
+/**
+ * Forcible rewrite the link through the proxy and force sanitization with
+ * an expected mime type
+ */
+public class SanitizingProxyingLinkRewriter extends ProxyingLinkRewriter {
+
+  private final String expectedMime;
+
+  public SanitizingProxyingLinkRewriter(ContentRewriterUris rewriterUris,
+      Uri gadgetUri, ContentRewriterFeature rewriterFeature, String container,
+      String expectedMime, boolean debug, boolean nocache) {
+    super(rewriterUris, gadgetUri, rewriterFeature, container, debug, nocache);
+    this.expectedMime = expectedMime;
+  }
+
+  @Override
+  public String rewrite(String link, Uri context) {
+    try {
+      Uri.parse(link);
+    } catch (RuntimeException re) {
+      // Any failure in parse
+      return "about:blank";
+    }
+    String rewritten = super.rewrite(link, context);
+    rewritten += '&' + ProxyBase.SANITIZE_CONTENT_PARAM + "=1";
+    rewritten += '&' + ProxyBase.REWRITE_MIME_TYPE_PARAM + '=' + expectedMime;
+    return rewritten;
+  }
+}
\ No newline at end of file

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingProxyingLinkRewriterFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingProxyingLinkRewriterFactory.java?rev=833128&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingProxyingLinkRewriterFactory.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingProxyingLinkRewriterFactory.java Thu Nov  5 19:03:04 2009
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.render;
+
+import com.google.inject.ImplementedBy;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.rewrite.ContentRewriterFeature;
+
+/**
+ * @author <a href="mailto:jweygandt@ebay.com">Jon Weygandt</a>
+ * @version $Id: $
+ */
+@ImplementedBy(DefaultSanitizingProxyingLinkRewriterFactory.class)
+public interface SanitizingProxyingLinkRewriterFactory {
+  public SanitizingProxyingLinkRewriter create(Uri gadgetUri,
+      ContentRewriterFeature rewriterFeature, String container,
+      String expectedMime, boolean debug, boolean nocache);
+}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingRequestRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingRequestRewriter.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingRequestRewriter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizingRequestRewriter.java Thu Nov  5 19:03:04 2009
@@ -26,10 +26,8 @@
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
 import org.apache.shindig.gadgets.parse.caja.CajaCssSanitizer;
-import org.apache.shindig.gadgets.render.SanitizingGadgetRewriter.SanitizingProxyingLinkRewriter;
 import org.apache.shindig.gadgets.rewrite.ContentRewriterFeature;
 import org.apache.shindig.gadgets.rewrite.ContentRewriterFeatureFactory;
-import org.apache.shindig.gadgets.rewrite.ContentRewriterUris;
 import org.apache.shindig.gadgets.rewrite.MutableContent;
 import org.apache.shindig.gadgets.rewrite.RequestRewriter;
 
@@ -48,16 +46,16 @@
 
   private final CajaCssSanitizer cssSanitizer;
   private final ContentRewriterFeatureFactory rewriterFeatureFactory;
-  private final ContentRewriterUris rewriterUris;
-
+  private final SanitizingProxyingLinkRewriterFactory sanitizingProxyingLinkRewriterFactory;
+  
   @Inject
   public SanitizingRequestRewriter(
       ContentRewriterFeatureFactory rewriterFeatureFactory,
-      ContentRewriterUris rewriterUris,
-      CajaCssSanitizer cssSanitizer) {
-    this.rewriterUris = rewriterUris;
+      CajaCssSanitizer cssSanitizer,
+      SanitizingProxyingLinkRewriterFactory sanitizingProxyingLinkRewriterFactory) {
     this.cssSanitizer = cssSanitizer;
     this.rewriterFeatureFactory = rewriterFeatureFactory;
+    this.sanitizingProxyingLinkRewriterFactory = sanitizingProxyingLinkRewriterFactory;
   }
 
   public boolean rewrite(HttpRequest request, HttpResponse resp, MutableContent content) {
@@ -137,11 +135,12 @@
     try {
       String contentType = response.getHeader("Content-Type");
       if (contentType == null || contentType.toLowerCase().startsWith("text/")) {
-        String proxyBaseNoGadget = rewriterUris.getProxyBase(request.getContainer());
-        SanitizingProxyingLinkRewriter cssImportRewriter = new SanitizingProxyingLinkRewriter(
-            request.getGadget(), rewriterFeature, proxyBaseNoGadget, "text/css");
-        SanitizingProxyingLinkRewriter cssImageRewriter = new SanitizingProxyingLinkRewriter(
-            request.getGadget(), rewriterFeature, proxyBaseNoGadget, "image/*");
+        SanitizingProxyingLinkRewriter cssImportRewriter = sanitizingProxyingLinkRewriterFactory
+            .create(request.getGadget(), rewriterFeature, request
+                .getContainer(), "text/css", false, request.getIgnoreCache());
+        SanitizingProxyingLinkRewriter cssImageRewriter = sanitizingProxyingLinkRewriterFactory
+            .create(request.getGadget(), rewriterFeature, request
+                .getContainer(), "image/*", false, request.getIgnoreCache());
         sanitized = cssSanitizer.sanitize(content.getContent(), request.getUri(), cssImportRewriter,
             cssImageRewriter);
       }

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ConcatLinkRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ConcatLinkRewriter.java?rev=833128&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ConcatLinkRewriter.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ConcatLinkRewriter.java Thu Nov  5 19:03:04 2009
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.rewrite;
+
+import com.google.common.collect.Lists;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.util.Utf8UrlCoder;
+import org.apache.shindig.gadgets.servlet.ProxyBase;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:jweygandt@ebay.com">Jon Weygandt</a>
+ * @version $Id: $
+ */
+public class ConcatLinkRewriter {
+  private final static int MAX_URL_LENGTH = 1500;
+
+  private final ContentRewriterUris rewriterUris;
+
+  private final ContentRewriterFeature rewriterFeature;
+  private final Uri gadgetUri;
+  private final String container;
+  private final boolean debug;
+  private final boolean ignoreCache;
+
+  public ConcatLinkRewriter(ContentRewriterUris rewriterUris, Uri gadgetUri,
+      ContentRewriterFeature rewriterFeature, String container, boolean debug,
+      boolean ignoreCache) {
+    this.rewriterUris = rewriterUris;
+    this.rewriterFeature = rewriterFeature;
+    this.gadgetUri = gadgetUri;
+    this.container = container;
+    this.debug = debug;
+    this.ignoreCache = ignoreCache;
+  }
+
+  public List<Uri> rewrite(String mimeType, LinkedHashSet<Uri> uris) {
+    String concatBase = getConcatBase(gadgetUri, rewriterFeature, mimeType,
+        container);
+    List<Uri> concatUris = Lists.newLinkedList();
+    int paramIndex = 1;
+    StringBuilder builder = null;
+    int maxUriLen = MAX_URL_LENGTH + concatBase.length();
+    try {
+      int uriIx = 0;
+      //
+      for (Uri uri : uris) {
+        String uriStr = uri.toString();
+        if (builder != null && builder.length() + uriStr.length() > maxUriLen) {
+          // The next one will go over limit
+          concatUris.add(Uri.parse(builder.toString()));
+          builder = null;
+          paramIndex = 1;
+          
+          // If the current uri is too long, simply don't rewrite, since
+          // concat is for developers benefit
+          if(uriStr.length() > MAX_URL_LENGTH) {
+            concatUris.add(uri);
+            continue;
+          }
+        } 
+
+        if (paramIndex == 1) {
+          builder = new StringBuilder(concatBase);
+          if (debug)
+            builder.append("debug=1&");
+          if (ignoreCache)
+            builder.append("nocache=1&");
+          if (rewriterFeature.getExpires() != null) {
+            builder.append(ProxyBase.REFRESH_PARAM).append('=').append(rewriterFeature.getExpires().toString()).append('&');
+          }
+        } else {
+          builder.append('&');
+        }
+        builder.append(paramIndex).append('=').append(
+            URLEncoder.encode(uriStr, "UTF-8"));
+        ++paramIndex;
+        ++uriIx;
+      }
+      if (builder != null)
+        concatUris.add(Uri.parse(builder.toString()));
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException(e);
+    }
+    return concatUris;
+  }
+
+  protected String getConcatBase(Uri gadgetUri, ContentRewriterFeature feature,
+      String mimeType, String container) {
+    String concatBaseNoGadget = rewriterUris.getConcatBase(container);
+    return concatBaseNoGadget
+        + ProxyBase.REWRITE_MIME_TYPE_PARAM
+        + '='
+        + mimeType
+        + ((gadgetUri == null) ? "" : "&gadget="
+            + Utf8UrlCoder.encode(gadgetUri.toString())) + "&fp="
+        + feature.getFingerprint() + '&';
+  }
+
+}

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ConcatLinkRewriterFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ConcatLinkRewriterFactory.java?rev=833128&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ConcatLinkRewriterFactory.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ConcatLinkRewriterFactory.java Thu Nov  5 19:03:04 2009
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.rewrite;
+
+import com.google.inject.ImplementedBy;
+
+import org.apache.shindig.common.uri.Uri;
+
+/**
+ * @author <a href="mailto:jweygandt@ebay.com">Jon Weygandt</a>
+ * @version $Id: $
+ */
+@ImplementedBy(DefaultConcatLinkRewriterFactory.class)
+public interface ConcatLinkRewriterFactory {
+  public ConcatLinkRewriter create(Uri gadgetUri,
+      ContentRewriterFeature rewriterFeature, String container, boolean debug,
+      boolean ignoreCache);
+
+}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java Thu Nov  5 19:03:04 2009
@@ -20,78 +20,132 @@
 import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+
 import org.apache.shindig.gadgets.spec.Feature;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.regex.Pattern;
 
 /**
  * Parser for the "content-rewrite" feature. The supported params are
- * include-urls,exclude-urls,include-tags. Default values are container specific.
- *
- * TODO: This really needs to be fixed, because it makes GadgetSpec mutable. It is *ONLY* needed
- * by code in the rewrite package, and that code isn't even being used, and can't be used the way
- * that they are currently written -- they require values from the gadget during construction, which
- * are, of course, unavailable.
+ * include-url and exclude-url which honor multiple occurances of the parameter,
+ * these are simple case insensitive substrings, with "*" being the match-all
+ * wildcard. Additionally expires is the seconds for caching of the rewritten
+ * result. For legacy applications include-urls and exclude-urls, which are
+ * regular expressions as well as a common seperated list in include-tags.
+ * Default values are container specific.
+ * 
+ * TODO: This really needs to be fixed, because it makes GadgetSpec mutable. It
+ * is *ONLY* needed by code in the rewrite package.
  */
 public class ContentRewriterFeature {
 
-  private static final String INCLUDE_URLS = "include-urls";
-  private static final String EXCLUDE_URLS = "exclude-urls";
-  private static final String INCLUDE_TAGS = "include-tags";
-  private static final String EXPIRES = "expires";
+  protected static final String INCLUDE_URLS = "include-urls";
+  protected static final String EXCLUDE_URLS = "exclude-urls";
+  protected static final String INCLUDE_URL = "include-url";
+  protected static final String EXCLUDE_URL = "exclude-url";
+  protected static final String INCLUDE_TAGS = "include-tags";
+  protected static final String EXPIRES = "expires";
 
   public static final String EXPIRES_DEFAULT = "HTTP";
 
   // Use tree set to maintain order for fingerprint
-  private Set<String> includeTags;
-
-  private boolean includeAll;
-  private boolean includeNone;
-
-  private Pattern include;
-  private Pattern exclude;
+  protected Set<String> includeTags;
 
-  // If null then dont enforce a min TTL for proxied content. Use contents headers
-  private Integer expires;
+  protected enum PATTERNS {
+    ALL, NONE, REGEX, STRINGS
+  };
+
+  protected PATTERNS includePatterns;
+  protected PATTERNS excludePatterns;
+
+  protected Pattern includePattern;
+  protected Pattern excludePattern;
+  protected Pattern excludeOverridePattern;
+  protected Collection<String> includes;
+  protected Collection<String> excludes;
+
+  // If null then dont enforce a min TTL for proxied content. Use contents
+  // headers
+  protected Integer expires;
 
-  private Integer fingerprint;
+  protected Integer fingerprint;
 
   /**
    * Constructor which takes a gadget spec and the default container settings
-   *
+   * 
    * @param spec
-   * @param defaultInclude As a regex
-   * @param defaultExclude As a regex
-   * @param defaultExpires Either "HTTP" or a ttl in seconds
-   * @param defaultTags    Set of default tags that can be rewritten
+   * @param defaultInclude
+   *          As a regex
+   * @param defaultExclude
+   *          As a regex
+   * @param defaultExpires
+   *          Either "HTTP" or a ttl in seconds
+   * @param defaultTags
+   *          Set of default tags that can be rewritten
    */
   public ContentRewriterFeature(GadgetSpec spec, String defaultInclude,
-                                String defaultExclude,
-                                String defaultExpires,
-      Set<String> defaultTags) {
+      String defaultExclude, String defaultExpires, Set<String> defaultTags,
+      boolean onlyAllowExcludes) {
     Feature f = null;
     if (spec != null) {
       f = spec.getModulePrefs().getFeatures().get("content-rewrite");
     }
-    String includeRegex = normalizeParam(defaultInclude, null);
-    String excludeRegex = normalizeParam(defaultExclude, null);
-
-    this.includeTags = ImmutableSortedSet.copyOf(defaultTags);
+    setUpIncludes(f, defaultInclude, onlyAllowExcludes);
+    setUpExcludes(f, defaultExclude, onlyAllowExcludes);
+    setUpIncludeTags(f, defaultTags, onlyAllowExcludes);
+    setUpExpires(f, defaultExpires, onlyAllowExcludes);
+  }
 
+  protected void setUpExpires(Feature f, String defaultExpires,
+      boolean onlyAllowExcludes) {
+    Integer defaultExpiresVal = null;
+    try {
+      defaultExpiresVal = new Integer(defaultExpires);
+    } catch (NumberFormatException e) {
+      // ignore
+    }
     List<String> expiresOptions = Lists.newArrayListWithCapacity(3);
     if (f != null) {
-      if (f.getParams().containsKey(INCLUDE_URLS)) {
-        includeRegex = normalizeParam(f.getParam(INCLUDE_URLS), includeRegex);
+      if (f.getParams().containsKey(EXPIRES)) {
+        String p = normalizeParam(f.getParam(EXPIRES), null);
+        Integer expiresParamVal = null;
+        try {
+          expiresParamVal = new Integer(p);
+        } catch (NumberFormatException e) {
+          // ignore
+        }
+        if (!onlyAllowExcludes || defaultExpiresVal == null
+            || (expiresParamVal != null && expiresParamVal < defaultExpiresVal))
+          expiresOptions.add(p);
       }
+    }
 
-      // Note use of default for exclude as null here to allow clearing value in the
-      // presence of a container default.
-      if (f.getParams().containsKey(EXCLUDE_URLS)) {
-        excludeRegex = normalizeParam(f.getParam(EXCLUDE_URLS), null);
+    expiresOptions.add(defaultExpires);
+    expiresOptions.add(EXPIRES_DEFAULT);
+
+    for (String expiryOption : expiresOptions) {
+      try {
+        expires = new Integer(expiryOption);
+        break;
+      } catch (NumberFormatException nfe) {
+        // Not an integer
+        if (EXPIRES_DEFAULT.equalsIgnoreCase(expiryOption)) {
+          break;
+        }
       }
+    }
+  }
+
+  protected void setUpIncludeTags(Feature f, Set<String> defaultTags,
+      boolean onlyAllowExcludes) {
+    this.includeTags = ImmutableSortedSet.copyOf(defaultTags);
+    if (f != null) {
       String includeTagList = f.getParam(INCLUDE_TAGS);
       if (includeTagList != null) {
         Set<String> tags = Sets.newTreeSet();
@@ -100,46 +154,121 @@
             tags.add(tag.trim().toLowerCase());
           }
         }
+        if (onlyAllowExcludes) {
+          tags.retainAll(defaultTags);
+        }
         includeTags = tags;
       }
-
-      if (f.getParams().containsKey(EXPIRES)) {
-        expiresOptions.add(normalizeParam(f.getParam(EXPIRES), null));
-      }
     }
+  }
 
-    expiresOptions.add(defaultExpires);
-    expiresOptions.add(EXPIRES_DEFAULT);
+  // Note: Shindig originally supported the plural versions with regular
+  // expressions. But the OpenSocial specification v0.9 allows for singular
+  // spellings, with multiple values. Plus they are case insensitive substrings.
+  // For backward compatibility, if the singular versions are present they
+  // will override the plural versions. 10/6/09
 
-    for (String expiryOption : expiresOptions) {
-      try {
-        expires = new Integer(expiryOption);
-        break;
-      } catch (NumberFormatException nfe) {
-        // Not an integer
-        if (EXPIRES_DEFAULT.equalsIgnoreCase(expiryOption)) {
-          break;
+  protected void setUpIncludes(Feature f, String defaultInclude,
+      boolean onlyAllowExcludes) {
+    String includeRegex = normalizeParam(defaultInclude, null);
+
+    if (f != null && !onlyAllowExcludes) {
+      if (f.getParams().containsKey(INCLUDE_URLS)) {
+        includeRegex = normalizeParam(f.getParam(INCLUDE_URLS), includeRegex);
+      }
+
+      Collection<String> includeUrls = f.getParamCollection(INCLUDE_URL);
+      if (includeUrls.size() == 0) {
+        includes = Collections.emptyList();
+      } else if (includeUrls.contains("*")) {
+        includes = Collections.singleton("*");
+      } else {
+        includes = new ArrayList<String>(includeUrls.size());
+        for (String s : includeUrls) {
+          if (s.length() > 0)
+            includes.add(s.toLowerCase());
         }
       }
+    } else {
+      includes = Collections.emptyList();
     }
 
-    if (".*".equals(includeRegex) && excludeRegex == null) {
-      includeAll = true;
+    if (includes.size() == 0
+        && (includeRegex == null || "".equals(includeRegex))) {
+      includePatterns = PATTERNS.NONE;
+    } else if (includes.size() > 0) {
+      if (includes.size() == 1 && "*".equals(includes.iterator().next())) {
+        includePatterns = PATTERNS.ALL;
+      } else {
+        includePatterns = PATTERNS.STRINGS;
+      }
+    } else {
+      if (".*".equals(includeRegex)) {
+        includePatterns = PATTERNS.ALL;
+      } else {
+        includePatterns = PATTERNS.REGEX;
+      }
+      includePattern = Pattern.compile(includeRegex);
     }
+  }
+
+  protected void setUpExcludes(Feature f, String defaultExclude,
+      boolean onlyAllowExcludes) {
+    String excludeRegex = normalizeParam(defaultExclude, null);
+    String excludeOverrideRegex = onlyAllowExcludes ? excludeRegex : null;
 
-    if (".*".equals(excludeRegex) || includeRegex == null) {
-      includeNone = true;
+    if (f != null) {
+      // Note use of default for exclude as null here to allow clearing value in
+      // the presence of a container default.
+      if (f.getParams().containsKey(EXCLUDE_URLS)) {
+        excludeRegex = normalizeParam(f.getParam(EXCLUDE_URLS), null);
+      }
+
+      Collection<String> excludeUrls = f.getParamCollection(EXCLUDE_URL);
+      if (excludeUrls.size() == 0) {
+        excludes = Collections.emptyList();
+      } else if (excludeUrls.contains("*")) {
+        excludes = Collections.singleton("*");
+      } else {
+        excludes = new ArrayList<String>(excludeUrls.size());
+        // Override Shindig defaults
+        excludeRegex = null;
+        for (String s : excludeUrls) {
+          if (s.length() > 0)
+            excludes.add(s.toLowerCase());
+        }
+      }
+    } else {
+      excludes = Collections.emptyList();
     }
 
-    if (includeRegex != null) {
-      include = Pattern.compile(includeRegex);
+    if (excludes.size() == 0
+        && (excludeRegex == null || "".equals(excludeRegex))) {
+      excludePatterns = PATTERNS.NONE;
+    } else if (excludes.size() > 0) {
+      if (excludes.size() == 1 && "*".equals(excludes.iterator().next())) {
+        excludePatterns = PATTERNS.ALL;
+      } else {
+        excludePatterns = PATTERNS.STRINGS;
+      }
+    } else {
+      if (".*".equals(excludeRegex)) {
+        excludePatterns = PATTERNS.ALL;
+      } else {
+        excludePatterns = PATTERNS.REGEX;
+      }
+      excludePattern = Pattern.compile(excludeRegex);
     }
-    if (excludeRegex != null) {
-      exclude = Pattern.compile(excludeRegex);
+
+    if (excludeOverrideRegex != null
+        && !excludeOverrideRegex.equals(excludeRegex)) {
+      excludeOverridePattern = Pattern.compile(excludeOverrideRegex);
+      if (excludePatterns == PATTERNS.NONE)
+        excludePatterns = PATTERNS.REGEX;
     }
   }
 
-  private String normalizeParam(String paramValue, String defaultVal) {
+  protected String normalizeParam(String paramValue, String defaultVal) {
     if (paramValue == null) {
       return defaultVal;
     }
@@ -150,21 +279,59 @@
     return paramValue;
   }
 
-  public boolean isRewriteEnabled() {
-    return !includeNone;
+  protected boolean shouldInclude(String url) {
+    switch (includePatterns) {
+    case NONE:
+      return false;
+    case ALL:
+      return true;
+    case REGEX:
+      return includePattern.matcher(url).find();
+    case STRINGS:
+      // "*" is handled by ALL
+      String urllc = url.toLowerCase();
+      for (String substr : includes) {
+        if (urllc.indexOf(substr) >= 0)
+          return true;
+      }
+      return false;
+    }
+    return false;
   }
 
-  public boolean shouldRewriteURL(String url) {
-    if (includeNone) {
+  protected boolean shouldExclude(String url) {
+    switch (excludePatterns) {
+    case NONE:
       return false;
-    } else if (includeAll) {
+    case ALL:
       return true;
-    } else if (include.matcher(url).find()) {
-      return !(exclude != null && exclude.matcher(url).find());
+    case REGEX:
+      return (excludeOverridePattern != null && excludeOverridePattern.matcher(
+          url).find())
+          || (excludePattern != null && excludePattern.matcher(url).find());
+    case STRINGS:
+      if (excludeOverridePattern != null
+          && excludeOverridePattern.matcher(url).find())
+        return true;
+      // "*" is handled by ALL
+      String urllc = url.toLowerCase();
+      for (String substr : excludes) {
+        if (urllc.indexOf(substr) >= 0)
+          return true;
+      }
+      return false;
     }
     return false;
   }
 
+  public boolean isRewriteEnabled() {
+    return includePatterns != PATTERNS.NONE && excludePatterns != PATTERNS.ALL;
+  }
+
+  public boolean shouldRewriteURL(String url) {
+    return shouldInclude(url) && !shouldExclude(url);
+  }
+
   public boolean shouldRewriteTag(String tag) {
     if (tag != null) {
       return this.includeTags.contains(tag.toLowerCase());
@@ -189,12 +356,20 @@
   public int getFingerprint() {
     if (fingerprint == null) {
       int result;
-      result = (include != null ? include.pattern().hashCode() : 0);
-      result = 31 * result + (exclude != null ? exclude.pattern().hashCode() : 0);
+      result = (includePattern != null ? includePattern.pattern().hashCode()
+          : 0);
+      for (String s : includes) {
+        result = 31 * result + s.hashCode();
+      }
+      result = 31 * result
+          + (excludePattern != null ? excludePattern.pattern().hashCode() : 0);
+      for (String s : excludes) {
+        result = 31 * result + s.hashCode();
+      }
       for (String s : includeTags) {
         result = 31 * result + s.hashCode();
       }
-      fingerprint =  result;
+      fingerprint = result;
     }
     return fingerprint;
   }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureFactory.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureFactory.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureFactory.java Thu Nov  5 19:03:04 2009
@@ -25,7 +25,6 @@
 import org.apache.shindig.gadgets.spec.GadgetSpec;
 
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.google.inject.name.Named;
@@ -44,6 +43,7 @@
   private final String excludeUrls;
   private final String expires;
   private final Set<String> includeTags;
+  private final boolean onlyAllowExcludes;
 
   private final ContentRewriterFeature defaultFeature;
 
@@ -53,11 +53,13 @@
       @Named("shindig.content-rewrite.include-urls")String includeUrls,
       @Named("shindig.content-rewrite.exclude-urls")String excludeUrls,
       @Named("shindig.content-rewrite.expires")String expires,
-      @Named("shindig.content-rewrite.include-tags")String includeTags) {
+      @Named("shindig.content-rewrite.include-tags")String includeTags,
+      @Named("shindig.content-rewrite.only-allow-excludes")String onlyAllowExcludes) {
     this.specFactory = specFactory;
     this.includeUrls = includeUrls;
     this.excludeUrls = excludeUrls;
     this.expires = expires;
+    this.onlyAllowExcludes = Boolean.parseBoolean(onlyAllowExcludes);
 
     ImmutableSet.Builder<String> includeTagsBuilder = ImmutableSet.builder();
     for (String s : includeTags.trim().toLowerCase().split("\\s*,\\s*")) {
@@ -67,7 +69,7 @@
     }
     this.includeTags = includeTagsBuilder.build();
     defaultFeature = new ContentRewriterFeature(null, includeUrls, excludeUrls, expires,
-        this.includeTags);
+        this.includeTags, this.onlyAllowExcludes);
   }
 
   public ContentRewriterFeature getDefault() {
@@ -102,7 +104,7 @@
         (ContentRewriterFeature)spec.getAttribute("content-rewriter");
     if (rewriterFeature != null) return rewriterFeature;
     rewriterFeature
-        = new ContentRewriterFeature(spec, includeUrls, excludeUrls, expires, includeTags);
+        = new ContentRewriterFeature(spec, includeUrls, excludeUrls, expires, includeTags, onlyAllowExcludes);
     spec.setAttribute("content-rewriter", rewriterFeature);
     return rewriterFeature;
   }
@@ -113,6 +115,6 @@
   public ContentRewriterFeature createRewriteAllFeature(int ttl) {
     return new ContentRewriterFeature(null,
         ".*", "", (ttl == -1) ? "HTTP" : Integer.toString(ttl),
-        Collections.<String>emptySet());
+        Collections.<String>emptySet(), false);
   }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CssRequestRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CssRequestRewriter.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CssRequestRewriter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CssRequestRewriter.java Thu Nov  5 19:03:04 2009
@@ -49,15 +49,15 @@
 
   private final ContentRewriterFeatureFactory rewriterFeatureFactory;
   private final CajaCssLexerParser cssParser;
-  private final ContentRewriterUris rewriterUris;
+  private final ProxyingLinkRewriterFactory proxyingLinkRewriterFactory;
 
   @Inject
   public CssRequestRewriter(ContentRewriterFeatureFactory rewriterFeatureFactory,
-      ContentRewriterUris rewriterUris,
-      CajaCssLexerParser cssParser) {
+      CajaCssLexerParser cssParser,
+      ProxyingLinkRewriterFactory proxyingLinkRewriterFactory) {
     this.rewriterFeatureFactory = rewriterFeatureFactory;
-    this.rewriterUris = rewriterUris;
     this.cssParser = cssParser;
+    this.proxyingLinkRewriterFactory = proxyingLinkRewriterFactory;
   }
 
   public boolean rewrite(HttpRequest request, HttpResponse original,
@@ -69,7 +69,8 @@
     String css = content.getContent();
     StringWriter sw = new StringWriter((css.length() * 110) / 100);
     rewrite(new StringReader(css), request.getUri(),
-        createLinkRewriter(request.getGadget(), feature, request.getContainer()), sw, false);
+        proxyingLinkRewriterFactory.create(request.getGadget(), feature,
+            request.getContainer(), false, request.getIgnoreCache()), sw, false);
     content.setContent(sw.toString());
 
     return true;
@@ -175,10 +176,5 @@
     }
     return imports;
   }
-
-  protected LinkRewriter createLinkRewriter(Uri gadgetUri, ContentRewriterFeature feature, String container) {
-    String proxyBase = rewriterUris.getProxyBase(container); 
-    return new ProxyingLinkRewriter(gadgetUri, feature, proxyBase);
-  }
 }
 

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultConcatLinkRewriterFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultConcatLinkRewriterFactory.java?rev=833128&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultConcatLinkRewriterFactory.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultConcatLinkRewriterFactory.java Thu Nov  5 19:03:04 2009
@@ -0,0 +1,32 @@
+/*
+ * To add signing
+ */
+package org.apache.shindig.gadgets.rewrite;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import org.apache.shindig.common.uri.Uri;
+
+/**
+ * @author <a href="mailto:jweygandt@ebay.com">Jon Weygandt</a>
+ * @version $Id: $
+ */
+@Singleton
+public class DefaultConcatLinkRewriterFactory implements
+    ConcatLinkRewriterFactory {
+
+  private final ContentRewriterUris rewriterUris;
+
+  @Inject
+  public DefaultConcatLinkRewriterFactory(ContentRewriterUris rewriterUris) {
+    this.rewriterUris = rewriterUris;
+  }
+
+  public ConcatLinkRewriter create(Uri gadgetUri,
+      ContentRewriterFeature rewriterFeature, String container, boolean debug,
+      boolean ignoreCache) {
+    return new ConcatLinkRewriter(rewriterUris, gadgetUri, rewriterFeature,
+        container, debug, ignoreCache);
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultProxyingLinkRewriterFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultProxyingLinkRewriterFactory.java?rev=833128&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultProxyingLinkRewriterFactory.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultProxyingLinkRewriterFactory.java Thu Nov  5 19:03:04 2009
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.rewrite;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import org.apache.shindig.common.uri.Uri;
+
+/**
+ * @author <a href="mailto:jweygandt@ebay.com">Jon Weygandt</a>
+ * @version $Id: $
+ */
+@Singleton
+public class DefaultProxyingLinkRewriterFactory implements
+    ProxyingLinkRewriterFactory {
+
+  private final ContentRewriterUris rewriterUris;
+
+  @Inject
+  public DefaultProxyingLinkRewriterFactory(ContentRewriterUris rewriterUris) {
+    this.rewriterUris = rewriterUris;
+  }
+
+  public ProxyingLinkRewriter create(Uri gadgetUri,
+      ContentRewriterFeature rewriterFeature, String container, boolean debug,
+      boolean ignoreCache) {
+    return new ProxyingLinkRewriter(rewriterUris, gadgetUri, rewriterFeature,
+        container, debug, ignoreCache);
+  }
+}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/HTMLContentRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/HTMLContentRewriter.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/HTMLContentRewriter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/HTMLContentRewriter.java Thu Nov  5 19:03:04 2009
@@ -18,19 +18,15 @@
 package org.apache.shindig.gadgets.rewrite;
 
 import org.apache.shindig.common.uri.Uri;
-import org.apache.shindig.common.util.Utf8UrlCoder;
 import org.apache.shindig.common.xml.DomUtil;
 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.servlet.ProxyBase;
 import org.apache.shindig.gadgets.spec.View;
 import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -51,7 +47,6 @@
  * - Proxying referred content of images and embeds
  */
 public class HTMLContentRewriter implements GadgetRewriter, RequestRewriter {
-  private final static int MAX_URL_LENGTH = 1500;
   
   private final static String JS_MIME_TYPE = "text/javascript";
 
@@ -64,15 +59,18 @@
 
   private final ContentRewriterFeatureFactory rewriterFeatureFactory;
   private final CssRequestRewriter cssRewriter;
-  private final ContentRewriterUris rewriterUris;
+  private final ConcatLinkRewriterFactory concatLinkRewriterFactory;
+  private final ProxyingLinkRewriterFactory proxyingLinkRewriterFactory;
 
   @Inject
   public HTMLContentRewriter(ContentRewriterFeatureFactory rewriterFeatureFactory,
-      ContentRewriterUris rewriterUris,
-      CssRequestRewriter cssRewriter) {
+      CssRequestRewriter cssRewriter,
+      ConcatLinkRewriterFactory concatLinkRewriterFactory,
+      ProxyingLinkRewriterFactory proxyingLinkRewriterFactory) {
     this.rewriterFeatureFactory = rewriterFeatureFactory;
-    this.rewriterUris = rewriterUris;
     this.cssRewriter = cssRewriter;
+    this.concatLinkRewriterFactory = concatLinkRewriterFactory;
+    this.proxyingLinkRewriterFactory = proxyingLinkRewriterFactory;
   }
 
   public boolean rewrite(HttpRequest request, HttpResponse original,
@@ -80,7 +78,7 @@
     if (RewriterUtils.isHtml(request, original)) {
       ContentRewriterFeature feature = rewriterFeatureFactory.get(request);
       return rewriteImpl(feature, request.getGadget(), request.getUri(), content,
-          request.getContainer());
+          request.getContainer(), false, request.getIgnoreCache());
     }
     
     return false;
@@ -101,11 +99,13 @@
     }
     
     rewriteImpl(feature, gadget.getSpec().getUrl(), contentBase, content,
-        gadget.getContext().getContainer());
+        gadget.getContext().getContainer(), gadget.getContext().getDebug(),
+        gadget.getContext().getIgnoreCache());
   }
 
   boolean rewriteImpl(ContentRewriterFeature feature, Uri gadgetUri,
-                                        Uri contentBase, MutableContent content, String container) {
+      Uri contentBase, MutableContent content, String container, boolean debug,
+      boolean ignoreCache) {
     if (!feature.isRewriteEnabled() || content.getDocument() == null) {
       return false;
     }
@@ -123,11 +123,11 @@
     // 1st step. Rewrite links in all embedded style tags. Convert @import statements into
     // links and add them to the tag list.
     // Move all style and link tags into head and concat the link tags
-    mutated = rewriteStyleTags(head, tagList, feature, gadgetUri, contentBase, container);
+    mutated = rewriteStyleTags(head, tagList, feature, gadgetUri, contentBase, container, debug, ignoreCache);
     // Concat script links
-    mutated |= rewriteJsTags(tagList, feature, gadgetUri, contentBase, container);
+    mutated |= rewriteJsTags(tagList, feature, gadgetUri, contentBase, container, debug, ignoreCache);
     // Rewrite links in images, embeds etc
-    mutated |= rewriteContentReferences(tagList, feature, gadgetUri, contentBase, container);
+    mutated |= rewriteContentReferences(tagList, feature, gadgetUri, contentBase, container, debug, ignoreCache);
 
     if (mutated) {
       MutableContent.notifyEdit(content.getDocument());
@@ -137,7 +137,8 @@
   }
 
   protected boolean rewriteStyleTags(Element head, List<Element> elementList,
-      ContentRewriterFeature feature, Uri gadgetUri, Uri contentBase, String container) {
+      ContentRewriterFeature feature, Uri gadgetUri, Uri contentBase, String container,
+      boolean debug, boolean ignoreCache) {
     if (!feature.getIncludedTags().contains("style")) {
       return false;
     }
@@ -151,7 +152,8 @@
       }
     }));
 
-    LinkRewriter linkRewriter = createLinkRewriter(gadgetUri, feature, container);
+    LinkRewriter linkRewriter = proxyingLinkRewriterFactory.create(gadgetUri,
+        feature, container, debug, ignoreCache);
 
     for (Element styleTag : styleTags) {
       mutated |= true;
@@ -183,30 +185,13 @@
           }
         }));
 
-    String concatBase = getConcatBase(gadgetUri, feature, "text/css", container);
-
-    concatenateTags(feature, linkTags, concatBase, contentBase, "href");
+    concatenateTags(feature, linkTags, gadgetUri, contentBase, "text/css", "href", container, debug, ignoreCache);
 
     return mutated;
   }
 
-  protected LinkRewriter createLinkRewriter(Uri gadgetUri, ContentRewriterFeature feature,
-      String container) {
-    return new ProxyingLinkRewriter(gadgetUri, feature, rewriterUris.getProxyBase(container));
-  }
-
-  protected String getConcatBase(Uri gadgetUri, ContentRewriterFeature feature, String mimeType,
-      String container) {
-    String concatBaseNoGadget = rewriterUris.getConcatBase(container);
-    return concatBaseNoGadget +
-           ProxyBase.REWRITE_MIME_TYPE_PARAM +
-        '=' + mimeType +
-           ((gadgetUri == null) ? "" : "&gadget=" + Utf8UrlCoder.encode(gadgetUri.toString())) +
-           "&fp=" + feature.getFingerprint() +'&';
-  }
-
   protected boolean rewriteJsTags(List<Element> elementList, ContentRewriterFeature feature,
-      Uri gadgetUri, Uri contentBase, String container) {
+      Uri gadgetUri, Uri contentBase, String container, boolean debug, boolean ignoreCache) {
     if (!feature.getIncludedTags().contains("script")) {
       return false;
     }
@@ -224,7 +209,6 @@
       }
     }));
 
-    String concatBase = getConcatBase(gadgetUri, feature, JS_MIME_TYPE, container);
     List<Element> concatenateable = Lists.newArrayList();
     for (int i = 0; i < scriptTags.size(); i++) {
       Element scriptTag = scriptTags.get(i);
@@ -239,22 +223,24 @@
         if (nextSciptTag == null ||
             !nextSciptTag.equals(getNextSiblingElement(scriptTag))) {
           // Next tag is not concatenateable
-          concatenateTags(feature, concatenateable, concatBase, contentBase, "src");
+          concatenateTags(feature, concatenateable, gadgetUri, contentBase, JS_MIME_TYPE, "src", container, debug, ignoreCache);
           concatenateable.clear();
         }
       } else {
-        concatenateTags(feature, concatenateable, concatBase, contentBase, "src");
+        concatenateTags(feature, concatenateable, gadgetUri, contentBase, JS_MIME_TYPE, "src", container, debug, ignoreCache);
         concatenateable.clear();
       }
     }
-    concatenateTags(feature, concatenateable, concatBase, contentBase, "src");
+    concatenateTags(feature, concatenateable, gadgetUri, contentBase, JS_MIME_TYPE, "src", container, debug, ignoreCache);
     return mutated;
   }
 
   protected boolean rewriteContentReferences(List<Element> elementList,
-      ContentRewriterFeature feature, Uri gadgetUri, Uri contentBase, String container) {
+      ContentRewriterFeature feature, Uri gadgetUri, Uri contentBase, String container,
+      boolean debug, boolean ignoreCache) {
     boolean mutated = false;
-    LinkRewriter rewriter = createLinkRewriter(gadgetUri, feature, container);
+    LinkRewriter rewriter = proxyingLinkRewriterFactory.create(gadgetUri,
+        feature, container, debug, ignoreCache);
 
     final Set<String> tagNames = Sets.intersection(LINKING_TAG_ATTRS.keySet(), feature.getIncludedTags());
 
@@ -279,9 +265,9 @@
     return mutated;
   }
 
-  private static void concatenateTags(final ContentRewriterFeature feature,
-                               List<Element> tags, String concatBase, Uri contentBase,
-                               final String attr) {
+  private void concatenateTags(final ContentRewriterFeature feature,
+      List<Element> tags, Uri gadgetUri, Uri contentBase, String mimeType,
+      final String attr, String container, boolean debug, boolean ignoreCache) {
     // Filter out excluded URLs
     tags = Lists.newArrayList(Iterables.filter(tags, new Predicate<Element>() {
       public boolean apply(Element element) {
@@ -301,7 +287,9 @@
       }
     }
 
-    List<Uri> concatented = getConcatenatedUris(concatBase, nodeRefList);
+    List<Uri> concatented = concatLinkRewriterFactory.create(gadgetUri,
+        feature, container, debug, ignoreCache).rewrite(mimeType, nodeRefList);
+    
     for (int i = 0; i < tags.size(); i++) {
       if (i < concatented.size()) {
         // Set new URLs into existing tags
@@ -313,38 +301,6 @@
     }
   }
 
-  private static List<Uri> getConcatenatedUris(String concatBase, LinkedHashSet<Uri> uris) {
-    List<Uri> concatUris = Lists.newLinkedList();
-    int paramIndex = 1;
-    StringBuilder builder = null;
-    int maxUriLen = MAX_URL_LENGTH + concatBase.length();
-    try {
-      int uriIx = 0, lastUriIx = (uris.size() - 1);
-      //
-      for (Uri uri : uris) {
-        if (paramIndex == 1) {
-          builder = new StringBuilder(concatBase);
-        } else {
-          builder.append('&');
-        }
-        builder.append(paramIndex).append('=')
-            .append(URLEncoder.encode(uri.toString(), "UTF-8"));
-        if (builder.length() > maxUriLen ||
-            uriIx == lastUriIx) {
-          // Went over URI length warning limit or on the last uri
-          concatUris.add(Uri.parse(builder.toString()));
-          builder = null;
-          paramIndex = 0;
-        }
-        ++paramIndex;
-        ++uriIx;
-      }
-    } catch (UnsupportedEncodingException e) {
-      throw new RuntimeException(e);
-    }
-    return concatUris;
-  }
-
 
   private Element getNextSiblingElement(Element elem) {
     Node n = elem;

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriter.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriter.java Thu Nov  5 19:03:04 2009
@@ -28,22 +28,27 @@
  */
 public class ProxyingLinkRewriter implements LinkRewriter {
 
-  private final String prefix;
-  private final Uri parsedPrefix;
-
-  private final ContentRewriterFeature rewriterFeature;
-
-  private final Uri gadgetUri;
-
-  public ProxyingLinkRewriter(Uri gadgetUri, ContentRewriterFeature rewriterFeature,
-      String prefix) {
-    this.prefix = prefix;
-    parsedPrefix = Uri.parse(prefix);
+  protected final ContentRewriterUris rewriterUris;
+  protected final ContentRewriterFeature rewriterFeature;
+  protected final Uri gadgetUri;
+  protected final String container;
+  protected final boolean debug;
+  protected final boolean ignoreCache;
+  
+  public ProxyingLinkRewriter(ContentRewriterUris rewriterUris, Uri gadgetUri,
+      ContentRewriterFeature rewriterFeature, String container, boolean debug,
+      boolean ignoreCache) {
+    this.rewriterUris = rewriterUris;
     this.rewriterFeature = rewriterFeature;
     this.gadgetUri = gadgetUri;
+    this.container = container;
+    this.debug = debug;
+    this.ignoreCache = ignoreCache;
   }
 
   public String rewrite(String link, Uri context) {
+    String prefix = rewriterUris.getProxyBase(container);
+    Uri parsedPrefix = Uri.parse(prefix);
     link = link.trim();
     // We shouldnt bother proxying empty URLs
     if (link.length() == 0) {
@@ -51,18 +56,23 @@
     }
 
     try {
-      Uri linkUri = processLink(Uri.parse(link));
+      Uri linkUri = processLink(parsedPrefix, Uri.parse(link));
       Uri uri = context.resolve(linkUri);
       if (rewriterFeature.shouldRewriteURL(uri.toString())) {
-        String result = prefix
-            + Utf8UrlCoder.encode(uri.toString())
-            + ((gadgetUri == null) ? "" : "&gadget=" + Utf8UrlCoder.encode(gadgetUri.toString()))
-            + "&fp="
-            + rewriterFeature.getFingerprint();
+        StringBuilder result = new StringBuilder();
+        result.append(prefix);
+        result.append(Utf8UrlCoder.encode(uri.toString()));
+        result.append(((gadgetUri == null) ? "" : "&gadget=" + Utf8UrlCoder.encode(gadgetUri.toString()))); 
+        result.append("&fp=");
+        result.append(rewriterFeature.getFingerprint());
+        if(debug)
+          result.append("&debug=1");
+        if(ignoreCache)
+          result.append("&nocache=1");
         if (rewriterFeature.getExpires() != null) {
-          result += '&' + ProxyBase.REFRESH_PARAM  + '=' + rewriterFeature.getExpires().toString();
+          result.append('&').append(ProxyBase.REFRESH_PARAM).append('=').append(rewriterFeature.getExpires().toString());
         }
-        return result;
+        return result.toString();
       } else {
         return uri.toString();
       }
@@ -75,7 +85,7 @@
   /**
    * Preprocess link to avoid double-proxying
    */
-  private Uri processLink(Uri original) {
+  private Uri processLink(Uri parsedPrefix, Uri original) {
     if (parsedPrefix.getPath().equals(original.getPath())) {
       // Link is already rewritten to the proxy so extract the url param
       return Uri.parse(original.getQueryParameter("url"));

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriterFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriterFactory.java?rev=833128&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriterFactory.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ProxyingLinkRewriterFactory.java Thu Nov  5 19:03:04 2009
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.rewrite;
+
+import com.google.inject.ImplementedBy;
+
+import org.apache.shindig.common.uri.Uri;
+
+/**
+ * @author <a href="mailto:jweygandt@ebay.com">Jon Weygandt</a>
+ * @version $Id: $
+ */
+@ImplementedBy(DefaultProxyingLinkRewriterFactory.class)
+public interface ProxyingLinkRewriterFactory {
+  public ProxyingLinkRewriter create(Uri gadgetUri,
+      ContentRewriterFeature rewriterFeature, String container, boolean debug,
+      boolean ignoreCache);
+}
+

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java Thu Nov  5 19:03:04 2009
@@ -18,12 +18,12 @@
 
 package org.apache.shindig.gadgets.servlet;
 
+import com.google.inject.Inject;
+
 import org.apache.shindig.common.servlet.HttpUtil;
 import org.apache.shindig.common.servlet.InjectedServlet;
 import org.apache.shindig.gadgets.GadgetException;
 
-import com.google.inject.Inject;
-
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
@@ -54,21 +54,28 @@
   }
 
   @SuppressWarnings("boxing")
-@Override
+  @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
       throws IOException {
     if (request.getHeader("If-Modified-Since") != null) {
       response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
       return;
     }
-    if (request.getParameter(ProxyBase.REWRITE_MIME_TYPE_PARAM) != null) {
+    // Avoid response splitting vulnerability
+    String ct = request.getParameter(ProxyBase.REWRITE_MIME_TYPE_PARAM);
+    if(ct != null && ct.indexOf('\r')<0 && ct.indexOf('\n')<0) {
       response.setHeader("Content-Type",
           request.getParameter(ProxyBase.REWRITE_MIME_TYPE_PARAM));
     }
-    if (request.getParameter(ProxyBase.REFRESH_PARAM) != null) {
-      HttpUtil.setCachingHeaders(response,
-          Integer.valueOf(request.getParameter(ProxyBase.REFRESH_PARAM)));
+    
+    boolean ignoreCache = proxyHandler.getIgnoreCache(request);
+    if (!ignoreCache && request.getParameter(ProxyBase.REFRESH_PARAM) != null) {
+        HttpUtil.setCachingHeaders(response, Integer.valueOf(request
+            .getParameter(ProxyBase.REFRESH_PARAM)));
+    } else {
+      HttpUtil.setNoCache(response);
     }
+    
     response.setHeader("Content-Disposition", "attachment;filename=p.txt");
     for (int i = 1; i < Integer.MAX_VALUE; i++) {
       String url = request.getParameter(Integer.toString(i));

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyBase.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyBase.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyBase.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyBase.java Thu Nov  5 19:03:04 2009
@@ -120,7 +120,7 @@
   protected void setResponseHeaders(HttpServletRequest request,
       HttpServletResponse response, HttpResponse results) throws GadgetException {
     int refreshInterval = 0;
-    if (results.isStrictNoCache()) {
+    if (results.isStrictNoCache() || "1".equals(request.getParameter(IGNORE_CACHE_PARAM))) {
       refreshInterval = 0;
     } else if (request.getParameter(REFRESH_PARAM) != null) {
       try {

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Feature.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Feature.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Feature.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/Feature.java Thu Nov  5 19:03:04 2009
@@ -76,6 +76,13 @@
   }
 
   /**
+   * Returns the values for the key, or an empty collection.
+   */
+  public Collection<String> getParamCollection(String key) {
+    return params.get(key);
+  }
+
+  /**
    * Whether this is a Require or an Optional feature.
    */
   private final boolean required;

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizingGadgetRewriterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizingGadgetRewriterTest.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizingGadgetRewriterTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizingGadgetRewriterTest.java Thu Nov  5 19:03:04 2009
@@ -60,7 +60,18 @@
   };
 
   private final GadgetContext unsanitaryGadgetContext = new GadgetContext();
+  private final GadgetContext unsanitaryGadgetContextNoCacheAndDebug = new GadgetContext(){
+    @Override
+    public boolean getIgnoreCache() {
+      return true;
+    }
+    @Override
+    public boolean getDebug() {
+      return true;
+    }
+  };
   private Gadget gadget;
+  private Gadget gadgetNoCacheAndDebug;
 
   @Before
   @Override
@@ -71,7 +82,12 @@
     gadget.setSpec(new GadgetSpec(Uri.parse("www.example.org/gadget.xml"),
         "<Module><ModulePrefs title=''/><Content type='x-html-sanitized'/></Module>"));
     gadget.setCurrentView(gadget.getSpec().getViews().values().iterator().next());
-  }
+
+    gadgetNoCacheAndDebug = new Gadget().setContext(unsanitaryGadgetContextNoCacheAndDebug);
+    gadgetNoCacheAndDebug.setSpec(new GadgetSpec(Uri.parse("www.example.org/gadget.xml"),
+        "<Module><ModulePrefs title=''/><Content type='x-html-sanitized'/></Module>"));
+    gadgetNoCacheAndDebug.setCurrentView(gadgetNoCacheAndDebug.getSpec().getViews().values().iterator().next());
+}
 
   private String rewrite(Gadget gadget, String content, Set<String> tags, Set<String> attributes)
       throws Exception {
@@ -95,9 +111,9 @@
     Set<String> newTags = new HashSet<String>(tags);
     newTags.addAll(DEFAULT_TAGS);
     ContentRewriterFeatureFactory rewriterFeatureFactory =
-        new ContentRewriterFeatureFactory(null, ".*", "", "HTTP", "embed,img,script,link,style");
+        new ContentRewriterFeatureFactory(null, ".*", "", "HTTP", "embed,img,script,link,style", "false");
     return new SanitizingGadgetRewriter(newTags, attributes, rewriterFeatureFactory,
-        rewriterUris, new CajaCssSanitizer(new CajaCssParser()));
+        new CajaCssSanitizer(new CajaCssParser()), new DefaultSanitizingProxyingLinkRewriterFactory(rewriterUris));
   }
 
   @Test
@@ -138,6 +154,21 @@
   }
 
   @Test
+  public void enforceStyleLinkRewrittenNoCacheAndDebug() throws Exception {
+    String markup =
+        "<link rel=\"stylesheet\" "
+            + "href=\"http://www.test.com/dir/proxy?"
+            + "url=http%3A%2F%2Fwww.evil.com%2Fx.css&gadget=www.example.org%2Fgadget.xml&"
+            + "fp=45508rewriteMime=text/css\"/>";
+    String sanitized = 
+        "<html><head><link href=\"http://www.test.com/dir/proxy?"
+            + "url=http%3A%2F%2Fwww.evil.com%2Fx.css&gadget=www.example.org%2Fgadget.xml&"
+            + "fp=45508&debug=1&nocache=1&sanitize=1&rewriteMime=text/css\" rel=\"stylesheet\"></head><body></body></html>";
+    String rewritten = rewrite(gadgetNoCacheAndDebug, markup, set("link"), set("rel", "href"));
+    assertEquals(sanitized, rewritten);
+  }
+
+  @Test
   public void enforceNonStyleLinkStripped() throws Exception {
     String markup =
         "<link rel=\"script\" "
@@ -147,6 +178,15 @@
   }
 
   @Test
+  public void enforceNonStyleLinkStrippedNoCacheAndDebug() throws Exception {
+    String markup =
+        "<link rel=\"script\" "
+            + "href=\"www.exmaple.org/evil.js\"/>";
+    String rewritten = rewrite(gadgetNoCacheAndDebug, markup, set("link"), set("rel", "href", "type"));
+    assertEquals("<html><head></head><body></body></html>", rewritten);
+  }
+
+  @Test
   public void enforceCssImportLinkRewritten() throws Exception {
     String markup =
         "<style type=\"text/css\">@import url('www.evil.com/x.js');</style>";
@@ -163,6 +203,22 @@
   }
 
   @Test
+  public void enforceCssImportLinkRewrittenNoCacheAndDebug() throws Exception {
+    String markup =
+        "<style type=\"text/css\">@import url('www.evil.com/x.js');</style>";
+    // The caja css sanitizer does *not* remove the initial colon in urls
+    // since this does not work in IE
+    String sanitized = 
+        "<html><head><style>"
+      + "@import url('http://www.test.com/dir/proxy?url=www.example.org%2F"
+      + "www.evil.com%2Fx.js&gadget=www.example.org%2Fgadget.xml&"
+      + "fp=45508&debug=1&nocache=1&sanitize=1&rewriteMime=text%2Fcss');"
+      + "</style></head><body></body></html>";
+    String rewritten = rewrite(gadgetNoCacheAndDebug, markup, set("style"), set());
+    assertEquals(sanitized, rewritten);
+  }
+
+  @Test
   public void enforceCssImportBadLinkStripped() throws Exception {
     String markup =
         "<style type=\"text/css\">@import url('javascript:doevil()'); A { font : bold }</style>";
@@ -187,6 +243,13 @@
   }
 
   @Test
+  public void enforceImageSrcProxiedNoCacheAndDebug() throws Exception {
+    String markup = "<img src='http://www.evil.com/x.js'>Evil happens</img>";
+    String sanitized = "<img src=\"http://www.test.com/dir/proxy?url=http%3A%2F%2Fwww.evil.com%2Fx.js&gadget=www.example.org%2Fgadget.xml&fp=45508&debug=1&nocache=1&sanitize=1&rewriteMime=image/*\">Evil happens";
+    assertEquals(sanitized, rewrite(gadgetNoCacheAndDebug, markup, set("img"), set("src")));
+  }
+
+  @Test
   public void enforceBadImageUrlStripped() throws Exception {
     String markup = "<img src='java\\ script:evil()'>Evil happens</img>";
     String sanitized = "<img>Evil happens";

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizingRequestRewriterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizingRequestRewriterTest.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizingRequestRewriterTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizingRequestRewriterTest.java Thu Nov  5 19:03:04 2009
@@ -54,9 +54,9 @@
 
   private RequestRewriter createRewriter(Set<String> tags, Set<String> attributes) {
     ContentRewriterFeatureFactory rewriterFeatureFactory =
-        new ContentRewriterFeatureFactory(null, ".*", "", "HTTP", "embed,img,script,link,style");
+        new ContentRewriterFeatureFactory(null, ".*", "", "HTTP", "embed,img,script,link,style", "false");
     return new SanitizingRequestRewriter(rewriterFeatureFactory,
-        rewriterUris, new CajaCssSanitizer(new CajaCssParser()));
+        new CajaCssSanitizer(new CajaCssParser()), new DefaultSanitizingProxyingLinkRewriterFactory(rewriterUris));
   }
 
   @Test
@@ -88,6 +88,26 @@
   }
 
   @Test
+  public void enforceValidProxedCssAcceptedNoCache() throws Exception {
+    HttpRequest req = new HttpRequest(CONTENT_URI);
+    req.setRewriteMimeType("text/css");
+    req.setIgnoreCache(true);
+    HttpResponse response = new HttpResponseBuilder().setResponseString(
+        "@import url('http://www.evil.com/more.css'); A { font : BOLD }").create();
+    // The caja css sanitizer does *not* remove the initial colon in urls
+    // since this does not work in IE
+    String sanitized = 
+      "@import url('http://www.test.com/dir/proxy?"
+        + "url=http%3A%2F%2Fwww.evil.com%2Fmore.css"
+        + "&fp=45508&nocache=1&sanitize=1&rewriteMime=text%2Fcss');\n"
+        + "A {\n"
+        + "  font: BOLD\n"
+        + "}";
+    String rewritten = rewrite(req, response);
+    assertEquals(sanitized, rewritten);
+  }
+
+  @Test
   public void enforceInvalidProxedImageRejected() throws Exception {
     HttpRequest req = new HttpRequest(CONTENT_URI);
     req.setRewriteMimeType("image/*");

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/BaseRewriterTestCase.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/BaseRewriterTestCase.java?rev=833128&r1=833127&r2=833128&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/BaseRewriterTestCase.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/BaseRewriterTestCase.java Thu Nov  5 19:03:04 2009
@@ -62,29 +62,43 @@
   protected ContentRewriterFeature defaultRewriterFeature;
   protected ContentRewriterFeatureFactory rewriterFeatureFactory;
   protected LinkRewriter defaultLinkRewriter;
+  protected LinkRewriter defaultLinkRewriterNoCache;
+  protected LinkRewriter defaultLinkRewriterNoCacheAndDebug;
   protected GadgetHtmlParser parser;
   protected Injector injector;
   protected HttpResponse fakeResponse;
-  protected ContainerConfig config;
   protected ContentRewriterUris rewriterUris;
   protected IMocksControl control;
+  protected ContentRewriterUris defaultContainerRewriterUris;
 
   @Before
   public void setUp() throws Exception {
-    rewriterFeatureFactory = new ContentRewriterFeatureFactory(null, ".*", "", "HTTP",
-        "embed,img,script,link,style");
+    rewriterFeatureFactory = new ContentRewriterFeatureFactory(null, ".*", "", "86400",
+        "embed,img,script,link,style", "false");
     defaultRewriterFeature = rewriterFeatureFactory.getDefault();
     tags = defaultRewriterFeature.getIncludedTags();
-    defaultLinkRewriter = new ProxyingLinkRewriter(
-        SPEC_URL,
-        defaultRewriterFeature,
-        DEFAULT_PROXY_BASE);
+    defaultContainerRewriterUris = new ContentRewriterUris(
+        new AbstractContainerConfig() {
+          @Override
+          public Object getProperty(String container, String name) {
+            return null;
+          }
+        }, DEFAULT_PROXY_BASE, DEFAULT_CONCAT_BASE);
+    defaultLinkRewriter = new DefaultProxyingLinkRewriterFactory(
+        defaultContainerRewriterUris).create(SPEC_URL, defaultRewriterFeature,
+        "default", false, false);
+    defaultLinkRewriterNoCache = new DefaultProxyingLinkRewriterFactory(
+        defaultContainerRewriterUris).create(SPEC_URL, defaultRewriterFeature,
+        "default", false, true);
+    defaultLinkRewriterNoCacheAndDebug = new DefaultProxyingLinkRewriterFactory(
+        defaultContainerRewriterUris).create(SPEC_URL, defaultRewriterFeature,
+        "default", true, true);
     injector = Guice.createInjector(new ParseModule(), new PropertiesModule(), new TestModule());
     parser = injector.getInstance(GadgetHtmlParser.class);
     fakeResponse = new HttpResponseBuilder().setHeader("Content-Type", "unknown")
         .setResponse(new byte[]{ (byte)0xFE, (byte)0xFF}).create();
 
-    config = new AbstractContainerConfig() {
+    ContainerConfig config = new AbstractContainerConfig() {
       @Override
       public Object getProperty(String container, String name) {
         if (MOCK_CONTAINER.equals(container)) {
@@ -106,18 +120,48 @@
 
   public static GadgetSpec createSpecWithRewrite(String include, String exclude, String expires,
       Set<String> tags) throws GadgetException {
-    String xml = "<Module>" +
-                 "<ModulePrefs title=\"title\">" +
-                 "<Optional feature=\"content-rewrite\">\n" +
-                 "      <Param name=\"expires\">" + expires + "</Param>\n" +
-                 "      <Param name=\"include-urls\">" + include + "</Param>\n" +
-                 "      <Param name=\"exclude-urls\">" + exclude + "</Param>\n" +
-                 "      <Param name=\"include-tags\">" + StringUtils.join(tags, ",") + "</Param>\n" +
-                 "</Optional>" +
-                 "</ModulePrefs>" +
-                 "<Content type=\"html\">Hello!</Content>" +
-                 "</Module>";
-    return new GadgetSpec(SPEC_URL, xml);
+    StringBuilder xml = new StringBuilder();
+    xml.append("<Module>");
+    xml.append("<ModulePrefs title=\"title\">");
+    xml.append("<Optional feature=\"content-rewrite\">\n");
+    if(expires != null)
+      xml.append("      <Param name=\"expires\">" + expires + "</Param>\n");
+    if(include != null)
+      xml.append("      <Param name=\"include-urls\">" + include + "</Param>\n");
+    if(exclude != null)
+      xml.append("      <Param name=\"exclude-urls\">" + exclude + "</Param>\n");
+    if(tags != null)
+      xml.append("      <Param name=\"include-tags\">" + StringUtils.join(tags, ",") + "</Param>\n");
+    xml.append("</Optional>");
+    xml.append("</ModulePrefs>");
+    xml.append("<Content type=\"html\">Hello!</Content>");
+    xml.append("</Module>");
+    return new GadgetSpec(SPEC_URL, xml.toString());
+  }
+
+  public static GadgetSpec createSpecWithRewriteOS9(String[] includes, String[] excludes, String expires,
+      Set<String> tags) throws GadgetException {
+    StringBuilder xml = new StringBuilder();
+    xml.append("<Module>");
+    xml.append("<ModulePrefs title=\"title\">");
+    xml.append("<Optional feature=\"content-rewrite\">\n");
+    if(expires != null)
+      xml.append("      <Param name=\"expires\">" + expires + "</Param>\n");
+    if(includes != null)
+      for (String include : includes) {
+        xml.append("      <Param name=\"include-url\">" + include + "</Param>\n");
+      }
+    if(excludes != null)
+      for (String exclude : excludes) {
+        xml.append("      <Param name=\"exclude-url\">" + exclude + "</Param>\n");
+      }
+    if(tags != null)
+      xml.append("      <Param name=\"include-tags\">" + StringUtils.join(tags, ",") + "</Param>\n");
+    xml.append("</Optional>");
+    xml.append("</ModulePrefs>");
+    xml.append("<Content type=\"html\">Hello!</Content>");
+    xml.append("</Module>");
+    return new GadgetSpec(SPEC_URL, xml.toString());
   }
 
   public static GadgetSpec createSpecWithoutRewrite() throws GadgetException {
@@ -152,7 +196,13 @@
     return rewrittenContent;
   }
 
-  MutableContent rewriteContent(GadgetRewriter rewriter, String s, final String container)
+  MutableContent rewriteContent(GadgetRewriter rewriter, String s,
+      final String container) throws Exception {
+    return rewriteContent(rewriter, s, container, false, false);
+  }
+  
+  MutableContent rewriteContent(GadgetRewriter rewriter, String s,
+      final String container, final boolean debug, final boolean ignoreCache)
       throws Exception {
     MutableContent mc = new MutableContent(parser, s);
 
@@ -169,6 +219,16 @@
       public String getContainer() {
         return container;
       }
+      
+      @Override
+      public boolean getDebug() {
+        return debug;
+      }
+      
+      @Override
+      public boolean getIgnoreCache() {
+        return ignoreCache;
+      }
     };
 
     Gadget gadget = new Gadget()
@@ -182,7 +242,7 @@
     private final ContentRewriterFeature feature;
 
     public FakeRewriterFeatureFactory(ContentRewriterFeature feature) {
-      super(null, ".*", "", "HTTP", "");
+      super(null, ".*", "", "HTTP", "", "false");
       this.feature = feature;
     }