Skip to content

Instantly share code, notes, and snippets.

@mpriour
Created September 11, 2013 18:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpriour/6527958 to your computer and use it in GitHub Desktop.
Save mpriour/6527958 to your computer and use it in GitHub Desktop.
a closure compiler compatible network request worker
/**
* Takes a worker message with a request object as the data member, then sends and recieves result via XHR
* @param {Event} evt
*/
function sendRequest(evt) {
var args = evt.data;
var method = args.method;
var url = args.url;
var options = args.options;
var data = options.data;
var async = !options.sync;
var query = options.query;
var xhr = new XMLHttpRequest();
if(!data && query){
url += "?"+query;
}
addEventListeners(xhr, args);
xhr.open(method, url, async, options.user || undefined, options.password || undefined);
if (options.withCredentials) {
xhr.withCredentials = options.withCredentials;
}
var headers = options.headers;
var contentType = 'application/x-www-form-urlencoded';
if (headers) {
for (var hdr in headers) {
if (hdr.toLowerCase() === 'content-type') {
contentType = headers[hdr];
} else if (headers[hdr]) {
//Only add header if it has a value. This allows for instance, skipping
//insertion of X-Requested-With by specifying empty value.
xhr.setRequestHeader(hdr, headers[hdr]);
}
}
}
if (contentType && contentType !== false) {
xhr.setRequestHeader('Content-Type', contentType);
}
if (args.handleAs) {
var handleAs = args.handleAs.toLowerCase();
switch (handleAs) {
case 'xml':
case 'html':
xhr.responseType = 'document';
var mime = (handleAs == 'xml') ? 'text/xml' : 'text/html';
xhr.overrideMimeType(mime);
break;
case 'json':
case 'text':
case 'blob':
case 'arraybuffer':
xhr.responseType = handleAs;
break;
}
}
postMessage({
qid: args.qid,
status: "progress",
"url": url,
headers: headers,
data: data
});
xhr.send(data);
}
/**
* @private
* @param {XMLHttpRequest} xhr
* @param {Object} args
*/
function addEventListeners(xhr, args) {
function onError(evt) {
var _xhr = evt.target;
var error = new Error('Unable to load ' + args.url + ' status: ' + _xhr.status, args);
postMessage({
qid: args.qid,
status: 'error',
url: args.url,
message: error.message/*,
error: error*/
});
}
function onProgress(evt) {
var response = {
qid: args.qid,
status: 'progress',
url: args.url
};
if (evt.lengthComputable) {
response.loaded = evt.loaded;
response.total = evt.total;
}
postMessage(response);
}
function onLoad(evt) {
var _xhr = evt.target;
var parsed = (_xhr.response instanceof Object) ? _xhr.response : parseResponse(_xhr, args.options.handleAs);
var headerText = _xhr.getAllResponseHeaders();
var keys = headerText.match(/\w+[\-]?\w+?\:\s/g);
headerText = headerText.split('\n');
var headers = keys.reduce(function(acc, val, ndx) {
acc[val.split(':')[0]] = headerText[ndx].split(val)[1];
return acc;
}, {});
postMessage({
qid: args.qid,
url: args.url,
response: parsed,
headers: headers,
statusText: _xhr.statusText,
status: _xhr.status,
readyState: _xhr.readyState
});
}
xhr.addEventListener('load', onLoad, false);
xhr.addEventListener('error', onError, false);
xhr.addEventListener('progress', onProgress, false);
}
/**
* @param {XMLHttpRequest} xhr
* @param {String=} overrideParser
* @return {Object}
*/
function parseResponse(xhr, overrideParser) {
var resp = xhr.responseText;
var contentType = xhr.getResponseHeader("content-type");
//TODO handle jsonp
//json
if (contentType.indexOf('json') > -1 || overrideParser == 'json') {
try {
resp = JSON.parse(xhr.responseText);
} catch (e){}
}
//xml
else if ((contentType.indexOf('xml') > -1 || overrideParser == 'xml') && xhr.responseXML) {
resp = xhr.responseXML;
}
return resp;
}
/**
* @typedef {{addEventListener: function(string, function(object)), postMessage: function(object), onmessage: function(object)}}
*/
self;
self.addEventListener('message', sendRequest);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment