Project

General

Profile

Statistics
| Revision:

root / trunk / web / dojo / dojox / io / proxy / xip_server.html

History | View | Annotate | Download (10.2 KB)

1 9 andrej.cim
<!--
2
        /*
3
                Copyright (c) 2004-2010, The Dojo Foundation
4
                All Rights Reserved.
5

6
                Licensed under the Academic Free License version 2.1 or above OR the
7
                modified BSD license. For more information on Dojo licensing, see:
8

9
                        http://dojotoolkit.org/community/licensing.shtml
10
        */
11
        Pieces taken from Dojo source to make this file stand-alone
12
-->
13
<html>
14
<head>
15
        <title></title>
16
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
17
        <script type="text/javascript" src="isAllowed.js"></script>
18
        <!--
19
        BY DEFAULT THIS FILE DOES NOT WORK SO THAT YOU DON'T ACCIDENTALLY EXPOSE
20
        ALL OF YOUR XHR-ENABLED SERVICES ON YOUR SITE.
21

22
        In order for this file to work, you need to uncomment the start and end script tags,
23
        and you should define a function with the following signature:
24

25
        function isAllowedRequest(request){
26
                return false;
27
        }
28

29
        Return true out of the function if you want to allow the cross-domain request.
30

31
        DON'T DEFINE THIS FUNCTION IN THIS FILE! Define it in a separate file called isAllowed.js
32
        and include it in this page with a script tag that has a src attribute pointing to the file.
33
        See the very first script tag in this file for an example. You do not have to place the
34
        script file in the same directory as this file, just update the path above if you move it
35
        somewhere else.
36

37
        Customize the isAllowedRequest function to restrict what types of requests are allowed
38
        for this server. The request object has the following properties:
39
        - requestHeaders: an object with the request headers that are to be added to
40
                          the XHR request.
41
        - method: the HTTP method (GET, POST, etc...)
42
        - uri: The URI for the request.
43
        - data: The URL-encoded data for the request. For a GET request, this would
44
                be the querystring parameters. For a POST request, it wll be the
45
                body data.
46

47
        See xip_client.html for more info on the xip fragment identifier protocol.
48
        -->
49
50
        <!-- Security protection: uncomment the script tag to enable. -->
51
        <!-- script type="text/javascript" -->
52
        // <!--
53
                //Core XHR handling taken from Dojo IO code.
54
                dojo = {};
55
                dojo.hostenv = {};
56
                // These are in order of decreasing likelihood; this will change in time.
57
                dojo.hostenv._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
58

59
                dojo.hostenv.getXmlhttpObject = function(){
60
                                var http = null;
61
                        var last_e = null;
62
                        try{ http = new XMLHttpRequest(); }catch(e){}
63
                                if(!http){
64
                                for(var i=0; i<3; ++i){
65
                                        var progid = dojo.hostenv._XMLHTTP_PROGIDS[i];
66
                                        try{
67
                                                http = new ActiveXObject(progid);
68
                                        }catch(e){
69
                                                last_e = e;
70
                                        }
71

72
                                        if(http){
73
                                                dojo.hostenv._XMLHTTP_PROGIDS = [progid];  // so faster next time
74
                                                break;
75
                                        }
76
                                }
77

78
                                /*if(http && !http.toString) {
79
                                        http.toString = function() { "[object XMLHttpRequest]"; }
80
                                }*/
81
                        }
82

83
                        if(!http){
84
                                throw "xip_server.html: XMLHTTP not available: " + last_e;
85
                        }
86

87
                        return http;
88
                }
89

90
                dojo.setHeaders = function(http, headers){
91
                        if(headers) {
92
                                for(var header in headers) {
93
                                        var headerValue = headers[header];
94
                                        http.setRequestHeader(header, headerValue);
95
                                }
96
                        }
97
                }
98

99
        //MSIE has the lowest limit for URLs with fragment identifiers,
100
        //at around 4K. Choosing a slightly smaller number for good measure.
101
        xipUrlLimit = 4000;
102
        xipIdCounter = 1;
103

104
        function xipServerInit(){
105
                xipStateId = "";
106
                xipCurrentHash = "";
107
                xipRequestMessage = "";
108
                xipResponseParts = [];
109
                xipPartIndex = 0;
110
        }
111

112
        function pollHash(){
113
                //Can't use location.hash because at least Firefox does a decodeURIComponent on it.
114
                var urlParts = window.location.href.split("#");
115
                if(urlParts.length == 2){
116
                        var newHash = urlParts[1];
117
                        if(newHash != xipCurrentHash){
118
                                try{
119
                                        messageReceived(newHash);
120
                                }catch(e){
121
                                        //Make sure to not keep processing the error hash value.
122
                                        xipCurrentHash = newHash;
123
                                        throw e;
124
                                }
125
                                xipCurrentHash = newHash;
126
                        }
127
                }
128
        }
129

130
        function messageReceived(encodedData){
131
                var msg = unpackMessage(encodedData);
132

133
                switch(msg.command){
134
                        case "ok":
135
                                sendResponsePart();
136
                                break;
137
                        case "start":
138
                                xipRequestMessage = "";
139
                                xipRequestMessage += msg.message;
140
                                setClientUrl("ok");
141
                                break;
142
                        case "part":
143
                                xipRequestMessage += msg.message;
144
                                setClientUrl("ok");
145
                                break;
146
                        case "end":
147
                                setClientUrl("ok");
148
                                xipRequestMessage += msg.message;
149
                                sendXhr();
150
                                break;
151
                }
152
        }
153

154
        function sendResponse(encodedData){
155
                //Break the message into parts, if necessary.
156
                xipResponseParts = [];
157
                var resData = encodedData;
158
                var urlLength = xipClientUrl.length;
159
                var partLength = xipUrlLimit - urlLength;
160
                var resIndex = 0;
161

162
                while((resData.length - resIndex) + urlLength > xipUrlLimit){
163
                        var part = resData.substring(resIndex, resIndex + partLength);
164
                        //Safari will do some extra hex escaping unless we keep the original hex
165
                        //escaping complete.
166
                        var percentIndex = part.lastIndexOf("%");
167
                        if(percentIndex == part.length - 1 || percentIndex == part.length - 2){
168
                                part = part.substring(0, percentIndex);
169
                        }
170
                        xipResponseParts.push(part);
171
                        resIndex += part.length;
172
                }
173
                xipResponseParts.push(resData.substring(resIndex, resData.length));
174

175
                xipPartIndex = 0;
176
                sendResponsePart();
177
        }
178

179
        function sendResponsePart(){
180
                if(xipPartIndex < xipResponseParts.length){
181
                        //Get the message part.
182
                        var partData = xipResponseParts[xipPartIndex];
183

184
                        //Get the command.
185
                        var cmd = "part";
186
                        if(xipPartIndex + 1 == xipResponseParts.length){
187
                                cmd = "end";
188
                        }else if (xipPartIndex == 0){
189
                                cmd = "start";
190
                        }
191

192
                        setClientUrl(cmd, partData);
193
                        xipPartIndex++;
194
                }else{
195
                        xipServerInit();
196
                }
197
        }
198

199
        function setClientUrl(cmd, message){
200
                var clientUrl = makeClientUrl(cmd, message);
201
                //Safari won't let us replace across domains.
202
                if(navigator.userAgent.indexOf("Safari") == -1){
203
                        xipClientWindow.location.replace(clientUrl);
204
                }else{
205
                        xipClientWindow.location = clientUrl;
206
                }
207
        }
208

209
        function makeClientUrl(cmd, message){
210
                var clientUrl = xipClientUrl + "#" + (xipIdCounter++) + ":" + cmd;
211
                if(message){
212
                        clientUrl += ":" + message;
213
                }
214
                return clientUrl
215
        }
216

217
        function xhrDone(xhr){
218
                /* Need to pull off and return the following data:
219
                        - responseHeaders
220
                        - status
221
                        - statusText
222
                        - responseText
223
                */
224
                var response = {};
225

226
                if(typeof(xhr.getAllResponseHeaders) != "undefined"){
227
                        var allHeaders = xhr.getAllResponseHeaders();
228
                        if(allHeaders){
229
                                response.responseHeaders = allHeaders;
230
                        }
231
                }
232

233
                if(xhr.status == 0 || xhr.status){
234
                        response.status = xhr.status;
235
                }
236

237
                if(xhr.statusText){
238
                        response.statusText = xhr.statusText;
239
                }
240

241
                if(xhr.responseText){
242
                        response.responseText = xhr.responseText;
243
                }
244

245
                //Build a string of the response object.
246
                var result = "";
247
                var isFirst = true;
248
                for (var param in response){
249
                        if(isFirst){
250
                                isFirst = false;
251
                        }else{
252
                                result += "&";
253
                        }
254
                        result += param + "=" + encodeURIComponent(response[param]);
255
                }
256
                sendResponse(result);
257
        }
258

259
        function sendXhr(){
260
                var request = {};
261
                var nvPairs = xipRequestMessage.split("&");
262
                var i = 0;
263
                var nameValue = null;
264
                for(i = 0; i < nvPairs.length; i++){
265
                        if(nvPairs[i]){
266
                                var nameValue = nvPairs[i].split("=");
267
                                request[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
268
                        }
269
                }
270

271
                //Split up the request headers, if any.
272
                var headers = {};
273
                if(request.requestHeaders){
274
                        nvPairs = request.requestHeaders.split("\r\n");
275
                        for(i = 0; i < nvPairs.length; i++){
276
                                if(nvPairs[i]){
277
                                        nameValue = nvPairs[i].split(": ");
278
                                        headers[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
279
                                }
280
                        }
281

282
                        request.requestHeaders = headers;
283
                }
284

285
                if(isAllowedRequest(request)){
286

287
                        //The request is allowed, so set up the XHR object.
288
                        var xhr = dojo.hostenv.getXmlhttpObject();
289

290
                        //Start timer to look for readyState.
291
                        var xhrIntervalId = setInterval(function(){
292

293
                                if(xhr.readyState == 4){
294
                                        clearInterval(xhrIntervalId);
295
                                        xhrDone(xhr);
296
                                }
297
                        }, 10);
298

299
                        //Actually start up the XHR request.
300
                        xhr.open(request.method, request.uri, true);
301
                        dojo.setHeaders(xhr, request.requestHeaders);
302

303
                        var content = "";
304
                        if(request.data){
305
                                content = request.data;
306
                        }
307

308
                        try{
309
                                xhr.send(content);
310
                        }catch(e){
311
                                if(typeof xhr.abort == "function"){
312
                                        xhr.abort();
313
                                        xhrDone({status: 404, statusText: "xip_server.html error: " + e});
314
                                }
315
                        }
316
                }
317
        }
318

319
        function unpackMessage(encodedMessage){
320
                var parts = encodedMessage.split(":");
321
                var command = parts[1];
322
                encodedMessage = parts[2] || "";
323

324
                var config = null;
325
                if(command == "init"){
326
                        var configParts = encodedMessage.split("&");
327
                        config = {};
328
                        for(var i = 0; i < configParts.length; i++){
329
                                var nameValue = configParts[i].split("=");
330
                                config[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
331
                        }
332
                }
333
                return {command: command, message: encodedMessage, config: config};
334
        }
335

336
        function onServerLoad(){
337
                xipServerInit();
338

339
                //Decode the init params
340
                var config = unpackMessage(window.location.href.split("#")[1]).config;
341

342
                xipStateId = config.id;
343
                xipClientUrl = config.client;
344

345
                //Make sure we don't have a javascript: url, just for good measure.
346
                if(xipClientUrl.split(":")[0].match(/javascript/i)){
347
                        throw "Invalid client URL";
348
                }
349
                if(!xipStateId.match(/^XhrIframeProxy[0-9]+$/)){
350
                        throw "Invalid state ID";
351
                }
352

353
                setInterval(pollHash, 10);
354

355
                var serverUrl = window.location.href.split("#")[0];
356
                document.getElementById("iframeHolder").innerHTML = '<iframe name="'
357
                        + xipStateId + '_clientEndPoint'
358
                        + '" src="javascript:false">'
359
                        + '</iframe>';
360
                xipClientWindow = document.getElementsByTagName("iframe")[0];
361
                xipClientWindow.src = makeClientUrl("init", 'id=' + xipStateId + "&callback=" + encodeURIComponent(config.callback));
362
                if(xipClientWindow.contentWindow){
363
                        xipClientWindow = xipClientWindow.contentWindow;
364
                }
365
        }
366

367
        if(typeof(window.addEventListener) == "undefined"){
368
                window.attachEvent("onload", onServerLoad);
369
        }else{
370
                window.addEventListener('load', onServerLoad, false);
371
        }
372
        // -->
373
        <!-- </script> -->
374
</head>
375
<body>
376
        <h4>The Dojo Toolkit -- xip_server.html</h4>
377
378
        <p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the the file
379
        that should go on the server that will actually be doing the XHR request.</p>
380
        <div id="iframeHolder"></div>
381
</body>
382
</html>