windowName.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.io.windowName"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.io.windowName"] = true;
  8. dojo.provide("dojox.io.windowName");
  9. // Implements the window.name transport
  10. dojox.io.windowName = {
  11. send: function(/*String*/ method, /*dojo.__IoArgs*/ args){
  12. // summary:
  13. // Provides secure cross-domain request capability.
  14. // Sends a request using an iframe (POST or GET) and reads the response through the
  15. // frame's window.name.
  16. //
  17. // method:
  18. // The method to use to send the request, GET or POST
  19. //
  20. // args:
  21. // See dojo.xhr
  22. //
  23. // args.authElement: DOMNode?
  24. // By providing an authElement, this indicates that windowName should use the
  25. // authorized window.name protocol, relying on
  26. // the loaded XD resource to return to the provided return URL on completion
  27. // of authorization/authentication. The provided authElement will be used to place
  28. // the iframe in, so the user can interact with the server resource for authentication
  29. // and/or authorization to access the resource.
  30. //
  31. // args.onAuthLoad: Function?
  32. // When using authorized access to resources, this function will be called when the
  33. // authorization page has been loaded. (When authorization is actually completed,
  34. // the deferred callback function is called with the result). The primary use for this
  35. // is to make the authElement visible to the user once the resource has loaded
  36. // (this can be preferable to showing the iframe while the resource is loading
  37. // since it may not require authorization, it may simply return the resource).
  38. //
  39. // description:
  40. // In order to provide a windowname transport accessible resources/web services, a server
  41. // should check for the presence of a parameter window.name=true and if a request includes
  42. // such a parameter, it should respond to the request with an HTML
  43. // document that sets it's window.name to the string that is to be
  44. // delivered to the client. For example, if a client makes a window.name request like:
  45. // | http://othersite.com/greeting?windowname=true
  46. // And server wants to respond to the client with "Hello", it should return an html page:
  47. // | <html><script type="text/javascript">
  48. // | window.name="Hello";
  49. // | </script></html>
  50. // One can provide XML or JSON data by simply quoting the data as a string, and parsing the data
  51. // on the client.
  52. // If you use the authorization window.name protocol, the requester should include an
  53. // authElement element in the args, and a request will be created like:
  54. // | http://othersite.com/greeting?windowname=auth
  55. // And the server can respond like this:
  56. // | <html><script type="text/javascript">
  57. // | var loc = window.name;
  58. // | authorizationButton.onclick = function(){
  59. // | window.name="Hello";
  60. // | location = loc;
  61. // | };
  62. // | </script></html>
  63. // When using windowName from a XD Dojo build, make sure to set the
  64. // dojo.dojoBlankHtmlUrl property to a local URL.
  65. args.url += (args.url.match(/\?/) ? '&' : '?') + "windowname=" + (args.authElement ? "auth" : true); // indicate our desire for window.name communication
  66. var authElement = args.authElement;
  67. var cleanup = function(result){
  68. try{
  69. // we have to do this to stop the wait cursor in FF
  70. var innerDoc = dfd.ioArgs.frame.contentWindow.document;
  71. innerDoc.write(" ");
  72. innerDoc.close();
  73. }catch(e){}
  74. (authElement || dojo.body()).removeChild(dfd.ioArgs.outerFrame); // clean up
  75. return result;
  76. }
  77. var dfd = dojo._ioSetArgs(args,cleanup,cleanup,cleanup);
  78. if(args.timeout){
  79. setTimeout(function(){
  80. if(dfd.fired == -1){
  81. dfd.callback(new Error("Timeout"));
  82. }
  83. },
  84. args.timeout
  85. );
  86. }
  87. var self = dojox.io.windowName;
  88. if(dojo.body()){
  89. // the DOM is ready
  90. self._send(dfd, method, authElement, args.onAuthLoad);
  91. }else{
  92. // we will wait for the DOM to be ready to proceed
  93. dojo.addOnLoad(function(){
  94. self._send(dfd, method, authElement, args.onAuthLoad);
  95. });
  96. }
  97. return dfd;
  98. },
  99. _send: function(dfd, method, authTarget, onAuthLoad){
  100. var ioArgs = dfd.ioArgs;
  101. var frameNum = dojox.io.windowName._frameNum++;
  102. var sameDomainUrl = (dojo.config.dojoBlankHtmlUrl||dojo.config.dojoCallbackUrl||dojo.moduleUrl("dojo", "resources/blank.html")) + "#" + frameNum;
  103. var frameName = new dojo._Url(window.location, sameDomainUrl);
  104. var doc = dojo.doc;
  105. var frameContainer = authTarget || dojo.body();
  106. function styleFrame(frame){
  107. frame.style.width="100%";
  108. frame.style.height="100%";
  109. frame.style.border="0px";
  110. }
  111. if(dojo.isMoz && ![].reduce){
  112. // FF2 allows unsafe sibling frame modification,
  113. // the fix for this is to create nested frames with getters and setters to protect access
  114. var outerFrame = doc.createElement("iframe");
  115. styleFrame(outerFrame);
  116. if(!authTarget){
  117. outerFrame.style.display='none';
  118. }
  119. frameContainer.appendChild(outerFrame);
  120. var firstWindow = outerFrame.contentWindow;
  121. doc = firstWindow.document;
  122. doc.write("<html><body margin='0px'><iframe style='width:100%;height:100%;border:0px' name='protectedFrame'></iframe></body></html>");
  123. doc.close();
  124. var secondWindow = firstWindow[0];
  125. firstWindow.__defineGetter__(0,function(){});
  126. firstWindow.__defineGetter__("protectedFrame",function(){});
  127. doc = secondWindow.document;
  128. doc.write("<html><body margin='0px'></body></html>");
  129. doc.close();
  130. frameContainer = doc.body;
  131. }
  132. var frame;
  133. if(dojo.isIE){
  134. var div = doc.createElement("div");
  135. div.innerHTML = '<iframe name="' + frameName + '" onload="dojox.io.windowName['+frameNum+']()">';
  136. frame = div.firstChild;
  137. }else{
  138. frame = doc.createElement('iframe');
  139. }
  140. ioArgs.frame = frame;
  141. styleFrame(frame);
  142. ioArgs.outerFrame = outerFrame = outerFrame || frame;
  143. if(!authTarget){
  144. outerFrame.style.display='none';
  145. }
  146. var state = 0;
  147. function getData(){
  148. var data = frame.contentWindow.name;
  149. if(typeof data == 'string'){
  150. if(data != frameName){
  151. state = 2; // we are done now
  152. dfd.ioArgs.hash = frame.contentWindow.location.hash;
  153. dfd.callback(data);
  154. }
  155. }
  156. }
  157. dojox.io.windowName[frameNum] = frame.onload = function(){
  158. try{
  159. if(!dojo.isMoz && frame.contentWindow.location =='about:blank'){
  160. // opera and safari will do an onload for about:blank first, we can ignore this first onload
  161. return;
  162. }
  163. }catch(e){
  164. // if we are in the target domain, frame.contentWindow.location will throw an ignorable error
  165. }
  166. if(!state){
  167. // we have loaded the target resource, now time to navigate back to our domain so we can read the frame name
  168. state=1;
  169. if(authTarget){
  170. // call the callback so it can make it visible
  171. if(onAuthLoad){
  172. onAuthLoad();
  173. }
  174. }else{
  175. // we are doing a synchronous capture, go directly to our same domain URL and retrieve the resource
  176. frame.contentWindow.location = sameDomainUrl;
  177. }
  178. }
  179. // back to our domain, we should be able to access the frame name now
  180. try{
  181. if(state<2){
  182. getData();
  183. }
  184. }
  185. catch(e){
  186. }
  187. };
  188. frame.name = frameName;
  189. if(method.match(/GET/i)){
  190. // if it is a GET we can just the iframe our src url
  191. dojo._ioAddQueryToUrl(ioArgs);
  192. frame.src = ioArgs.url;
  193. frameContainer.appendChild(frame);
  194. if(frame.contentWindow){
  195. frame.contentWindow.location.replace(ioArgs.url);
  196. }
  197. }else if(method.match(/POST/i)){
  198. // if it is a POST we will build a form to post it
  199. frameContainer.appendChild(frame);
  200. var form = dojo.doc.createElement("form");
  201. dojo.body().appendChild(form);
  202. var query = dojo.queryToObject(ioArgs.query);
  203. for(var i in query){
  204. var values = query[i];
  205. values = values instanceof Array ? values : [values];
  206. for(var j = 0; j < values.length; j++){
  207. // create hidden inputs for all the parameters
  208. var input = doc.createElement("input");
  209. input.type = 'hidden';
  210. input.name = i;
  211. input.value = values[j];
  212. form.appendChild(input);
  213. }
  214. }
  215. form.method = 'POST';
  216. form.action = ioArgs.url;
  217. form.target = frameName;// connect the form to the iframe
  218. form.submit();
  219. form.parentNode.removeChild(form);
  220. }else{
  221. throw new Error("Method " + method + " not supported with the windowName transport");
  222. }
  223. if(frame.contentWindow){
  224. frame.contentWindow.name = frameName; // IE likes it afterwards
  225. }
  226. },
  227. _frameNum: 0
  228. }
  229. }