Created
May 18, 2015 16:12
-
-
Save timraymond/042cbed0ef0a9fe3ef30 to your computer and use it in GitHub Desktop.
IE9 Compatible XHR Adapter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Connection class to use with the elasticsearch.js client for limited compatibility with | |
* IE 9 (also IE 8 is you include an es5 shim like https://github.com/es-shims/es5-shim). | |
* | |
* All connections from the browser, directly to elasticsearch, are assumed to be cross-domain | |
* and therefore suffer from a lack of support in legacy browsers. To prevent the client from | |
* behaving differently based on the browser version, the following limitations have been imposed | |
* on all requests: | |
* | |
* - only GET and POST are supported | |
* - Authentication can't be used | |
* - Custom headers can't be set | |
* - Requests can't be made to localhost unless the page is running on localhost | |
* - Protocols of the parent window and the request must match. | |
* | |
* Also because of restrictions put in place by IE8/9, responses will be different | |
* in the following ways: | |
* - Status codes are not available for the responses | |
* - Any non-20x status code is considered a generic error. No response body will be available | |
* | |
* @class Ie9CompatibleXhrConnector | |
*/ | |
window.Ie9CompatibleXhrConnector = (function () { | |
var EsXhrConnection = elasticsearch.ConnectionPool.connectionClasses.xhr; | |
var ConnectionFault = elasticsearch.errors.ConnectionFault; | |
// perminent references | |
var ModernXhr = window.XMLHttpRequest; | |
var LegacyXhr = window.XDomainRequest; | |
var setImmediate = window.setImmediate || function (cb) { setTimeout(cb, 1); }; | |
var currentProtocol = window.location.protocol.substr(0, window.location.protocol.length - 1); | |
var localhostRE = /:\/\/(localhost|127\.0\.0\.1)[:\/]/; | |
function Ie9CompatibleXhrConnector(host, config) { | |
EsXhrConnection.call(this, host, config); | |
this._XhrConstructor = (function () { | |
if (typeof ModernXhr !== 'undefined') { | |
var req = new ModernXhr(); | |
if ('withCredentials' in req) { | |
return ModernXhr; | |
} | |
} | |
if (typeof LegacyXhr !== 'undefined') { | |
return LegacyXhr; | |
} | |
throw new Error('Unable to find a suitable Cross-Domain AJAX handler.'); | |
}()); | |
} | |
// inherit EsXhrConnection's prototype | |
Ie9CompatibleXhrConnector.prototype = Object.create(EsXhrConnection.prototype, { 'constructor': Ie9CompatibleXhrConnector }); | |
Ie9CompatibleXhrConnector.prototype.request = function (params, cb) { | |
var xhr = new this._XhrConstructor(); | |
// This is a patch to this.host by Tim Raymond to get results working | |
// on search. It isn't really necessary for that page. | |
this.host.getHeaders = function() { return false }; | |
var hasHeaders = !!this.host.getHeaders(params.headers); | |
var url = this.host.makeUrl(params); | |
var log = this.log; | |
var hasAuth = this.host.auth; | |
var method = (params.method || 'GET').toUpperCase(); | |
var err = function (msg) { | |
// always callback async | |
setImmediate(function () { | |
cb(new TypeError('Cross-domain AJAX requests ' + msg + ' are not supported')); | |
}); | |
}; | |
/** | |
* To prevent some browsers from behaving differently from others, implement some checks here | |
*/ | |
if (method !== 'GET' && method !== 'POST') { | |
return err('using HTTP method ' + method); | |
} | |
if (localhostRE.test(url) && !localhostRE.test(window.location.href)) { | |
return err('to localhost from other domains'); | |
} | |
if (hasAuth) { | |
return err('with authentication'); | |
} | |
if (hasHeaders) { | |
return err('with custom headers'); | |
} | |
if (this.host.protocol !== currentProtocol) { | |
return err('across protocols'); | |
} | |
/** | |
* Setup listeners for the response | |
*/ | |
if (this._XhrConstructor === LegacyXhr) { | |
// XDomainRequest does not support onreadystatechange | |
xhr.onload = function () { | |
log.trace(params.method, url, params.body, xhr.responseText, xhr.status); | |
cb(void 0, xhr.responseText, 200); | |
}; | |
// XDomainRequest also sends errors elsewhere | |
xhr.onerror = function (err) { | |
log.trace(params.method, url, params.body, xhr.responseText, xhr.status); | |
cb(new ConnectionFault(err.message), xhr.responseText, void 0); | |
}; | |
} | |
if (this._XhrConstructor === ModernXhr) { | |
xhr.onreadystatechange = function () { | |
if (xhr.readyState === 4) { | |
log.trace(params.method, url, params.body, xhr.responseText, xhr.status); | |
var err = xhr.status ? void 0 : new ConnectionFault(xhr.statusText || 'Request failed to complete.'); | |
cb(err, xhr.responseText, xhr.status); | |
} | |
}; | |
} | |
/** | |
* Send the request | |
*/ | |
xhr.open(method, url); | |
xhr.send(params.body || void 0); | |
return function () { | |
xhr.abort(); | |
}; | |
}; | |
return Ie9CompatibleXhrConnector; | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment