/* Copyright (c) 2004-2006, The Dojo Foundation All Rights Reserved. Licensed under the Academic Free License version 2.1 or above OR the modified BSD license. For more information on Dojo licensing, see: http://dojotoolkit.org/community/licensing.shtml */ dojo.provide("dojo.io.XhrIframeProxy"); dojo.require("dojo.experimental"); dojo.experimental("dojo.io.XhrIframeProxy"); dojo.require("dojo.io.IframeIO"); dojo.require("dojo.dom"); dojo.require("dojo.uri.Uri"); dojo.io.XhrIframeProxy = { //summary: Object that implements the iframe handling for XMLHttpRequest //IFrame Proxying. //description: Do not use this object directly. See the Dojo Book page //on XMLHttpRequest IFrame Proxying: //http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book75 //Usage of XHR IFrame Proxying does not work from local disk in Safari. xipClientUrl: djConfig["xipClientUrl"] || dojo.uri.dojoUri("src/io/xip_client.html"), _state: {}, _stateIdCounter: 0, needFrameRecursion: function(){ return (true == dojo.render.html.ie70); }, send: function(facade){ var stateId = "XhrIframeProxy" + (this._stateIdCounter++); facade._stateId = stateId; var frameUrl = this.xipClientUrl + "#0:init:id=" + stateId + "&server=" + encodeURIComponent(facade._ifpServerUrl) + "&fr=false"; if(this.needFrameRecursion()){ //IE7 hack. Need to load server URL, and have that load the xip_client.html. //Also, this server URL needs to different from the one eventually loaded by xip_client.html //Otherwise, IE7 will not load it. Funky. var fullClientUrl = window.location.href.substring(0, window.location.href.lastIndexOf("/") + 1); fullClientUrl += this.xipClientUrl; var serverUrl = facade._ifpServerUrl + (facade._ifpServerUrl.indexOf("?") == -1 ? "?" : "&") + "dojo.fr=1"; frameUrl = serverUrl + "#0:init:id=" + stateId + "&client=" + encodeURIComponent(fullClientUrl) + "&fr=" + this.needFrameRecursion(); //fr is for Frame Recursion } this._state[stateId] = { facade: facade, stateId: stateId, clientFrame: dojo.io.createIFrame(stateId, "", frameUrl) }; return stateId; }, receive: function(/*String*/stateId, /*String*/urlEncodedData){ /* urlEncodedData should have the following params: - responseHeaders - status - statusText - responseText */ //Decode response data. var response = {}; var nvPairs = urlEncodedData.split("&"); for(var i = 0; i < nvPairs.length; i++){ if(nvPairs[i]){ var nameValue = nvPairs[i].split("="); response[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]); } } //Set data on facade object. var state = this._state[stateId]; var facade = state.facade; facade._setResponseHeaders(response.responseHeaders); if(response.status == 0 || response.status){ facade.status = parseInt(response.status, 10); } if(response.statusText){ facade.statusText = response.statusText; } if(response.responseText){ facade.responseText = response.responseText; //Fix responseXML. var contentType = facade.getResponseHeader("Content-Type"); if(contentType && (contentType == "application/xml" || contentType == "text/xml")){ facade.responseXML = dojo.dom.createDocumentFromText(response.responseText, contentType); } } facade.readyState = 4; this.destroyState(stateId); }, clientFrameLoaded: function(/*String*/stateId){ var state = this._state[stateId]; var facade = state.facade; if(this.needFrameRecursion()){ var clientWindow = window.open("", state.stateId + "_clientEndPoint"); }else{ var clientWindow = state.clientFrame.contentWindow; } var reqHeaders = []; for(var param in facade._requestHeaders){ reqHeaders.push(param + ": " + facade._requestHeaders[param]); } var requestData = { uri: facade._uri }; if(reqHeaders.length > 0){ requestData.requestHeaders = reqHeaders.join("\r\n"); } if(facade._method){ requestData.method = facade._method; } if(facade._bodyData){ requestData.data = facade._bodyData; } clientWindow.send(dojo.io.argsFromMap(requestData, "utf8")); }, destroyState: function(/*String*/stateId){ var state = this._state[stateId]; if(state){ delete this._state[stateId]; var parentNode = state.clientFrame.parentNode; parentNode.removeChild(state.clientFrame); state.clientFrame = null; state = null; } }, createFacade: function(){ if(arguments && arguments[0] && arguments[0]["iframeProxyUrl"]){ return new dojo.io.XhrIframeFacade(arguments[0]["iframeProxyUrl"]); }else{ return dojo.io.XhrIframeProxy.oldGetXmlhttpObject.apply(dojo.hostenv, arguments); } } } //Replace the normal XHR factory with the proxy one. dojo.io.XhrIframeProxy.oldGetXmlhttpObject = dojo.hostenv.getXmlhttpObject; dojo.hostenv.getXmlhttpObject = dojo.io.XhrIframeProxy.createFacade; /** Using this a reference: http://www.w3.org/TR/XMLHttpRequest/ Does not implement the onreadystate callback since dojo.io.BrowserIO does not use it. */ dojo.io.XhrIframeFacade = function(ifpServerUrl){ //summary: XMLHttpRequest facade object used by dojo.io.XhrIframeProxy. //description: Do not use this object directly. See the Dojo Book page //on XMLHttpRequest IFrame Proxying: //http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book75 this._requestHeaders = {}; this._allResponseHeaders = null; this._responseHeaders = {}; this._method = null; this._uri = null; this._bodyData = null; this.responseText = null; this.responseXML = null; this.status = null; this.statusText = null; this.readyState = 0; this._ifpServerUrl = ifpServerUrl; this._stateId = null; } dojo.lang.extend(dojo.io.XhrIframeFacade, { //The open method does not properly reset since Dojo does not reuse XHR objects. open: function(/*String*/method, /*String*/uri){ this._method = method; this._uri = uri; this.readyState = 1; }, setRequestHeader: function(/*String*/header, /*String*/value){ this._requestHeaders[header] = value; }, send: function(/*String*/stringData){ this._bodyData = stringData; this._stateId = dojo.io.XhrIframeProxy.send(this); this.readyState = 2; }, abort: function(){ dojo.io.XhrIframeProxy.destroyState(this._stateId); }, getAllResponseHeaders: function(){ return this._allResponseHeaders; //String }, getResponseHeader: function(/*String*/header){ return this._responseHeaders[header]; //String }, _setResponseHeaders: function(/*String*/allHeaders){ if(allHeaders){ this._allResponseHeaders = allHeaders; //Make sure ther are now CR characters in the headers. allHeaders = allHeaders.replace(/\r/g, ""); var nvPairs = allHeaders.split("\n"); for(var i = 0; i < nvPairs.length; i++){ if(nvPairs[i]){ var nameValue = nvPairs[i].split(": "); this._responseHeaders[nameValue[0]] = nameValue[1]; } } } } });