XMLHttpRequest
1 /* 2 3 Cross-Browser XMLHttpRequest v1.2 4 ================================= 5 6 Emulate Gecko 'XMLHttpRequest()' functionality in IE and Opera. Opera requires 7 the Sun Java Runtime Environment <http://www.java.com/>. 8 9 by Andrew Gregory 10 http://www.scss.com.au/family/andrew/webdesign/xmlhttprequest/ 11 12 This work is licensed under the Creative Commons Attribution License. To view a 13 copy of this license, visit http://creativecommons.org/licenses/by-sa/2.5/ or 14 send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 15 94305, USA. 16 17 Attribution: Leave my name and web address in this script intact. 18 19 Not Supported in Opera 20 ---------------------- 21 * user/password authentication 22 * responseXML data member 23 24 Not Fully Supported in Opera 25 ---------------------------- 26 * async requests 27 * abort() 28 * getAllResponseHeaders(), getAllResponseHeader(header) 29 30 */ 31 // IE support 32 if (window.ActiveXObject && !window.XMLHttpRequest) { 33 window.XMLHttpRequest = function() { 34 var msxmls = new Array( 35 'Msxml2.XMLHTTP.5.0', 36 'Msxml2.XMLHTTP.4.0', 37 'Msxml2.XMLHTTP.3.0', 38 'Msxml2.XMLHTTP', 39 'Microsoft.XMLHTTP'); 40 for (var i = 0; i < msxmls.length; i++) { 41 try { 42 return new ActiveXObject(msxmls[i]); 43 } catch (e) { 44 } 45 } 46 return null; 47 }; 48 } 49 // Gecko support 50 /* ;-) */ 51 // Opera support 52 if (window.opera && !window.XMLHttpRequest) { 53 window.XMLHttpRequest = function() { 54 this.readyState = 0; // 0=uninitialized,1=loading,2=loaded,3=interactive,4=complete 55 this.status = 0; // HTTP status codes 56 this.statusText = ''; 57 this._headers = []; 58 this._aborted = false; 59 this._async = true; 60 this._defaultCharset = 'ISO-8859-1'; 61 this._getCharset = function() { 62 var charset = _defaultCharset; 63 var contentType = this.getResponseHeader('Content-type').toUpperCase(); 64 val = contentType.indexOf('CHARSET='); 65 if (val != -1) { 66 charset = contentType.substring(val); 67 } 68 val = charset.indexOf(';'); 69 if (val != -1) { 70 charset = charset.substring(0, val); 71 } 72 val = charset.indexOf(','); 73 if (val != -1) { 74 charset = charset.substring(0, val); 75 } 76 return charset; 77 }; 78 this.abort = function() { 79 this._aborted = true; 80 }; 81 this.getAllResponseHeaders = function() { 82 return this.getAllResponseHeader('*'); 83 }; 84 this.getAllResponseHeader = function(header) { 85 var ret = ''; 86 for (var i = 0; i < this._headers.length; i++) { 87 if (header == '*' || this._headers[i].h == header) { 88 ret += this._headers[i].h + ': ' + this._headers[i].v + '\n'; 89 } 90 } 91 return ret; 92 }; 93 this.getResponseHeader = function(header) { 94 var ret = getAllResponseHeader(header); 95 var i = ret.indexOf('\n'); 96 if (i != -1) { 97 ret = ret.substring(0, i); 98 } 99 return ret; 100 }; 101 this.setRequestHeader = function(header, value) { 102 this._headers[this._headers.length] = {h:header, v:value}; 103 }; 104 this.open = function(method, url, async, user, password) { 105 this.method = method; 106 this.url = url; 107 this._async = true; 108 this._aborted = false; 109 this._headers = []; 110 if (arguments.length >= 3) { 111 this._async = async; 112 } 113 if (arguments.length > 3) { 114 opera.postError('XMLHttpRequest.open() - user/password not supported'); 115 } 116 this.readyState = 1; 117 if (this.onreadystatechange) { 118 this.onreadystatechange(); 119 } 120 }; 121 this.send = function(data) { 122 if (!navigator.javaEnabled()) { 123 alert("XMLHttpRequest.send() - Java must be installed and enabled."); 124 return; 125 } 126 if (this._async) { 127 setTimeout(this._sendasync, 0, this, data); 128 // this is not really asynchronous and won't execute until the current 129 // execution context ends 130 } else { 131 this._sendsync(data); 132 } 133 } 134 this._sendasync = function(req, data) { 135 if (!req._aborted) { 136 req._sendsync(data); 137 } 138 }; 139 this._sendsync = function(data) { 140 this.readyState = 2; 141 if (this.onreadystatechange) { 142 this.onreadystatechange(); 143 } 144 // open connection 145 var url = new java.net.URL(new java.net.URL(window.location.href), this.url); 146 var conn = url.openConnection(); 147 for (var i = 0; i < this._headers.length; i++) { 148 conn.setRequestProperty(this._headers[i].h, this._headers[i].v); 149 } 150 this._headers = []; 151 if (this.method == 'POST') { 152 // POST data 153 conn.setDoOutput(true); 154 var wr = new java.io.OutputStreamWriter(conn.getOutputStream(), this._getCharset()); 155 wr.write(data); 156 wr.flush(); 157 wr.close(); 158 } 159 // read response headers 160 // NOTE: the getHeaderField() methods always return nulls for me :( 161 var gotContentEncoding = false; 162 var gotContentLength = false; 163 var gotContentType = false; 164 var gotDate = false; 165 var gotExpiration = false; 166 var gotLastModified = false; 167 for (var i = 0; ; i++) { 168 var hdrName = conn.getHeaderFieldKey(i); 169 var hdrValue = conn.getHeaderField(i); 170 if (hdrName == null && hdrValue == null) { 171 break; 172 } 173 if (hdrName != null) { 174 this._headers[this._headers.length] = {h:hdrName, v:hdrValue}; 175 switch (hdrName.toLowerCase()) { 176 case 'content-encoding': gotContentEncoding = true; break; 177 case 'content-length' : gotContentLength = true; break; 178 case 'content-type' : gotContentType = true; break; 179 case 'date' : gotDate = true; break; 180 case 'expires' : gotExpiration = true; break; 181 case 'last-modified' : gotLastModified = true; break; 182 } 183 } 184 } 185 // try to fill in any missing header information 186 var val; 187 val = conn.getContentEncoding(); 188 if (val != null && !gotContentEncoding) this._headers[this._headers.length] = {h:'Content-encoding', v:val}; 189 val = conn.getContentLength(); 190 if (val != -1 && !gotContentLength) this._headers[this._headers.length] = {h:'Content-length', v:val}; 191 val = conn.getContentType(); 192 if (val != null && !gotContentType) this._headers[this._headers.length] = {h:'Content-type', v:val}; 193 val = conn.getDate(); 194 if (val != 0 && !gotDate) this._headers[this._headers.length] = {h:'Date', v:(new Date(val)).toUTCString()}; 195 val = conn.getExpiration(); 196 if (val != 0 && !gotExpiration) this._headers[this._headers.length] = {h:'Expires', v:(new Date(val)).toUTCString()}; 197 val = conn.getLastModified(); 198 if (val != 0 && !gotLastModified) this._headers[this._headers.length] = {h:'Last-modified', v:(new Date(val)).toUTCString()}; 199 // read response data 200 var reqdata = ''; 201 var stream = conn.getInputStream(); 202 if (stream) { 203 var reader = new java.io.BufferedReader(new java.io.InputStreamReader(stream, this._getCharset())); 204 var line; 205 while ((line = reader.readLine()) != null) { 206 if (this.readyState == 2) { 207 this.readyState = 3; 208 if (this.onreadystatechange) { 209 this.onreadystatechange(); 210 } 211 } 212 reqdata += line + '\n'; 213 } 214 reader.close(); 215 this.status = 200; 216 this.statusText = 'OK'; 217 this.responseText = reqdata; 218 this.readyState = 4; 219 if (this.onreadystatechange) { 220 this.onreadystatechange(); 221 } 222 if (this.onload) { 223 this.onload(); 224 } 225 } else { 226 // error 227 this.status = 404; 228 this.statusText = 'Not Found'; 229 this.responseText = ''; 230 this.readyState = 4; 231 if (this.onreadystatechange) { 232 this.onreadystatechange(); 233 } 234 if (this.onerror) { 235 this.onerror(); 236 } 237 } 238 }; 239 }; 240 } 241 // ActiveXObject emulation 242 if (!window.ActiveXObject && window.XMLHttpRequest) { 243 window.ActiveXObject = function(type) { 244 switch (type.toLowerCase()) { 245 case 'microsoft.xmlhttp': 246 case 'msxml2.xmlhttp': 247 case 'msxml2.xmlhttp.3.0': 248 case 'msxml2.xmlhttp.4.0': 249 case 'msxml2.xmlhttp.5.0': 250 return new XMLHttpRequest(); 251 } 252 return null; 253 }; 254 }