org.apache.shindig.gadgets.servlet.GadgetsHandlerService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of shindig-gadgets Show documentation
Show all versions of shindig-gadgets Show documentation
Renders gadgets, provides the gadget metadata service, and serves
all javascript required by the OpenSocial specification.
The newest version!
/*
* 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 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;
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;
import org.apache.shindig.common.Nullable;
import org.apache.shindig.common.servlet.HttpUtil;
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.admin.GadgetAdminStore;
import org.apache.shindig.gadgets.features.ApiDirective;
import org.apache.shindig.gadgets.features.FeatureRegistry;
import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
import org.apache.shindig.gadgets.features.FeatureRegistry.LookupResult;
import org.apache.shindig.gadgets.features.FeatureRegistryProvider;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.js.JsException;
import org.apache.shindig.gadgets.js.JsRequestBuilder;
import org.apache.shindig.gadgets.js.JsResponse;
import org.apache.shindig.gadgets.js.JsServingPipeline;
import org.apache.shindig.gadgets.process.ProcessingException;
import org.apache.shindig.gadgets.process.Processor;
import org.apache.shindig.gadgets.servlet.CajaContentRewriter.CajoledResult;
import org.apache.shindig.gadgets.spec.Feature;
import org.apache.shindig.gadgets.spec.GadgetSpec;
import org.apache.shindig.gadgets.spec.LinkSpec;
import org.apache.shindig.gadgets.spec.ModulePrefs;
import org.apache.shindig.gadgets.spec.OAuthService;
import org.apache.shindig.gadgets.spec.OAuthSpec;
import org.apache.shindig.gadgets.spec.UserPref;
import org.apache.shindig.gadgets.spec.UserPref.EnumValuePair;
import org.apache.shindig.gadgets.spec.View;
import org.apache.shindig.gadgets.uri.IframeUriManager;
import org.apache.shindig.gadgets.uri.JsUriManager;
import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
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 com.google.caja.lexer.TokenConsumer;
import com.google.caja.parser.html.Nodes;
import com.google.caja.render.Concatenator;
import com.google.caja.render.JsMinimalPrinter;
import com.google.caja.render.JsPrettyPrinter;
import com.google.caja.reporting.MessageContext;
import com.google.caja.reporting.RenderContext;
import com.google.caja.util.Sets;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.name.Named;
/**
* Service that interfaces with the system to provide information about gadgets.
*
* @since 2.0.0
*/
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>> API_CLASSES =
new ImmutableMap.Builder, Class>>()
.put(View.class, GadgetsHandlerApi.View.class)
.put(UserPref.class, GadgetsHandlerApi.UserPref.class)
.put(EnumValuePair.class, GadgetsHandlerApi.EnumValuePair.class)
.put(ModulePrefs.class, GadgetsHandlerApi.ModulePrefs.class)
.put(Feature.class, GadgetsHandlerApi.Feature.class)
.put(LinkSpec.class, GadgetsHandlerApi.LinkSpec.class)
.put(OAuthSpec.class, GadgetsHandlerApi.OAuthSpec.class)
.put(OAuthService.class, GadgetsHandlerApi.OAuthService.class)
.put(OAuthService.EndPoint.class, GadgetsHandlerApi.EndPoint.class)
// Enums
.put(View.ContentType.class, GadgetsHandlerApi.ViewContentType.class)
.put(UserPref.DataType.class, GadgetsHandlerApi.UserPrefDataType.class)
.put(GadgetsHandlerApi.RenderingContext.class, RenderingContext.class)
.put(OAuthService.Method.class, GadgetsHandlerApi.Method.class)
.put(OAuthService.Location.class, GadgetsHandlerApi.Location.class)
.build();
// Provide mapping for internal enums to api enums
@VisibleForTesting
static final Map, Enum>> ENUM_CONVERSION_MAP =
new ImmutableMap.Builder, Enum>>()
// View.ContentType mapping
.putAll(BeanDelegator.createDefaultEnumMap(View.ContentType.class,
GadgetsHandlerApi.ViewContentType.class))
// UserPref.DataType mapping
.putAll(BeanDelegator.createDefaultEnumMap(UserPref.DataType.class,
GadgetsHandlerApi.UserPrefDataType.class))
.putAll(BeanDelegator.createDefaultEnumMap(OAuthService.Method.class,
GadgetsHandlerApi.Method.class))
.putAll(BeanDelegator.createDefaultEnumMap(OAuthService.Location.class,
GadgetsHandlerApi.Location.class))
.putAll(BeanDelegator.createDefaultEnumMap(GadgetsHandlerApi.RenderingContext.class,
RenderingContext.class))
.build();
protected final TimeSource timeSource;
protected final Processor processor;
protected final IframeUriManager iframeUriManager;
protected final SecurityTokenCodec securityTokenCodec;
protected final ProxyUriManager proxyUriManager;
protected final JsUriManager jsUriManager;
protected final JsServingPipeline jsPipeline;
protected final JsRequestBuilder jsRequestBuilder;
protected final ProxyHandler proxyHandler;
protected final BeanDelegator beanDelegator;
protected final long specRefreshInterval;
protected final BeanFilter beanFilter;
protected final CajaContentRewriter cajaContentRewriter;
protected final GadgetAdminStore gadgetAdminStore;
protected final FeatureRegistryProvider featureRegistryProvider;
@Inject
public GadgetsHandlerService(TimeSource timeSource, Processor processor,
IframeUriManager iframeUriManager, SecurityTokenCodec securityTokenCodec,
ProxyUriManager proxyUriManager, JsUriManager jsUriManager, ProxyHandler proxyHandler,
JsServingPipeline jsPipeline, JsRequestBuilder jsRequestBuilder,
@Named("shindig.cache.xml.refreshInterval") long specRefreshInterval,
BeanFilter beanFilter, CajaContentRewriter cajaContentRewriter,
GadgetAdminStore gadgetAdminStore,
FeatureRegistryProvider featureRegistryProvider) {
this.timeSource = timeSource;
this.processor = processor;
this.iframeUriManager = iframeUriManager;
this.securityTokenCodec = securityTokenCodec;
this.proxyUriManager = proxyUriManager;
this.jsUriManager = jsUriManager;
this.proxyHandler = proxyHandler;
this.jsPipeline = jsPipeline;
this.jsRequestBuilder = jsRequestBuilder;
this.specRefreshInterval = specRefreshInterval;
this.beanFilter = beanFilter;
this.cajaContentRewriter = cajaContentRewriter;
this.gadgetAdminStore = gadgetAdminStore;
this.featureRegistryProvider = featureRegistryProvider;
this.beanDelegator = new BeanDelegator(API_CLASSES, ENUM_CONVERSION_MAP);
}
/**
* Get gadget metadata information and iframe url. Support filtering of fields
* @param request request parameters
* @return gadget metadata nd iframe url
* @throws ProcessingException
*/
public GadgetsHandlerApi.MetadataResponse getMetadata(GadgetsHandlerApi.MetadataRequest request)
throws ProcessingException {
verifyBaseParams(request, true);
Set fields = beanFilter.processBeanFields(request.getFields());
GadgetContext context = new MetadataGadgetContext(request);
Gadget gadget = processor.process(context);
boolean needIfrUrl = isFieldIncluded(fields, "iframeurl");
if (needIfrUrl) {
if(!gadgetAdminStore.checkFeatureAdminInfo(gadget)) {
throw new ProcessingException("Gadget is not trusted to render in this container.",
HttpResponse.SC_BAD_REQUEST);
}
if(gadget.getCurrentView() == null) {
throw new ProcessingException("View " + request.getView() + " does not exist",
HttpResponse.SC_BAD_REQUEST);
}
}
String iframeUrl = needIfrUrl ? iframeUriManager.makeRenderingUri(gadget).toString() : null;
Boolean needsTokenRefresh =
isFieldIncluded(fields, "needstokenrefresh") ?
gadget.getAllFeatures().contains("auth-refresh") : null;
Set rpcServiceIds = getRpcServiceIds(gadget);
Integer tokenTTL = isFieldIncluded(fields, "tokenTTL") ?
securityTokenCodec.getTokenTimeToLive() : null;
return createMetadataResponse(context.getUrl(), gadget.getSpec(), iframeUrl,
needsTokenRefresh, fields, timeSource.currentTimeMillis() + specRefreshInterval, tokenTTL,
rpcServiceIds);
}
/**
* Gets the set of allowed RPC service ids.
*
* @param gadget
* the gadget to get the service ids for.
* @return the set of allowed RPC service ids.
*/
private Set getRpcServiceIds(Gadget gadget) {
GadgetContext context = gadget.getContext();
Set rpcEndpoints = Sets.newHashSet();
List modulePrefFeatures = gadget.getSpec().getModulePrefs().getAllFeatures();
List featureNames = Lists.newArrayList();
for(Feature feature : modulePrefFeatures) {
if(gadgetAdminStore.isAllowedFeature(feature, gadget)) {
featureNames.add(feature.getName());
}
}
try {
FeatureRegistry featureRegistry = featureRegistryProvider.get(context.getRepository());
LookupResult result = featureRegistry.getFeatureResources(context, featureRegistry.getFeatures(featureNames),
null);
List bundles = result.getBundles();
for (FeatureBundle bundle : bundles) {
rpcEndpoints.addAll(bundle.getApis(ApiDirective.Type.RPC, false));
}
} catch (GadgetException e) {
LOG.log(Level.WARNING, "Error getting features from feature registry", e);
}
return rpcEndpoints;
}
private boolean isFieldIncluded(Set fields, String name) {
return fields.contains(BeanFilter.ALL_FIELDS) || fields.contains(name.toLowerCase());
}
/**
* Create security token
* @param request token paramaters (gadget, owner and viewer)
* @return Security token
* @throws SecurityTokenException
*/
public GadgetsHandlerApi.TokenResponse getToken(GadgetsHandlerApi.TokenRequest request)
throws SecurityTokenException, ProcessingException {
verifyBaseParams(request, true);
Set fields = beanFilter.processBeanFields(request.getFields());
SecurityToken tokenData = convertAuthContext(request.getAuthContext(), request.getContainer(),
request.getUrl().toString());
String token = securityTokenCodec.encodeToken(tokenData);
Long expiryTimeMs = tokenData == null ? null : tokenData.getExpiresAt();
return createTokenResponse(request.getUrl(), token, fields, expiryTimeMs);
}
public GadgetsHandlerApi.JsResponse getJs(GadgetsHandlerApi.JsRequest request)
throws ProcessingException {
verifyBaseParams(request, false);
Set fields = beanFilter.processBeanFields(request.getFields());
JsUri jsUri = createJsUri(request);
Uri servedUri = jsUriManager.makeExternJsUri(jsUri);
String content = null;
Long expireMs = null;
if (isFieldIncluded(fields, "jsContent")) {
JsResponse response;
try {
response = jsPipeline.execute(jsRequestBuilder.build(jsUri, servedUri.getAuthority()));
} catch (JsException e) {
throw new ProcessingException(e.getMessage(), e.getStatusCode());
}
content = response.toJsString();
if (response.isProxyCacheable()) {
expireMs = getDefaultExpiration();
}
} else {
expireMs = getDefaultExpiration();
}
return createJsResponse(request.getUrl(), servedUri, content, fields, expireMs);
}
public GadgetsHandlerApi.ProxyResponse getProxy(GadgetsHandlerApi.ProxyRequest request)
throws ProcessingException {
verifyBaseParams(request, true);
Set fields = beanFilter.processBeanFields(request.getFields());
ProxyUri proxyUri = createProxyUri(request);
List 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);
}
}
/**
* Convert message level to Shindig's serializable message type
*/
public static GadgetsHandlerApi.MessageLevel convertMessageLevel(String name) {
try {
return GadgetsHandlerApi.MessageLevel.valueOf(name);
}
catch (Exception ex) {
return GadgetsHandlerApi.MessageLevel.UNKNOWN;
}
}
/**
* Convert messages from Caja's internal message type to Shindig's serializable message type
*/
private List convertMessages(
List msgs,
final MessageContext mc) {
List result = Lists.newArrayListWithExpectedSize(msgs.size());
for (final com.google.caja.reporting.Message m : msgs) {
MessageImpl msg = new MessageImpl(m.getMessageType().name(),
m.format(mc), convertMessageLevel(m.getMessageLevel().name()));
result.add(msg);
}
return result;
}
public GadgetsHandlerApi.CajaResponse getCaja(GadgetsHandlerApi.CajaRequest request)
throws ProcessingException {
verifyBaseParams(request, true);
Set fields = beanFilter.processBeanFields(request.getFields());
MessageContext mc = new MessageContext();
CajoledResult result =
cajaContentRewriter.rewrite(request.getUrl(), request.getContainer(),
request.getMimeType(), true /* only support es53 */, request.getDebug());
String html = null;
String js = null;
if (!result.hasErrors && null != result.html) {
html = Nodes.render(result.html);
}
if (!result.hasErrors && null != result.js) {
StringBuilder builder = new StringBuilder();
TokenConsumer tc = request.getDebug() ?
new JsPrettyPrinter(new Concatenator(builder))
: new JsMinimalPrinter(new Concatenator(builder));
RenderContext rc = new RenderContext(tc)
.withAsciiOnly(true)
.withEmbeddable(true);
result.js.render(rc);
rc.getOut().noMoreTokens();
js = builder.toString();
}
// TODO(jasvir): Improve Caja responses expiration handling
return createCajaResponse(request.getUrl(),
html, js, convertMessages(result.messages, mc), fields,
timeSource.currentTimeMillis() + specRefreshInterval);
}
/**
* Verify request parameter are defined.
*/
protected void verifyBaseParams(GadgetsHandlerApi.BaseRequest request, boolean checkUrl)
throws ProcessingException {
if (checkUrl && request.getUrl() == null) {
throw new ProcessingException("Missing url parameter", HttpResponse.SC_BAD_REQUEST);
}
if (request.getContainer() == null) {
throw new ProcessingException("Missing container parameter", HttpResponse.SC_BAD_REQUEST);
}
if (request.getFields() == null) {
throw new ProcessingException("Missing fields parameter", HttpResponse.SC_BAD_REQUEST);
}
}
protected Long getProxyExpireMs(ProxyUri proxyUri, @Nullable HttpResponse httpResponse) {
if (httpResponse != null) {
return httpResponse.getCacheExpiration();
} else if (proxyUri.getRefresh() != null) {
return timeSource.currentTimeMillis() + proxyUri.getRefresh() * 1000;
}
return getDefaultExpiration();
}
protected long getDefaultExpiration() {
return timeSource.currentTimeMillis() + (HttpUtil.getDefaultTtl() * 1000);
}
/**
* GadgetContext for metadata request. Used by the gadget processor
*/
protected class MetadataGadgetContext extends GadgetContext {
private final GadgetsHandlerApi.MetadataRequest request;
private final SecurityToken authContext;
public MetadataGadgetContext(GadgetsHandlerApi.MetadataRequest request) {
this.request = request;
this.authContext = convertAuthContext(
request.getAuthContext(), request.getContainer(), request.getUrl().toString());
}
@Override
public Uri getUrl() {
return request.getUrl();
}
@Override
public String getContainer() {
return request.getContainer();
}
@Override
public RenderingContext getRenderingContext() {
return RenderingContext.METADATA;
}
@Override
public int getModuleId() {
return 1;
}
@Override
public Locale getLocale() {
return (request.getLocale() == null ? DEFAULT_LOCALE : request.getLocale());
}
@Override
public boolean getIgnoreCache() {
return request.getIgnoreCache();
}
@Override
public boolean getDebug() {
return request.getDebug();
}
@Override
public String getView() {
return request.getView();
}
@Override
public SecurityToken getToken() {
return authContext;
}
@Override
public boolean getSanitize() {
return (request.getRenderingType() == GadgetsHandlerApi.RenderingType.SANITIZED);
}
@Override
public boolean getCajoled() {
return (request.getRenderingType() == GadgetsHandlerApi.RenderingType.IFRAME_CAJOLED);
}
}
private SecurityToken convertAuthContext(GadgetsHandlerApi.AuthContext authContext,
String container, String url) {
if (authContext == null) {
return null;
}
return beanDelegator.createDelegator(authContext, SecurityToken.class,
ImmutableMap.of("container", container,
"appid", url, "appurl", url));
}
public GadgetsHandlerApi.BaseResponse createErrorResponse(
Uri uri, Exception e, String defaultMsg) {
if (e instanceof ProcessingException) {
ProcessingException processingExc = (ProcessingException) e;
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);
}
public GadgetsHandlerApi.BaseResponse createErrorResponse(Uri url, int code, String error) {
GadgetsHandlerApi.Error errorBean = beanDelegator.createDelegator(
null, GadgetsHandlerApi.Error.class, ImmutableMap.of(
"message", BeanDelegator.nullable(error), "code", code));
return beanDelegator.createDelegator(error, GadgetsHandlerApi.BaseResponse.class,
ImmutableMap.of("url", BeanDelegator.nullable(url), "error", errorBean,
"responsetimems", BeanDelegator.NULL, "expiretimems", BeanDelegator.NULL));
}
@VisibleForTesting
GadgetsHandlerApi.MetadataResponse createMetadataResponse(
Uri url, GadgetSpec spec, String iframeUrl, Boolean needsTokenRefresh,
Set fields, Long expireTime, Integer tokenTTL, Set rpcServiceIds) {
return (GadgetsHandlerApi.MetadataResponse) beanFilter.createFilteredBean(
beanDelegator.createDelegator(spec, GadgetsHandlerApi.MetadataResponse.class,
ImmutableMap.builder()
.put("url", url)
.put("error", BeanDelegator.NULL)
.put("iframeurl", BeanDelegator.nullable(iframeUrl))
.put("needstokenrefresh", BeanDelegator.nullable(needsTokenRefresh))
.put("responsetimems", timeSource.currentTimeMillis())
.put("expiretimems", BeanDelegator.nullable(expireTime))
.put("rpcserviceids", BeanDelegator.nullable(rpcServiceIds))
.put("tokenttl", BeanDelegator.nullable(tokenTTL)).build()),
fields);
}
@VisibleForTesting
GadgetsHandlerApi.TokenResponse createTokenResponse(
Uri url, String token, Set fields, Long tokenExpire) {
return (GadgetsHandlerApi.TokenResponse) beanFilter.createFilteredBean(
beanDelegator.createDelegator(null, GadgetsHandlerApi.TokenResponse.class,
ImmutableMap.of(
"url", url,
"error", BeanDelegator.NULL,
"token", BeanDelegator.nullable(token),
"responsetimems", timeSource.currentTimeMillis(),
"expiretimems", BeanDelegator.nullable(tokenExpire))),
fields);
}
protected JsUri createJsUri(GadgetsHandlerApi.JsRequest request) {
RenderingContext context = (RenderingContext)
(request.getContext() != null ?
// TODO: Figure out why maven complain about casting and clean the dummy cast
(Object) beanDelegator.convertEnum(request.getContext())
: RenderingContext.GADGET);
return new JsUri(request.getRefresh(), request.getDebug(), request.getIgnoreCache(),
request.getContainer(), request.getGadget(), request.getFeatures(),
request.getLoadedFeatures(), request.getOnload(), false, false, context, request.getUrl(),
request.getRepository());
}
@VisibleForTesting
GadgetsHandlerApi.JsResponse createJsResponse(
Uri url, Uri jsUri, String content, Set fields, Long expireMs) {
return (GadgetsHandlerApi.JsResponse) beanFilter.createFilteredBean(
beanDelegator.createDelegator(null, GadgetsHandlerApi.JsResponse.class,
ImmutableMap.builder()
.put("url", BeanDelegator.nullable(url))
.put("error", BeanDelegator.NULL)
.put("jsurl", jsUri)
.put("jscontent", BeanDelegator.nullable(content))
.put("responsetimems", timeSource.currentTimeMillis())
.put("expiretimems", BeanDelegator.nullable(expireMs)).build()),
fields);
}
protected ProxyUri createProxyUri(GadgetsHandlerApi.ProxyRequest request) {
ProxyUriManager.ProxyUri proxyUri = new ProxyUriManager.ProxyUri(request.getRefresh(),
request.getDebug(), request.getIgnoreCache(), request.getContainer(),
request.getGadget(), request.getUrl());
proxyUri.setFallbackUrl(request.getFallbackUrl())
.setRewriteMimeType(request.getRewriteMimeType())
.setSanitizeContent(request.getSanitize());
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 fields, Long expireMs) throws IOException {
GadgetsHandlerApi.HttpResponse beanHttp = null;
if (httpResponse != null) {
String content = "";
if (httpResponse.getContentLength() > 0) {
// Stream out the base64-encoded data.
// Ctor args indicate to encode w/o line breaks.
Base64InputStream b64input =
new Base64InputStream(httpResponse.getResponse(), true, 0, null);
content = IOUtils.toString(b64input);
}
ImmutableList.Builder headersBuilder =
ImmutableList.builder();
for (final Map.Entry entry : httpResponse.getHeaders().entries()) {
headersBuilder.add(
beanDelegator.createDelegator(null, GadgetsHandlerApi.NameValuePair.class,
ImmutableMap.of("name", entry.getKey(), "value", entry.getValue()))
);
}
beanHttp = beanDelegator.createDelegator(null, GadgetsHandlerApi.HttpResponse.class,
ImmutableMap.of(
"code", httpResponse.getHttpStatusCode(),
"encoding", httpResponse.getEncoding(),
"contentbase64", content,
"headers", headersBuilder.build()));
}
return (GadgetsHandlerApi.ProxyResponse) beanFilter.createFilteredBean(
beanDelegator.createDelegator(null, GadgetsHandlerApi.ProxyResponse.class,
ImmutableMap.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);
}
@VisibleForTesting
GadgetsHandlerApi.CajaResponse createCajaResponse(Uri uri,
String html, String js, List messages,
Set fields, Long expireMs) {
ImmutableList.Builder msgBuilder =
ImmutableList.builder();
for (final GadgetsHandlerApi.Message m : messages) {
msgBuilder.add(
beanDelegator.createDelegator(null, GadgetsHandlerApi.Message.class,
ImmutableMap.of("name", m.getName(),
"level", m.getLevel(), "message", m.getMessage())));
}
return (GadgetsHandlerApi.CajaResponse) beanFilter.createFilteredBean(
beanDelegator.createDelegator(null, GadgetsHandlerApi.CajaResponse.class,
ImmutableMap.builder()
.put("url", uri)
.put("html", BeanDelegator.nullable(html))
.put("js", BeanDelegator.nullable(js))
.put("messages", msgBuilder.build())
.put("error", BeanDelegator.NULL)
.put("responsetimems", timeSource.currentTimeMillis())
.put("expiretimems", BeanDelegator.nullable(expireMs))
.build()),
fields);
}
private static class MessageImpl implements GadgetsHandlerApi.Message {
private final GadgetsHandlerApi.MessageLevel level;
private final String message;
private final String name;
public MessageImpl(String name, String message, GadgetsHandlerApi.MessageLevel level) {
this.name = name;
this.message = message;
this.level = level;
}
public GadgetsHandlerApi.MessageLevel getLevel() {
return level;
}
public String getMessage() {
return message;
}
public String getName() {
return name;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy