Rev 1422 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
<!-- Security protection: uncomment the script tag to enable. -->
<!-- script type="text/javascript" -->
// <!--
/*
This file is really focused on just sending one message to the server, and
receiving one response. The code does not expect to be re-used for multiple messages.
This might be reworked later if performance indicates a need for it.
xip fragment identifier/hash values have the form:
#id:cmd:realEncodedMessage
id: some ID that should be unique among messages. No inherent meaning,
just something to make sure the hash value is unique so the message
receiver knows a new message is available.
cmd: command to the receiver. Valid values are:
- init: message used to init the frame. Sent as the first URL when loading
the page. Contains some config parameters.
- loaded: the remote frame is loaded. Only sent from server to client.
- ok: the message that this page sent was received OK. The next message may
now be sent.
- start: the start message of a block of messages (a complete message may
need to be segmented into many messages to get around the limitiations
of the size of an URL that a browser accepts.
- part: indicates this is a part of a message.
- end: the end message of a block of messages. The message can now be acted upon.
If the message is small enough that it doesn't need to be segmented, then
just one hash value message can be sent with "end" as the command.
To reassemble a segmented message, the realEncodedMessage parts just have to be concatenated
together.
*/
//MSIE has the lowest limit for URLs with fragment identifiers,
//at around 4K. Choosing a slightly smaller number for good measure.
xipUrlLimit = 4000;
xipIdCounter = 1;
function xipInit(){
xipStateId = "";
xipIsSending = false;
xipServerUrl = null;
xipStateId = null;
xipRequestData = null;
xipCurrentHash = "";
xipResponseMessage = "";
xipRequestParts = [];
xipPartIndex = 0;
xipServerWindow = null;
xipUseFrameRecursion = false;
}
xipInit();
function send(encodedData){
if(xipUseFrameRecursion == "true"){
var clientEndPoint = window.open(xipStateId + "_clientEndPoint");
clientEndPoint.send(encodedData);
}else{
if(!xipIsSending){
xipIsSending = true;
xipRequestData = encodedData || "";
//Get a handle to the server iframe.
xipServerWindow = frames[xipStateId + "_frame"];
if (!xipServerWindow){
xipServerWindow = document.getElementById(xipStateId + "_frame").contentWindow;
}
sendRequestStart();
}
}
}
//Modify the server URL if it is a local path and
//This is done for local/same domain testing.
function fixServerUrl(ifpServerUrl){
if(ifpServerUrl.indexOf("..") == 0){
var parts = ifpServerUrl.split("/");
ifpServerUrl = parts[parts.length - 1];
}
return ifpServerUrl;
}
function pollHash(){
//Can't use location.hash because at least Firefox does a decodeURIComponent on it.
var urlParts = window.location.href.split("#");
if(urlParts.length == 2){
var newHash = urlParts[1];
if(newHash != xipCurrentHash){
try{
messageReceived(newHash);
}catch(e){
//Make sure to not keep processing the error hash value.
xipCurrentHash = newHash;
throw e;
}
xipCurrentHash = newHash;
}
}
}
function messageReceived(encodedData){
var msg = unpackMessage(encodedData);
switch(msg.command){
case "loaded":
xipMasterFrame.dojo.io.XhrIframeProxy.clientFrameLoaded(xipStateId);
break;
case "ok":
sendRequestPart();
break;
case "start":
xipResponseMessage = "";
xipResponseMessage += msg.message;
setServerUrl("ok");
break;
case "part":
xipResponseMessage += msg.message;
setServerUrl("ok");
break;
case "end":
setServerUrl("ok");
xipResponseMessage += msg.message;
xipMasterFrame.dojo.io.XhrIframeProxy.receive(xipStateId, xipResponseMessage);
break;
}
}
function sendRequestStart(){
//Break the message into parts, if necessary.
xipRequestParts = [];
var reqData = xipRequestData;
var urlLength = xipServerUrl.length;
var partLength = xipUrlLimit - urlLength;
var reqIndex = 0;
while((reqData.length - reqIndex) + urlLength > xipUrlLimit){
var part = reqData.substring(reqIndex, reqIndex + partLength);
//Safari will do some extra hex escaping unless we keep the original hex
//escaping complete.
var percentIndex = part.lastIndexOf("%");
if(percentIndex == part.length - 1 || percentIndex == part.length - 2){
part = part.substring(0, percentIndex);
}
xipRequestParts.push(part);
reqIndex += part.length;
}
xipRequestParts.push(reqData.substring(reqIndex, reqData.length));
xipPartIndex = 0;
sendRequestPart();
}
function sendRequestPart(){
if(xipPartIndex < xipRequestParts.length){
//Get the message part.
var partData = xipRequestParts[xipPartIndex];
//Get the command.
var cmd = "part";
if(xipPartIndex + 1 == xipRequestParts.length){
cmd = "end";
}else if (xipPartIndex == 0){
cmd = "start";
}
setServerUrl(cmd, partData);
xipPartIndex++;
}
}
function setServerUrl(cmd, message){
var serverUrl = makeServerUrl(cmd, message);
//Safari won't let us replace across domains.
if(navigator.userAgent.indexOf("Safari") == -1){
xipServerWindow.location.replace(serverUrl);
}else{
xipServerWindow.location = serverUrl;
}
}
function makeServerUrl(cmd, message){
var serverUrl = xipServerUrl + "#" + (xipIdCounter++) + ":" + cmd;
if(message){
serverUrl += ":" + message;
}
return serverUrl;
}
function unpackMessage(encodedMessage){
var parts = encodedMessage.split(":");
var command = parts[1];
encodedMessage = parts[2] || "";
var config = null;
if(command == "init"){
var configParts = encodedMessage.split("&");
config = {};
for(var i = 0; i < configParts.length; i++){
var nameValue = configParts[i].split("=");
config[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
}
}
return {command: command, message: encodedMessage, config: config};
}
function onClientLoad(){
//Decode the init params
var config = unpackMessage(window.location.href.split("#")[1]).config;
xipStateId = config.id;
//Remove the query param for the IE7 recursive case.
xipServerUrl = fixServerUrl(config.server).replace(/(\?|\&)dojo\.fr\=1/, "");
//Make sure we don't have a javascript: url, just for good measure.
if(xipServerUrl.split(":")[0].match(/javascript/i)){
throw "Invalid server URL";
}
xipUseFrameRecursion = config["fr"];
if(xipUseFrameRecursion == "endpoint"){
xipMasterFrame = parent.parent;
}else{
xipMasterFrame = parent;
}
//Start counter to inspect hash value.
setInterval(pollHash, 10);
var clientUrl = window.location.href.split("#")[0];
var iframeNode = document.getElementsByTagName("iframe")[0];
iframeNode.id = xipStateId + "_frame";
iframeNode.src = makeServerUrl("init", 'id=' + xipStateId + '&client='
+ encodeURIComponent(clientUrl) + '&fr=' + xipUseFrameRecursion);
}
if(typeof(window.addEventListener) == "undefined"){
window.attachEvent("onload", onClientLoad);
}else{
window.addEventListener('load', onClientLoad, false);
}
// -->
</script>
</head>
<body>
<h4>The Dojo Toolkit -- xip_client.html</h4>
<p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the "client" file used
internally by dojo.io.XhrIframeProxy.</p>
<iframe src="javascript:false"></iframe>
</body>
</html>