diff options
Diffstat (limited to 'js/dojo/dojox/io')
| -rw-r--r-- | js/dojo/dojox/io/OAuth.js | 307 | ||||
| -rw-r--r-- | js/dojo/dojox/io/README | 82 | ||||
| -rw-r--r-- | js/dojo/dojox/io/httpParse.js | 82 | ||||
| -rw-r--r-- | js/dojo/dojox/io/proxy/README | 82 | ||||
| -rw-r--r-- | js/dojo/dojox/io/proxy/xip.js | 440 | ||||
| -rw-r--r-- | js/dojo/dojox/io/proxy/xip_client.html | 102 | ||||
| -rw-r--r-- | js/dojo/dojox/io/proxy/xip_server.html | 382 | ||||
| -rw-r--r-- | js/dojo/dojox/io/scriptFrame.js | 85 | ||||
| -rw-r--r-- | js/dojo/dojox/io/windowName.js | 224 | ||||
| -rw-r--r-- | js/dojo/dojox/io/xhrMultiPart.js | 161 | ||||
| -rw-r--r-- | js/dojo/dojox/io/xhrPlugins.js | 171 | ||||
| -rw-r--r-- | js/dojo/dojox/io/xhrScriptPlugin.js | 36 | ||||
| -rw-r--r-- | js/dojo/dojox/io/xhrWindowNamePlugin.js | 61 |
13 files changed, 2215 insertions, 0 deletions
diff --git a/js/dojo/dojox/io/OAuth.js b/js/dojo/dojox/io/OAuth.js new file mode 100644 index 0000000..7e62811 --- /dev/null +++ b/js/dojo/dojox/io/OAuth.js @@ -0,0 +1,307 @@ +//>>built +define("dojox/io/OAuth", [ + "dojo/_base/kernel", // dojo + "dojo/_base/lang", // mixin + "dojo/_base/array", // isArray, map + "dojo/_base/xhr", // formToObject, queryToObject, xhr + "dojo/dom", // byId + "dojox/encoding/digests/SHA1" // SHA1 +], function(dojo, lang, array, xhr, dom, SHA1){ +dojo.getObject("io.OAuth", true, dojox); + +dojox.io.OAuth = new (function(){ + // summary: + // Helper singleton for signing any kind of Ajax request using the OAuth 1.0 protocol. + // description: + // dojox.io.OAuth is a singleton class designed to allow anyone to sign a request, + // based on the OAuth 1.0 specification, made with any of the Dojo Toolkit's Ajax + // methods (such as dojo.xhr[verb], dojo.io.iframe, etc.). + // + // The main method of dojox.io.OAuth is the sign method (see documentation for .sign); + // the idea is that you will "sign" the kwArgs object you'd normally pass to any of + // the Ajax methods, and then pass the signed object along. As long as the token + // object used is valid (and the client's date and time are synced with a public + // time server), a signed object should be passed along correctly. + // + // dojox.io.OAuth does not deal with the OAuth handshake process at all. + // + // This object was developed against the Netflix API (OAuth-based service); see + // http://developer.netflix.com for more details. + var encode = this.encode = function(s){ + if(!("" + s).length){ return ""; } + return encodeURIComponent(s) + .replace(/\!/g, "%21") + .replace(/\*/g, "%2A") + .replace(/\'/g, "%27") + .replace(/\(/g, "%28") + .replace(/\)/g, "%29"); + }; + + var decode = this.decode = function(str){ + // summary: + // Break apart the passed string and decode. + // Some special cases are handled. + var a=[], list=str.split("&"); + for(var i=0, l=list.length; i<l; i++){ + var item=list[i]; + if(list[i]==""){ continue; } // skip this one. + if(list[i].indexOf("=")>-1){ + var tmp=list[i].split("="); + a.push([ decodeURIComponent(tmp[0]), decodeURIComponent(tmp[1]) ]); + } else { + a.push([ decodeURIComponent(list[i]), null ]); + } + } + return a; + }; + + function parseUrl(url){ + // summary: + // Create a map out of the passed URL. Need to pull any + // query string parameters off the URL for the base signature string. + var keys = [ + "source","protocol","authority","userInfo", + "user","password","host","port", + "relative","path","directory", + "file","query","anchor" + ], + parser=/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, + match=parser.exec(url), + map = {}, + i=keys.length; + + // create the base map first. + while(i--){ map[keys[i]] = match[i] || ""; } + + // create the normalized version of the url and add it to the map + var p=map.protocol.toLowerCase(), + a=map.authority.toLowerCase(), + b=(p=="http"&&map.port==80)||(p=="https"&&map.port==443); + if(b){ + if(a.lastIndexOf(":")>-1){ + a=a.substring(0, a.lastIndexOf(":")); + } + } + var path=map.path||"/"; + map.url=p+"://"+a+path; + + // return the map + return map; + } + + var tab="0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz"; + function nonce(length){ + var s="", tl=tab.length; + for(var i=0; i<length; i++){ + s+=tab.charAt(Math.floor(Math.random()*tl)); + } + return s; + } + function timestamp(){ + return Math.floor(new Date().valueOf()/1000)-2; + } + function signature(data, key, type){ + if(type && type!="PLAINTEXT" && type!="HMAC-SHA1"){ + throw new Error("dojox.io.OAuth: the only supported signature encodings are PLAINTEXT and HMAC-SHA1."); + } + + if(type=="PLAINTEXT"){ + return key; + } else { + // assume SHA1 HMAC + return SHA1._hmac(data, key); + } + } + + function key(args){ + // summary: + // return the key used to sign a message based on the token object. + return encode(args.consumer.secret) + + "&" + + (args.token && args.token.secret ? encode(args.token.secret) : ""); + } + + function addOAuth(/* dojo.__XhrArgs */args, /* dojox.io.__OAuthArgs */oaa){ + // summary: + // Add the OAuth parameters to the query string/content. + var o = { + oauth_consumer_key: oaa.consumer.key, + oauth_nonce: nonce(16), + oauth_signature_method: oaa.sig_method || "HMAC-SHA1", + oauth_timestamp: timestamp(), + oauth_version: "1.0" + } + if(oaa.token){ + o.oauth_token = oaa.token.key; + } + args.content = dojo.mixin(args.content||{}, o); + } + + function convertArgs(args){ + // summary: + // Because of the need to create a base string, we have to do + // some manual args preparation instead of relying on the internal + // Dojo xhr functions. But we'll let dojo.xhr assemble things + // as it normally would. + var miArgs = [{}], formObject; + + if(args.form){ + if(!args.content){ args.content = {}; } + var form = dojo.byId(args.form); + var actnNode = form.getAttributeNode("action"); + args.url = args.url || (actnNode ? actnNode.value : null); + formObject = dojo.formToObject(form); + delete args.form; + } + if(formObject){ miArgs.push(formObject); } + if(args.content){ miArgs.push(args.content); } + + // pull anything off the query string + var map = parseUrl(args.url); + if(map.query){ + var tmp = dojo.queryToObject(map.query); + // re-encode the values. sigh + for(var p in tmp){ tmp[p] = encodeURIComponent(tmp[p]); } + miArgs.push(tmp); + } + args._url = map.url; + + // now set up all the parameters as an array of 2 element arrays. + var a = []; + for(var i=0, l=miArgs.length; i<l; i++){ + var item=miArgs[i]; + for(var p in item){ + if(dojo.isArray(item[p])){ + // handle multiple values + for(var j=0, jl=item.length; j<jl; j++){ + a.push([ p, item[j] ]); + } + } else { + a.push([ p, item[p] ]); + } + } + } + + args._parameters = a; + return args; + } + + function baseString(/* String */method, /* dojo.__XhrArgs */args, /* dojox.io.__OAuthArgs */oaa){ + // create and return the base string out of the args. + addOAuth(args, oaa); + convertArgs(args); + + var a = args._parameters; + + // sort the parameters + a.sort(function(a,b){ + if(a[0]>b[0]){ return 1; } + if(a[0]<b[0]){ return -1; } + if(a[1]>b[1]){ return 1; } + if(a[1]<b[1]){ return -1; } + return 0; + }); + + // encode. + var s = dojo.map(a, function(item){ + return encode(item[0]) + "=" + encode((""+item[1]).length ? item[1] : ""); + }).join("&"); + + var baseString = method.toUpperCase() + + "&" + encode(args._url) + + "&" + encode(s); + return baseString; + } + + function sign(method, args, oaa){ + // return the oauth_signature for this message. + var k = key(oaa), + message = baseString(method, args, oaa), + s = signature(message, k, oaa.sig_method || "HMAC-SHA1"); + args.content["oauth_signature"] = s; + return args; + } + + /*===== + dojox.io.OAuth.__AccessorArgs = function(key, secret){ + // key: String + // The key or token issued to either the consumer or by the OAuth service. + // secret: String + // The secret (shared secret for consumers, issued secret by OAuth service). + this.key = key; + this.secret = secret; + }; + dojox.io.OAuth.__OAuthArgs = function(consumer, sig_method, token){ + // consumer: dojox.io.OAuth.__AccessorArgs + // The consumer information issued to your OpenAuth application. + // sig_method: String + // The method used to create the signature. Should be PLAINTEXT or HMAC-SHA1. + // token: dojox.io.OAuth.__AccessorArgs? + // The request token and secret issued by the OAuth service. If not + // issued yet, this should be null. + this.consumer = consumer; + this.token = token; + } + =====*/ + + /* + * Process goes something like this: + * 1. prepare the base string + * 2. create the key + * 3. create the signature based on the base string and the key + * 4. send the request using dojo.xhr[METHOD]. + */ + + this.sign = function(/* String*/method, /* dojo.__XhrArgs */args, /* dojox.io.OAuth.__OAuthArgs */oaa){ + // summary: + // Given the OAuth access arguments, sign the kwArgs that you would pass + // to any dojo Ajax method (dojo.xhr*, dojo.io.iframe, dojo.io.script). + // example: + // Sign the kwArgs object for use with dojo.xhrGet: + // | var oaa = { + // | consumer: { + // | key: "foobar", + // | secret: "barbaz" + // | } + // | }; + // | + // | var args = dojox.io.OAuth.sign("GET", myAjaxKwArgs, oaa); + // | dojo.xhrGet(args); + return sign(method, args, oaa); + }; + + + // TODO: handle redirect requests? + this.xhr = function(/* String */method, /* dojo.__XhrArgs */args, /* dojox.io.OAuth.__OAuthArgs */oaa, /* Boolean? */hasBody){ + /* summary: + * Make an XHR request that is OAuth signed. + * example: + * | var dfd = dojox.io.OAuth.xhrGet({ + * | url: "http://someauthdomain.com/path?foo=bar", + * | load: function(response, ioArgs){ } + * | }, + * | { + * | consumer:{ key: "lasdkf9asdnfsdf", secret: "9asdnfskdfysjr" } + * | }); + */ + sign(method, args, oaa); + return xhr(method, args, hasBody); + }; + + this.xhrGet = function(/* dojo.__XhrArgs */args, /* dojox.io.OAuth.__OAuthArgs*/ oaa){ + return this.xhr("GET", args, oaa); + }; + this.xhrPost = this.xhrRawPost = function(/* dojo.__XhrArgs */args, /* dojox.io.OAuth.__OAuthArgs*/ oaa){ + return this.xhr("POST", args, oaa, true); + }; + this.xhrPut = this.xhrRawPut = function(/* dojo.__XhrArgs */args, /* dojox.io.OAuth.__OAuthArgs*/ oaa){ + return this.xhr("PUT", args, oaa, true); + }; + this.xhrDelete = function(/* dojo.__XhrArgs */args, /* dojox.io.OAuth.__OAuthArgs*/ oaa){ + return this.xhr("DELETE", args, oaa); + }; +})(); + +return dojox.io.OAuth; + +}); diff --git a/js/dojo/dojox/io/README b/js/dojo/dojox/io/README new file mode 100644 index 0000000..ed35581 --- /dev/null +++ b/js/dojo/dojox/io/README @@ -0,0 +1,82 @@ +------------------------------------------------------------------------------- +DojoX IO +------------------------------------------------------------------------------- +Version 0.4.0 +Release date: 07/04/2008 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + Bryan Forbes (bryan AT reigndropsfall.net) + Kris Zyp (kris AT sitepen.com) + James Burke (jburke AT dojotoolkit.org) + Tom Trenka (ttrenka AT gmail.com) + +------------------------------------------------------------------------------- +Project description + + A Collection of advanced and experimental IO modules: + + * scriptFrame.js - Uses an iframe for dojo.io.script requests. Useful in some + long-polling comet situations in Firefox and Opera. Those browsers execute scripts + in DOM order, not network-receive order, so a long-polling script will block other + dynamically appended scripts from running until it completes. By using an iframe + for the dojo.io.script requests, this issue can be avoided. + + * xhrMultiPart.js - Constructs multi-part mime XHR requests. Useful when wanting + multi-part requests but not using a form with a file input. Note that it does not + allow you to send files from local disks -- a form with a file input is required + for that use case. xhrMultipart is not useful in that use case. + + * xhrPlugins.js - An adapter registry for having multiple XHR handlers (like + XDomainRequest, CS-XHR, proxy, and window.name) + + * windowName.js - Cross-domain transport using window.name + xhrWindowNamePlugin.js - window.name plugin for XHR adapter registry + + * httpParse.js - HTTP message parser. Parses to an XHR like interface. + + * OAuth.js - Object to be used for signing OpenAuth requests. Includes easy + wrappers for xhr. + +------------------------------------------------------------------------------- +Dependencies: + +DojoX IO xhrMultiPart depends on Dojo Core and DojoX UUID's generateRandomUuid +function. + +xhrWindowNamePlugin depends on dojox.secure.capability for safe JSON parsing + +OAuth depends on dojox.encoding.digests.SHA1. +------------------------------------------------------------------------------- +Documentation + +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/uuid.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/uuid/* +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/secure/* +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/encoding/digests/* + +Install into the following directory structure: +/dojox/uuid/ +/dojox/secure/ +/dojox/encoding/digests/ + +AND + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/io/* + +Install into the following directory structure: +/dojox/io/ + +...both of which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- +Additional Notes + +The information contained in this README does not pertain to DojoX XHR IFrame Proxy. +For that information see proxy/README. diff --git a/js/dojo/dojox/io/httpParse.js b/js/dojo/dojox/io/httpParse.js new file mode 100644 index 0000000..bcc20dd --- /dev/null +++ b/js/dojo/dojox/io/httpParse.js @@ -0,0 +1,82 @@ +//>>built +define("dojox/io/httpParse", ["dojo/_base/kernel"], function(dojo){ +dojo.getObject("io.httpParse", true, dojox); + +dojox.io.httpParse = function(/*String*/httpStream, /*String?*/topHeaders,/*Boolean?*/ partial){ + // summary: + // Parses an HTTP stream for a message. + // httpStream: + // HTTP stream to parse + // topHeaders: + // Extra header information to add to each HTTP request (kind of HTTP inheritance) + // partial: + // A true value indicates that the stream may not be finished, it may end arbitrarily in mid stream. + // The last XHR object will have a special property _lastIndex that indicates the how far along + // the httpStream could be successfully parsed into HTTP messages. + // return: + // Returns an array of XHR-like object for reading the headers for each message + // + var xhrs=[]; + var streamLength = httpStream.length; + do{ + var headers = {}; + var httpParts = httpStream.match(/(\n*[^\n]+)/); + if(!httpParts){ + return null; + } + httpStream = httpStream.substring(httpParts[0].length+1); + httpParts = httpParts[1]; + var headerParts = httpStream.match(/([^\n]+\n)*/)[0]; + + httpStream = httpStream.substring(headerParts.length); + var headerFollowingChar = httpStream.substring(0,1); + httpStream = httpStream.substring(1); + headerParts = (topHeaders || "") + headerParts; + var headerStr = headerParts; + headerParts = headerParts.match(/[^:\n]+:[^\n]+\n/g); // parse the containing and contained response headers with the contained taking precedence (by going last) + for(var j = 0; j < headerParts.length; j++){ + var colonIndex = headerParts[j].indexOf(':'); + headers[headerParts[j].substring(0,colonIndex)] = headerParts[j].substring(colonIndex+1).replace(/(^[ \r\n]*)|([ \r\n]*)$/g,''); // trim + } + + httpParts = httpParts.split(' '); + var xhr = { // make it look like an xhr object, at least for the response part of the API + status : parseInt(httpParts[1],10), + statusText : httpParts[2], + readyState : 3, // leave it at 3 until we get a full body + getAllResponseHeaders : function(){ + return headerStr; + }, + getResponseHeader : function(name){ + return headers[name]; + } + }; + var contentLength = headers['Content-Length']; + var content; + if(contentLength){ + if(contentLength <= httpStream.length){ + content = httpStream.substring(0,contentLength); + }else{ + return xhrs; // the content is not finished + } + }else if((content = httpStream.match(/(.*)HTTP\/\d\.\d \d\d\d[\w\s]*\n/))){ // assign content + // if we spot another HTTP message coming up, we will just assign all the in between text to the content + content = content[0]; + }else if(!partial || headerFollowingChar == '\n'){ + // if we have to finish + content = httpStream; + }else{ + return xhrs; + } + xhrs.push(xhr); // add it to the list, since it is a full HTTP message + httpStream = httpStream.substring(content.length); // move along the stream + xhr.responseText = content; + xhr.readyState = 4; + xhr._lastIndex = streamLength - httpStream.length; // need to pick up from where we left on streaming connections + }while(httpStream); + return xhrs; +}; + +return dojox.io.httpParse; + +}); diff --git a/js/dojo/dojox/io/proxy/README b/js/dojo/dojox/io/proxy/README new file mode 100644 index 0000000..8898a56 --- /dev/null +++ b/js/dojo/dojox/io/proxy/README @@ -0,0 +1,82 @@ +------------------------------------------------------------------------------- +Project Name +------------------------------------------------------------------------------- +Version 0.6 +Release date: 01/31/2008 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + James Burke (jburke@dojotoolkit.org) +------------------------------------------------------------------------------- +Project description + +The XHR IFrame Proxy (xip) allows you to do cross-domain XMLHttpRequests (XHRs). +It works by using two iframes, one your domain (xip_client.html), one on the +other domain (xip_server.html). They use fragment IDs in the iframe URLs to pass +messages to each other. The xip.js file defines dojox.io.proxy.xip. This module +intercepts XHR calls made by the Dojo XHR methods (dojo.xhr* methods). The module +returns a facade object that acts like an XHR object. Once send is called on the +facade, the facade's data is serialized, given to xip_client.html. xip_client.html +then passes the serialized data to xip_server.html by changing xip_server.html's +URL fragment ID (the #xxxx part of an URL). xip_server.html deserializes the +message fragments, and does an XHR call, gets the response, and serializes the +data. The serialized data is then passed back to xip_client.html by changing +xip_client.html's fragment ID. Then the response is deserialized and used as +the response inside the facade XHR object that was created by dojox.io.proxy.xip. +------------------------------------------------------------------------------- +Dependencies: + +xip.js: Dojo Core, dojox.data.dom +xip_client.html: none +xip_server.html: none (but see Additional Notes section) +------------------------------------------------------------------------------- +Documentation + +There is some documentation that applies to the Dojo 0.4.x version of these files: +http://dojotoolkit.org/book/dojo-book-0-4/part-5-connecting-pieces/i-o/cross-domain-xmlhttprequest-using-iframe-proxy + +The general theory still applies to this code, but the specifics are different +for the Dojo 0.9+ codebase. Doc updates hopefully after the basic code is ported. + +The current implementation destroys the iframes used for a request after the request +completes. This seems to cause a memory leak, particularly in IE. So, it is not +suited for doing polling cross-domain requests. +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojox SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/io/proxy/xip.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/io/proxy/xip_client.html + +Install into the following directory structure: +/dojox/io/proxy/ + +...which should be at the same level as your Dojo checkout. + +Grab the following from the Dojox SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/io/proxy/xip_server.html + +and install it on the domain that you want to allow receiving cross-domain +requests. Be sure to read the documentation, the Additional Notes below, and +the in-file comments. +------------------------------------------------------------------------------- +Additional Notes + +xip_client.html and xip_server.html do not work right away. You need to uncomment +out the script tags in the files. Additionally, xip_server.html requires a JS file, +isAllowed.js, to be defined. See the notes in xip_server.html for more informaiton. + +XDOMAIN BUILD INSTRUCTIONS: +The dojox.io.proxy module requires some setup to use with an xdomain build. +The xip_client.html file has to be served from the same domain as your web page. +It cannot be served from the domain that has the xdomain build. Download xip_client.html +and install it on your server. Then set djConfig.xipClientUrl to the local path +of xip_client.html (just use a path, not a whole URL, since it will be on the same +domain as the page). The path to the file should be the path relative to the web +page that is using dojox.io.proxy. + + + + diff --git a/js/dojo/dojox/io/proxy/xip.js b/js/dojo/dojox/io/proxy/xip.js new file mode 100644 index 0000000..b28bff1 --- /dev/null +++ b/js/dojo/dojox/io/proxy/xip.js @@ -0,0 +1,440 @@ +//>>built +define("dojox/io/proxy/xip", ['dojo/main', 'dojo/io/iframe', 'dojox/data/dom', 'dojo/_base/xhr', 'dojo/_base/url'], function(dojo, iframe, dom){ + dojo.getObject("io.proxy.xip", true, dojox); + +dojox.io.proxy.xip = { + //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://dojotoolkit.org/book/dojo-book-0-4/part-5-connecting-pieces/i-o/cross-domain-xmlhttprequest-using-iframe-proxy + //Usage of XHR IFrame Proxying does not work from local disk in Safari. + + /* + This code is really focused on just sending one complete request to the server, and + receiving one complete response per iframe. The code does not expect to reuse iframes for multiple XHR request/response + sequences. 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 message fragments. 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 xip_client.html to this module. + - 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. + */ + + xipClientUrl: ((dojo.config || djConfig)["xipClientUrl"]) || dojo.moduleUrl("dojox.io.proxy", "xip_client.html").toString(), + + + //MSIE has the lowest limit for URLs with fragment identifiers, + //at around 4K. Choosing a slightly smaller number for good measure. + urlLimit: 4000, + + _callbackName: (dojox._scopeName || "dojox") + ".io.proxy.xip.fragmentReceived", + _state: {}, + _stateIdCounter: 0, + _isWebKit: navigator.userAgent.indexOf("WebKit") != -1, + + + send: function(/*Object*/facade){ + //summary: starts the xdomain request using the provided facade. + //This method first does some init work, then delegates to _realSend. + + var url = this.xipClientUrl; + //Make sure we are not dealing with javascript urls, just to be safe. + if(url.split(":")[0].match(/javascript/i) || facade._ifpServerUrl.split(":")[0].match(/javascript/i)){ + return null; + } + + //Make xip_client a full URL. + var colonIndex = url.indexOf(":"); + var slashIndex = url.indexOf("/"); + if(colonIndex == -1 || slashIndex < colonIndex){ + //No colon or we are starting with a / before a colon, so we need to make a full URL. + var loc = window.location.href; + if(slashIndex == 0){ + //Have a full path, just need the domain. + url = loc.substring(0, loc.indexOf("/", 9)) + url; //Using 9 to get past http(s):// + }else{ + url = loc.substring(0, (loc.lastIndexOf("/") + 1)) + url; + } + } + this.fullXipClientUrl = url; + + //Set up an HTML5 messaging listener if postMessage exists. + //As of this writing, this is only useful to get Opera 9.25+ to work. + if(typeof document.postMessage != "undefined"){ + document.addEventListener("message", dojo.hitch(this, this.fragmentReceivedEvent), false); + } + + //Now that we did first time init, always use the realSend method. + this.send = this._realSend; + return this._realSend(facade); //Object + }, + + _realSend: function(facade){ + //summary: starts the actual xdomain request using the provided facade. + var stateId = "XhrIframeProxy" + (this._stateIdCounter++); + facade._stateId = stateId; + + var frameUrl = facade._ifpServerUrl + "#0:init:id=" + stateId + "&client=" + + encodeURIComponent(this.fullXipClientUrl) + "&callback=" + encodeURIComponent(this._callbackName); + + this._state[stateId] = { + facade: facade, + stateId: stateId, + clientFrame: iframe.create(stateId, "", frameUrl), + isSending: false, + serverUrl: facade._ifpServerUrl, + requestData: null, + responseMessage: "", + requestParts: [], + idCounter: 1, + partIndex: 0, + serverWindow: null + }; + + return stateId; //Object + }, + + 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){ + var mimeType = contentType.split(";")[0]; + if(mimeType.indexOf("application/xml") == 0 || mimeType.indexOf("text/xml") == 0){ + facade.responseXML = dom.createDocument(response.responseText, contentType); + } + } + } + facade.readyState = 4; + + this.destroyState(stateId); + }, + + frameLoaded: function(/*String*/stateId){ + var state = this._state[stateId]; + var facade = state.facade; + + 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; + } + + this.sendRequest(stateId, dojo.objectToQuery(requestData)); + }, + + 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 dojox.io.proxy.xip.XhrIframeFacade(arguments[0].iframeProxyUrl); + }else{ + return dojox.io.proxy.xip._xhrObjOld.apply(dojo, arguments); + } + }, + + //**** State-bound methods **** + sendRequest: function(stateId, encodedData){ + var state = this._state[stateId]; + if(!state.isSending){ + state.isSending = true; + + state.requestData = encodedData || ""; + + //Get a handle to the server iframe. + state.serverWindow = frames[state.stateId]; + if (!state.serverWindow){ + state.serverWindow = document.getElementById(state.stateId).contentWindow; + } + + //Make sure we have contentWindow, but only do this for non-postMessage + //browsers (right now just opera is postMessage). + if(typeof document.postMessage == "undefined"){ + if(state.serverWindow.contentWindow){ + state.serverWindow = state.serverWindow.contentWindow; + } + } + + this.sendRequestStart(stateId); + } + }, + + sendRequestStart: function(stateId){ + //Break the message into parts, if necessary. + var state = this._state[stateId]; + state.requestParts = []; + var reqData = state.requestData; + var urlLength = state.serverUrl.length; + var partLength = this.urlLimit - urlLength; + var reqIndex = 0; + + while((reqData.length - reqIndex) + urlLength > this.urlLimit){ + 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); + } + state.requestParts.push(part); + reqIndex += part.length; + } + state.requestParts.push(reqData.substring(reqIndex, reqData.length)); + + state.partIndex = 0; + this.sendRequestPart(stateId); + + }, + + sendRequestPart: function(stateId){ + var state = this._state[stateId]; + + if(state.partIndex < state.requestParts.length){ + //Get the message part. + var partData = state.requestParts[state.partIndex]; + + //Get the command. + var cmd = "part"; + if(state.partIndex + 1 == state.requestParts.length){ + cmd = "end"; + }else if (state.partIndex == 0){ + cmd = "start"; + } + + this.setServerUrl(stateId, cmd, partData); + state.partIndex++; + } + }, + + setServerUrl: function(stateId, cmd, message){ + var serverUrl = this.makeServerUrl(stateId, cmd, message); + var state = this._state[stateId]; + + //Safari won't let us replace across domains. + if(this._isWebKit){ + state.serverWindow.location = serverUrl; + }else{ + state.serverWindow.location.replace(serverUrl); + } + }, + + makeServerUrl: function(stateId, cmd, message){ + var state = this._state[stateId]; + var serverUrl = state.serverUrl + "#" + (state.idCounter++) + ":" + cmd; + if(message){ + serverUrl += ":" + message; + } + return serverUrl; + }, + + fragmentReceivedEvent: function(evt){ + //summary: HTML5 document messaging endpoint. Unpack the event to see + //if we want to use it. + if(evt.uri.split("#")[0] == this.fullXipClientUrl){ + this.fragmentReceived(evt.data); + } + }, + + fragmentReceived: function(frag){ + var index = frag.indexOf("#"); + var stateId = frag.substring(0, index); + var encodedData = frag.substring(index + 1, frag.length); + + var msg = this.unpackMessage(encodedData); + var state = this._state[stateId]; + + switch(msg.command){ + case "loaded": + this.frameLoaded(stateId); + break; + case "ok": + this.sendRequestPart(stateId); + break; + case "start": + state.responseMessage = "" + msg.message; + this.setServerUrl(stateId, "ok"); + break; + case "part": + state.responseMessage += msg.message; + this.setServerUrl(stateId, "ok"); + break; + case "end": + this.setServerUrl(stateId, "ok"); + state.responseMessage += msg.message; + this.receive(stateId, state.responseMessage); + break; + } + }, + + unpackMessage: function(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}; + } +} + +//Replace the normal XHR factory with the proxy one. +dojox.io.proxy.xip._xhrObjOld = dojo._xhrObj; +dojo._xhrObj = dojox.io.proxy.xip.createFacade; + +/** + Using this a reference: http://www.w3.org/TR/XMLHttpRequest/ + + Does not implement the onreadystate callback since dojo.xhr* does + not use it. +*/ +dojox.io.proxy.xip.XhrIframeFacade = function(ifpServerUrl){ + //summary: XMLHttpRequest facade object used by dojox.io.proxy.xip. + + //description: Do not use this object directly. See the Dojo Book page + //on XMLHttpRequest IFrame Proxying: + //http://dojotoolkit.org/book/dojo-book-0-4/part-5-connecting-pieces/i-o/cross-domain-xmlhttprequest-using-iframe-proxy + 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.extend(dojox.io.proxy.xip.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 = dojox.io.proxy.xip.send(this); + + this.readyState = 2; + }, + abort: function(){ + dojox.io.proxy.xip.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]; + } + } + } + } +}); + +return dojox.io.proxy.xip; + +}); diff --git a/js/dojo/dojox/io/proxy/xip_client.html b/js/dojo/dojox/io/proxy/xip_client.html new file mode 100644 index 0000000..7dcc566 --- /dev/null +++ b/js/dojo/dojox/io/proxy/xip_client.html @@ -0,0 +1,102 @@ +<!-- + /* + Copyright (c) 2004-2011, 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 + */ +--> +<!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 start and end script tags to enable. --> + <!-- script type="text/javascript" --> + // <!-- + + 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{ + callMaster(xipStateId, newHash); + }catch(e){ + //Make sure to not keep processing the error hash value. + xipCurrentHash = newHash; + throw e; + } + xipCurrentHash = newHash; + } + } + } + + 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}; + } + + //************** Init ************************** + xipCurrentHash = ""; + + //Decode the init params + var fragId = window.location.href.split("#")[1]; + var config = unpackMessage(fragId).config; + + xipStateId = config.id; + xipMasterFrame = parent.parent; + + //Set up an HTML5 messaging publisher if postMessage exists. + //As of this writing, this is only useful to get Opera 9.25+ to work. + if(typeof document.postMessage != "undefined"){ + callMaster = function(stateId, message){ + xipMasterFrame.document.postMessage(stateId + "#" + message); + } + }else{ + var parts = config.callback.split("."); + xipCallbackObject = xipMasterFrame; + for(var i = 0; i < parts.length - 1; i++){ + xipCallbackObject = xipCallbackObject[parts[i]]; + } + xipCallback = parts[parts.length - 1]; + + callMaster = function(stateId, message){ + xipCallbackObject[xipCallback](stateId + "#" + message); + } + } + + //Call the master frame to let it know it is OK to start sending. + callMaster(xipStateId, "0:loaded"); + + //Start counter to inspect hash value. + setInterval(pollHash, 10); + + // --> + <!-- </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 dojox.io.proxy.xip.</p> +</body> +</html> diff --git a/js/dojo/dojox/io/proxy/xip_server.html b/js/dojo/dojox/io/proxy/xip_server.html new file mode 100644 index 0000000..90be252 --- /dev/null +++ b/js/dojo/dojox/io/proxy/xip_server.html @@ -0,0 +1,382 @@ +<!-- + /* + Copyright (c) 2004-2011, 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 + */ + Pieces taken from Dojo source to make this file stand-alone +--> +<html> +<head> + <title></title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta> + <script type="text/javascript" src="isAllowed.js"></script> + <!-- + BY DEFAULT THIS FILE DOES NOT WORK SO THAT YOU DON'T ACCIDENTALLY EXPOSE + ALL OF YOUR XHR-ENABLED SERVICES ON YOUR SITE. + + In order for this file to work, you need to uncomment the start and end script tags, + and you should define a function with the following signature: + + function isAllowedRequest(request){ + return false; + } + + Return true out of the function if you want to allow the cross-domain request. + + DON'T DEFINE THIS FUNCTION IN THIS FILE! Define it in a separate file called isAllowed.js + and include it in this page with a script tag that has a src attribute pointing to the file. + See the very first script tag in this file for an example. You do not have to place the + script file in the same directory as this file, just update the path above if you move it + somewhere else. + + Customize the isAllowedRequest function to restrict what types of requests are allowed + for this server. The request object has the following properties: + - requestHeaders: an object with the request headers that are to be added to + the XHR request. + - method: the HTTP method (GET, POST, etc...) + - uri: The URI for the request. + - data: The URL-encoded data for the request. For a GET request, this would + be the querystring parameters. For a POST request, it wll be the + body data. + + See xip_client.html for more info on the xip fragment identifier protocol. + --> + + <!-- Security protection: uncomment the script tag to enable. --> + <!-- script type="text/javascript" --> + // <!-- + //Core XHR handling taken from Dojo IO code. + dojo = {}; + dojo.hostenv = {}; + // These are in order of decreasing likelihood; this will change in time. + dojo.hostenv._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0']; + + dojo.hostenv.getXmlhttpObject = function(){ + var http = null; + var last_e = null; + try{ http = new XMLHttpRequest(); }catch(e){} + if(!http){ + for(var i=0; i<3; ++i){ + var progid = dojo.hostenv._XMLHTTP_PROGIDS[i]; + try{ + http = new ActiveXObject(progid); + }catch(e){ + last_e = e; + } + + if(http){ + dojo.hostenv._XMLHTTP_PROGIDS = [progid]; // so faster next time + break; + } + } + + /*if(http && !http.toString) { + http.toString = function() { "[object XMLHttpRequest]"; } + }*/ + } + + if(!http){ + throw "xip_server.html: XMLHTTP not available: " + last_e; + } + + return http; + } + + dojo.setHeaders = function(http, headers){ + if(headers) { + for(var header in headers) { + var headerValue = headers[header]; + http.setRequestHeader(header, headerValue); + } + } + } + + //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 xipServerInit(){ + xipStateId = ""; + xipCurrentHash = ""; + xipRequestMessage = ""; + xipResponseParts = []; + xipPartIndex = 0; + } + + 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 "ok": + sendResponsePart(); + break; + case "start": + xipRequestMessage = ""; + xipRequestMessage += msg.message; + setClientUrl("ok"); + break; + case "part": + xipRequestMessage += msg.message; + setClientUrl("ok"); + break; + case "end": + setClientUrl("ok"); + xipRequestMessage += msg.message; + sendXhr(); + break; + } + } + + function sendResponse(encodedData){ + //Break the message into parts, if necessary. + xipResponseParts = []; + var resData = encodedData; + var urlLength = xipClientUrl.length; + var partLength = xipUrlLimit - urlLength; + var resIndex = 0; + + while((resData.length - resIndex) + urlLength > xipUrlLimit){ + var part = resData.substring(resIndex, resIndex + 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); + } + xipResponseParts.push(part); + resIndex += part.length; + } + xipResponseParts.push(resData.substring(resIndex, resData.length)); + + xipPartIndex = 0; + sendResponsePart(); + } + + function sendResponsePart(){ + if(xipPartIndex < xipResponseParts.length){ + //Get the message part. + var partData = xipResponseParts[xipPartIndex]; + + //Get the command. + var cmd = "part"; + if(xipPartIndex + 1 == xipResponseParts.length){ + cmd = "end"; + }else if (xipPartIndex == 0){ + cmd = "start"; + } + + setClientUrl(cmd, partData); + xipPartIndex++; + }else{ + xipServerInit(); + } + } + + function setClientUrl(cmd, message){ + var clientUrl = makeClientUrl(cmd, message); + //Safari won't let us replace across domains. + if(navigator.userAgent.indexOf("Safari") == -1){ + xipClientWindow.location.replace(clientUrl); + }else{ + xipClientWindow.location = clientUrl; + } + } + + function makeClientUrl(cmd, message){ + var clientUrl = xipClientUrl + "#" + (xipIdCounter++) + ":" + cmd; + if(message){ + clientUrl += ":" + message; + } + return clientUrl + } + + function xhrDone(xhr){ + /* Need to pull off and return the following data: + - responseHeaders + - status + - statusText + - responseText + */ + var response = {}; + + if(typeof(xhr.getAllResponseHeaders) != "undefined"){ + var allHeaders = xhr.getAllResponseHeaders(); + if(allHeaders){ + response.responseHeaders = allHeaders; + } + } + + if(xhr.status == 0 || xhr.status){ + response.status = xhr.status; + } + + if(xhr.statusText){ + response.statusText = xhr.statusText; + } + + if(xhr.responseText){ + response.responseText = xhr.responseText; + } + + //Build a string of the response object. + var result = ""; + var isFirst = true; + for (var param in response){ + if(isFirst){ + isFirst = false; + }else{ + result += "&"; + } + result += param + "=" + encodeURIComponent(response[param]); + } + sendResponse(result); + } + + function sendXhr(){ + var request = {}; + var nvPairs = xipRequestMessage.split("&"); + var i = 0; + var nameValue = null; + for(i = 0; i < nvPairs.length; i++){ + if(nvPairs[i]){ + var nameValue = nvPairs[i].split("="); + request[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]); + } + } + + //Split up the request headers, if any. + var headers = {}; + if(request.requestHeaders){ + nvPairs = request.requestHeaders.split("\r\n"); + for(i = 0; i < nvPairs.length; i++){ + if(nvPairs[i]){ + nameValue = nvPairs[i].split(": "); + headers[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]); + } + } + + request.requestHeaders = headers; + } + + if(isAllowedRequest(request)){ + + //The request is allowed, so set up the XHR object. + var xhr = dojo.hostenv.getXmlhttpObject(); + + //Start timer to look for readyState. + var xhrIntervalId = setInterval(function(){ + + if(xhr.readyState == 4){ + clearInterval(xhrIntervalId); + xhrDone(xhr); + } + }, 10); + + //Actually start up the XHR request. + xhr.open(request.method, request.uri, true); + dojo.setHeaders(xhr, request.requestHeaders); + + var content = ""; + if(request.data){ + content = request.data; + } + + try{ + xhr.send(content); + }catch(e){ + if(typeof xhr.abort == "function"){ + xhr.abort(); + xhrDone({status: 404, statusText: "xip_server.html error: " + e}); + } + } + } + } + + 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 onServerLoad(){ + xipServerInit(); + + //Decode the init params + var config = unpackMessage(window.location.href.split("#")[1]).config; + + xipStateId = config.id; + xipClientUrl = config.client; + + //Make sure we don't have a javascript: url, just for good measure. + if(xipClientUrl.split(":")[0].match(/javascript/i)){ + throw "Invalid client URL"; + } + if(!xipStateId.match(/^XhrIframeProxy[0-9]+$/)){ + throw "Invalid state ID"; + } + + setInterval(pollHash, 10); + + var serverUrl = window.location.href.split("#")[0]; + document.getElementById("iframeHolder").innerHTML = '<iframe name="' + + xipStateId + '_clientEndPoint' + + '" src="javascript:false">' + + '</iframe>'; + xipClientWindow = document.getElementsByTagName("iframe")[0]; + xipClientWindow.src = makeClientUrl("init", 'id=' + xipStateId + "&callback=" + encodeURIComponent(config.callback)); + if(xipClientWindow.contentWindow){ + xipClientWindow = xipClientWindow.contentWindow; + } + } + + if(typeof(window.addEventListener) == "undefined"){ + window.attachEvent("onload", onServerLoad); + }else{ + window.addEventListener('load', onServerLoad, false); + } + // --> + <!-- </script> --> +</head> +<body> + <h4>The Dojo Toolkit -- xip_server.html</h4> + + <p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the the file + that should go on the server that will actually be doing the XHR request.</p> + <div id="iframeHolder"></div> +</body> +</html> diff --git a/js/dojo/dojox/io/scriptFrame.js b/js/dojo/dojox/io/scriptFrame.js new file mode 100644 index 0000000..8d5d328 --- /dev/null +++ b/js/dojo/dojox/io/scriptFrame.js @@ -0,0 +1,85 @@ +//>>built +define("dojox/io/scriptFrame", ["dojo/main", "dojo/io/script", "dojo/io/iframe"], function(dojo, ioScript, iframe){ + dojo.deprecated("dojox.io.scriptFrame", "dojo.io.script now supports parallel requests without dojox.io.scriptFrame", "2.0"); + dojo.getObject("io.scriptFrame", true, dojox); + +//This module extends dojo.io.script to use an iframe for the dojo.io.script.attach calls +//if the frameDoc argument is passed to dojo.io.script.get(), and if frameDoc is a string (representing +//the DOM ID of an iframe that should be used for the connection. If frameDoc is not a string, then +//it is probably a document object, and dojox.io.scriptFrame should not get involved with the request. +//This is useful in some long-polling comet situations in Firefox and Opera. Those browsers execute scripts +//in DOM order, not network-receive order, so a long-polling script will block other +//dynamically appended scripts from running until it completes. By using an iframe +//for the dojo.io.script requests, this issue can be avoided. + +//WARNING: the url argument to dojo.io.script MUST BE relative to the iframe document's location, +//NOT the parent page location. This iframe document's URL will be (dojo.moduleUrl("dojo", "resources/blank.html") +//or djConfig.dojoBlankHtmlUrl (for xdomain loading). + + dojox.io.scriptFrame = { + _waiters: {}, + _loadedIds: {}, + + _getWaiters: function(/*String*/frameId){ + return this._waiters[frameId] || (this._waiters[frameId] = []); + }, + + _fixAttachUrl: function(/*String*/url){ + //summary: fixes the URL so that + }, + + _loaded: function(/*String*/frameId){ + //summary: callback used when waiting for a frame to load (related to the usage of + //the frameId argument to dojo.io.script.get(). + var waiters = this._getWaiters(frameId); + this._loadedIds[frameId] = true; + this._waiters[frameId] = null; + + for(var i = 0; i < waiters.length; i++){ + var ioArgs = waiters[i]; + ioArgs.frameDoc = iframe.doc(dojo.byId(frameId)); + ioScript.attach(ioArgs.id, ioArgs.url, ioArgs.frameDoc); + } + } + }; + + //Hold on to the old _canAttach function. + var oldCanAttach = ioScript._canAttach; + var scriptFrame = dojox.io.scriptFrame; + + //Define frame-aware _canAttach method on dojo.io.script + ioScript._canAttach = function(/*Object*/ioArgs){ + //summary: provides an override of dojo.io.script._canAttach to check for + //the existence of a the args.frameDoc property. If it is there, and it is a string, + //not a document, then create the iframe with an ID of frameDoc, and use that for the calls. + //If frameDoc is a document, then dojox.io.scriptFrame should not get involved. + var fId = ioArgs.args.frameDoc; + + if(fId && dojo.isString(fId)){ + var frame = dojo.byId(fId); + var waiters = scriptFrame._getWaiters(fId); + if(!frame){ + //Need to create frame, but the frame document, which *must* be + //on the same domain as the page (set djConfig.dojoBlankHtmlUrl + //if using xdomain loading). Loading of the frame document is asynchronous, + //so we need to do callback stuff. + waiters.push(ioArgs); + iframe.create(fId, dojox._scopeName + ".io.scriptFrame._loaded('" + fId + "');"); + }else{ + //Frame loading could still be happening. Only call attach if the frame has loaded. + if(scriptFrame._loadedIds[fId]){ + ioArgs.frameDoc = iframe.doc(frame); + this.attach(ioArgs.id, ioArgs.url, ioArgs.frameDoc); + }else{ + waiters.push(ioArgs); + } + } + return false; + }else{ + return oldCanAttach.apply(this, arguments); + } + }; + + return dojox.io.scriptFrame; +}); + diff --git a/js/dojo/dojox/io/windowName.js b/js/dojo/dojox/io/windowName.js new file mode 100644 index 0000000..bca56b4 --- /dev/null +++ b/js/dojo/dojox/io/windowName.js @@ -0,0 +1,224 @@ +//>>built +define("dojox/io/windowName", ["dojo/_base/kernel", "dojo/_base/window", "dojo/_base/xhr", "dojo/_base/sniff", "dojo/_base/url", "dojo/domReady!"], function(dojo){ +dojo.getObject("io.windowName", true, dojox); +// Implements the window.name transport + +dojox.io.windowName = { + send: function(/*String*/ method, /*dojo.__IoArgs*/ args){ + // summary: + // Provides secure cross-domain request capability. + // Sends a request using an iframe (POST or GET) and reads the response through the + // frame's window.name. + // + // method: + // The method to use to send the request, GET or POST + // + // args: + // See dojo.xhr + // + // args.authElement: DOMNode? + // By providing an authElement, this indicates that windowName should use the + // authorized window.name protocol, relying on + // the loaded XD resource to return to the provided return URL on completion + // of authorization/authentication. The provided authElement will be used to place + // the iframe in, so the user can interact with the server resource for authentication + // and/or authorization to access the resource. + // + // args.onAuthLoad: Function? + // When using authorized access to resources, this function will be called when the + // authorization page has been loaded. (When authorization is actually completed, + // the deferred callback function is called with the result). The primary use for this + // is to make the authElement visible to the user once the resource has loaded + // (this can be preferable to showing the iframe while the resource is loading + // since it may not require authorization, it may simply return the resource). + // + // description: + // In order to provide a windowname transport accessible resources/web services, a server + // should check for the presence of a parameter window.name=true and if a request includes + // such a parameter, it should respond to the request with an HTML + // document that sets it's window.name to the string that is to be + // delivered to the client. For example, if a client makes a window.name request like: + // | http://othersite.com/greeting?windowname=true + // And server wants to respond to the client with "Hello", it should return an html page: + // | <html><script type="text/javascript"> + // | window.name="Hello"; + // | </script></html> + // One can provide XML or JSON data by simply quoting the data as a string, and parsing the data + // on the client. + // If you use the authorization window.name protocol, the requester should include an + // authElement element in the args, and a request will be created like: + // | http://othersite.com/greeting?windowname=auth + // And the server can respond like this: + // | <html><script type="text/javascript"> + // | var loc = window.name; + // | authorizationButton.onclick = function(){ + // | window.name="Hello"; + // | location = loc; + // | }; + // | </script></html> + // When using windowName from a XD Dojo build, make sure to set the + // dojo.dojoBlankHtmlUrl property to a local URL. + args.url += (args.url.match(/\?/) ? '&' : '?') + "windowname=" + (args.authElement ? "auth" : true); // indicate our desire for window.name communication + var authElement = args.authElement; + var cleanup = function(result){ + try{ + // we have to do this to stop the wait cursor in FF + var innerDoc = dfd.ioArgs.frame.contentWindow.document; + innerDoc.write(" "); + innerDoc.close(); + }catch(e){} + (authElement || dojo.body()).removeChild(dfd.ioArgs.outerFrame); // clean up + return result; + } + var dfd = dojo._ioSetArgs(args,cleanup,cleanup,cleanup); + if(args.timeout){ + setTimeout(function(){ + if(dfd.fired == -1){ + dfd.callback(new Error("Timeout")); + } + }, + args.timeout + ); + } + dojox.io.windowName._send(dfd, method, authElement, args.onAuthLoad); + return dfd; + }, + _send: function(dfd, method, authTarget, onAuthLoad){ + + var ioArgs = dfd.ioArgs; + var frameNum = dojox.io.windowName._frameNum++; + var sameDomainUrl = (dojo.config.dojoBlankHtmlUrl||dojo.config.dojoCallbackUrl||dojo.moduleUrl("dojo", "resources/blank.html")) + "#" + frameNum; + var frameName = new dojo._Url(window.location, sameDomainUrl); + var doc = dojo.doc; + var frameContainer = authTarget || dojo.body(); + function styleFrame(frame){ + frame.style.width="100%"; + frame.style.height="100%"; + frame.style.border="0px"; + } + if(dojo.isMoz && ![].reduce){ + // FF2 allows unsafe sibling frame modification, + // the fix for this is to create nested frames with getters and setters to protect access + var outerFrame = doc.createElement("iframe"); + styleFrame(outerFrame); + if(!authTarget){ + outerFrame.style.display='none'; + } + frameContainer.appendChild(outerFrame); + + var firstWindow = outerFrame.contentWindow; + doc = firstWindow.document; + doc.write("<html><body margin='0px'><iframe style='width:100%;height:100%;border:0px' name='protectedFrame'></iframe></body></html>"); + doc.close(); + var secondWindow = firstWindow[0]; + firstWindow.__defineGetter__(0,function(){}); + firstWindow.__defineGetter__("protectedFrame",function(){}); + doc = secondWindow.document; + doc.write("<html><body margin='0px'></body></html>"); + doc.close(); + frameContainer = doc.body; + } + var frame; + if(dojo.isIE){ + var div = doc.createElement("div"); + div.innerHTML = '<iframe name="' + frameName + '" onload="dojox.io.windowName['+frameNum+']()">'; + frame = div.firstChild; + }else{ + frame = doc.createElement('iframe'); + } + ioArgs.frame = frame; + styleFrame(frame); + ioArgs.outerFrame = outerFrame = outerFrame || frame; + if(!authTarget){ + outerFrame.style.display='none'; + } + var state = 0; + function getData(){ + var data = frame.contentWindow.name; + if(typeof data == 'string'){ + if(data != frameName){ + state = 2; // we are done now + dfd.ioArgs.hash = frame.contentWindow.location.hash; + dfd.callback(data); + } + } + } + dojox.io.windowName[frameNum] = frame.onload = function(){ + try{ + if(!dojo.isMoz && frame.contentWindow.location =='about:blank'){ + // opera and safari will do an onload for about:blank first, we can ignore this first onload + return; + } + }catch(e){ + // if we are in the target domain, frame.contentWindow.location will throw an ignorable error + } + if(!state){ + // we have loaded the target resource, now time to navigate back to our domain so we can read the frame name + state=1; + if(authTarget){ + // call the callback so it can make it visible + if(onAuthLoad){ + onAuthLoad(); + } + }else{ + // we are doing a synchronous capture, go directly to our same domain URL and retrieve the resource + frame.contentWindow.location = sameDomainUrl; + } + } + // back to our domain, we should be able to access the frame name now + try{ + if(state<2){ + getData(); + } + } + catch(e){ + } + + }; + frame.name = frameName; + if(method.match(/GET/i)){ + // if it is a GET we can just the iframe our src url + dojo._ioAddQueryToUrl(ioArgs); + frame.src = ioArgs.url; + frameContainer.appendChild(frame); + if(frame.contentWindow){ + frame.contentWindow.location.replace(ioArgs.url); + } + }else if(method.match(/POST/i)){ + // if it is a POST we will build a form to post it + frameContainer.appendChild(frame); + var form = dojo.doc.createElement("form"); + dojo.body().appendChild(form); + var query = dojo.queryToObject(ioArgs.query); + for(var i in query){ + var values = query[i]; + values = values instanceof Array ? values : [values]; + for(var j = 0; j < values.length; j++){ + // create hidden inputs for all the parameters + var input = doc.createElement("input"); + input.type = 'hidden'; + input.name = i; + input.value = values[j]; + form.appendChild(input); + } + } + form.method = 'POST'; + form.action = ioArgs.url; + form.target = frameName;// connect the form to the iframe + + form.submit(); + form.parentNode.removeChild(form); + }else{ + throw new Error("Method " + method + " not supported with the windowName transport"); + } + if(frame.contentWindow){ + frame.contentWindow.name = frameName; // IE likes it afterwards + } + }, + _frameNum: 0 + +}; + +return dojox.io.windowName; + +}); diff --git a/js/dojo/dojox/io/xhrMultiPart.js b/js/dojo/dojox/io/xhrMultiPart.js new file mode 100644 index 0000000..29fe9fb --- /dev/null +++ b/js/dojo/dojox/io/xhrMultiPart.js @@ -0,0 +1,161 @@ +//>>built +define("dojox/io/xhrMultiPart", [ + "dojo/_base/kernel", + "dojo/_base/array", + "dojo/_base/xhr", + "dojo/query", + "dojox/uuid/generateRandomUuid" +], function(dojo, array, xhr, query, generateRandomUuid){ + dojo.getObject("io.xhrMultiPart", true, dojox); + + /*===== + dojox.io.__xhrContentArgs = function(){ + // name: String + // Name of the form value. + // content: String + // The contents of the value. + // filename: String? + // An optional filename to pass to the server, as defined by the boundary. + // contentType: String? + // An optional content-type (MIME) to pass to the server, if value is being + // treated as a file. + // charset: String? + // Optional charset to pass, for the server to interpret the file correctly. + // contentTransferEncoding: String? + // Optional transfer encoding header value. + this.name = name; + this.content = content; + this.filename = filename; + this.contentType = contentType; + this.charset = charset; + this.contentTransferEncoding = contentTransferEncoding; + } + =====*/ + function _createPart(/* dojox.io.__xhrContentArgs */args, /* String */boundary){ + // summary + // Assemble an array of boundary parts based on the passed values in args. + if(!args["name"] && !args["content"]){ + throw new Error("Each part of a multi-part request requires 'name' and 'content'."); + } + + var tmp = []; + tmp.push( + "--" + boundary, + "Content-Disposition: form-data; name=\"" + args.name + "\"" + (args["filename"] ? "; filename=\"" + args.filename + "\"" : "") + ); + + if(args["contentType"]){ + var ct = "Content-Type: " + args.contentType; + if(args["charset"]){ + ct += "; Charset=" + args.charset; + } + tmp.push(ct); + } + + if(args["contentTransferEncoding"]){ + tmp.push("Content-Transfer-Encoding: " + args.contentTransferEncoding); + } + tmp.push("", args.content); + return tmp; // Array + } + + function _partsFromNode(/* DOMNode */node, /* String */boundary){ + // summary + // Assemble an array of boundary parts based on the passed FORM node. + var o=dojo.formToObject(node), parts=[]; + for(var p in o){ + if(dojo.isArray(o[p])){ + dojo.forEach(o[p], function(item){ + parts = parts.concat(_createPart({ name: p, content: item }, boundary)); + }); + } else { + parts = parts.concat(_createPart({ name: p, content: o[p] }, boundary)); + } + } + return parts; // Array + } + + /*===== + dojox.io.__xhrMultiArgs = function(){ + // url: String + // URL to server endpoint. + // content: Object? + // Contains properties with string values. These + // properties will be serialized using multi-part + // boundaries. + // file: Object? + // Alias for "content". Provided for backwards compatibility. + // timeout: Integer? + // Milliseconds to wait for the response. If this time + // passes, the then error callbacks are called. + // form: DOMNode? + // DOM node for a form. Used to extract the form values + // and send to the server; each form value will be serialized + // using multi-part boundaries. + // preventCache: Boolean? + // Default is false. If true, then a + // "dojo.preventCache" parameter is sent in the request + // with a value that changes with each request + // (timestamp). Useful only with GET-type requests. + // handleAs: String? + // Acceptable values depend on the type of IO + // transport (see specific IO calls for more information). + // load: Function? + // function(response, ioArgs){}. response is an Object, ioArgs + // is of type dojo.__IoCallbackArgs. The load function will be + // called on a successful response. + // error: Function? + // function(response, ioArgs){}. response is an Object, ioArgs + // is of type dojo.__IoCallbackArgs. The error function will + // be called in an error case. + // handle: Function? + // function(response, ioArgs){}. response is an Object, ioArgs + // is of type dojo.__IoCallbackArgs. The handle function will + // be called in either the successful or error case. + this.url = url; + this.content = content; + this.file = file; + this.timeout = timeout; + this.form = form; + this.preventCache = preventCache; + this.handleAs = handleAs; + this.load = load; + this.error = error; + this.handle = handle; + } + =====*/ + dojox.io.xhrMultiPart = function(/* dojox.io.__xhrMultiArgs */args){ + if(!args["file"] && !args["content"] && !args["form"]){ + throw new Error("content, file or form must be provided to dojox.io.xhrMultiPart's arguments"); + } + + // unique guid as a boundary value for multipart posts + var boundary=generateRandomUuid(), tmp=[], out=""; + if(args["file"] || args["content"]){ + var v = args["file"] || args["content"]; + dojo.forEach((dojo.isArray(v) ? v : [v]), function(item){ + tmp = tmp.concat(_createPart(item, boundary)); + }); + } + else if(args["form"]){ + if(query("input[type=file]", args["form"]).length){ + throw new Error("dojox.io.xhrMultiPart cannot post files that are values of an INPUT TYPE=FILE. Use dojo.io.iframe.send() instead."); + } + tmp = _partsFromNode(args["form"], boundary); + } + + if(tmp.length){ + tmp.push("--"+boundary+"--", ""); + out = tmp.join("\r\n"); + } + + console.log(out); + + return dojo.rawXhrPost(dojo.mixin(args, { + contentType: "multipart/form-data; boundary=" + boundary, + postData: out + })); // dojo.Deferred + }; + + return dojox.io.xhrMultiPart; +}); diff --git a/js/dojo/dojox/io/xhrPlugins.js b/js/dojo/dojox/io/xhrPlugins.js new file mode 100644 index 0000000..70fd8f5 --- /dev/null +++ b/js/dojo/dojox/io/xhrPlugins.js @@ -0,0 +1,171 @@ +//>>built +define("dojox/io/xhrPlugins", ["dojo/_base/kernel", "dojo/_base/xhr", "dojo/AdapterRegistry"], function(dojo, xhr, AdapterRegistry){ + dojo.getObject("io.xhrPlugins", true, dojox); + + var registry; + var plainXhr; + function getPlainXhr(){ + return plainXhr = dojox.io.xhrPlugins.plainXhr = plainXhr || dojo._defaultXhr || xhr; + } + dojox.io.xhrPlugins.register = function(){ + // summary: + // overrides the default xhr handler to implement a registry of + // xhr handlers + var plainXhr = getPlainXhr(); + if(!registry){ + registry = new AdapterRegistry(); + // replaces the default xhr() method. Can we just use connect() instead? + dojo[dojo._defaultXhr ? "_defaultXhr" : "xhr"] = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){ + return registry.match.apply(registry,arguments); + }; + registry.register( + "xhr", + function(method,args){ + if(!args.url.match(/^\w*:\/\//)){ + // if it is not an absolute url (or relative to the + // protocol) we can use this plain XHR + return true; + } + var root = window.location.href.match(/^.*?\/\/.*?\//)[0]; + return args.url.substring(0, root.length) == root; // or check to see if we have the same path + }, + plainXhr + ); + } + return registry.register.apply(registry, arguments); + }; + dojox.io.xhrPlugins.addProxy = function(proxyUrl){ + // summary: + // adds a server side proxy xhr handler for cross-site URLs + // proxyUrl: + // This is URL to send the requests to. + // example: + // Define a proxy: + // | dojox.io.xhrPlugins.addProxy("/proxy?url="); + // And then when you call: + // | dojo.xhr("GET",{url:"http://othersite.com/file"}); + // It would result in the request (to your origin server): + // | GET /proxy?url=http%3A%2F%2Fothersite.com%2Ffile HTTP/1.1 + var plainXhr = getPlainXhr(); + dojox.io.xhrPlugins.register( + "proxy", + function(method,args){ + // this will match on URL + + // really can be used for anything, but plain XHR will take + // precedent by order of loading + return true; + }, + function(method,args,hasBody){ + args.url = proxyUrl + encodeURIComponent(args.url); + return plainXhr.call(dojo, method, args, hasBody); + }); + }; + var csXhrSupport; + dojox.io.xhrPlugins.addCrossSiteXhr = function(url, httpAdapter){ + // summary: + // Adds W3C Cross site XHR or XDomainRequest handling for the given URL prefix + // + // url: + // Requests that start with this URL will be considered for using + // cross-site XHR. + // + // httpAdapter: This allows for adapting HTTP requests that could not otherwise be + // sent with XDR, so you can use a convention for headers and PUT/DELETE methods. + // + // description: + // This can be used for servers that support W3C cross-site XHR. In order for + // a server to allow a client to make cross-site XHR requests, + // it should respond with the header like: + // | Access-Control: allow <*> + // see: http://www.w3.org/TR/access-control/ + var plainXhr = getPlainXhr(); + if(csXhrSupport === undefined && window.XMLHttpRequest){ + // just run this once to see if we have cross-site support + try{ + var xhr = new XMLHttpRequest(); + xhr.open("GET","http://testing-cross-domain-capability.com",true); + csXhrSupport = true; + dojo.config.noRequestedWithHeaders = true; + }catch(e){ + csXhrSupport = false; + } + } + dojox.io.xhrPlugins.register( + "cs-xhr", + function(method,args){ + return (csXhrSupport || + (window.XDomainRequest && args.sync !== true && + (method == "GET" || method == "POST" || httpAdapter))) && + (args.url.substring(0,url.length) == url); + }, + csXhrSupport ? plainXhr : function(){ + var normalXhrObj = dojo._xhrObj; + // we will just substitute this in temporarily so we can use XDomainRequest instead of XMLHttpRequest + dojo._xhrObj = function(){ + + var xdr = new XDomainRequest(); + xdr.readyState = 1; + xdr.setRequestHeader = function(){}; // just absorb them, we can't set headers :/ + xdr.getResponseHeader = function(header){ // this is the only header we can access + return header == "Content-Type" ? xdr.contentType : null; + } + // adapt the xdr handlers to xhr + function handler(status, readyState){ + return function(){ + xdr.readyState = readyState; + xdr.status = status; + } + } + xdr.onload = handler(200, 4); + xdr.onprogress = handler(200, 3); + xdr.onerror = handler(404, 4); // an error, who knows what the real status is + return xdr; + }; + var dfd = (httpAdapter ? httpAdapter(getPlainXhr()) : getPlainXhr()).apply(dojo,arguments); + dojo._xhrObj = normalXhrObj; + return dfd; + } + ); + }; + dojox.io.xhrPlugins.fullHttpAdapter = function(plainXhr,noRawBody){ + // summary: + // Provides a HTTP adaption. + // description: + // The following convention is used: + // method name -> ?http-method=PUT + // Header -> http-Header-Name=header-value + // X-Header -> header_name=header-value + // example: + // dojox.io.xhrPlugins.addXdr("http://somesite.com", dojox.io.xhrPlugins.fullHttpAdapter); + return function(method,args,hasBody){ + var content = {}; + var parameters = {}; + if(method != "GET"){ + parameters["http-method"] = method; + if(args.putData && noRawBody){ + content["http-content"] = args.putData; + delete args.putData; + hasBody = false; + } + if(args.postData && noRawBody){ + content["http-content"] = args.postData; + delete args.postData; + hasBody = false; + } + method = "POST"; + + } + for(var i in args.headers){ + var parameterName = i.match(/^X-/) ? i.substring(2).replace(/-/g,'_').toLowerCase() : ("http-" + i); + parameters[parameterName] = args.headers[i]; + } + args.query = dojo.objectToQuery(parameters); + dojo._ioAddQueryToUrl(args); + args.content = dojo.mixin(args.content || {},content); + return plainXhr.call(dojo,method,args,hasBody); + }; + }; + + return dojox.io.xhrPlugins; +}); diff --git a/js/dojo/dojox/io/xhrScriptPlugin.js b/js/dojo/dojox/io/xhrScriptPlugin.js new file mode 100644 index 0000000..1fe6140 --- /dev/null +++ b/js/dojo/dojox/io/xhrScriptPlugin.js @@ -0,0 +1,36 @@ +//>>built +define("dojox/io/xhrScriptPlugin", ["dojo/_base/kernel", "dojo/_base/window", "dojo/io/script", "dojox/io/xhrPlugins", "dojox/io/scriptFrame"], function(dojo, window, script, xhrPlugins, scriptFrame){ +dojo.getObject("io.xhrScriptPlugin", true, dojox); + +dojox.io.xhrScriptPlugin = function(/*String*/url, /*String*/callbackParamName, /*Function?*/httpAdapter){ + // summary: + // Adds the script transport (JSONP) as an XHR plugin for the given site. See + // dojox.io.script for more information on the transport. Note, that JSONP + // is *not* a secure transport, by loading data from a third-party site using JSONP + // the site has full access to your JavaScript environment. + // url: + // Url prefix of the site which can handle JSONP requests. + // httpAdapter: This allows for adapting HTTP requests that could not otherwise be + // sent with JSONP, so you can use a convention for headers and PUT/DELETE methods. + xhrPlugins.register( + "script", + function(method,args){ + return args.sync !== true && + (method == "GET" || httpAdapter) && + (args.url.substring(0,url.length) == url); + }, + function(method,args,hasBody){ + var send = function(){ + args.callbackParamName = callbackParamName; + if(dojo.body()){ + args.frameDoc = "frame" + Math.random(); + } + return script.get(args); + }; + return (httpAdapter ? httpAdapter(send, true) : send)(method, args, hasBody); // use the JSONP transport + } + ); +}; + +return dojox.io.xhrScriptPlugin; +}); diff --git a/js/dojo/dojox/io/xhrWindowNamePlugin.js b/js/dojo/dojox/io/xhrWindowNamePlugin.js new file mode 100644 index 0000000..729f36e --- /dev/null +++ b/js/dojo/dojox/io/xhrWindowNamePlugin.js @@ -0,0 +1,61 @@ +//>>built +define("dojox/io/xhrWindowNamePlugin", [ + "dojo/_base/kernel", + "dojo/_base/json", + "dojo/_base/xhr", + "dojox/io/xhrPlugins", + "dojox/io/windowName", + "dojox/io/httpParse", + "dojox/secure/capability" +], function(dojo, json, xhr, xhrPlugins, windowName, httpParse, capability){ +dojo.getObject("io.xhrWindowNamePlugin", true, dojox); + +dojox.io.xhrWindowNamePlugin = function(/*String*/url, /*Function?*/httpAdapter, /*Boolean?*/trusted){ + // summary: + // Adds the windowName transport as an XHR plugin for the given site. See + // dojox.io.windowName for more information on the transport. + // url: + // Url prefix of the site which can handle windowName requests. + // httpAdapter: This allows for adapting HTTP requests that could not otherwise be + // sent with window.name, so you can use a convention for headers and PUT/DELETE methods. + xhrPlugins.register( + "windowName", + function(method,args){ + return args.sync !== true && + (method == "GET" || method == "POST" || httpAdapter) && + (args.url.substring(0,url.length) == url); + }, + function(method,args,hasBody){ + var send = windowName.send; + var load = args.load; + args.load = undefined; //we don't want send to set this callback + var dfd = (httpAdapter ? httpAdapter(send, true) : send)(method, args, hasBody); // use the windowName transport + dfd.addCallback(function(result){ + var ioArgs = dfd.ioArgs; + ioArgs.xhr = { + getResponseHeader: function(name){ + // convert the hash to an object to act like response headers + return dojo.queryToObject(ioArgs.hash.match(/[^#]*$/)[0])[name]; + } + } + // use the XHR content handlers for handling + if(ioArgs.handleAs == 'json'){ + // use a secure json verifier, using object capability validator for now + if(!trusted){ + capability.validate(result,["Date"],{}); + } + return dojo.fromJson(result); + } + return dojo._contentHandlers[ioArgs.handleAs || "text"]({responseText:result}); + }); + args.load = load; + if(load){ + dfd.addCallback(load); + } + return dfd; + } + ); +}; + +return dojox.io.xhrWindowNamePlugin; +}); |
