root / trunk / src / io / xip_client.html

Revision 8613, 7.8 kB (checked in by jburke, 20 months ago)

Fixes #3011

  • Property svn:eol-style set to native
Line 
1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
4<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5<head>
6        <title></title>
7        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
8        <!-- Security protection: uncomment the script tag to enable. -->
9        <!-- script type="text/javascript" -->
10        // <!--
11        /*
12        This file is really focused on just sending one message to the server, and
13        receiving one response. The code does not expect to be re-used for multiple messages.
14        This might be reworked later if performance indicates a need for it.
15       
16        xip fragment identifier/hash values have the form:
17        #id:cmd:realEncodedMessage
18
19        id: some ID that should be unique among messages. No inherent meaning,
20                just something to make sure the hash value is unique so the message
21                receiver knows a new message is available.
22               
23        cmd: command to the receiver. Valid values are:
24                 - init: message used to init the frame. Sent as the first URL when loading
25                         the page. Contains some config parameters.
26                 - loaded: the remote frame is loaded. Only sent from server to client.
27                 - ok: the message that this page sent was received OK. The next message may
28                       now be sent.
29                 - start: the start message of a block of messages (a complete message may
30                          need to be segmented into many messages to get around the limitiations
31                          of the size of an URL that a browser accepts.
32                 - part: indicates this is a part of a message.
33                 - end: the end message of a block of messages. The message can now be acted upon.
34                        If the message is small enough that it doesn't need to be segmented, then
35                        just one hash value message can be sent with "end" as the command.
36       
37        To reassemble a segmented message, the realEncodedMessage parts just have to be concatenated
38        together.
39        */
40
41        //MSIE has the lowest limit for URLs with fragment identifiers,
42        //at around 4K. Choosing a slightly smaller number for good measure.
43        xipUrlLimit = 4000;
44        xipIdCounter = 1;
45
46        function xipInit(){
47                xipStateId = "";
48                xipIsSending = false;
49                xipServerUrl = null;
50                xipStateId = null;
51                xipRequestData = null;
52                xipCurrentHash = "";
53                xipResponseMessage = "";
54                xipRequestParts = [];
55                xipPartIndex = 0;
56                xipServerWindow = null;
57                xipUseFrameRecursion = false;
58        }
59        xipInit();
60       
61        function send(encodedData){
62                if(xipUseFrameRecursion == "true"){
63                        var clientEndPoint = window.open(xipStateId + "_clientEndPoint");
64                        clientEndPoint.send(encodedData);
65                }else{
66                        if(!xipIsSending){
67                                xipIsSending = true;
68       
69                                xipRequestData = encodedData || "";
70
71                                //Get a handle to the server iframe.
72                                xipServerWindow = frames[xipStateId + "_frame"];
73                                if (!xipServerWindow){
74                                        xipServerWindow = document.getElementById(xipStateId + "_frame").contentWindow;
75                                }
76       
77                                sendRequestStart();
78                        }
79                }
80        }
81
82        //Modify the server URL if it is a local path and
83        //This is done for local/same domain testing.
84        function fixServerUrl(ifpServerUrl){
85                if(ifpServerUrl.indexOf("..") == 0){
86                        var parts = ifpServerUrl.split("/");
87                        ifpServerUrl = parts[parts.length - 1];
88                }
89                return ifpServerUrl;
90        }
91       
92       
93        function pollHash(){
94                //Can't use location.hash because at least Firefox does a decodeURIComponent on it.
95                var urlParts = window.location.href.split("#");
96                if(urlParts.length == 2){
97                        var newHash = urlParts[1];
98                        if(newHash != xipCurrentHash){
99                                try{
100                                        messageReceived(newHash);
101                                }catch(e){
102                                        //Make sure to not keep processing the error hash value.
103                                        xipCurrentHash = newHash;
104                                        throw e;
105                                }
106                                xipCurrentHash = newHash;
107                        }
108                }
109        }
110
111        function messageReceived(encodedData){
112                var msg = unpackMessage(encodedData);
113
114                switch(msg.command){
115                        case "loaded":
116                                xipMasterFrame.dojo.io.XhrIframeProxy.clientFrameLoaded(xipStateId);
117                                break;
118                        case "ok":
119                                sendRequestPart();
120                                break;
121                        case "start":
122                                xipResponseMessage = "";
123                                xipResponseMessage += msg.message;
124                                setServerUrl("ok");
125                                break;
126                        case "part":
127                                xipResponseMessage += msg.message;                     
128                                setServerUrl("ok");
129                                break;
130                        case "end":
131                                setServerUrl("ok");
132                                xipResponseMessage += msg.message;
133                                xipMasterFrame.dojo.io.XhrIframeProxy.receive(xipStateId, xipResponseMessage);
134                                break;
135                }
136        }
137       
138        function sendRequestStart(){
139                //Break the message into parts, if necessary.
140                xipRequestParts = [];
141                var reqData = xipRequestData;
142                var urlLength = xipServerUrl.length;
143                var partLength = xipUrlLimit - urlLength;
144                var reqIndex = 0;
145
146                while((reqData.length - reqIndex) + urlLength > xipUrlLimit){
147                        var part = reqData.substring(reqIndex, reqIndex + partLength);
148                        //Safari will do some extra hex escaping unless we keep the original hex
149                        //escaping complete.
150                        var percentIndex = part.lastIndexOf("%");
151                        if(percentIndex == part.length - 1 || percentIndex == part.length - 2){
152                                part = part.substring(0, percentIndex);
153                        }
154                        xipRequestParts.push(part);
155                        reqIndex += part.length;
156                }
157                xipRequestParts.push(reqData.substring(reqIndex, reqData.length));
158               
159                xipPartIndex = 0;
160                sendRequestPart();
161               
162        }
163       
164        function sendRequestPart(){
165                if(xipPartIndex < xipRequestParts.length){
166                        //Get the message part.
167                        var partData = xipRequestParts[xipPartIndex];
168
169                        //Get the command.
170                        var cmd = "part";
171                        if(xipPartIndex + 1 == xipRequestParts.length){
172                                cmd = "end";
173                        }else if (xipPartIndex == 0){
174                                cmd = "start";
175                        }
176                       
177                        setServerUrl(cmd, partData);
178                        xipPartIndex++;
179                }
180        }
181       
182        function setServerUrl(cmd, message){
183                var serverUrl = makeServerUrl(cmd, message);
184
185                //Safari won't let us replace across domains.
186                if(navigator.userAgent.indexOf("Safari") == -1){
187                        xipServerWindow.location.replace(serverUrl);
188                }else{
189                        xipServerWindow.location = serverUrl;
190                }
191        }
192       
193        function makeServerUrl(cmd, message){
194                var serverUrl = xipServerUrl + "#" + (xipIdCounter++) + ":" + cmd;
195                if(message){
196                        serverUrl += ":" + message;
197                }
198                return serverUrl;
199        }
200
201        function unpackMessage(encodedMessage){
202                var parts = encodedMessage.split(":");
203                var command = parts[1];
204                encodedMessage = parts[2] || "";
205
206                var config = null;
207                if(command == "init"){
208                        var configParts = encodedMessage.split("&");
209                        config = {};
210                        for(var i = 0; i < configParts.length; i++){
211                                var nameValue = configParts[i].split("=");
212                                config[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
213                        }
214                }
215                return {command: command, message: encodedMessage, config: config};
216        }
217
218        function onClientLoad(){
219                //Decode the init params
220                var config = unpackMessage(window.location.href.split("#")[1]).config;
221
222                xipStateId = config.id;
223
224                //Remove the query param for the IE7 recursive case.
225                xipServerUrl = fixServerUrl(config.server).replace(/(\?|\&)dojo\.fr\=1/, "");
226               
227                //Make sure we don't have a javascript: url, just for good measure.
228                if(xipServerUrl.split(":")[0].match(/javascript/i)){
229                        throw "Invalid server URL";
230                }
231
232                xipUseFrameRecursion = config["fr"];
233               
234                if(xipUseFrameRecursion == "endpoint"){
235                        xipMasterFrame = parent.parent;
236                }else{
237                        xipMasterFrame = parent;
238                }
239               
240                //Start counter to inspect hash value.
241                setInterval(pollHash, 10);
242
243                var clientUrl = window.location.href.split("#")[0];
244                var iframeNode = document.getElementsByTagName("iframe")[0];
245                iframeNode.id = xipStateId + "_frame";
246                iframeNode.src = makeServerUrl("init", 'id=' + xipStateId + '&client='
247                        + encodeURIComponent(clientUrl) + '&fr=' + xipUseFrameRecursion);
248        }
249
250        if(typeof(window.addEventListener) == "undefined"){
251                window.attachEvent("onload", onClientLoad);
252        }else{
253                window.addEventListener('load', onClientLoad, false);
254        }
255       
256        // -->
257        </script>
258</head>
259<body>
260        <h4>The Dojo Toolkit -- xip_client.html</h4>
261
262        <p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the "client" file used
263        internally by dojo.io.XhrIframeProxy.</p>
264       
265        <iframe src="javascript:false"></iframe>
266</body>
267</html>
Note: See TracBrowser for help on using the browser.