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>
<!-- ====================================================================== -->