1 // Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
16 * @requires OpenLayers/Request.js
21 // Save reference to earlier defined object implementation (if any)
22 var oXMLHttpRequest = window.XMLHttpRequest;
24 // Define on browser type
25 var bGecko = !!window.controllers,
26 bIE = window.document.all && !window.opera;
29 function cXMLHttpRequest() {
30 this._object = oXMLHttpRequest ? new oXMLHttpRequest : new window.ActiveXObject('Microsoft.XMLHTTP');
33 // BUGFIX: Firefox with Firebug installed would break pages if not executed
34 if (bGecko && oXMLHttpRequest.wrapped)
35 cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped;
38 cXMLHttpRequest.UNSENT = 0;
39 cXMLHttpRequest.OPENED = 1;
40 cXMLHttpRequest.HEADERS_RECEIVED = 2;
41 cXMLHttpRequest.LOADING = 3;
42 cXMLHttpRequest.DONE = 4;
45 cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT;
46 cXMLHttpRequest.prototype.responseText = "";
47 cXMLHttpRequest.prototype.responseXML = null;
48 cXMLHttpRequest.prototype.status = 0;
49 cXMLHttpRequest.prototype.statusText = "";
51 // Instance-level Events Handlers
52 cXMLHttpRequest.prototype.onreadystatechange = null;
54 // Class-level Events Handlers
55 cXMLHttpRequest.onreadystatechange = null;
56 cXMLHttpRequest.onopen = null;
57 cXMLHttpRequest.onsend = null;
58 cXMLHttpRequest.onabort = null;
61 cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) {
63 // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
66 // Set the onreadystatechange handler
68 nState = this.readyState;
70 // BUGFIX: IE - memory leak on page unload (inter-page leak)
72 var fOnUnload = function() {
73 if (oRequest._object.readyState != cXMLHttpRequest.DONE)
74 fCleanTransport(oRequest);
77 window.attachEvent("onunload", fOnUnload);
80 this._object.onreadystatechange = function() {
81 if (bGecko && !bAsync)
85 oRequest.readyState = oRequest._object.readyState;
88 fSynchronizeValues(oRequest);
90 // BUGFIX: Firefox fires unneccesary DONE when aborting
91 if (oRequest._aborted) {
92 // Reset readyState to UNSENT
93 oRequest.readyState = cXMLHttpRequest.UNSENT;
99 if (oRequest.readyState == cXMLHttpRequest.DONE) {
101 fCleanTransport(oRequest);
102 // Uncomment this block if you need a fix for IE cache
104 // BUGFIX: IE - cache issue
105 if (!oRequest._object.getResponseHeader("Date")) {
106 // Save object to cache
107 oRequest._cached = oRequest._object;
109 // Instantiate a new transport object
110 cXMLHttpRequest.call(oRequest);
113 oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
114 oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
116 if (oRequest._headers)
117 for (var sHeader in oRequest._headers)
118 if (typeof oRequest._headers[sHeader] == "string") // Some frameworks prototype objects with functions
119 oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
121 oRequest._object.onreadystatechange = function() {
123 oRequest.readyState = oRequest._object.readyState;
125 if (oRequest._aborted) {
127 oRequest.readyState = cXMLHttpRequest.UNSENT;
133 if (oRequest.readyState == cXMLHttpRequest.DONE) {
135 fCleanTransport(oRequest);
137 // get cached request
138 if (oRequest.status == 304)
139 oRequest._object = oRequest._cached;
142 delete oRequest._cached;
145 fSynchronizeValues(oRequest);
148 fReadyStateChange(oRequest);
150 // BUGFIX: IE - memory leak in interrupted
152 window.detachEvent("onunload", fOnUnload);
155 oRequest._object.send(null);
157 // Return now - wait untill re-sent request is finished
161 // BUGFIX: IE - memory leak in interrupted
163 window.detachEvent("onunload", fOnUnload);
166 // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
167 if (nState != oRequest.readyState)
168 fReadyStateChange(oRequest);
170 nState = oRequest.readyState;
173 // Add method sniffer
174 if (cXMLHttpRequest.onopen)
175 cXMLHttpRequest.onopen.apply(this, arguments);
177 this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
179 // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
180 if (!bAsync && bGecko) {
181 this.readyState = cXMLHttpRequest.OPENED;
183 fReadyStateChange(this);
186 cXMLHttpRequest.prototype.send = function(vData) {
187 // Add method sniffer
188 if (cXMLHttpRequest.onsend)
189 cXMLHttpRequest.onsend.apply(this, arguments);
191 // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
192 // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
193 // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
194 if (vData && vData.nodeType) {
195 vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
196 if (!this._headers["Content-Type"])
197 this._object.setRequestHeader("Content-Type", "application/xml");
200 this._object.send(vData);
202 // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
203 if (bGecko && !this._async) {
204 this.readyState = cXMLHttpRequest.OPENED;
207 fSynchronizeValues(this);
209 // Simulate missing states
210 while (this.readyState < cXMLHttpRequest.DONE) {
212 fReadyStateChange(this);
213 // Check if we are aborted
219 cXMLHttpRequest.prototype.abort = function() {
220 // Add method sniffer
221 if (cXMLHttpRequest.onabort)
222 cXMLHttpRequest.onabort.apply(this, arguments);
224 // BUGFIX: Gecko - unneccesary DONE when aborting
225 if (this.readyState > cXMLHttpRequest.UNSENT)
226 this._aborted = true;
228 this._object.abort();
230 // BUGFIX: IE - memory leak
231 fCleanTransport(this);
233 cXMLHttpRequest.prototype.getAllResponseHeaders = function() {
234 return this._object.getAllResponseHeaders();
236 cXMLHttpRequest.prototype.getResponseHeader = function(sName) {
237 return this._object.getResponseHeader(sName);
239 cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) {
240 // BUGFIX: IE - cache issue
243 this._headers[sName] = sValue;
245 return this._object.setRequestHeader(sName, sValue);
247 cXMLHttpRequest.prototype.toString = function() {
248 return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
250 cXMLHttpRequest.toString = function() {
251 return '[' + "XMLHttpRequest" + ']';
255 function fReadyStateChange(oRequest) {
256 // Execute onreadystatechange
257 if (oRequest.onreadystatechange)
258 oRequest.onreadystatechange.apply(oRequest);
261 if (cXMLHttpRequest.onreadystatechange)
262 cXMLHttpRequest.onreadystatechange.apply(oRequest);
265 function fGetDocument(oRequest) {
266 var oDocument = oRequest.responseXML;
267 // Try parsing responseText
268 if (bIE && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
269 oDocument = new ActiveXObject('Microsoft.XMLDOM');
270 oDocument.loadXML(oRequest.responseText);
272 // Check if there is no error in document
274 if ((bIE && oDocument.parseError != 0) || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror"))
279 function fSynchronizeValues(oRequest) {
280 try { oRequest.responseText = oRequest._object.responseText; } catch (e) {}
281 try { oRequest.responseXML = fGetDocument(oRequest._object); } catch (e) {}
282 try { oRequest.status = oRequest._object.status; } catch (e) {}
283 try { oRequest.statusText = oRequest._object.statusText; } catch (e) {}
286 function fCleanTransport(oRequest) {
287 // BUGFIX: IE - memory leak (on-page leak)
288 oRequest._object.onreadystatechange = new window.Function;
290 // Delete private properties
291 delete oRequest._headers;
294 // Internet Explorer 5.0 (missing apply)
295 if (!window.Function.prototype.apply) {
296 window.Function.prototype.apply = function(oRequest, oArguments) {
299 oRequest.__func = this;
300 oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
301 delete oRequest.__func;
305 // Register new object with window
307 * Class: OpenLayers.Request.XMLHttpRequest
308 * Standard-compliant (W3C) cross-browser implementation of the
309 * XMLHttpRequest object. From
310 * http://code.google.com/p/xmlhttprequest/.
312 OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;