You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by jo...@apache.org on 2010/06/14 23:18:21 UTC

svn commit: r954649 - in /shindig/trunk: ./ java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ java/gadgets/src/test/j...

Author: johnh
Date: Mon Jun 14 21:18:20 2010
New Revision: 954649

URL: http://svn.apache.org/viewvc?rev=954649&view=rev
Log:
Patch by Gagan Singh.

Refactor HtmlAccelServlet to behave like a proxying servlet rather than faking a gadget render.


Added:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/AccelUriManager.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriUtils.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/AccelUriManagerTest.java
Modified:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyBase.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HtmlAccelServletTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java
    shindig/trunk/pom.xml

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java?rev=954649&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/AccelHandler.java Mon Jun 14 21:18:20 2010
@@ -0,0 +1,175 @@
+/*
+ * 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.servlet;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+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.GadgetException;
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.http.HttpResponse;
+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.AccelUriManager;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+import org.apache.shindig.gadgets.uri.UriUtils;
+
+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());
+
+  static final String ERROR_FETCHING_DATA = "Error fetching data";
+
+  // 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 ResponseRewriterRegistry contentRewriterRegistry;
+  private final AccelUriManager uriManager;
+
+  @Inject
+  public AccelHandler(RequestPipeline requestPipeline,
+                      ResponseRewriterRegistry contentRewriterRegistry,
+                      AccelUriManager accelUriManager) {
+    this.requestPipeline = requestPipeline;
+    this.contentRewriterRegistry = contentRewriterRegistry;
+    this.uriManager = accelUriManager;
+  }
+
+  @Override
+  protected void doFetch(HttpServletRequest request, HttpServletResponse response)
+      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 = uriManager.parseAndNormalize(requestUri);
+
+    // 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) {
+      throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e,
+                                e.getHttpStatusCode());
+    }
+
+    // Copy the response headers and status code to the final http servlet
+    // response.
+    UriUtils.copyResponseHeadersAndStatusCode(
+        results, response,
+        UriUtils.DisallowedResponseHeaders.OUTPUT_TRANSFER_DIRECTIVES,
+        UriUtils.DisallowedResponseHeaders.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);
+
+    IOUtils.copy(results.getResponse(), response.getOutputStream());
+  }
+
+  /**
+   * Generate a remote content request based on the parameters sent from the client.
+   * @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.
+   */
+  private HttpRequest buildHttpRequest(HttpServletRequest 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);
+    }
+  }
+
+  /**
+   * Process errors when fetching uri using request pipeline by throwing
+   * GadgetException in error cases.
+   * @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.
+   */
+  protected boolean handleErrors(HttpResponse results, HttpServletResponse response)
+      throws IOException {
+    if (results == null) {
+      response.sendError(HttpServletResponse.SC_BAD_REQUEST, ERROR_FETCHING_DATA);
+      return false;
+    }
+    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;
+    }
+
+    return true;
+  }
+}

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java?rev=954649&r1=954648&r2=954649&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HtmlAccelServlet.java Mon Jun 14 21:18:20 2010
@@ -17,267 +17,44 @@
  */
 package org.apache.shindig.gadgets.servlet;
 
-import com.google.common.collect.ImmutableList;
 import com.google.inject.Inject;
-import com.google.inject.name.Named;
 
-import org.apache.commons.io.IOUtils;
-import org.apache.shindig.common.uri.UriBuilder;
-import org.apache.shindig.gadgets.DefaultGadgetSpecFactory;
+import org.apache.shindig.common.servlet.InjectedServlet;
 import org.apache.shindig.gadgets.GadgetContext;
-import org.apache.shindig.gadgets.GadgetException;
-import org.apache.shindig.gadgets.GadgetException.Code;
-import org.apache.shindig.gadgets.http.HttpRequest;
-import org.apache.shindig.gadgets.http.HttpResponse;
-import org.apache.shindig.gadgets.http.RequestPipeline;
-import org.apache.shindig.gadgets.uri.UriCommon;
 
 import java.io.IOException;
-import java.util.List;
-import java.util.Map;
+import java.util.logging.Logger;
 
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
 
 /**
- * Html pages acceleration servlet.
- * It uses the rewriter pipeline to improve speed of loading html.
- * Internally it create a fake gadget spec and uses the Gadget rendering servlet.
- * Only html content is being rewritten, other content is passed as is.
- * (It uses the rawxml tag to pass spec, so require DefaultGadgetSpecFactory)
+ * Handles requests for accel servlet.
+ * The objective is to accelerate web pages.
  */
-public class HtmlAccelServlet extends GadgetRenderingServlet {
+public class HtmlAccelServlet extends InjectedServlet {
+
+  private AccelHandler accelHandler;
+  private static Logger logger = Logger.getLogger(
+      HtmlAccelServlet.class.getName());
 
-  public static final String URL_PARAM_NAME = "url";
-  /**
-   * Use ACCEL_GADGET parameter to check for AccelServlet during rendering.
-   */
   public static final String ACCEL_GADGET_PARAM_NAME = "accelGadget";
-  /** 
-   * Use the next value with '==' operation when checking for ACCEL_GADGET,
-   * That will prevent spoofing it using url params.
-   */
   public static final String ACCEL_GADGET_PARAM_VALUE = "true";
-  public static final String CONTENT_TYPE = "Content-Type";
-  public static final String HTML_CONTENT = "text/html";
-  public static final String CONTENT_ENCODING = "Content-Encoding";
-  public static final String CONTENT_LENGTH = "Content-Length";
-  public static final String DEFAULT_CONTAINER ="accel";
-
-  /** Fake spec to wrap the html data */
-  private static final String FAKE_SPEC_TPL = 
-      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-      + "<Module>\n"
-      + "  <ModulePrefs title=\"Apache Shindig Accelerator\"\n"
-      + "               author=\"Apache Shindig\"\n"
-      + "               author_email=\"no-reply@gmail.com\">\n"
-      + "    <Require feature=\"core.none\"/>\n"
-      + "    <Optional feature=\"content-rewrite\">\n"
-      + "      <Param name=\"include-urls\">.*</Param>\n"
-      + "    </Optional>\n"
-      + "  </ModulePrefs>\n"
-      + "  <Content type=\"html\">\n"
-      + "    <![CDATA[%s]]>\n" 
-      + "  </Content>\n"
-      + "</Module>\n";
 
-  private RequestPipeline requestPipeline;
-  private Map<String, String> addedServletParams = null;
-  
   @Inject
-  public void setRequestPipeline(RequestPipeline pipeline) {
-    this.requestPipeline = pipeline;
-  }
-  
-  @Inject(optional = true)
-  public void setAddedServletParams(
-      @Named("shindig.accelerate.added-params") Map<String, String> params) {
-    this.addedServletParams = params;
-  }
-
-  public static boolean isAccel(GadgetContext context) {
-    return context.getParameter(HtmlAccelServlet.ACCEL_GADGET_PARAM_NAME) ==
-      HtmlAccelServlet.ACCEL_GADGET_PARAM_VALUE;
-  }
-
-  @Override
-  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
-      throws IOException {
-
-    // Get data to accelerate:
-    HttpResponse data;
-    final Map<String, List<String>> requestParams = getAccelParams(req);
-
-    // Create request to handle parsed params
-    final HttpServletRequestWrapper dataWrapper = new HttpServletRequestWrapper(req) {
-      @Override
-      public String getParameter(String name) {
-        if (requestParams.containsKey(name)) {
-          List<String> values = requestParams.get(name);
-          if (values != null && !values.isEmpty()) return values.get(0);
-        }
-        return null;
-      }
-    };
-    HttpGadgetContext context = new HttpGadgetContext(dataWrapper);
-    try {
-      data = fetch(context);
-    } catch (GadgetException e) {
-      resp.sendError(e.getHttpStatusCode(), e.getMessage());
-      return;
-    }
-    
-    // No such page:
-    if (data == null) {
-      resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Error fetching data");
-      return;
-    }
-
-    // If not html, just return data
-    if (!isHtmlContent(data)) {
-      respondVerbatim(data, resp);
-      return;
-    }
-    
-    // For html, use the gadgetServlet for rewrite
-    String content = data.getResponseAsString();
-
-    // Use response TTL, by using the refresh param:
-    if (!requestParams.containsKey(UriCommon.Param.REFRESH.getKey()) && data.getCacheTtl() > 0) {
-      requestParams.put(UriCommon.Param.REFRESH.getKey(),
-          ImmutableList.of(Long.toString(data.getCacheTtl() / 1000)));
-    }
-    
-    // Create fake spec wrapper for the html:
-    // (Note that the content can be big so don't use the limited String.Format)
-    final String spec = createFakeSpec(content);
-    
-    // wrap the request with the added params
-    HttpServletRequestWrapper reqWrapper = new HttpServletRequestWrapper(req) {
-      @Override
-      public String getParameter(String name) {
-        // Mark this as an accelerate page spec
-        // (The code that check for that field have to use the defined constant,
-        //  hence the use of == )
-        if (name == ACCEL_GADGET_PARAM_NAME) {
-          return ACCEL_GADGET_PARAM_VALUE;
-        }
-        // Pass the spec using rawxml (require DefaultGadgetSpecFactory):
-        if (name == DefaultGadgetSpecFactory.RAW_GADGETSPEC_XML_PARAM_NAME) {
-          return spec;
-        }
-        String value = dataWrapper.getParameter(name);
-        if (value != null) {
-          return value;
-        }
-        // Allow overriding extra params
-        if (addedServletParams != null && addedServletParams.containsKey(name)) {
-          return addedServletParams.get(name);
-        }
-        return super.getParameter(name);
-      }
-    };
-    
-    // Call the gadget renderer to rewrite content:
-    super.doGet(reqWrapper,resp);
-    
-    // Pass original return code:
-    if (data.getHttpStatusCode() == HttpResponse.SC_INTERNAL_SERVER_ERROR) {
-      // Convert external "internal error" to gateway error
-      resp.setStatus(HttpServletResponse.SC_BAD_GATEWAY);
-    } else if (data.getHttpStatusCode() >= 400) {
-      resp.setStatus(data.getHttpStatusCode());
-    }
+  public void setHandler(AccelHandler accelHandler) {
+    this.accelHandler = accelHandler;
   }
 
   @Override
-  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-    doGet(req,resp);
-  }
-  
-  protected boolean isHtmlContent(HttpResponse data) {
-    return data.getHeader(CONTENT_TYPE) != null &&
-           data.getHeader(CONTENT_TYPE).contains(HTML_CONTENT);
-  }
-
-  private HttpResponse fetch(HttpGadgetContext context) throws GadgetException {
-    if (context.getUrl() == null) {
-      throw new GadgetException(Code.INVALID_PARAMETER, "Missing url paramater",
-          HttpResponse.SC_BAD_REQUEST);
-    }
-
-    HttpRequest request = new HttpRequest(context.getUrl())
-        .setIgnoreCache(context.getIgnoreCache())
-        .setContainer(context.getContainer());
-
-    return requestPipeline.execute(request);
-  }
-  
-  private void respondVerbatim(HttpResponse results, HttpServletResponse response) 
+  protected void doGet(HttpServletRequest request, HttpServletResponse response)
       throws IOException {
-    
-    for (Map.Entry<String, String> entry : results.getHeaders().entries()) {
-      // Encoding such as gzip was already stripped from data
-      if (!CONTENT_ENCODING.equals(entry.getKey()) &&
-          !CONTENT_LENGTH.equals(entry.getKey())) {
-        response.setHeader(entry.getKey(), entry.getValue());
-      }
-    }
-    response.setStatus(results.getHttpStatusCode());
-    if (results.getHttpStatusCode() == HttpResponse.SC_INTERNAL_SERVER_ERROR) {
-      // Convert external "internal error" to gateway error
-      response.setStatus(HttpServletResponse.SC_BAD_GATEWAY);
-    }
-    IOUtils.copy(results.getResponse(), response.getOutputStream());
-  }
-
-  private String createFakeSpec(String content) {
-    // need to rescape CDATA: ( each "]]>" and "<![CDATA[" should be "]]><![CDATA[")
-    // TODO: just xml escape this and remove the CDATA section
-    String data = content.replace("]]>", "<![CDATA[")
-      .replace("<![CDATA[", "]]><![CDATA[");
-    return String.format(FAKE_SPEC_TPL, data);   
+    logger.fine("accel request = " + request.toString());
+    accelHandler.fetch(request, response);
   }
-  
-  /**
-   * Parse request to get accelerated parameters
-   * Support parameterize using the url query param,
-   * Or chained using the url pattern: <prefix>/<params>/<url>
-   * For example:
-   * http://shindig.com/gadgets/accel/refresh=300/http://example.com/accelerate.html?id=X
-   */
-  protected Map<String, List<String>> getAccelParams(HttpServletRequest req) {
-    String path = new UriBuilder(req).getPath();
-    String accelServletPrefix = req.getServletPath();
 
-    String paramsStr = null;
-    String accelUrl = null;
-    // Check for chain param style request:
-    if (path.startsWith(accelServletPrefix + '/')) {
-      int startQuery = accelServletPrefix.length() + 1;
-      int endQuery = path.indexOf('/', startQuery);
-      if (endQuery >= startQuery) {
-        paramsStr = path.substring(startQuery, endQuery);
-        accelUrl = path.substring(endQuery + 1); // + "?" + req.getQueryString();
-      }
-    }
-    // Otherwise Get original request params:
-    if (paramsStr == null) {
-      paramsStr = req.getQueryString();
-    }
-    
-    // Convert to parameter maps:
-    UriBuilder uriBuilder = new UriBuilder().setQuery(paramsStr);
-    Map<String, List<String>> params = uriBuilder.getQueryParameters();
-    if (accelUrl != null) {
-      params.put(UriCommon.Param.URL.getKey(), ImmutableList.of(accelUrl));
-    }
-
-    // Add defaults:
-    if (!params.containsKey(UriCommon.Param.CONTAINER.getKey())) {
-      params.put(UriCommon.Param.CONTAINER.getKey(), ImmutableList.of(DEFAULT_CONTAINER));
-    }
-    return params;
+  public static boolean isAccel(GadgetContext context) {
+    return context.getParameter(HtmlAccelServlet.ACCEL_GADGET_PARAM_NAME) ==
+        HtmlAccelServlet.ACCEL_GADGET_PARAM_VALUE;
   }
 }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyBase.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyBase.java?rev=954649&r1=954648&r2=954649&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyBase.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyBase.java Mon Jun 14 21:18:20 2010
@@ -180,7 +180,8 @@ public abstract class ProxyBase {
     
     int responseCode;
     Level level = Level.FINE;
-    
+
+    // TODO: Recosider if we should be passing on 404 to the user as is.
     switch (e.getCode()) {
       case INTERNAL_SERVER_ERROR:
         responseCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/AccelUriManager.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/AccelUriManager.java?rev=954649&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/AccelUriManager.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/AccelUriManager.java Mon Jun 14 21:18:20 2010
@@ -0,0 +1,43 @@
+/*
+ * 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.uri;
+
+import com.google.inject.Inject;
+import com.google.inject.internal.Nullable;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.config.ContainerConfig;
+import org.apache.shindig.gadgets.GadgetException;
+
+/**
+ * UriManager for Accel servlet.
+ */
+public class AccelUriManager extends DefaultProxyUriManager {
+
+  @Inject
+  public AccelUriManager(ContainerConfig config,
+                         @Nullable Versioner versioner) {
+    super(config, versioner);
+  }
+
+  public ProxyUri parseAndNormalize(Uri requestUri) throws GadgetException {
+    // TODO: Handle normalization.
+    return process(requestUri);
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriUtils.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriUtils.java?rev=954649&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriUtils.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/UriUtils.java Mon Jun 14 21:18:20 2010
@@ -0,0 +1,132 @@
+/*
+ * 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.uri;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.apache.shindig.gadgets.http.HttpResponse;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Utility functions related to URI and Http servlet response management.
+ */
+public class UriUtils {
+  /**
+   * Enum of disallowed response headers that should not be passed on as is to
+   * the user. The webserver serving out the response should be responsible
+   * for filling these.
+   */
+  public enum DisallowedResponseHeaders {
+    // Directives controlled by the serving infrastructure.
+    OUTPUT_TRANSFER_DIRECTIVES(ImmutableSet.of(
+        "content-length", "transfer-encoding", "content-encoding", "server",
+        "accept-ranges")),
+
+    CACHING_DIRECTIVES(ImmutableSet.of("vary", "expires", "date", "pragma",
+                                       "cache-control")),
+
+    CLIENT_STATE_DIRECTIVES(ImmutableSet.of("set-cookie", "www-authenticate"));
+
+    // Miscellaneous headers we should take care of, but are left for now.
+    // "set-cookie", "content-length", "content-encoding", "etag",
+    // "last-modified" ,"accept-ranges", "vary", "expires", "date",
+    // "pragma", "cache-control", "transfer-encoding", "www-authenticate"
+
+    private Set<String> responseHeaders;
+    DisallowedResponseHeaders(Set<String> responseHeaders) {
+      this.responseHeaders = responseHeaders;
+    }
+
+    public Set<String> getResponseHeaders() {
+      return responseHeaders;
+    }
+  }
+
+  /**
+   * Returns true if the header name is valid.
+   * NOTE: RFC 822 section 3.1.2 describes the structure of header fields. 
+   * @param name The header name.
+   * @return True if the header name is valid, false otherwise.
+   */
+  public static boolean isValidHeaderName(String name) {
+    char[] dst = new char[name.length()];
+    name.getChars(0, name.length(), dst, 0);
+
+    for (char c : dst) {
+      if (c < 33 || c > 126) {
+        return false;
+      }
+      if (c == ':') {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Returns true if the header value is valid.
+   * NOTE: RFC 822 section 3.1.2 describes the structure of header fields.
+   * @param val The header value.
+   * @return True if the header value is valid, false otherwise.
+   */
+  public static boolean isValidHeaderValue(String val) {
+    // TODO: complete this.
+    return true;
+  }
+
+  /**
+   * Copies the http response headers and status code to the final servlet
+   *   response.
+   * @param data The http response when fetching the requested accel uri.
+   * @param resp The servlet response to return back to client.
+   * @param disallowedResponseHeaderses Disallowed response headers to omit from the response
+   *   returned to the user. 
+   * @throws IOException In case the http response was not successful.
+   */
+  public static void copyResponseHeadersAndStatusCode(
+      HttpResponse data, HttpServletResponse resp,
+      DisallowedResponseHeaders... disallowedResponseHeaderses)
+      throws IOException {
+    // Pass original return code:
+    resp.setStatus(data.getHttpStatusCode());
+
+    Set<String> allDisallowedHeaders = new HashSet<String>();
+    for (DisallowedResponseHeaders h : disallowedResponseHeaderses) {
+      allDisallowedHeaders.addAll(h.getResponseHeaders());
+    }
+
+    for (Map.Entry<String, String> entry : data.getHeaders().entries()) {
+      if (isValidHeaderName(entry.getKey()) && isValidHeaderValue(entry.getValue()) &&
+          !allDisallowedHeaders.contains(entry.getKey().toLowerCase())) {
+        resp.setHeader(entry.getKey(), entry.getValue());
+      }
+    }
+
+    // External "internal error" should be mapped to gateway error.
+    if (data.getHttpStatusCode() == HttpResponse.SC_INTERNAL_SERVER_ERROR) {
+      resp.sendError(HttpResponse.SC_BAD_GATEWAY);
+    }
+  }
+}

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HtmlAccelServletTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HtmlAccelServletTest.java?rev=954649&r1=954648&r2=954649&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HtmlAccelServletTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/HtmlAccelServletTest.java Mon Jun 14 21:18:20 2010
@@ -18,53 +18,77 @@
  */
 package org.apache.shindig.gadgets.servlet;
 
-import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.isA;
-
 import com.google.common.collect.Maps;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.shindig.common.uri.Uri;
-import org.apache.shindig.gadgets.Gadget;
-import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.config.AbstractContainerConfig;
 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.render.Renderer;
-import org.apache.shindig.gadgets.render.RenderingResults;
-import org.apache.shindig.gadgets.uri.IframeUriManager;
-import org.apache.shindig.gadgets.uri.UriStatus;
-import org.easymock.Capture;
+import org.apache.shindig.gadgets.rewrite.CaptureRewriter;
+import org.apache.shindig.gadgets.rewrite.DefaultResponseRewriterRegistry;
+import org.apache.shindig.gadgets.rewrite.ResponseRewriter;
+import org.apache.shindig.gadgets.uri.AccelUriManager;
+import static org.easymock.EasyMock.expect;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.Arrays;
 import java.util.Map;
 
 public class HtmlAccelServletTest extends ServletTestFixture {
 
+  private static class FakeContainerConfig extends AbstractContainerConfig {
+    protected final Map<String, Object> data = Maps.newHashMap();
+
+    @Override
+    public Object getProperty(String container, String name) {
+      return data.get(name);
+    }
+  }
+
+  private class FakeCaptureRewriter extends CaptureRewriter {
+    String contentToRewrite;
+
+    public void setContentToRewrite(String s) {
+      contentToRewrite = s;
+    }
+    @Override
+    public void rewrite(HttpRequest request, HttpResponseBuilder original) {
+      super.rewrite(request, original);
+      if (!StringUtils.isEmpty(contentToRewrite)) {
+        original.setResponse(contentToRewrite.getBytes());
+      }
+    }
+  }
+
   private static final String REWRITE_CONTENT = "working rewrite";
   private static final String SERVLET = "/gadgets/accel";
   private HtmlAccelServlet servlet;
-  private Renderer renderer;
 
   @Before
   public void setUp() throws Exception {
     servlet = new HtmlAccelServlet();
-    servlet.setRequestPipeline(pipeline);
-    servlet.setIframeUriManager(new FakeIframeUriManager());
-    renderer = mock(Renderer.class);
-    servlet.setRenderer(renderer);
+    AccelUriManager accelUriManager = new AccelUriManager(
+        new FakeContainerConfig(), null);
+
+    rewriter = new FakeCaptureRewriter();
+    rewriterRegistry = new DefaultResponseRewriterRegistry(
+        Arrays.<ResponseRewriter>asList(rewriter), null);
+    servlet.setHandler(new AccelHandler(pipeline, rewriterRegistry,
+                                        accelUriManager));
   }
 
   @Test
   public void testHtmlAccelNoData() throws Exception {
     String url = "http://example.org/data.html";
-    
+
     HttpRequest req = new HttpRequest(Uri.parse(url));
     expect(pipeline.execute(req)).andReturn(null).once();
     expectRequest("", url);
     replay();
-    
+
     servlet.doGet(request, recorder);
     verify();
     assertEquals("Error fetching data", recorder.getResponseAsString());
@@ -75,7 +99,7 @@ public class HtmlAccelServletTest extend
   public void testHtmlAccelNoHtml() throws Exception {
     String url = "http://example.org/data.xml";
     String data = "<html><body>Hello World</body></html>";
-    
+
     HttpRequest req = new HttpRequest(Uri.parse(url));
     HttpResponse resp = new HttpResponseBuilder()
         .setResponse(data.getBytes())
@@ -85,7 +109,7 @@ public class HtmlAccelServletTest extend
     expect(pipeline.execute(req)).andReturn(resp).once();
     expectRequest("", url);
     replay();
-    
+
     servlet.doGet(request, recorder);
     verify();
     assertEquals(data, recorder.getResponseAsString());
@@ -95,7 +119,8 @@ public class HtmlAccelServletTest extend
   public void testHtmlAccelRewriteSimple() throws Exception {
     String url = "http://example.org/data.html";
     String data = "<html><body>Hello World</body></html>";
-    
+
+    ((FakeCaptureRewriter) rewriter).setContentToRewrite(REWRITE_CONTENT);
     HttpRequest req = new HttpRequest(Uri.parse(url));
     HttpResponse resp = new HttpResponseBuilder()
         .setResponse(data.getBytes())
@@ -104,78 +129,21 @@ public class HtmlAccelServletTest extend
         .create();
     expect(pipeline.execute(req)).andReturn(resp).once();
     expectRequest("", url);
-    expect(renderer.render(isA(GadgetContext.class)))
-        .andReturn(RenderingResults.ok(REWRITE_CONTENT));
     replay();
-    
-    servlet.doGet(request, recorder);
-    verify();
-    assertEquals(REWRITE_CONTENT, recorder.getResponseAsString());
-    assertEquals(200, recorder.getHttpStatusCode());
-  }
 
-  @Test
-  public void testHtmlAccelRewriteChain() throws Exception {
-    String url = "http://example.org/data.html?id=1";
-    String data = "<html><body>Hello World</body></html>";
-    
-    Capture<HttpRequest> reqCapture = new Capture<HttpRequest>();
-    HttpResponse resp = new HttpResponseBuilder()
-        .setResponse(data.getBytes())
-        .setHeader("Content-Type", "text/html")
-        .setCacheTtl(567)
-        .setHttpStatusCode(200)
-        .create();
-    expect(pipeline.execute(capture(reqCapture))).andReturn(resp).once();
-    expectRequest("//" + url, null);
-    expect(renderer.render(isA(GadgetContext.class)))
-        .andReturn(RenderingResults.ok(REWRITE_CONTENT));
-    replay();
-    
     servlet.doGet(request, recorder);
     verify();
-    HttpRequest req = reqCapture.getValue();
-    assertEquals(url, req.getUri().toString());
-    assertEquals("accel", req.getContainer());
     assertEquals(REWRITE_CONTENT, recorder.getResponseAsString());
     assertEquals(200, recorder.getHttpStatusCode());
-    assertTrue(recorder.getHeader("Cache-Control").equals("private,max-age=566") 
-        || recorder.getHeader("Cache-Control").equals("private,max-age=567"));
-    // Note: due to rounding (MS to S conversion), ttl is down by 1
-  }
-
-  @Test
-  public void testHtmlAccelRewriteChainParams() throws Exception {
-    String url = "http://example.org/data.html?id=1";
-    String data = "<html><body>Hello World</body></html>";
-    
-    HttpResponse resp = new HttpResponseBuilder()
-        .setResponse(data.getBytes())
-        .setHeader("Content-Type", "text/html")
-        .setHttpStatusCode(200)
-        .create();
-    Capture<HttpRequest> reqCapture = new Capture<HttpRequest>();
-    expect(pipeline.execute(capture(reqCapture))).andReturn(resp).once();
-    expectRequest("/container=open&refresh=3600/" + url, null);
-    expect(renderer.render(isA(GadgetContext.class)))
-        .andReturn(RenderingResults.ok(REWRITE_CONTENT));
-    replay();
-    
-    servlet.doGet(request, recorder);
-    verify();
-    HttpRequest req = reqCapture.getValue();
-    assertEquals(url, req.getUri().toString());
-    assertEquals("open", req.getContainer());
-    assertEquals(REWRITE_CONTENT, recorder.getResponseAsString());
-    assertEquals(200, recorder.getHttpStatusCode());
-    assertEquals("private,max-age=3600", recorder.getHeader("Cache-Control"));
+    assertTrue(rewriter.responseWasRewritten());
   }
 
   @Test
   public void testHtmlAccelRewriteErrorCode() throws Exception {
     String url = "http://example.org/data.html";
     String data = "<html><body>This is error page</body></html>";
-    
+
+    ((FakeCaptureRewriter) rewriter).setContentToRewrite(REWRITE_CONTENT);
     HttpRequest req = new HttpRequest(Uri.parse(url));
     HttpResponse resp = new HttpResponseBuilder()
         .setResponse(data.getBytes())
@@ -184,21 +152,21 @@ public class HtmlAccelServletTest extend
         .create();
     expect(pipeline.execute(req)).andReturn(resp).once();
     expectRequest("", url);
-    expect(renderer.render(isA(GadgetContext.class)))
-        .andReturn(RenderingResults.ok(REWRITE_CONTENT));
     replay();
-    
+
     servlet.doGet(request, recorder);
     verify();
-    assertEquals(REWRITE_CONTENT, recorder.getResponseAsString());
+    assertEquals(AccelHandler.ERROR_FETCHING_DATA, recorder.getResponseAsString());
     assertEquals(404, recorder.getHttpStatusCode());
+    assertFalse(rewriter.responseWasRewritten());
   }
 
   @Test
   public void testHtmlAccelRewriteInternalError() throws Exception {
     String url = "http://example.org/data.html";
     String data = "<html><body>This is error page</body></html>";
-    
+
+    ((FakeCaptureRewriter) rewriter).setContentToRewrite(data);
     HttpRequest req = new HttpRequest(Uri.parse(url));
     HttpResponse resp = new HttpResponseBuilder()
         .setResponse(data.getBytes())
@@ -207,69 +175,25 @@ public class HtmlAccelServletTest extend
         .create();
     expect(pipeline.execute(req)).andReturn(resp).once();
     expectRequest("", url);
-    expect(renderer.render(isA(GadgetContext.class)))
-        .andReturn(RenderingResults.ok(REWRITE_CONTENT));
     replay();
-    
-    servlet.doGet(request, recorder);
-    verify();
-    assertEquals(REWRITE_CONTENT, recorder.getResponseAsString());
-    assertEquals(502, recorder.getHttpStatusCode());
-  }
-
-  @Test
-  public void testHtmlAccelParams() throws Exception {
 
-    Renderer newRenderer = new Renderer(null, null, null, lockedDomainService) {
-      @Override
-      public RenderingResults render(GadgetContext context) {
-        assertTrue(HtmlAccelServlet.isAccel(context));
-        assertEquals("accel", context.getParameter("container"));
-        return RenderingResults.ok(REWRITE_CONTENT);
-      }
-    };
-    servlet.setRenderer(newRenderer);
-    Map<String,String> paramMap = Maps.newHashMap();
-    paramMap.put("container","accel");
-    servlet.setAddedServletParams(paramMap);
-    
-    String url = "http://example.org/data.html";
-    
-    HttpRequest req = new HttpRequest(Uri.parse(url));
-    HttpResponse resp = new HttpResponseBuilder()
-        .setHeader("Content-Type", "text/html")
-        .setHttpStatusCode(200)
-        .create();
-    expect(pipeline.execute(req)).andReturn(resp).once();
-    expectRequest("", url);
-    replay();
-   
     servlet.doGet(request, recorder);
     verify();
+    assertEquals(AccelHandler.ERROR_FETCHING_DATA, recorder.getResponseAsString());
+    assertEquals(502, recorder.getHttpStatusCode());
+    assertFalse(rewriter.responseWasRewritten());
   }
 
   private void expectRequest(String extraPath, String url) {
     expect(request.getServletPath()).andReturn(SERVLET).anyTimes();
     expect(request.getScheme()).andReturn("http").anyTimes();
     expect(request.getServerName()).andReturn("apache.org").anyTimes();
-    expect(request.getServerPort()).andReturn(-1).anyTimes();    
-    expect(request.getRequestURI()).andReturn(SERVLET + extraPath).anyTimes();    
+    expect(request.getServerPort()).andReturn(-1).anyTimes();
+    expect(request.getRequestURI()).andReturn(SERVLET + extraPath).anyTimes();
     expect(request.getRequestURL())
         .andReturn(new StringBuffer("apache.org" + SERVLET + extraPath))
         .anyTimes();
-    String queryParams = (url == null ? "" : "url=" + url);
+    String queryParams = (url == null ? "" : "url=" + url + "&container=accel");
     expect(request.getQueryString()).andReturn(queryParams).anyTimes();
   }
-
-  private static class FakeIframeUriManager implements IframeUriManager {
-    public UriStatus validateRenderingUri(Uri uri) {
-      return UriStatus.VALID_UNVERSIONED;
-    }
-
-    public Uri makeRenderingUri(Gadget gadget) {
-      throw new UnsupportedOperationException();
-    }
-  }
-
-
 }

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java?rev=954649&r1=954648&r2=954649&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java Mon Jun 14 21:18:20 2010
@@ -40,8 +40,8 @@ import javax.servlet.http.HttpServletRes
  */
 public abstract class ServletTestFixture extends EasyMockTestCase {
   public final RequestPipeline pipeline = mock(RequestPipeline.class);
-  public final CaptureRewriter rewriter = new CaptureRewriter();
-  public final ResponseRewriterRegistry rewriterRegistry
+  public CaptureRewriter rewriter = new CaptureRewriter();
+  public ResponseRewriterRegistry rewriterRegistry
       = new DefaultResponseRewriterRegistry(Arrays.<ResponseRewriter>asList(rewriter), null);
   public final HttpServletRequest request = mock(HttpServletRequest.class);
   public final HttpServletResponse response = mock(HttpServletResponse.class);

Added: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/AccelUriManagerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/AccelUriManagerTest.java?rev=954649&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/AccelUriManagerTest.java (added)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/AccelUriManagerTest.java Mon Jun 14 21:18:20 2010
@@ -0,0 +1,41 @@
+/*
+ * 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.uri;
+
+import org.apache.shindig.config.ContainerConfig;
+import static org.junit.Assert.assertTrue;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test fot AccelUriManager.
+ */
+public class AccelUriManagerTest {
+  AccelUriManager uriManager;
+  ContainerConfig config;
+
+  @Before
+  public void setUp() {
+    uriManager = new AccelUriManager(config, null);
+  }
+
+  @Test
+  public void testHttpBadPort() throws Exception {
+    assertTrue(true);
+  }
+}

Modified: shindig/trunk/pom.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/pom.xml?rev=954649&r1=954648&r2=954649&view=diff
==============================================================================
--- shindig/trunk/pom.xml (original)
+++ shindig/trunk/pom.xml Mon Jun 14 21:18:20 2010
@@ -1270,6 +1270,11 @@
       <id>java.net</id>
       <url>http://download.java.net/maven/2/</url>
     </repository>
+    <repository>
+      <id>mortbay-release-repo</id>
+      <name>MortBay Release Repo</name>
+      <url>http://jetty.mortbay.org/maven2/release</url>
+    </repository>
   </repositories>
 
   <!-- ====================================================================== -->