Skip to content

Instantly share code, notes, and snippets.

@Noitidart
Last active August 29, 2015 13:56
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 Noitidart/9088113 to your computer and use it in GitHub Desktop.
Save Noitidart/9088113 to your computer and use it in GitHub Desktop.
_firefox-addon-snippet-HTTPWrapper - Forked from an addon long ago and slightly tweaked here and there. Designed for use in privelaged scope, meaning it does not need access to nsIDOMWindow for any properies or functions.
var XMLHttpRequest = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'];
var timeoutTimer;
/**
* The following keys can be sent:
* onSuccess (required) a function called when the response is 2xx
* onFailure a function called when the response is not 2xx (IF onFailure and onTimeout are defined, when times out then onTimeout is executed only and not onFailure. IF onFailure is defined and onTimeout is NOT defined then when times out it will execute onFailure) (not called if aborted)
* username The username for basic auth
* password The password for basic auth
* overrideMimeType The mime type to use for non-XML response mime types
* timeout A timeout value in milliseconds for the response
* onTimeout A function to call if the request times out.
* body A string containing the entity body of the request
* contentType The content type of the entity body of the request
* headers A hash of optional headers
* returnHeaders Set to true if want headers returned in the "headers" var of the onSuccess etc
*/
function HTTP(method,url,options)
{
var requester = new XMLHttpRequest();
if (!timeoutTimer && options.timeout) {
timeoutTimer = Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer);
}
if (!options.synchronizedRequest) {
requester.onreadystatechange = function() {
switch (requester.readyState) {
case 0:
if (options.onUnsent) {
options.onUnsent(requester);
}
break;
case 1:
if (options.onOpened) {
options.onOpened(requester);
}
break;
case 2:
if (options.onHeaders) {
options.onHeaders(requester);
}
break;
case 3:
if (options.onLoading) {
options.onLoading(requester);
}
break;
case 4:
if (options.timeout) {
timeoutTimer.cancel();
}
if (requester.status==0 || (requester.status>=200 && requester.status<300)) {
options.onSuccess(
requester.status,
requester.responseXML,
requester.responseText,
options.returnHeaders ? _HTTP_parseHeaders(requester.getAllResponseHeaders()) : null,
requester.statusText
);
} else {
if (options.onFailure) {
options.onFailure(
requester.status,
requester.responseXML,
requester.responseText,
options.returnHeaders ? _HTTP_parseHeaders(requester.getAllResponseHeaders()) : null,
requester.statusText
);
}
}
break;
}
}
}
if (options.overrideMimeType) {
requester.overrideMimeType(options.overrideMimeType);
}
if (options.username) {
requester.open(method,url,!options.synchronizedRequest,options.username,options.password);
} else {
requester.open(method,url,!options.synchronizedRequest);
}
if (options.timeout && !options.synchronizedRequest) {
var timeoutEvent = {
notify: function(timer) {
requester.abort();
var callback = options.onTimeout ? options.onTimeout : options.onFailure;
if (callback) {
callback(0, 'Operation timeout.');
}
}
}
timeoutTimer.initWithCallback(timeoutEvent, options.timeout, Ci.nsITimer.TYPE_ONE_SHOT);
}
if (options.headers) {
for (var name in options.headers) {
requester.setRequestHeader(name,options.headers[name]);
}
}
if (options.sendAsBinary) {
Cu.reportError('sending as binary');
requester.sendAsBinary(options.body);
} else if (options.body) {
requester.setRequestHeader("Content-Type",options.contentType);
requester.send(options.body);
} else {
requester.send(null);
}
if (options.synchronizedRequest) {
if (requester.status==0 || (requester.status>=200 && requester.status<300)) {
options.onSuccess(
requester.status,
requester.responseXML,
requester.responseText,
options.returnHeaders ? _HTTP_parseHeaders(requester.getAllResponseHeaders()) : null,
requester.statusText
);
} else {
if (options.onFailure) {
options.onFailure(
requester.status,
requester.responseXML,
requester.responseText,
options.returnHeaders ? _HTTP_parseHeaders(requester.getAllResponseHeaders()) : null,
requester.statusText
);
}
}
return {
abort: function() {
}
};
} else {
return {
abort: function() {
requester.abort();
if (options.timeout) {
timeoutTimer.cancel();
}
}
};
}
}
var _HTTP_HEADER_NAME = new RegExp("^([a-zA-Z0-9_-]+):");
function _HTTP_parseHeaders(headerText)
{
var headers = {};
if (headerText) {
var eol = headerText.indexOf("\n");
while (eol>=0) {
var line = headerText.substring(0,eol);
headerText = headerText.substring(eol+1);
while (headerText.length>0 && !headerText.match(_HTTP_HEADER_NAME)) {
eol = headerText.indexOf("\n");
var nextLine = eol<0 ? headerText : headerText.substring(0,eol);
line = line+' '+nextLine;
headerText = eol<0 ? "" : headerText.substring(eol+1);
}
// Parse the name value pair
var colon = line.indexOf(':');
var name = line.substring(0,colon);
var value = line.substring(colon+1);
headers[name] = value;
eol = headerText.indexOf("\n");
}
if (headerText.length>0) {
var colon = headerText.indexOf(':');
var name = headerText.substring(0,colon);
var value = headerText.substring(colon+1);
headers[name] = value;
}
}
return headers;
}
@Noitidart
Copy link
Author

README

Rev1

  • Pseudo-fork (copy/paste) from addon Poster
  • Modified so it works without window context for all except timeout

Rev2

  • Making it standalone, brought in the XMLHttpRequest const at L#1 which it wouldnt work without
  • Making timeout nsITimer
  • Fixed bug on L#47 it was if (timeout) it should be if(options.timeout)
  • Another bug fixed, on timeout timer complete it was not aborting the requester, just calling the callback
  • In current design, if onTimeout is set and onFailure is set, it only executes onTimeout when times out and not the onFailure, although I think I should make it execute onFailure too
  • Another bug, well incomplete, when sync it was not returning abort function that actually aborted it, it was just returning an empty abort function strike through, this is actually not an incomplete, because its sync, you can't run abort while its doing something
  • Outstanding issue when times out, it still calls onSuccess I dont know why

Rev3

  • Made it check on L#22, if options.timeout is set and timeoutTimer is not set then create it, otherwise don't worry about creating it as its overhead

@Noitidart
Copy link
Author

Basic example:

HTTP('GET','http://www.bing.com/',{
onSuccess: function(status, responseXML, responseText, headers, statusText) {
alert('success')
},
onFailure: function(status, responseXML, responseText, headers, statusText) {
alert('failed')
}
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment