Author: zhoresh
Date: Thu Nov 4 00:30:42 2010
New Revision: 1030777
URL: http://svn.apache.org/viewvc?rev=1030777&view=rev
Log:
Ref http://codereview.appspot.com/2851041/
Add proxy request to GadgetHandler
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java?rev=1030777&r1=1030776&r2=1030777&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java
Thu Nov 4 00:30:42 2010
@@ -46,6 +46,7 @@ import java.util.concurrent.CompletionSe
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
+import java.util.logging.Logger;
import javax.servlet.http.HttpServletResponse;
@@ -60,12 +61,18 @@ public class GadgetsHandler {
static final String FAILURE_METADATA = "Failed to get gadget metadata.";
@VisibleForTesting
static final String FAILURE_TOKEN = "Failed to get gadget token.";
+ @VisibleForTesting
+ static final String FAILURE_PROXY = "Failed to get proxy data.";
private static final List<String> DEFAULT_METADATA_FIELDS =
ImmutableList.of("iframeUrl", "userPrefs.*", "modulePrefs.*", "views.*");
private static final List<String> DEFAULT_TOKEN_FIELDS =
ImmutableList.of("token");
+ private static final List<String> DEFAULT_PROXY_FIELDS =
ImmutableList.of("proxyUrl");
+
+ private static final Logger LOG =
Logger.getLogger(GadgetsHandler.class.getName());
+
protected final ExecutorService executor;
protected final GadgetsHandlerService handlerService;
@@ -106,6 +113,18 @@ public class GadgetsHandler {
}.execute(request);
}
+ @Operation(httpMethods = {"POST", "GET"}, path = "proxy.get")
+ public Map<String, GadgetsHandlerApi.BaseResponse> proxy(BaseRequestItem
request)
+ throws ProtocolException {
+ return new AbstractExecutor() {
+ @Override
+ protected Callable<CallableData> createJob(String url, BaseRequestItem
request)
+ throws ProcessingException {
+ return createProxyJob(url, request);
+ }
+ }.execute(request);
+ }
+
@Operation(httpMethods = "GET", path = "/@metadata.supportedFields")
public Set<String> supportedFields(RequestItem request) {
return ImmutableSet.copyOf(beanFilter
@@ -118,6 +137,12 @@ public class GadgetsHandler {
beanFilter.getBeanFields(GadgetsHandlerApi.TokenResponse.class, 5));
}
+ @Operation(httpMethods = "GET", path = "/@proxy.supportedFields")
+ public Set<String> proxySupportedFields(RequestItem request) {
+ return ImmutableSet.copyOf(
+ beanFilter.getBeanFields(GadgetsHandlerApi.ProxyResponse.class, 5));
+ }
+
/**
* Class to handle threaded reply.
* Mainly it made to support filtering the id (url)
@@ -214,6 +239,23 @@ public class GadgetsHandler {
};
}
+ // Hook to override in sub-class.
+ protected Callable<CallableData> createProxyJob(final String url,
+ BaseRequestItem request) throws ProcessingException {
+ final ProxyRequestData proxyRequest = new ProxyRequestData(url, request);
+ return new Callable<CallableData>() {
+ public CallableData call() throws Exception {
+ try {
+ return new CallableData(url, handlerService.getProxy(proxyRequest));
+ } catch (Exception e) {
+ return new CallableData(url,
+ handlerService.createErrorResponse(null, e, FAILURE_PROXY));
+ }
+ }
+ };
+ }
+
+
/**
* Gadget context classes used to translate JSON BaseRequestItem into a more
* meaningful model objects that Java can work with.
@@ -236,6 +278,29 @@ public class GadgetsHandler {
this.fields = processFields(request, defaultFields);
}
+ protected Boolean getBooleanParam(BaseRequestItem request, String field) {
+ String val = request.getParameter(field);
+ if (val != null) {
+ return "1".equals(val) || Boolean.valueOf(val);
+ }
+ return false;
+ }
+
+ protected Integer getIntegerParam(BaseRequestItem request, String field)
+ throws ProcessingException {
+ String val = request.getParameter(field);
+ Integer intVal = null;
+ if (val != null) {
+ try {
+ intVal = Integer.valueOf(val);
+ } catch (NumberFormatException e) {
+ throw new ProcessingException("Error parsing " + field + "
parameter",
+ HttpServletResponse.SC_BAD_REQUEST);
+ }
+ }
+ return intVal;
+ }
+
public Uri getUrl() {
return uri;
}
@@ -254,6 +319,87 @@ public class GadgetsHandler {
}
}
+ protected class ProxyRequestData extends AbstractRequest
+ implements GadgetsHandlerApi.ProxyRequest {
+
+ private final String gadget;
+ private final Integer refresh;
+ private final boolean debug;
+ private final boolean ignoreCache;
+ private final String fallbackUrl;
+ private final String mimetype;
+ private final boolean sanitize;
+ private final boolean cajole;
+ private final GadgetsHandlerApi.ImageParams imageParams;
+
+ public ProxyRequestData(String url, BaseRequestItem request) throws
ProcessingException {
+ super(url, request, DEFAULT_PROXY_FIELDS);
+ this.ignoreCache = getBooleanParam(request, "ignoreCache");
+ this.debug = getBooleanParam(request, "debug");
+ this.sanitize = getBooleanParam(request, "sanitize");
+ this.cajole = getBooleanParam(request, "cajole");
+ this.gadget = request.getParameter("gadget");
+ this.fallbackUrl = request.getParameter("fallback_url");
+ this.mimetype = request.getParameter("rewriteMime");
+ this.refresh = getIntegerParam(request, "refresh");
+ imageParams = getImageParams(request);
+ }
+
+ private GadgetsHandlerApi.ImageParams getImageParams(BaseRequestItem
request)
+ throws ProcessingException {
+ GadgetsHandlerApi.ImageParams params = null;
+ Boolean doNotExpand = getBooleanParam(request, "no_expand");
+ Integer height = getIntegerParam(request, "resize_h");
+ Integer width = getIntegerParam(request, "resize_w");
+ Integer quality = getIntegerParam(request, "resize_q");
+
+ if (height != null || width != null) {
+ return beanDelegator.createDelegator(null,
GadgetsHandlerApi.ImageParams.class,
+ ImmutableMap.<String, Object>of(
+ "height", BeanDelegator.nullable(height),
+ "width", BeanDelegator.nullable(width),
+ "quality", BeanDelegator.nullable(quality),
+ "donotexpand", BeanDelegator.nullable(doNotExpand)));
+ }
+ return params;
+ }
+
+ public boolean getDebug() {
+ return debug;
+ }
+
+ public String getFallbackUrl() {
+ return fallbackUrl;
+ }
+
+ public boolean getIgnoreCahce() {
+ return ignoreCache;
+ }
+
+ public GadgetsHandlerApi.ImageParams getImageParams() {
+ return imageParams;
+ }
+
+ public Integer getRefresh() {
+ return refresh;
+ }
+
+ public String getRewriteMimeType() {
+ return mimetype;
+ }
+
+ public boolean getSanitize() {
+ return sanitize;
+ }
+
+ public boolean getCajole() {
+ return cajole;
+ }
+
+ public String getGadget() {
+ return gadget;
+ }
+ }
protected class TokenRequestData extends AbstractRequest
implements GadgetsHandlerApi.TokenRequest {
@@ -284,8 +430,8 @@ public class GadgetsHandler {
this.locale =
(lang != null && country != null) ? new Locale(lang, country) :
(lang != null)
? new Locale(lang) : GadgetSpec.DEFAULT_LOCALE;
- this.ignoreCache = Boolean.valueOf(request.getParameter("ignoreCache"));
- this.debug = Boolean.valueOf(request.getParameter("debug"));
+ this.ignoreCache = getBooleanParam(request, "ignoreCache");
+ this.debug = getBooleanParam(request, "debug");
}
public int getModuleId() {
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java?rev=1030777&r1=1030776&r2=1030777&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java
Thu Nov 4 00:30:42 2010
@@ -54,8 +54,10 @@ public class GadgetsHandlerApi {
@Unfiltered
public Error getError();
/** The response expiration time (miliseconds since epoch), -1 for no
caching */
+ @Unfiltered
public Long getExpireTimeMs();
/** The response time (miliseconds since epoch) - usefull for
misconfigured client time */
+ @Unfiltered
public Long getResponseTimeMs();
}
@@ -100,10 +102,8 @@ public class GadgetsHandlerApi {
public Uri getHref();
public boolean getQuirks();
public String getContent();
- public int getPreferredHeight();
- public int getPreferredWidth();
- public boolean needsUserPrefSubstitution();
- public Map<String, String> getAttributes();
+ public int getPreferredHeight(); // Default to 0
+ public int getPreferredWidth(); // Default to 0
}
public enum UserPrefDataType {
@@ -116,7 +116,6 @@ public class GadgetsHandlerApi {
public String getDefaultValue();
public boolean getRequired();
public UserPrefDataType getDataType();
- public Map<String, String> getEnumValues();
public List<EnumValuePair> getOrderedEnumValues();
}
@@ -172,4 +171,50 @@ public class GadgetsHandlerApi {
public interface TokenResponse extends BaseResponse {
public String getToken();
}
+
+ public interface ProxyRequest extends BaseRequest {
+ // The BaseRequest.url store the resource to proxy
+ public String getGadget();
+ public Integer getRefresh();
+ public boolean getDebug();
+ public boolean getIgnoreCahce();
+ public String getFallbackUrl();
+ public String getRewriteMimeType();
+ public boolean getSanitize();
+ public boolean getCajole();
+ public ImageParams getImageParams();
+ }
+
+ public interface ImageParams {
+ public Integer getHeight();
+ public Integer getWidth();
+ public Integer getQuality();
+ public Boolean getDoNotExpand();
+ }
+
+ public interface ProxyResponse extends BaseResponse {
+ public Uri getProxyUrl();
+ public HttpResponse getProxyContent();
+ }
+
+ public interface HttpResponse {
+ public int getCode();
+ public String getEncoding();
+ public String getContentBase64();
+ public List<NameValuePair> getHeaders();
+ }
+
+ public interface NameValuePair {
+ public String getName();
+ public String getValue();
+ }
+
+ public interface JsRequest extends BaseRequest {
+ public List<String> getFeatures();
+ public boolean getForContainer();
+ }
+
+ public interface JsResponse extends BaseResponse {
+ public Uri getJsUrl();
+ }
}
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java?rev=1030777&r1=1030776&r2=1030777&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
Thu Nov 4 00:30:42 2010
@@ -19,10 +19,13 @@
package org.apache.shindig.gadgets.servlet;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import com.google.inject.name.Named;
+import org.apache.commons.codec.binary.Base64InputStream;
+import org.apache.commons.io.IOUtils;
import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.auth.SecurityTokenCodec;
import org.apache.shindig.auth.SecurityTokenException;
@@ -30,6 +33,7 @@ import org.apache.shindig.common.uri.Uri
import org.apache.shindig.common.util.TimeSource;
import org.apache.shindig.gadgets.Gadget;
import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.RenderingContext;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.process.ProcessingException;
@@ -42,12 +46,19 @@ import org.apache.shindig.gadgets.spec.U
import org.apache.shindig.gadgets.spec.View;
import org.apache.shindig.gadgets.spec.UserPref.EnumValuePair;
import org.apache.shindig.gadgets.uri.IframeUriManager;
+import org.apache.shindig.gadgets.uri.JsUriManager;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+import org.apache.shindig.gadgets.uri.ProxyUriManager.ProxyUri;
import org.apache.shindig.protocol.conversion.BeanDelegator;
import org.apache.shindig.protocol.conversion.BeanFilter;
+import java.io.IOException;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.servlet.http.HttpServletResponse;
@@ -60,6 +71,8 @@ public class GadgetsHandlerService {
private static final Locale DEFAULT_LOCALE = new Locale("all", "all");
+ private static final Logger LOG =
Logger.getLogger(GadgetsHandler.class.getName());
+
// Map shindig data class to API interfaces
@VisibleForTesting
static final Map<Class<?>, Class<?>> apiClasses =
@@ -91,6 +104,9 @@ public class GadgetsHandlerService {
protected final Processor processor;
protected final IframeUriManager iframeUriManager;
protected final SecurityTokenCodec securityTokenCodec;
+ protected final ProxyUriManager proxyUriManager;
+ protected final JsUriManager jsUriManager;
+ protected final ProxyHandler proxyHandler;
protected final BeanDelegator beanDelegator;
protected final long specRefreshInterval;
protected final BeanFilter beanFilter;
@@ -98,12 +114,16 @@ public class GadgetsHandlerService {
@Inject
public GadgetsHandlerService(TimeSource timeSource, Processor processor,
IframeUriManager iframeUriManager, SecurityTokenCodec securityTokenCodec,
+ ProxyUriManager proxyUriManager, JsUriManager jsUriManager, ProxyHandler
proxyHandler,
@Named("shindig.cache.xml.refreshInterval") long specRefreshInterval,
BeanFilter beanFilter) {
this.timeSource = timeSource;
this.processor = processor;
this.iframeUriManager = iframeUriManager;
this.securityTokenCodec = securityTokenCodec;
+ this.proxyUriManager = proxyUriManager;
+ this.jsUriManager = jsUriManager;
+ this.proxyHandler = proxyHandler;
this.specRefreshInterval = specRefreshInterval;
this.beanFilter = beanFilter;
@@ -170,6 +190,57 @@ public class GadgetsHandlerService {
return createTokenResponse(request.getUrl(), token, fields, expiryTimeMs);
}
+ public GadgetsHandlerApi.ProxyResponse
getProxy(GadgetsHandlerApi.ProxyRequest request)
+ throws ProcessingException {
+ if (request.getContainer() == null) {
+ throw new ProcessingException("Missing container paramater",
HttpResponse.SC_BAD_REQUEST);
+ }
+ if (request.getUrl() == null) {
+ throw new ProcessingException("Missing proxy url paramater",
HttpResponse.SC_BAD_REQUEST);
+ }
+ if (request.getFields() == null) {
+ throw new ProcessingException("Missing fields paramater",
HttpResponse.SC_BAD_REQUEST);
+ }
+ Set<String> fields = beanFilter.processBeanFields(request.getFields());
+
+ ProxyUri proxyUri = createProxyUri(request);
+ List<Uri> uris = proxyUriManager.make(ImmutableList.of(proxyUri), null);
+
+ HttpResponse httpResponse = null;
+ try {
+ if (isFieldIncluded(fields, "proxyContent")) {
+ httpResponse = proxyHandler.fetch(proxyUri);
+ }
+ } catch (IOException e) {
+ LOG.log(Level.INFO, "Failed to fetch resource " +
proxyUri.getResource().toString(), e);
+ throw new ProcessingException("Error getting response content",
HttpResponse.SC_BAD_GATEWAY);
+ } catch (GadgetException e) {
+ // TODO: Clean this log if it is too spammy
+ LOG.log(Level.INFO, "Failed to fetch resource " +
proxyUri.getResource().toString(), e);
+ throw new ProcessingException("Error getting response content",
HttpResponse.SC_BAD_GATEWAY);
+ }
+
+ try {
+ return createProxyResponse(uris.get(0), httpResponse, fields,
+ getProxyExpireMs(proxyUri, httpResponse));
+ } catch (IOException e) {
+ // Should never happen!
+ LOG.log(Level.WARNING, "Error creating proxy response", e);
+ throw new ProcessingException("Error getting response content",
+ HttpResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ protected Long getProxyExpireMs(ProxyUri proxyUri, HttpResponse
httpResponse) {
+ Long expireMs = null;
+ if (httpResponse != null) {
+ expireMs = httpResponse.getCacheExpiration();
+ } else if (proxyUri.getRefresh() != null) {
+ expireMs = timeSource.currentTimeMillis() + proxyUri.getRefresh() * 1000;
+ }
+ return expireMs;
+ }
+
/**
* GadgetContext for metadata request. Used by the gadget processor
*/
@@ -247,6 +318,7 @@ public class GadgetsHandlerService {
return createErrorResponse(uri, processingExc.getHttpStatusCode(),
processingExc.getMessage());
}
+ LOG.log(Level.WARNING, "Error handling request: " + (uri != null ?
uri.toString() : ""), e);
return createErrorResponse(uri,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR, defaultMsg);
}
@@ -289,4 +361,64 @@ public class GadgetsHandlerService {
"expiretimems", BeanDelegator.nullable(tokenExpire))),
fields);
}
+
+ @VisibleForTesting
+ ProxyUri createProxyUri(GadgetsHandlerApi.ProxyRequest request) {
+ ProxyUriManager.ProxyUri proxyUri = new
ProxyUriManager.ProxyUri(request.getRefresh(),
+ request.getDebug(), request.getIgnoreCahce(), request.getContainer(),
+ request.getGadget(), request.getUrl());
+
+ proxyUri.setFallbackUrl(request.getFallbackUrl())
+ .setRewriteMimeType(request.getRewriteMimeType())
+ .setSanitizeContent(request.getSanitize())
+ .setCajoleContent(request.getCajole());
+
+ GadgetsHandlerApi.ImageParams image = request.getImageParams();
+ if (image != null) {
+ proxyUri.setResize( image.getWidth(), image.getHeight(),
+ image.getQuality(), image.getDoNotExpand());
+ }
+ return proxyUri;
+ }
+
+ @VisibleForTesting
+ GadgetsHandlerApi.ProxyResponse createProxyResponse(Uri uri, HttpResponse
httpResponse,
+ Set<String> fields, Long expireMs) throws IOException {
+
+ GadgetsHandlerApi.HttpResponse beanHttp = null;
+ if (httpResponse != null) {
+ // Stream out the base64-encoded data.
+ // Ctor args indicate to encode w/o line breaks.
+ Base64InputStream b64input = new
Base64InputStream(httpResponse.getResponse(), true, 0, null);
+ String content = IOUtils.toString(b64input);
+
+ ImmutableList.Builder<GadgetsHandlerApi.NameValuePair> headersBuilder =
+ ImmutableList.builder();
+ for (final Map.Entry<String, String> entry :
httpResponse.getHeaders().entries()) {
+ headersBuilder.add(
+ beanDelegator.createDelegator(null,
GadgetsHandlerApi.NameValuePair.class,
+ ImmutableMap.<String, Object>of("name", entry.getKey(),
"value", entry.getValue()))
+ );
+ }
+
+ beanHttp = beanDelegator.createDelegator(null,
GadgetsHandlerApi.HttpResponse.class,
+ ImmutableMap.<String, Object>of(
+ "code", httpResponse.getHttpStatusCode(),
+ "encoding", httpResponse.getEncoding(),
+ "contentbase64", content,
+ "headers", headersBuilder.build()));
+ }
+
+ return (GadgetsHandlerApi.ProxyResponse) beanFilter.createFilteredBean(
+ beanDelegator.createDelegator(null,
GadgetsHandlerApi.ProxyResponse.class,
+ ImmutableMap.<String, Object>builder()
+ .put("proxyurl", uri)
+ .put("proxycontent", BeanDelegator.nullable(beanHttp))
+ .put("url", BeanDelegator.NULL)
+ .put("error", BeanDelegator.NULL)
+ .put("responsetimems", timeSource.currentTimeMillis())
+ .put("expiretimems", BeanDelegator.nullable(expireMs))
+ .build()),
+ fields);
+ }
}
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java?rev=1030777&r1=1030776&r2=1030777&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java
Thu Nov 4 00:30:42 2010
@@ -217,7 +217,9 @@ public class ProxyUriBase {
// Add all params common to both chained and query syntax.
String container = getContainer();
queryBuilder.addQueryParameter(Param.CONTAINER.getKey(), container);
- queryBuilder.addQueryParameter(Param.GADGET.getKey(), getGadget());
+ if (getGadget() != null) {
+ queryBuilder.addQueryParameter(Param.GADGET.getKey(), getGadget());
+ }
queryBuilder.addQueryParameter(Param.DEBUG.getKey(), isDebug() ? "1" :
"0");
queryBuilder.addQueryParameter(Param.NO_CACHE.getKey(), isNoCache() ? "1"
: "0");
if (!isNoCache()) {
Modified:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java?rev=1030777&r1=1030776&r2=1030777&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java
(original)
+++
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java
Thu Nov 4 00:30:42 2010
@@ -18,23 +18,37 @@
*/
package org.apache.shindig.gadgets.servlet;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.capture;
+
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
+import org.apache.commons.codec.binary.Base64;
import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.auth.SecurityTokenCodec;
import org.apache.shindig.auth.SecurityTokenException;
import org.apache.shindig.common.EasyMockTestCase;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.common.util.FakeTimeSource;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.GadgetException.Code;
import org.apache.shindig.gadgets.features.FeatureRegistry;
+import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.http.HttpResponseBuilder;
import org.apache.shindig.gadgets.process.ProcessingException;
+import org.apache.shindig.gadgets.uri.JsUriManager;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+import org.apache.shindig.gadgets.uri.ProxyUriManager.ProxyUri;
import org.apache.shindig.protocol.conversion.BeanDelegator;
import org.apache.shindig.protocol.conversion.BeanFilter;
+import org.easymock.Capture;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
+import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
@@ -48,6 +62,8 @@ public class GadgetsHandlerServiceTest e
private static final Long SPEC_REFRESH_INTERVAL_MS = 456L;
private static final Long METADATA_EXPIRY_TIME_MS = CURRENT_TIME_MS +
SPEC_REFRESH_INTERVAL_MS;
private static final Long TOKEN_EXPIRY_TIME_MS = CURRENT_TIME_MS + 789L;
+ private static final Uri RESOURCE = Uri.parse("http://example.com/data");
+ private static final String FALLBACK = "http://example.com/data2";
private final BeanDelegator delegator = new BeanDelegator(
GadgetsHandlerService.apiClasses, GadgetsHandlerService.enumConversionMap);
@@ -56,6 +72,9 @@ public class GadgetsHandlerServiceTest e
private final FeatureRegistry mockRegistry = mock(FeatureRegistry.class);
private final FakeProcessor processor = new FakeProcessor(mockRegistry);
private final FakeIframeUriManager urlGenerator = new FakeIframeUriManager();
+ private final ProxyUriManager proxyUriManager = mock(ProxyUriManager.class);
+ private final JsUriManager jsUriManager = mock(JsUriManager.class);
+ private final ProxyHandler proxyHandler = mock(ProxyHandler.class);
private FakeSecurityTokenCodec tokenCodec;
private GadgetsHandlerService gadgetHandler;
@@ -64,7 +83,8 @@ public class GadgetsHandlerServiceTest e
public void setUp() {
tokenCodec = new FakeSecurityTokenCodec();
gadgetHandler = new GadgetsHandlerService(timeSource, processor,
urlGenerator,
- tokenCodec, SPEC_REFRESH_INTERVAL_MS, new BeanFilter());
+ tokenCodec, proxyUriManager, jsUriManager, proxyHandler,
+ SPEC_REFRESH_INTERVAL_MS, new BeanFilter());
}
// Next test verify that the API data classes are configured correctly.
@@ -98,7 +118,7 @@ public class GadgetsHandlerServiceTest e
response.getModulePrefs().getLinks().get(FakeProcessor.LINK_REL).getRel());
assertEquals(1, response.getUserPrefs().size());
assertEquals("up_one",
response.getUserPrefs().get("up_one").getDisplayName());
- assertEquals(4,
response.getUserPrefs().get("up_one").getEnumValues().size());
+ assertEquals(4,
response.getUserPrefs().get("up_one").getOrderedEnumValues().size());
assertEquals(CURRENT_TIME_MS, response.getResponseTimeMs());
assertEquals(METADATA_EXPIRY_TIME_MS, response.getExpireTimeMs());
verify();
@@ -239,6 +259,150 @@ public class GadgetsHandlerServiceTest e
verify();
}
+ @Test
+ public void testCreateProxyUri() throws Exception {
+ GadgetsHandlerApi.ImageParams image =
mock(GadgetsHandlerApi.ImageParams.class);
+ expect(image.getDoNotExpand()).andStubReturn(true);
+ expect(image.getHeight()).andStubReturn(120);
+ expect(image.getWidth()).andStubReturn(210);
+ expect(image.getQuality()).andStubReturn(77);
+
+ GadgetsHandlerApi.ProxyRequest request =
mock(GadgetsHandlerApi.ProxyRequest.class);
+ expect(request.getContainer()).andStubReturn(CONTAINER);
+ expect(request.getUrl()).andStubReturn(RESOURCE);
+ expect(request.getCajole()).andStubReturn(true);
+ expect(request.getRefresh()).andStubReturn(new Integer(333));
+ expect(request.getDebug()).andStubReturn(true);
+ expect(request.getFallbackUrl()).andStubReturn(FALLBACK);
+
expect(request.getGadget()).andStubReturn(FakeProcessor.SPEC_URL.toString());
+ expect(request.getIgnoreCahce()).andStubReturn(true);
+ expect(request.getImageParams()).andStubReturn(image);
+ expect(request.getRewriteMimeType()).andStubReturn("image/png");
+ expect(request.getSanitize()).andStubReturn(true);
+ replay();
+ ProxyUri pUri = gadgetHandler.createProxyUri(request);
+
+ ProxyUri expectedUri = new ProxyUri(333, true, true, CONTAINER,
+ FakeProcessor.SPEC_URL.toString(), RESOURCE);
+
expectedUri.setCajoleContent(true).setRewriteMimeType("image/png").setSanitizeContent(true);
+ expectedUri.setResize(210, 120, 77, true).setFallbackUrl(FALLBACK);
+ assertEquals(pUri, expectedUri);
+ verify();
+ }
+
+ @Test
+ public void testValidateProxyResponse() throws Exception {
+ GadgetsHandlerApi.ProxyResponse response =
+ gadgetHandler.createProxyResponse(RESOURCE, null,
ImmutableSet.<String>of("*"), 1000001L);
+
+ BeanDelegator.validateDelegator(response);
+ assertEquals(RESOURCE, response.getProxyUrl());
+ assertNull(response.getProxyContent());
+ }
+
+ @Test
+ public void testCreateProxyResponse() throws Exception {
+ HttpResponseBuilder httpResponse = new HttpResponseBuilder();
+ httpResponse.setContent("Content");
+ httpResponse.addHeader("header", "hval");
+ httpResponse.setEncoding(Charset.forName("UTF8"));
+ httpResponse.setHttpStatusCode(404);
+
+ GadgetsHandlerApi.ProxyResponse response =
gadgetHandler.createProxyResponse(
+ RESOURCE, httpResponse.create(), ImmutableSet.<String>of("*"),
1000001L);
+ BeanDelegator.validateDelegator(response);
+ assertEquals("Content",
+ new
String(Base64.decodeBase64(response.getProxyContent().getContentBase64())));
+ assertEquals(404, response.getProxyContent().getCode());
+ assertEquals(2, response.getProxyContent().getHeaders().size());
+ assertEquals("Date",
response.getProxyContent().getHeaders().get(0).getName());
+ assertEquals("header",
response.getProxyContent().getHeaders().get(1).getName());
+ assertEquals("hval",
response.getProxyContent().getHeaders().get(1).getValue());
+ }
+
+ @Test
+ public void testFilterProxyResponse() throws Exception {
+ HttpResponse httpResponse = new HttpResponse("data");
+ GadgetsHandlerApi.ProxyResponse response =
gadgetHandler.createProxyResponse(
+ RESOURCE, httpResponse, ImmutableSet.<String>of("proxyurl"), 1000001L);
+ assertNull(response.getProxyContent());
+ assertEquals(RESOURCE, response.getProxyUrl());
+ }
+
+ @Test
+ public void testGetProxySimple() throws Exception {
+ List<String> fields = ImmutableList.of("proxyurl");
+ Uri resUri = Uri.parse("server.com/gadgets/proxy?url=" + RESOURCE);
+ GadgetsHandlerApi.ProxyRequest request = createProxyRequest(RESOURCE,
CONTAINER, fields);
+ Capture<List<ProxyUri>> uriCapture = new Capture<List<ProxyUri>>();
+ expect(proxyUriManager.make(capture(uriCapture), EasyMock.anyInt()))
+ .andReturn(ImmutableList.of(resUri));
+ replay();
+ GadgetsHandlerApi.ProxyResponse response = gadgetHandler.getProxy(request);
+ assertEquals(1, uriCapture.getValue().size());
+ ProxyUri pUri = uriCapture.getValue().get(0);
+ assertEquals(CONTAINER, pUri.getContainer());
+ assertEquals(resUri, response.getProxyUrl());
+ assertNull(response.getProxyContent());
+ verify();
+ }
+
+ @Test(expected = ProcessingException.class)
+ public void testGetProxyNoContainer() throws Exception {
+ List<String> fields = ImmutableList.of("*");
+ GadgetsHandlerApi.ProxyRequest request = createProxyRequest(RESOURCE,
null, fields);
+ GadgetsHandlerApi.ProxyResponse response = gadgetHandler.getProxy(request);
+ }
+
+ @Test(expected = ProcessingException.class)
+ public void testGetProxyNoResource() throws Exception {
+ List<String> fields = ImmutableList.of("*");
+ GadgetsHandlerApi.ProxyRequest request = createProxyRequest(null,
CONTAINER, fields);
+ GadgetsHandlerApi.ProxyResponse response = gadgetHandler.getProxy(request);
+ }
+
+ @Test(expected = ProcessingException.class)
+ public void testGetProxyNoFields() throws Exception {
+ GadgetsHandlerApi.ProxyRequest request = createProxyRequest(RESOURCE,
CONTAINER, null);
+ GadgetsHandlerApi.ProxyResponse response = gadgetHandler.getProxy(request);
+ }
+
+ @Test
+ public void testGetProxyData() throws Exception {
+ List<String> fields = ImmutableList.of("proxycontent.*");
+ Uri resUri = Uri.parse("server.com/gadgets/proxy?url=" + RESOURCE);
+ GadgetsHandlerApi.ProxyRequest request = createProxyRequest(RESOURCE,
CONTAINER, fields);
+ Capture<List<ProxyUri>> uriCapture = new Capture<List<ProxyUri>>();
+ expect(proxyUriManager.make(capture(uriCapture), EasyMock.anyInt()))
+ .andReturn(ImmutableList.of(resUri));
+ HttpResponse httpResponse = new HttpResponse("response");
+
expect(proxyHandler.fetch(EasyMock.isA(ProxyUri.class))).andReturn(httpResponse);
+ replay();
+ GadgetsHandlerApi.ProxyResponse response = gadgetHandler.getProxy(request);
+ assertEquals(1, uriCapture.getValue().size());
+ ProxyUri pUri = uriCapture.getValue().get(0);
+ assertEquals(CONTAINER, pUri.getContainer());
+ assertNull(response.getProxyUrl());
+ assertEquals("response",
+ new
String(Base64.decodeBase64(response.getProxyContent().getContentBase64())));
+ verify();
+ }
+
+ @Test(expected = ProcessingException.class)
+ public void testGetProxyDataFail() throws Exception {
+ List<String> fields = ImmutableList.of("proxycontent.*");
+ Uri resUri = Uri.parse("server.com/gadgets/proxy?url=" + RESOURCE);
+ GadgetsHandlerApi.ProxyRequest request = createProxyRequest(RESOURCE,
CONTAINER, fields);
+ Capture<List<ProxyUri>> uriCapture = new Capture<List<ProxyUri>>();
+ expect(proxyUriManager.make(capture(uriCapture), EasyMock.anyInt()))
+ .andReturn(ImmutableList.of(resUri));
+ HttpResponse httpResponse = new HttpResponse("response");
+ expect(proxyHandler.fetch(EasyMock.isA(ProxyUri.class)))
+ .andThrow(new GadgetException(Code.FAILED_TO_RETRIEVE_CONTENT));
+ replay();
+ GadgetsHandlerApi.ProxyResponse response = gadgetHandler.getProxy(request);
+ }
+
private GadgetsHandlerApi.TokenData createTokenData(String ownerId, String
viewerId) {
GadgetsHandlerApi.TokenData token =
mock(GadgetsHandlerApi.TokenData.class);
if (ownerId != null) {
@@ -271,6 +435,14 @@ public class GadgetsHandlerServiceTest e
return request;
}
+ private GadgetsHandlerApi.ProxyRequest createProxyRequest(Uri url, String
container,
+ List<String> fields) {
+ GadgetsHandlerApi.ProxyRequest request =
mock(GadgetsHandlerApi.ProxyRequest.class);
+ EasyMock.expect(request.getFields()).andStubReturn(fields);
+ EasyMock.expect(request.getContainer()).andStubReturn(container);
+ EasyMock.expect(request.getUrl()).andStubReturn(url);
+ return request;
+ }
private class FakeSecurityTokenCodec implements SecurityTokenCodec {
public SecurityToken inputToken = null;
public SecurityTokenException exc = null;
Modified:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java?rev=1030777&r1=1030776&r2=1030777&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
(original)
+++
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
Thu Nov 4 00:30:42 2010
@@ -22,6 +22,7 @@ import com.google.common.collect.Immutab
import com.google.inject.Guice;
import com.google.inject.Injector;
+import org.apache.commons.codec.binary.Base64;
import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.auth.SecurityTokenCodec;
import org.apache.shindig.auth.SecurityTokenException;
@@ -29,9 +30,14 @@ import org.apache.shindig.common.EasyMoc
import org.apache.shindig.common.JsonAssert;
import org.apache.shindig.common.testing.FakeGadgetToken;
import org.apache.shindig.common.testing.TestExecutorService;
+import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.common.util.FakeTimeSource;
+import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.process.ProcessingException;
import org.apache.shindig.gadgets.spec.GadgetSpec;
+import org.apache.shindig.gadgets.uri.JsUriManager;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+import org.apache.shindig.gadgets.uri.ProxyUriManager.ProxyUri;
import org.apache.shindig.protocol.DefaultHandlerRegistry;
import org.apache.shindig.protocol.HandlerExecutionListener;
import org.apache.shindig.protocol.HandlerRegistry;
@@ -48,6 +54,7 @@ import org.junit.Before;
import org.junit.Test;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
@@ -64,6 +71,9 @@ public class GadgetsHandlerTest extends
private final FakeProcessor processor = new FakeProcessor();
private final FakeIframeUriManager urlGenerator = new FakeIframeUriManager();
private final Map<String, FormDataItem> emptyFormItems =
Collections.emptyMap();
+ private final ProxyUriManager proxyUriManager = mock(ProxyUriManager.class);
+ private final JsUriManager jsUriManager = mock(JsUriManager.class);
+ private final ProxyHandler proxyHandler = mock(ProxyHandler.class);
private Injector injector;
private BeanJsonConverter converter;
@@ -81,7 +91,8 @@ public class GadgetsHandlerTest extends
private void registerGadgetsHandler(SecurityTokenCodec codec) {
BeanFilter beanFilter = new BeanFilter();
GadgetsHandlerService service = new GadgetsHandlerService(timeSource,
processor,
- urlGenerator, codec, SPEC_REFRESH_INTERVAL, beanFilter);
+ urlGenerator, codec, proxyUriManager, jsUriManager, proxyHandler,
+ SPEC_REFRESH_INTERVAL, beanFilter);
GadgetsHandler handler =
new GadgetsHandler(new TestExecutorService(), service, beanFilter);
registry = new DefaultHandlerRegistry(
@@ -196,19 +207,16 @@ public class GadgetsHandlerTest extends
JSONObject userPrefData = userPrefs.getJSONObject("up_one");
assertNotNull(userPrefData);
- JSONObject upEnums = userPrefData.getJSONObject("enumValues");
- assertNotNull(upEnums);
- assertEquals("disp1", upEnums.get("val1"));
- assertEquals("disp2", upEnums.get("abc"));
- assertEquals("disp3", upEnums.get("z_xabc"));
- assertEquals("disp4", upEnums.get("foo"));
-
JSONArray orderedEnums = userPrefData.getJSONArray("orderedEnumValues");
assertNotNull(orderedEnums);
assertEquals(4, orderedEnums.length());
+ assertEquals("disp1",
orderedEnums.getJSONObject(0).getString("displayValue"));
assertEquals("val1", orderedEnums.getJSONObject(0).getString("value"));
+ assertEquals("disp2",
orderedEnums.getJSONObject(1).getString("displayValue"));
assertEquals("abc", orderedEnums.getJSONObject(1).getString("value"));
+ assertEquals("disp3",
orderedEnums.getJSONObject(2).getString("displayValue"));
assertEquals("z_xabc", orderedEnums.getJSONObject(2).getString("value"));
+ assertEquals("disp4",
orderedEnums.getJSONObject(3).getString("displayValue"));
assertEquals("foo", orderedEnums.getJSONObject(3).getString("value"));
}
@@ -338,4 +346,106 @@ public class GadgetsHandlerTest extends
assertEquals(HttpServletResponse.SC_BAD_REQUEST,
gadget2.getJSONObject("error").getInt("code"));
}
+
+ private JSONObject makeSimpleProxyRequest(String fields, String... uris)
throws JSONException {
+ JSONObject params = new JSONObject().put("ids", ImmutableList.copyOf(uris))
+ .put("container", CONTAINER);
+ if (fields != null) {
+ params.put("fields", fields);
+ }
+ JSONObject req =
+ new JSONObject().put("method", "gadgets.proxy").put("id",
"req1").put("params", params);
+ return req;
+ }
+
+ @Test
+ public void testSimpleProxy() throws Exception {
+ registerGadgetsHandler(null);
+ String resUri = "http://example.com/data";
+ String proxyUri = "http://shindig.com/gadgets/proxy?url=" + resUri;
+ JSONObject request = makeSimpleProxyRequest(null, resUri);
+ Capture<List<ProxyUri>> captureProxyUri = new Capture<List<ProxyUri>>();
+ EasyMock.expect(proxyUriManager.make(EasyMock.capture(captureProxyUri),
+
EasyMock.isNull(Integer.class))).andReturn(ImmutableList.<Uri>of(Uri.parse(proxyUri)));
+ replay();
+ RpcHandler operation = registry.getRpcHandler(request);
+ Object responseObj = operation.execute(emptyFormItems, token,
converter).get();
+ JSONObject response = new
JSONObject(converter.convertToString(responseObj));
+
+ JSONObject gadget1 = response.getJSONObject(resUri);
+ assertEquals(proxyUri, gadget1.getString("proxyUrl"));
+ ProxyUri pUri = captureProxyUri.getValue().get(0);
+ ProxyUri expectedUri = new ProxyUri(null, false, false, CONTAINER, null,
Uri.parse(resUri));
+ assertTrue(expectedUri.equals(pUri));
+ assertFalse(gadget1.has("error"));
+ verify();
+ }
+
+ @Test
+ public void testSimpleProxyData() throws Exception {
+ registerGadgetsHandler(null);
+ String resUri = "http://example.com/data";
+ String proxyUri = "http://shindig.com/gadgets/proxy?url=" + resUri;
+ JSONObject request = makeSimpleProxyRequest("*", resUri);
+ Capture<List<ProxyUri>> captureProxyUri = new Capture<List<ProxyUri>>();
+ EasyMock.expect(proxyUriManager.make(EasyMock.capture(captureProxyUri),
+
EasyMock.isNull(Integer.class))).andReturn(ImmutableList.<Uri>of(Uri.parse(proxyUri)));
+ String responseData = "response data";
+ HttpResponse httpResponse = new HttpResponse(responseData);
+
EasyMock.expect(proxyHandler.fetch(EasyMock.isA(ProxyUri.class))).andReturn(httpResponse);
+ replay();
+
+ RpcHandler operation = registry.getRpcHandler(request);
+ Object responseObj = operation.execute(emptyFormItems, token,
converter).get();
+ JSONObject response = new
JSONObject(converter.convertToString(responseObj));
+
+ JSONObject gadget1 = response.getJSONObject(resUri);
+ assertEquals(proxyUri, gadget1.getString("proxyUrl"));
+ ProxyUri pUri = captureProxyUri.getValue().get(0);
+ ProxyUri expectedUri = new ProxyUri(null, false, false, CONTAINER, null,
Uri.parse(resUri));
+ assertTrue(expectedUri.equals(pUri));
+ assertEquals(responseData, new String(Base64.decodeBase64(((JSONObject)
+ gadget1.get("proxyContent")).getString("contentBase64").getBytes())));
+ assertFalse(gadget1.has("error"));
+ verify();
+ }
+
+ private JSONObject makeComplexProxyRequest(String... uris) throws
JSONException {
+ JSONObject req =
+ new JSONObject().put("method", "gadgets.proxy").put("id",
"req1").put("params",
+ new JSONObject().put("ids",
ImmutableList.copyOf(uris)).put("container", CONTAINER)
+ .put("ignoreCache", "1").put("debug", "1").put("sanitize",
"true")
+ .put("cajole", "true").put("gadget",
GADGET1_URL).put("refresh", "333")
+ .put("rewriteMime", "text/xml").put("fallback_url", uris[0])
+ .put("no_expand", "true").put("resize_h",
"444").put("resize_w", "555")
+ .put("resize_q", "88")
+ );
+ return req;
+ }
+
+ @Test
+ public void testComplexProxy() throws Exception {
+ registerGadgetsHandler(null);
+ String resUri = "http://example.com/data";
+ String proxyUri = "http://shindig.com/gadgets/proxy?url=" + resUri;
+ JSONObject request = makeComplexProxyRequest(resUri);
+ Capture<List<ProxyUri>> captureProxyUri = new Capture<List<ProxyUri>>();
+ EasyMock.expect(proxyUriManager.make(EasyMock.capture(captureProxyUri),
+
EasyMock.isNull(Integer.class))).andReturn(ImmutableList.<Uri>of(Uri.parse(proxyUri)));
+ replay();
+ RpcHandler operation = registry.getRpcHandler(request);
+ Object responseObj = operation.execute(emptyFormItems, token,
converter).get();
+ JSONObject response = new
JSONObject(converter.convertToString(responseObj));
+
+ JSONObject gadget1 = response.getJSONObject(resUri);
+ assertEquals(proxyUri, gadget1.getString("proxyUrl"));
+ ProxyUri pUri = captureProxyUri.getValue().get(0);
+ ProxyUri expectedUri = new ProxyUri(333, true, true, CONTAINER,
GADGET1_URL, Uri.parse(resUri));
+
expectedUri.setCajoleContent(true).setRewriteMimeType("text/xml").setSanitizeContent(true);
+ expectedUri.setFallbackUrl(resUri).setResize(555, 444, 88, true);
+ assertTrue(expectedUri.equals(pUri));
+ assertFalse(gadget1.has("error"));
+ verify();
+ }
+
}