You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by jo...@apache.org on 2008/07/17 23:53:23 UTC

svn commit: r677755 - /incubator/shindig/trunk/features/rpc/rpc.js

Author: johnh
Date: Thu Jul 17 14:53:22 2008
New Revision: 677755

URL: http://svn.apache.org/viewvc?rev=677755&view=rev
Log:
Same-domain gadgets.rpc call support.

Detects if the receiving context of a given gadgets.rpc call
is on the same domain as the caller. In that case, makes a direct call to the
receiver rather than relying on other cross-domain tricks. This is useful
for trusted gadgets rendered on the same domain as their container, irrespective
of browser, since this "transport" is simply a function call that works on any
browser.

This patch closes SHINDIG-456.


Modified:
    incubator/shindig/trunk/features/rpc/rpc.js

Modified: incubator/shindig/trunk/features/rpc/rpc.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/rpc/rpc.js?rev=677755&r1=677754&r2=677755&view=diff
==============================================================================
--- incubator/shindig/trunk/features/rpc/rpc.js (original)
+++ incubator/shindig/trunk/features/rpc/rpc.js Thu Jul 17 14:53:22 2008
@@ -47,6 +47,7 @@
   var callId = 0;
   var callbacks = {};
   var setup = {};
+  var sameDomain = {};
 
   var params = {};
 
@@ -371,6 +372,45 @@
     setTimeout(function() { document.body.appendChild(iframe); }, 0);
   }
 
+  /**
+   * Attempts to make an rpc by calling the target's receive method directly.
+   * This works when gadgets are rendered on the same domain as their container,
+   * a potentially useful optimization for trusted content which keeps
+   * RPC behind a consistent interface.
+   * @param {String} target Module id of the rpc service provider
+   * @param {String} from Module id of the caller (this)
+   * @param {String} callbackId Id of the call
+   * @param {String} rpcData JSON-encoded RPC payload
+   * @return
+   */
+  function callSameDomain(target, rpc) {
+    if (typeof sameDomain[target] === 'undefined') {
+      // Seed with a negative, typed value to avoid
+      // hitting this code path repeatedly
+      sameDomain[target] = false;
+      var targetEl = null;
+      if (target === '..') {
+        targetEl = parent;
+      } else {
+        targetEl = frames[target];
+      }
+      try {
+        // If this succeeds, then same-domain policy applied
+        sameDomain[target] = targetEl.gadgets.rpc.receiveSameDomain;
+      } catch (e) {
+        // Usual case: different domains
+      }
+    }
+
+    if (typeof sameDomain[target] === 'function') {
+      // Call target's receive method
+      sameDomain[target](rpc);
+      return true;
+    }
+
+    return false;
+  }
+
   // gadgets.config might not be available, such as when serving container js.
   if (gadgets.config) {
     /**
@@ -493,13 +533,20 @@
       }
 
       // Not used by legacy, create it anyway...
-      var rpcData = gadgets.json.stringify({
+      var rpc = {
         s: serviceName,
         f: from,
         c: callback ? callId : 0,
         a: Array.prototype.slice.call(arguments, 3),
         t: authToken[targetId]
-      });
+      };
+
+      // If target is on the same domain, call method directly
+      if (callSameDomain(targetId, rpc)) {
+        return;
+      }
+
+      var rpcData = gadgets.json.stringify(rpc);
 
       var channelType = relayChannel;
 
@@ -595,6 +642,18 @@
         process(gadgets.json.parse(
             decodeURIComponent(fragment[fragment.length - 1])));
       }
+    },
+
+    /**
+     * Receives and processes an RPC request sent via the same domain.
+     * (Not to be used directly). Converts the inbound rpc object's
+     * Array into a local Array to pass the process() Array test.
+     * @param {Object} rpc RPC object containing all request params
+     */
+    receiveSameDomain: function(rpc) {
+      // Pass through to local process method but converting to a local Array
+      rpc.a = Array.prototype.slice.call(rpc.a);
+      window.setTimeout(function() { process(rpc) }, 0);
     }
   };
 }();