xip_server.html 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. <!--
  2. /*
  3. Copyright (c) 2004-2006, The Dojo Foundation
  4. All Rights Reserved.
  5. Licensed under the Academic Free License version 2.1 or above OR the
  6. modified BSD license. For more information on Dojo licensing, see:
  7. http://dojotoolkit.org/community/licensing.shtml
  8. */
  9. Pieces taken from Dojo source to make this file stand-alone
  10. -->
  11. <html>
  12. <head>
  13. <title></title>
  14. <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
  15. <script type="text/javascript" src="isAllowed.js"></script>
  16. <!--
  17. BY DEFAULT THIS FILE DOES NOT WORK SO THAT YOU DON'T ACCIDENTALLY EXPOSE
  18. ALL OF YOUR XHR-ENABLED SERVICES ON YOUR SITE.
  19. In order for this file to work, you need to uncomment the start and end script tags,
  20. and you should define a function with the following signature:
  21. function isAllowedRequest(request){
  22. return false;
  23. }
  24. Return true out of the function if you want to allow the cross-domain request.
  25. DON'T DEFINE THIS FUNCTION IN THIS FILE! Define it in a separate file called isAllowed.js
  26. and include it in this page with a script tag that has a src attribute pointing to the file.
  27. See the very first script tag in this file for an example. You do not have to place the
  28. script file in the same directory as this file, just update the path above if you move it
  29. somewhere else.
  30. Customize the isAllowedRequest function to restrict what types of requests are allowed
  31. for this server. The request object has the following properties:
  32. - requestHeaders: an object with the request headers that are to be added to
  33. the XHR request.
  34. - method: the HTTP method (GET, POST, etc...)
  35. - uri: The URI for the request.
  36. - data: The URL-encoded data for the request. For a GET request, this would
  37. be the querystring parameters. For a POST request, it wll be the
  38. body data.
  39. See xip_client.html for more info on the xip fragment identifier protocol.
  40. -->
  41. <!-- Security protection: uncomment the script tag to enable. -->
  42. <!-- script type="text/javascript" -->
  43. // <!--
  44. //Core XHR handling taken from Dojo IO code.
  45. dojo = {};
  46. dojo.hostenv = {};
  47. // These are in order of decreasing likelihood; this will change in time.
  48. dojo.hostenv._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
  49. dojo.hostenv.getXmlhttpObject = function(){
  50. var http = null;
  51. var last_e = null;
  52. try{ http = new XMLHttpRequest(); }catch(e){}
  53. if(!http){
  54. for(var i=0; i<3; ++i){
  55. var progid = dojo.hostenv._XMLHTTP_PROGIDS[i];
  56. try{
  57. http = new ActiveXObject(progid);
  58. }catch(e){
  59. last_e = e;
  60. }
  61. if(http){
  62. dojo.hostenv._XMLHTTP_PROGIDS = [progid]; // so faster next time
  63. break;
  64. }
  65. }
  66. /*if(http && !http.toString) {
  67. http.toString = function() { "[object XMLHttpRequest]"; }
  68. }*/
  69. }
  70. if(!http){
  71. throw "xip_server.html: XMLHTTP not available: " + last_e;
  72. }
  73. return http;
  74. }
  75. dojo.setHeaders = function(http, headers){
  76. if(headers) {
  77. for(var header in headers) {
  78. var headerValue = headers[header];
  79. http.setRequestHeader(header, headerValue);
  80. }
  81. }
  82. }
  83. //MSIE has the lowest limit for URLs with fragment identifiers,
  84. //at around 4K. Choosing a slightly smaller number for good measure.
  85. xipUrlLimit = 4000;
  86. xipIdCounter = 1;
  87. function xipServerInit(){
  88. xipStateId = "";
  89. xipCurrentHash = "";
  90. xipRequestMessage = "";
  91. xipResponseParts = [];
  92. xipPartIndex = 0;
  93. }
  94. function pollHash(){
  95. //Can't use location.hash because at least Firefox does a decodeURIComponent on it.
  96. var urlParts = window.location.href.split("#");
  97. if(urlParts.length == 2){
  98. var newHash = urlParts[1];
  99. if(newHash != xipCurrentHash){
  100. try{
  101. messageReceived(newHash);
  102. }catch(e){
  103. //Make sure to not keep processing the error hash value.
  104. xipCurrentHash = newHash;
  105. throw e;
  106. }
  107. xipCurrentHash = newHash;
  108. }
  109. }
  110. }
  111. function messageReceived(encodedData){
  112. var msg = unpackMessage(encodedData);
  113. switch(msg.command){
  114. case "ok":
  115. sendResponsePart();
  116. break;
  117. case "start":
  118. xipRequestMessage = "";
  119. xipRequestMessage += msg.message;
  120. setClientUrl("ok");
  121. break;
  122. case "part":
  123. xipRequestMessage += msg.message;
  124. setClientUrl("ok");
  125. break;
  126. case "end":
  127. setClientUrl("ok");
  128. xipRequestMessage += msg.message;
  129. sendXhr();
  130. break;
  131. }
  132. }
  133. function sendResponse(encodedData){
  134. //Break the message into parts, if necessary.
  135. xipResponseParts = [];
  136. var resData = encodedData;
  137. var urlLength = xipClientUrl.length;
  138. var partLength = xipUrlLimit - urlLength;
  139. var resIndex = 0;
  140. while((resData.length - resIndex) + urlLength > xipUrlLimit){
  141. var part = resData.substring(resIndex, resIndex + partLength);
  142. //Safari will do some extra hex escaping unless we keep the original hex
  143. //escaping complete.
  144. var percentIndex = part.lastIndexOf("%");
  145. if(percentIndex == part.length - 1 || percentIndex == part.length - 2){
  146. part = part.substring(0, percentIndex);
  147. }
  148. xipResponseParts.push(part);
  149. resIndex += part.length;
  150. }
  151. xipResponseParts.push(resData.substring(resIndex, resData.length));
  152. xipPartIndex = 0;
  153. sendResponsePart();
  154. }
  155. function sendResponsePart(){
  156. if(xipPartIndex < xipResponseParts.length){
  157. //Get the message part.
  158. var partData = xipResponseParts[xipPartIndex];
  159. //Get the command.
  160. var cmd = "part";
  161. if(xipPartIndex + 1 == xipResponseParts.length){
  162. cmd = "end";
  163. }else if (xipPartIndex == 0){
  164. cmd = "start";
  165. }
  166. setClientUrl(cmd, partData);
  167. xipPartIndex++;
  168. }else{
  169. xipServerInit();
  170. }
  171. }
  172. function setClientUrl(cmd, message){
  173. var clientUrl = makeClientUrl(cmd, message);
  174. //Safari won't let us replace across domains.
  175. if(navigator.userAgent.indexOf("Safari") == -1){
  176. parent.location.replace(clientUrl);
  177. }else{
  178. parent.location = clientUrl;
  179. }
  180. }
  181. function makeClientUrl(cmd, message){
  182. var clientUrl = xipClientUrl + "#" + (xipIdCounter++) + ":" + cmd;
  183. if(message){
  184. clientUrl += ":" + message;
  185. }
  186. return clientUrl
  187. }
  188. function xhrDone(xhr){
  189. /* Need to pull off and return the following data:
  190. - responseHeaders
  191. - status
  192. - statusText
  193. - responseText
  194. */
  195. var response = {};
  196. if(typeof(xhr.getAllResponseHeaders) != "undefined"){
  197. var allHeaders = xhr.getAllResponseHeaders();
  198. if(allHeaders){
  199. response.responseHeaders = allHeaders;
  200. }
  201. }
  202. if(xhr.status == 0 || xhr.status){
  203. response.status = xhr.status;
  204. }
  205. if(xhr.statusText){
  206. response.statusText = xhr.statusText;
  207. }
  208. if(xhr.responseText){
  209. response.responseText = xhr.responseText;
  210. }
  211. //Build a string of the response object.
  212. var result = "";
  213. var isFirst = true;
  214. for (var param in response){
  215. if(isFirst){
  216. isFirst = false;
  217. }else{
  218. result += "&";
  219. }
  220. result += param + "=" + encodeURIComponent(response[param]);
  221. }
  222. sendResponse(result);
  223. }
  224. function sendXhr(){
  225. var request = {};
  226. var nvPairs = xipRequestMessage.split("&");
  227. var i = 0;
  228. var nameValue = null;
  229. for(i = 0; i < nvPairs.length; i++){
  230. if(nvPairs[i]){
  231. var nameValue = nvPairs[i].split("=");
  232. request[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
  233. }
  234. }
  235. //Split up the request headers, if any.
  236. var headers = {};
  237. if(request.requestHeaders){
  238. nvPairs = request.requestHeaders.split("\r\n");
  239. for(i = 0; i < nvPairs.length; i++){
  240. if(nvPairs[i]){
  241. nameValue = nvPairs[i].split(": ");
  242. headers[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
  243. }
  244. }
  245. request.requestHeaders = headers;
  246. }
  247. if(isAllowedRequest(request)){
  248. //The request is allowed, so set up the XHR object.
  249. var xhr = dojo.hostenv.getXmlhttpObject();
  250. //Start timer to look for readyState.
  251. var xhrIntervalId = setInterval(function(){
  252. if(xhr.readyState == 4){
  253. clearInterval(xhrIntervalId);
  254. xhrDone(xhr);
  255. }
  256. }, 10);
  257. //Actually start up the XHR request.
  258. xhr.open(request.method, request.uri, true);
  259. dojo.setHeaders(xhr, request.requestHeaders);
  260. var content = "";
  261. if(request.data){
  262. content = request.data;
  263. }
  264. try{
  265. xhr.send(content);
  266. }catch(e){
  267. if(typeof xhr.abort == "function"){
  268. xhr.abort();
  269. xhrDone({status: 404, statusText: "xip_server.html error: " + e});
  270. }
  271. }
  272. }
  273. }
  274. function unpackMessage(encodedMessage){
  275. var parts = encodedMessage.split(":");
  276. var command = parts[1];
  277. encodedMessage = parts[2] || "";
  278. var config = null;
  279. if(command == "init"){
  280. var configParts = encodedMessage.split("&");
  281. config = {};
  282. for(var i = 0; i < configParts.length; i++){
  283. var nameValue = configParts[i].split("=");
  284. config[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
  285. }
  286. }
  287. return {command: command, message: encodedMessage, config: config};
  288. }
  289. function onServerLoad(){
  290. xipServerInit();
  291. //Decode the init params
  292. var config = unpackMessage(window.location.href.split("#")[1]).config;
  293. xipStateId = config.id;
  294. xipClientUrl = config.client;
  295. //Make sure we don't have a javascript: url, just for good measure.
  296. if(xipClientUrl.split(":")[0].match(/javascript/i)){
  297. throw "Invalid client URL";
  298. }
  299. if(!xipStateId.match(/^XhrIframeProxy[0-9]+$/)){
  300. throw "Invalid state ID";
  301. }
  302. xipUseFrameRecursion = config["fr"];
  303. setInterval(pollHash, 10);
  304. if(xipUseFrameRecursion == "true"){
  305. var serverUrl = window.location.href.split("#")[0];
  306. document.getElementById("iframeHolder").innerHTML = '<iframe name="'
  307. + xipStateId + '_clientEndPoint'
  308. + '" src="javascript:false">'
  309. + '</iframe>';
  310. var iframeNode = document.getElementsByTagName("iframe")[0];
  311. iframeNode.src = makeClientUrl("init", 'id=' + xipStateId + '&server='
  312. + encodeURIComponent(serverUrl) + '&fr=endpoint');
  313. }else{
  314. setClientUrl("loaded");
  315. }
  316. }
  317. if(typeof(window.addEventListener) == "undefined"){
  318. window.attachEvent("onload", onServerLoad);
  319. }else{
  320. window.addEventListener('load', onServerLoad, false);
  321. }
  322. // -->
  323. <!-- </script> -->
  324. </head>
  325. <body>
  326. <h4>The Dojo Toolkit -- xip_server.html</h4>
  327. <p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the the file
  328. that should go on the server that will actually be doing the XHR request.</p>
  329. <div id="iframeHolder"></div>
  330. </body>
  331. </html>