/// <summary> /// Attempts to extract the "current" view for the given gadget. /// </summary> /// <param name="context"></param> /// <param name="spec"></param> /// <returns></returns> private View GetView(GadgetContext context, GadgetSpec spec) { String viewName = context.getView(); View view = spec.getView(viewName); if (view == null) { JsonObject views = containerConfig.GetJsonObject(context.getContainer(), "gadgets.features/views"); foreach (DictionaryEntry v in views) { JsonArray aliases = ((JsonObject)v.Value)["aliases"] as JsonArray; if (aliases != null && view == null) { for (int i = 0, j = aliases.Length; i < j; ++i) { if (viewName == aliases.GetString(i)) { view = spec.getView(v.Key.ToString()); if (view != null) { break; } } } } } } if (view == null) { view = spec.getView(GadgetSpec.DEFAULT_VIEW); } return(view); }
/** * Validates that the parent parameter was acceptable. * * @return True if the parent parameter is valid for the current container. */ private bool ValidateParent(GadgetContext context) { String container = context.getContainer(); String parent = context.getParameter("parent"); if (parent == null) { // If there is no parent parameter, we are still safe because no // dependent code ever has to trust it anyway. return(true); } try { JsonArray parents = containerConfig.GetJsonArray(container, "gadgets.parent"); if (parents == null) { return(true); } // We need to check each possible parent parameter against this regex. for (int i = 0, j = parents.Length; i < j; ++i) { if (Regex.IsMatch(parents[i].ToString(), parent)) { return(true); } } } catch (JsonException) { } return(false); }
/** * Render the gadget into a string by performing the following steps: * * - Retrieve gadget specification information (GadgetSpec, MessageBundle, etc.) * * - Fetch any preloaded data needed to handle the request, as handled by Preloader. * * - Perform rewriting operations on the output content, handled by Rewriter. * * @param gadget The gadget for the rendering operation. * @return The rendered gadget content * @throws RenderingException if any issues arise that prevent rendering. */ public String render(Gadget gadget) { try { View view = gadget.getCurrentView(); GadgetContext context = gadget.getContext(); GadgetSpec spec = gadget.getSpec(); IPreloads preloads = preloader.preload(context, spec, PreloaderService.PreloadPhase.HTML_RENDER); gadget.setPreloads(preloads); String content; if (view.getHref() == null) { content = view.getContent(); } else { // TODO: Add current url to GadgetContext to support transitive proxying. UriBuilder uri = new UriBuilder(view.getHref()); uri.addQueryParameter("lang", context.getLocale().getLanguage()); uri.addQueryParameter("country", context.getLocale().getCountry()); sRequest request = new sRequest(uri.toUri()) .setIgnoreCache(context.getIgnoreCache()) .setOAuthArguments(new OAuthArguments(view)) .setAuthType(view.getAuthType()) .setSecurityToken(context.getToken()) .setContainer(context.getContainer()) .setGadget(spec.getUrl()); sResponse response = DefaultHttpCache.Instance.getResponse(request); if (response == null || response.isStale()) { sRequest proxyRequest = createPipelinedProxyRequest(gadget, request); response = requestPipeline.execute(proxyRequest); DefaultHttpCache.Instance.addResponse(request, response); } if (response.isError()) { throw new RenderingException("Unable to reach remote host. HTTP status " + response.getHttpStatusCode()); } content = response.responseString; } return(rewriter.rewriteGadget(gadget, content)); } catch (GadgetException e) { throw new RenderingException(e.Message, e); } }
/** * Creates a set of all configuration needed to satisfy the requested feature set. * * Appends special configuration for gadgets.util.hasFeature and gadgets.util.getFeatureParams to * the output js. * * This can't be handled via the normal configuration mechanism because it is something that * varies per request. * * @param reqs The features needed to satisfy the request. * @throws GadgetException If there is a problem with the gadget auth token */ private String GetLibraryConfig(Gadget gadget, ICollection <GadgetFeature> reqs) { GadgetContext context = gadget.getContext(); JsonObject features = containerConfig.GetJsonObject(context.getContainer(), FEATURES_KEY); Dictionary <String, Object> config = new Dictionary <string, object>(features == null ? 2 : features.Names.Count + 2); if (features != null) { // Discard what we don't care about. foreach (GadgetFeature feature in reqs) { String name = feature.getName(); Object conf = features.Opt(name); if (conf != null) { config.Add(name, conf); } } } // Add gadgets.util support. This is calculated dynamically based on request inputs. ModulePrefs prefs = gadget.getSpec().getModulePrefs(); var values = prefs.getFeatures().Values; Dictionary <String, Dictionary <String, String> > featureMap = new Dictionary <string, Dictionary <string, string> >(values.Count); foreach (Feature feature in values) { featureMap.Add(feature.getName(), feature.getParams()); } config.Add("core.util", featureMap); // Add authentication token config ISecurityToken authToken = context.getToken(); if (authToken != null) { Dictionary <String, String> authConfig = new Dictionary <String, String>(2); String updatedToken = authToken.getUpdatedToken(); if (updatedToken != null) { authConfig.Add("authToken", updatedToken); } String trustedJson = authToken.getTrustedJson(); if (trustedJson != null) { authConfig.Add("trustedJson", trustedJson); } config.Add("shindig.auth", authConfig); } return("gadgets.config.init(" + JsonConvert.ExportToString(config) + ");\n"); }
public static sRequest newHttpRequest(GadgetContext context, RequestAuthenticationInfo authenticationInfo) { sRequest request = new sRequest(authenticationInfo.getHref()) .setSecurityToken(context.getToken()) .setOAuthArguments(new OAuthArguments(authenticationInfo)) .setAuthType(authenticationInfo.getAuthType()) .setContainer(context.getContainer()) .setGadget(Uri.fromJavaUri(context.getUrl())); return request; }
public static sRequest newHttpRequest(GadgetContext context, RequestAuthenticationInfo authenticationInfo) { sRequest request = new sRequest(authenticationInfo.getHref()) .setSecurityToken(context.getToken()) .setOAuthArguments(new OAuthArguments(authenticationInfo)) .setAuthType(authenticationInfo.getAuthType()) .setContainer(context.getContainer()) .setGadget(Uri.fromJavaUri(context.getUrl())); return(request); }
/** * Attempts to render the requested gadget. * * @return The results of the rendering attempt. * * TODO: Localize error messages. */ public RenderingResults Render(GadgetContext context) { if (!ValidateParent(context)) { return RenderingResults.error("Unsupported parent parameter. Check your container code."); } try { Gadget gadget = processor.Process(context); if (gadget.getCurrentView() == null) { return RenderingResults.error("Unable to locate an appropriate view in this gadget. " + "Requested: '" + gadget.getContext().getView() + "' Available: " + String.Join(",",gadget.getSpec().getViews().Keys.ToArray())); } if (gadget.getCurrentView().getType() == View.ContentType.URL) { return RenderingResults.mustRedirect(getRedirect(gadget)); } GadgetSpec spec = gadget.getSpec(); if (!lockedDomainService.gadgetCanRender(context.getHost(), spec, context.getContainer())) { return RenderingResults.mustRedirect(getRedirect(gadget)); } return RenderingResults.ok(renderer.render(gadget)); } catch (RenderingException e) { return LogError(context.getUrl(), e); } catch (ProcessingException e) { return LogError(context.getUrl(), e); } catch (Exception e) { if (e.GetBaseException() is GadgetException) { return LogError(context.getUrl(), e.GetBaseException()); } throw; } }
/** * Attempts to render the requested gadget. * * @return The results of the rendering attempt. * * TODO: Localize error messages. */ public RenderingResults Render(GadgetContext context) { if (!ValidateParent(context)) { return(RenderingResults.error("Unsupported parent parameter. Check your container code.")); } try { Gadget gadget = processor.Process(context); if (gadget.getCurrentView() == null) { return(RenderingResults.error("Unable to locate an appropriate view in this gadget. " + "Requested: '" + gadget.getContext().getView() + "' Available: " + String.Join(",", gadget.getSpec().getViews().Keys.ToArray()))); } if (gadget.getCurrentView().getType() == View.ContentType.URL) { return(RenderingResults.mustRedirect(getRedirect(gadget))); } GadgetSpec spec = gadget.getSpec(); if (!lockedDomainService.gadgetCanRender(context.getHost(), spec, context.getContainer())) { return(RenderingResults.mustRedirect(getRedirect(gadget))); } return(RenderingResults.ok(renderer.render(gadget))); } catch (RenderingException e) { return(LogError(context.getUrl(), e)); } catch (ProcessingException e) { return(LogError(context.getUrl(), e)); } catch (Exception e) { if (e.GetBaseException() is GadgetException) { return(LogError(context.getUrl(), e.GetBaseException())); } throw; } }
private void InjectBaseTag(Gadget gadget, Node headTag) { GadgetContext context = gadget.getContext(); if ("true".Equals(containerConfig.Get(context.getContainer(), INSERT_BASE_ELEMENT_KEY))) { Uri baseUrl = gadget.getSpec().getUrl(); View view = gadget.getCurrentView(); if (view != null && view.getHref() != null) { baseUrl = view.getHref(); } Element baseTag = headTag.getOwnerDocument().createElement("base"); baseTag.setAttribute("href", baseUrl.ToString()); headTag.insertBefore(baseTag, headTag.getFirstChild()); } }
/** * Fetches js configuration for the given feature set & container. * * @param config The configuration to extract js config from. * @param context The request context. * @param features A set of all features needed. */ public static JsonObject GetJsConfig(ContainerConfig config, GadgetContext context, HashSet <string> features) { JsonObject containerFeatures = config.GetJsonObject(context.getContainer(), "gadgets.features"); JsonObject retv = new JsonObject(); if (containerFeatures != null) { foreach (string feat in features) { if (containerFeatures.Contains(feat)) { retv.Put(feat, containerFeatures[feat]); } } } return(retv); }
/** * Validates that the parent parameter was acceptable. * * @return True if the parent parameter is valid for the current container. */ private bool ValidateParent(GadgetContext context) { String container = context.getContainer(); String parent = context.getParameter("parent"); if (parent == null) { // If there is no parent parameter, we are still safe because no // dependent code ever has to trust it anyway. return true; } try { JsonArray parents = containerConfig.GetJsonArray(container, "gadgets.parent"); if (parents == null) { return true; } // We need to check each possible parent parameter against this regex. for (int i = 0, j = parents.Length; i < j; ++i) { if (Regex.IsMatch(parents[i].ToString(), parent)) { return true; } } } catch (JsonException) { } return false; }
/// <summary> /// Attempts to extract the "current" view for the given gadget. /// </summary> /// <param name="context"></param> /// <param name="spec"></param> /// <returns></returns> private View GetView(GadgetContext context, GadgetSpec spec) { String viewName = context.getView(); View view = spec.getView(viewName); if (view == null) { JsonObject views = containerConfig.GetJsonObject(context.getContainer(), "gadgets.features/views"); foreach (DictionaryEntry v in views) { JsonArray aliases = ((JsonObject)v.Value)["aliases"] as JsonArray; if (aliases != null && view == null) { for (int i = 0, j = aliases.Length; i < j; ++i) { if (viewName == aliases.GetString(i)) { view = spec.getView(v.Key.ToString()); if (view != null) { break; } } } } } } if (view == null) { view = spec.getView(GadgetSpec.DEFAULT_VIEW); } return view; }
/** * Fetches js configuration for the given feature set & container. * * @param config The configuration to extract js config from. * @param context The request context. * @param features A set of all features needed. */ public static JsonObject GetJsConfig(ContainerConfig config, GadgetContext context, HashSet<string> features) { JsonObject containerFeatures = config.GetJsonObject(context.getContainer(), "gadgets.features"); JsonObject retv = new JsonObject(); if (containerFeatures != null) { foreach (string feat in features) { if (containerFeatures.Contains(feat)) { retv.Put(feat, containerFeatures[feat]); } } } return retv; }
/// <summary> /// Injects javascript libraries needed to satisfy feature dependencies. /// </summary> /// <param name="gadget"></param> /// <param name="headTag"></param> private void InjectFeatureLibraries(Gadget gadget, Node headTag) { // TODO: If there isn't any js in the document, we can skip this. Unfortunately, that means // both script tags (easy to detect) and event handlers (much more complex). GadgetContext context = gadget.getContext(); GadgetSpec spec = gadget.getSpec(); String forcedLibs = context.getParameter("libs"); HashKey <String> forced; if (string.IsNullOrEmpty(forcedLibs)) { forced = new HashKey <string>(); } else { forced = new HashKey <string>(); foreach (var item in forcedLibs.Split(':')) { forced.Add(item); } } // Forced libs are always done first. if (forced.Count != 0) { String jsUrl = urlGenerator.getBundledJsUrl(forced, context); Element libsTag = headTag.getOwnerDocument().createElement("script"); libsTag.setAttribute("src", jsUrl); headTag.appendChild(libsTag); // Forced transitive deps need to be added as well so that they don't get pulled in twice. // TODO: Figure out a clean way to avoid having to call getFeatures twice. foreach (GadgetFeature dep in featureRegistry.GetFeatures(forced)) { forced.Add(dep.getName()); } } // Inline any libs that weren't forced. The ugly context switch between inline and external // Js is needed to allow both inline and external scripts declared in feature.xml. String container = context.getContainer(); ICollection <GadgetFeature> features = GetFeatures(spec, forced); // Precalculate the maximum length in order to avoid excessive garbage generation. int size = 0; foreach (GadgetFeature feature in features) { foreach (JsLibrary library in feature.getJsLibraries(RenderingContext.GADGET, container)) { if (library._Type == JsLibrary.Type.URL) { size += library.Content.Length; } } } // Really inexact. StringBuilder inlineJs = new StringBuilder(size); foreach (GadgetFeature feature in features) { foreach (JsLibrary library in feature.getJsLibraries(RenderingContext.GADGET, container)) { if (library._Type == JsLibrary.Type.URL) { if (inlineJs.Length > 0) { Element inlineTag = headTag.getOwnerDocument().createElement("script"); headTag.appendChild(inlineTag); inlineTag.appendChild(headTag.getOwnerDocument().createTextNode(inlineJs.ToString())); inlineJs.Length = 0; } Element referenceTag = headTag.getOwnerDocument().createElement("script"); referenceTag.setAttribute("src", library.Content); headTag.appendChild(referenceTag); } else { if (!forced.Contains(feature.getName())) { // already pulled this file in from the shared contents. if (context.getDebug()) { inlineJs.Append(library.DebugContent); } else { inlineJs.Append(library.Content); } inlineJs.Append(";\n"); } } } } inlineJs.Append(GetLibraryConfig(gadget, features)); if (inlineJs.Length > 0) { Element inlineTag = headTag.getOwnerDocument().createElement("script"); headTag.appendChild(inlineTag); inlineTag.appendChild(headTag.getOwnerDocument().createTextNode(inlineJs.ToString())); } }