aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore15
-rw-r--r--caldav.js90
-rw-r--r--lib/caldav/request/abstract.js4
-rw-r--r--lib/caldav/request/asset.js12
-rw-r--r--lib/caldav/request/calendar_home.js13
-rw-r--r--lib/caldav/xhr.js61
-rw-r--r--test-agent/config.json3
-rw-r--r--test/caldav/request/abstract_test.js7
-rw-r--r--test/caldav/xhr_test.js36
9 files changed, 168 insertions, 73 deletions
diff --git a/.gitignore b/.gitignore
index bca33be..206e778 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,10 @@
-node_modules
.DS_Store
-data/
-vendor/
-sandbox/
-.gitignore
-test/servers/servers.json \ No newline at end of file
+
+/data/
+/node_modules/
+/sandbox/
+/vendor/
+
+/test/servers/servers.json
+/test-agent/config.json
+
diff --git a/caldav.js b/caldav.js
index ba6bc7a..dfe8694 100644
--- a/caldav.js
+++ b/caldav.js
@@ -2025,6 +2025,7 @@ function write (chunk) {
Xhr.prototype = {
globalXhrOptions: null,
xhrClass: Native,
+ xhr: null,
method: 'GET',
async: true,
waiting: false,
@@ -2035,7 +2036,7 @@ function write (chunk) {
headers: {},
data: null,
- _seralize: function _seralize() {
+ _serialize: function _serialize() {
return this.data;
},
@@ -2052,31 +2053,45 @@ function write (chunk) {
},
/**
+ * Aborts the request if it has already been sent.
+ * @param {Function=} cb An optional callback function.
+ */
+ abort: function(cb) {
+ if (this.waiting) {
+ this.xhr.abort();
+ this.waiting = false;
+ }
+
+ if (cb !== undefined) {
+ cb();
+ }
+ },
+
+ /**
* Sends request to server.
*
* @param {Function} callback success/failure handler.
*/
send: function send(callback) {
- var header, xhr;
+ var header;
if (typeof(callback) === 'undefined') {
callback = this.callback;
}
- if (this.globalXhrOptions) {
- xhr = new this.xhrClass(this.globalXhrOptions);
- } else {
- xhr = new this.xhrClass();
- }
+ this.xhr = new this.xhrClass(
+ this.globalXhrOptions ? this.globalXhrOptions : undefined);
+
// This hack is in place due to some platform
// bug in gecko when using mozSystem xhr
// the credentials only seem to work as expected
// when constructing them manually.
if (!this.globalXhrOptions || !this.globalXhrOptions.mozSystem) {
- xhr.open(this.method, this.url, this.async, this.user, this.password);
+ this.xhr.open(
+ this.method, this.url, this.async, this.user, this.password);
} else {
- xhr.open(this.method, this.url, this.async);
- xhr.setRequestHeader('Authorization', this._credentials(
+ this.xhr.open(this.method, this.url, this.async);
+ this.xhr.setRequestHeader('Authorization', this._credentials(
this.user,
this.password
));
@@ -2085,12 +2100,12 @@ function write (chunk) {
var useMozChunkedText = false;
if (this.globalXhrOptions && this.globalXhrOptions.useMozChunkedText) {
useMozChunkedText = true;
- xhr.responseType = 'moz-chunked-text';
+ this.xhr.responseType = 'moz-chunked-text';
}
for (header in this.headers) {
if (Object.hasOwnProperty.call(this.headers, header)) {
- xhr.setRequestHeader(header, this.headers[header]);
+ this.xhr.setRequestHeader(header, this.headers[header]);
}
}
@@ -2098,19 +2113,19 @@ function write (chunk) {
var hasProgressEvents = false;
// check for progress event support.
- if ('onprogress' in xhr) {
+ if ('onprogress' in this.xhr) {
hasProgressEvents = true;
var last = 0;
if (useMozChunkedText) {
- xhr.onprogress = (function onChunkedProgress(event) {
+ this.xhr.onprogress = (function onChunkedProgress(event) {
if (this.ondata) {
- this.ondata(xhr.responseText);
+ this.ondata(this.xhr.responseText);
}
}.bind(this));
} else {
- xhr.onprogress = (function onProgress(event) {
- var chunk = xhr.responseText.substr(last, event.loaded);
+ this.xhr.onprogress = (function onProgress(event) {
+ var chunk = this.xhr.responseText.substr(last, event.loaded);
last = event.loaded;
if (this.ondata) {
this.ondata(chunk);
@@ -2119,10 +2134,10 @@ function write (chunk) {
}
}
- xhr.onreadystatechange = (function onReadyStateChange() {
+ this.xhr.onreadystatechange = (function onReadyStateChange() {
var data;
- if (xhr.readyState === 4) {
- data = xhr.responseText;
+ if (this.xhr.readyState === 4) {
+ data = this.xhr.responseText;
// emulate progress events for node...
// this really lame we should probably just
@@ -2133,14 +2148,14 @@ function write (chunk) {
}
this.waiting = false;
- callback(null, xhr);
+ callback(null, this.xhr);
}
}.bind(this));
this.waiting = true;
- xhr.send(this._seralize());
+ this.xhr.send(this._serialize());
- return xhr;
+ return this.xhr;
}
};
@@ -2694,6 +2709,8 @@ function write (chunk) {
* @param {Function} callback node style callback.
* Receives three arguments
* error, parsedData, xhr.
+ * @return {Caldav.Xhr} The xhr request so that the caller
+ * has a chance to abort the request.
*/
send: function(callback) {
var self = this;
@@ -2715,6 +2732,8 @@ function write (chunk) {
callback(new Errors.CaldavHttpError(xhr.status));
}
});
+
+ return req;
}
};
@@ -2799,6 +2818,8 @@ function write (chunk) {
*
* @param {Object} [options] calendar options.
* @param {Function} callback node style [err, data, xhr].
+ * @return {Caldav.Xhr} The underlying xhr request so that the caller
+ * has a chance to abort the request.
*/
get: function(options, callback) {
if (typeof(options) === 'function') {
@@ -2808,7 +2829,7 @@ function write (chunk) {
var req = this._buildRequest('GET', options);
- req.send(function(err, xhr) {
+ return req.send(function(err, xhr) {
callback(err, xhr.responseText, xhr);
});
},
@@ -2819,6 +2840,8 @@ function write (chunk) {
* @param {Object} [options] see get.
* @param {String} data post content.
* @param {Function} callback node style [err, data, xhr].
+ * @return {Caldav.Xhr} The underlying xhr request so that the caller
+ * has a chance to abort the request.
*/
put: function(options, data, callback) {
if (typeof(options) === 'string') {
@@ -2834,7 +2857,7 @@ function write (chunk) {
var req = this._buildRequest('PUT', options);
req.data = data;
- req.send(function(err, xhr) {
+ return req.send(function(err, xhr) {
callback(err, xhr.responseText, xhr);
});
},
@@ -2844,6 +2867,8 @@ function write (chunk) {
*
* @param {Object} [options] see get.
* @param {Function} callback node style [err, data, xhr].
+ * @return {Caldav.Xhr} The underlying xhr request so that the caller
+ * has a chance to abort the request.
*/
delete: function(options, callback) {
if (typeof(options) === 'function') {
@@ -2853,7 +2878,7 @@ function write (chunk) {
var req = this._buildRequest('DELETE', options);
- req.send(function(err, xhr) {
+ return req.send(function(err, xhr) {
callback(err, xhr.responseText, xhr);
});
}
@@ -3092,6 +3117,10 @@ function write (chunk) {
Propfind: ns.require('request/propfind'),
+ /**
+ * @return {Caldav.Xhr} The underlying xhr request so that the caller
+ * has a chance to abort the request.
+ */
_findPrincipal: function(url, callback) {
var find = new this.Propfind(this.connection, {
url: url
@@ -3100,7 +3129,7 @@ function write (chunk) {
find.prop('current-user-principal');
find.prop('principal-URL');
- find.send(function(err, data) {
+ return find.send(function(err, data) {
var principal;
if (err) {
@@ -3121,7 +3150,6 @@ function write (chunk) {
} else {
callback(new Errors.CaldavHttpError(404));
}
-
});
},
@@ -3133,7 +3161,7 @@ function write (chunk) {
find.prop(['caldav', 'calendar-home-set']);
- find.send(function(err, data) {
+ return find.send(function(err, data) {
if (err) {
callback(err);
return;
@@ -3152,10 +3180,12 @@ function write (chunk) {
*
* @param {Function} callback node style where second argument
* are the details of the home calendar.
+ * @return {Caldav.Xhr} The underlying xhr request so that the caller
+ * has a chance to abort the request.
*/
send: function(callback) {
var self = this;
- self._findPrincipal(self.url, function(err, url) {
+ return self._findPrincipal(self.url, function(err, url) {
if (!url) {
callback(err);
diff --git a/lib/caldav/request/abstract.js b/lib/caldav/request/abstract.js
index 7116217..9edf6fd 100644
--- a/lib/caldav/request/abstract.js
+++ b/lib/caldav/request/abstract.js
@@ -54,6 +54,8 @@
* @param {Function} callback node style callback.
* Receives three arguments
* error, parsedData, xhr.
+ * @return {Caldav.Xhr} The xhr request so that the caller
+ * has a chance to abort the request.
*/
send: function(callback) {
var self = this;
@@ -75,6 +77,8 @@
callback(new Errors.CaldavHttpError(xhr.status));
}
});
+
+ return req;
}
};
diff --git a/lib/caldav/request/asset.js b/lib/caldav/request/asset.js
index b26e4f7..98c943a 100644
--- a/lib/caldav/request/asset.js
+++ b/lib/caldav/request/asset.js
@@ -71,6 +71,8 @@
*
* @param {Object} [options] calendar options.
* @param {Function} callback node style [err, data, xhr].
+ * @return {Caldav.Xhr} The underlying xhr request so that the caller
+ * has a chance to abort the request.
*/
get: function(options, callback) {
if (typeof(options) === 'function') {
@@ -80,7 +82,7 @@
var req = this._buildRequest('GET', options);
- req.send(function(err, xhr) {
+ return req.send(function(err, xhr) {
callback(err, xhr.responseText, xhr);
});
},
@@ -91,6 +93,8 @@
* @param {Object} [options] see get.
* @param {String} data post content.
* @param {Function} callback node style [err, data, xhr].
+ * @return {Caldav.Xhr} The underlying xhr request so that the caller
+ * has a chance to abort the request.
*/
put: function(options, data, callback) {
if (typeof(options) === 'string') {
@@ -106,7 +110,7 @@
var req = this._buildRequest('PUT', options);
req.data = data;
- req.send(function(err, xhr) {
+ return req.send(function(err, xhr) {
callback(err, xhr.responseText, xhr);
});
},
@@ -116,6 +120,8 @@
*
* @param {Object} [options] see get.
* @param {Function} callback node style [err, data, xhr].
+ * @return {Caldav.Xhr} The underlying xhr request so that the caller
+ * has a chance to abort the request.
*/
delete: function(options, callback) {
if (typeof(options) === 'function') {
@@ -125,7 +131,7 @@
var req = this._buildRequest('DELETE', options);
- req.send(function(err, xhr) {
+ return req.send(function(err, xhr) {
callback(err, xhr.responseText, xhr);
});
}
diff --git a/lib/caldav/request/calendar_home.js b/lib/caldav/request/calendar_home.js
index 24b27bc..a1f8ca6 100644
--- a/lib/caldav/request/calendar_home.js
+++ b/lib/caldav/request/calendar_home.js
@@ -52,6 +52,10 @@
Propfind: ns.require('request/propfind'),
+ /**
+ * @return {Caldav.Xhr} The underlying xhr request so that the caller
+ * has a chance to abort the request.
+ */
_findPrincipal: function(url, callback) {
var find = new this.Propfind(this.connection, {
url: url
@@ -60,7 +64,7 @@
find.prop('current-user-principal');
find.prop('principal-URL');
- find.send(function(err, data) {
+ return find.send(function(err, data) {
var principal;
if (err) {
@@ -81,7 +85,6 @@
} else {
callback(new Errors.CaldavHttpError(404));
}
-
});
},
@@ -93,7 +96,7 @@
find.prop(['caldav', 'calendar-home-set']);
- find.send(function(err, data) {
+ return find.send(function(err, data) {
if (err) {
callback(err);
return;
@@ -112,10 +115,12 @@
*
* @param {Function} callback node style where second argument
* are the details of the home calendar.
+ * @return {Caldav.Xhr} The underlying xhr request so that the caller
+ * has a chance to abort the request.
*/
send: function(callback) {
var self = this;
- self._findPrincipal(self.url, function(err, url) {
+ return self._findPrincipal(self.url, function(err, url) {
if (!url) {
callback(err);
diff --git a/lib/caldav/xhr.js b/lib/caldav/xhr.js
index 77ecd5c..e88e789 100644
--- a/lib/caldav/xhr.js
+++ b/lib/caldav/xhr.js
@@ -43,6 +43,7 @@
Xhr.prototype = {
globalXhrOptions: null,
xhrClass: Native,
+ xhr: null,
method: 'GET',
async: true,
waiting: false,
@@ -53,7 +54,7 @@
headers: {},
data: null,
- _seralize: function _seralize() {
+ _serialize: function _serialize() {
return this.data;
},
@@ -70,31 +71,45 @@
},
/**
+ * Aborts the request if it has already been sent.
+ * @param {Function=} cb An optional callback function.
+ */
+ abort: function(cb) {
+ if (this.waiting) {
+ this.xhr.abort();
+ this.waiting = false;
+ }
+
+ if (cb !== undefined) {
+ cb();
+ }
+ },
+
+ /**
* Sends request to server.
*
* @param {Function} callback success/failure handler.
*/
send: function send(callback) {
- var header, xhr;
+ var header;
if (typeof(callback) === 'undefined') {
callback = this.callback;
}
- if (this.globalXhrOptions) {
- xhr = new this.xhrClass(this.globalXhrOptions);
- } else {
- xhr = new this.xhrClass();
- }
+ this.xhr = new this.xhrClass(
+ this.globalXhrOptions ? this.globalXhrOptions : undefined);
+
// This hack is in place due to some platform
// bug in gecko when using mozSystem xhr
// the credentials only seem to work as expected
// when constructing them manually.
if (!this.globalXhrOptions || !this.globalXhrOptions.mozSystem) {
- xhr.open(this.method, this.url, this.async, this.user, this.password);
+ this.xhr.open(
+ this.method, this.url, this.async, this.user, this.password);
} else {
- xhr.open(this.method, this.url, this.async);
- xhr.setRequestHeader('Authorization', this._credentials(
+ this.xhr.open(this.method, this.url, this.async);
+ this.xhr.setRequestHeader('Authorization', this._credentials(
this.user,
this.password
));
@@ -103,12 +118,12 @@
var useMozChunkedText = false;
if (this.globalXhrOptions && this.globalXhrOptions.useMozChunkedText) {
useMozChunkedText = true;
- xhr.responseType = 'moz-chunked-text';
+ this.xhr.responseType = 'moz-chunked-text';
}
for (header in this.headers) {
if (Object.hasOwnProperty.call(this.headers, header)) {
- xhr.setRequestHeader(header, this.headers[header]);
+ this.xhr.setRequestHeader(header, this.headers[header]);
}
}
@@ -116,19 +131,19 @@
var hasProgressEvents = false;
// check for progress event support.
- if ('onprogress' in xhr) {
+ if ('onprogress' in this.xhr) {
hasProgressEvents = true;
var last = 0;
if (useMozChunkedText) {
- xhr.onprogress = (function onChunkedProgress(event) {
+ this.xhr.onprogress = (function onChunkedProgress(event) {
if (this.ondata) {
- this.ondata(xhr.responseText);
+ this.ondata(this.xhr.responseText);
}
}.bind(this));
} else {
- xhr.onprogress = (function onProgress(event) {
- var chunk = xhr.responseText.substr(last, event.loaded);
+ this.xhr.onprogress = (function onProgress(event) {
+ var chunk = this.xhr.responseText.substr(last, event.loaded);
last = event.loaded;
if (this.ondata) {
this.ondata(chunk);
@@ -137,10 +152,10 @@
}
}
- xhr.onreadystatechange = (function onReadyStateChange() {
+ this.xhr.onreadystatechange = (function onReadyStateChange() {
var data;
- if (xhr.readyState === 4) {
- data = xhr.responseText;
+ if (this.xhr.readyState === 4) {
+ data = this.xhr.responseText;
// emulate progress events for node...
// this really lame we should probably just
@@ -151,14 +166,14 @@
}
this.waiting = false;
- callback(null, xhr);
+ callback(null, this.xhr);
}
}.bind(this));
this.waiting = true;
- xhr.send(this._seralize());
+ this.xhr.send(this._serialize());
- return xhr;
+ return this.xhr;
}
};
diff --git a/test-agent/config.json b/test-agent/config.json
deleted file mode 100644
index 0453099..0000000
--- a/test-agent/config.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{"tests": [
-"/test/caldav/connection_test.js","/test/caldav/index_test.js","/test/caldav/query_builder_test.js","/test/caldav/request/abstract_test.js","/test/caldav/request/asset_test.js","/test/caldav/request/calendar_home_test.js","/test/caldav/request/calendar_query_test.js","/test/caldav/request/propfind_test.js","/test/caldav/request/resources_test.js","/test/caldav/resources/calendar_test.js","/test/caldav/sax/base_test.js","/test/caldav/sax/calendar_data_handler_test.js","/test/caldav/sax/dav_response_test.js","/test/caldav/sax_test.js","/test/caldav/template_test.js","/test/caldav/xhr_test.js","/test/servers/home_test.js","/test/servers/query_test.js","/test/servers/resources_test.js"
- ]}
diff --git a/test/caldav/request/abstract_test.js b/test/caldav/request/abstract_test.js
index 21bde48..e2fb3d1 100644
--- a/test/caldav/request/abstract_test.js
+++ b/test/caldav/request/abstract_test.js
@@ -70,6 +70,13 @@ suite('caldav/request/abstract.js', function() {
return FakeXhr.instances.pop();
}
+ test('should return a Caldav.Xhr object', function() {
+ var req = subject.send(function() {});
+ assert.deepEqual(url, req.url)
+ assert.deepEqual(con.user, req.user);
+ assert.deepEqual(con.password, req.password);
+ });
+
suite('error', function() {
var calledWith;
diff --git a/test/caldav/xhr_test.js b/test/caldav/xhr_test.js
index 6130346..a3e6b66 100644
--- a/test/caldav/xhr_test.js
+++ b/test/caldav/xhr_test.js
@@ -76,10 +76,9 @@ suite('webacls/xhr', function() {
});
suite('when xhr is a success and responds /w data', function() {
- var response = '<html></html>', cb;
+ var response = '<html></html>', cb, xhr;
setup(function(done) {
- var xhr;
request({
data: data,
url: url,
@@ -88,8 +87,8 @@ suite('webacls/xhr', function() {
cb = callback.bind(this, done);
xhr = subject.send(cb);
- //should be waiting inbetween requests
- assert.equal(subject.waiting, true);
+ // should be waiting inbetween requests
+ assert.deepEqual(subject.waiting, true);
xhr.readyState = 4;
xhr.responseText = response;
@@ -101,6 +100,35 @@ suite('webacls/xhr', function() {
});
});
+ suite('when abort is called on the request', function() {
+ var aborted, xhr;
+
+ setup(function() {
+ request({
+ data: data,
+ url: url,
+ method: 'PUT'
+ });
+ xhr = subject.send(callback);
+
+ // should be waiting inbetween requests
+ assert.deepEqual(subject.waiting, true);
+
+ aborted = false;
+ });
+
+ test('underlying request should be aborted', function(done) {
+ xhr.abort = function() {
+ aborted = true;
+ };
+
+ subject.abort(function() {
+ assert.deepEqual(true, aborted);
+ assert.deepEqual(false, subject.waiting);
+ done();
+ });
+ });
+ });
});
suite('requests real files', function() {