diff --git a/services/sync/BookmarksSyncService.js b/services/sync/BookmarksSyncService.js
index 382794538b2a..fb6b422ab0c9 100644
--- a/services/sync/BookmarksSyncService.js
+++ b/services/sync/BookmarksSyncService.js
@@ -1037,21 +1037,23 @@ BookmarksSyncService.prototype = {
server.deltas.push(serverDelta);
- this._dav.PUT("bookmarks-deltas.json",
- this._mungeCommands(server.deltas), cont);
+ gen = this._dav.PUT("bookmarks-deltas.json",
+ this._mungeCommands(server.deltas), cont);
let deltasPut = yield;
+ gen.close();
// FIXME: need to watch out for the storage format version changing,
// in that case we'll have to re-upload all the files, not just these
- this._dav.PUT("bookmarks-status.json",
- uneval({GUID: this._snapshotGUID,
- formatVersion: STORAGE_FORMAT_VERSION,
- snapVersion: server.snapVersion,
- maxVersion: this._snapshotVersion}), cont);
+ gen = this._dav.PUT("bookmarks-status.json",
+ uneval({GUID: this._snapshotGUID,
+ formatVersion: STORAGE_FORMAT_VERSION,
+ snapVersion: server.snapVersion,
+ maxVersion: this._snapshotVersion}), cont);
let statusPut = yield;
+ gen.close();
- if (deltasPut.target.status >= 200 && deltasPut.target.status < 300 &&
- statusPut.target.status >= 200 && statusPut.target.status < 300) {
+ if (deltasPut.status >= 200 && deltasPut.status < 300 &&
+ statusPut.status >= 200 && statusPut.status < 300) {
this._log.info("Successfully updated deltas and status on server");
this._saveSnapshot();
} else {
@@ -1145,14 +1147,16 @@ BookmarksSyncService.prototype = {
try {
this._log.info("Getting bookmarks status from server");
- this._dav.GET("bookmarks-status.json", cont);
- let statusResp = yield;
+ let gen = this._dav.GET("bookmarks-status.json", cont);
+ let resp = yield;
+ let status = resp.status;
+ gen.close();
- switch (statusResp.target.status) {
+ switch (status) {
case 200:
this._log.info("Got bookmarks status from server");
- let status = eval(statusResp.target.responseText);
+ let status = eval(resp.responseText);
let snap, deltas, allDeltas;
// Bail out if the server has a newer format version than we can parse
@@ -1177,24 +1181,28 @@ BookmarksSyncService.prototype = {
this._log.info("Local snapshot is out of date");
this._log.info("Downloading server snapshot");
- this._dav.GET("bookmarks-snapshot.json", cont);
- let snapResp = yield;
- if (snapResp.target.status < 200 || snapResp.target.status >= 300) {
+ gen = this._dav.GET("bookmarks-snapshot.json", cont);
+ resp = yield;
+ gen.close()
+
+ if (resp.status < 200 || resp.status >= 300) {
this._log.error("Could not download server snapshot");
generatorDone(this, onComplete, ret)
throw 'close generator';
}
- snap = eval(snapResp.target.responseText);
+ snap = eval(resp.responseText);
this._log.info("Downloading server deltas");
- this._dav.GET("bookmarks-deltas.json", cont);
- let deltasResp = yield;
- if (deltasResp.target.status < 200 || deltasResp.target.status >= 300) {
+ gen = this._dav.GET("bookmarks-deltas.json", cont);
+ resp = yield;
+ gen.close();
+
+ if (resp.status < 200 || resp.status >= 300) {
this._log.error("Could not download server deltas");
generatorDone(this, onComplete, ret)
throw 'close generator';
}
- allDeltas = eval(deltasResp.target.responseText);
+ allDeltas = eval(resp.responseText);
deltas = eval(uneval(allDeltas));
} else if (this._snapshotVersion >= status.snapVersion &&
@@ -1202,14 +1210,16 @@ BookmarksSyncService.prototype = {
snap = eval(uneval(this._snapshot));
this._log.info("Downloading server deltas");
- this._dav.GET("bookmarks-deltas.json", cont);
- let deltasResp = yield;
- if (deltasResp.target.status < 200 || deltasResp.target.status >= 300) {
+ gen = this._dav.GET("bookmarks-deltas.json", cont);
+ resp = yield;
+ gen.close();
+
+ if (resp.status < 200 || resp.status >= 300) {
this._log.error("Could not download server deltas");
generatorDone(this, onComplete, ret)
throw 'close generator';
}
- allDeltas = eval(deltasResp.target.responseText);
+ allDeltas = eval(resp.responseText);
deltas = allDeltas.slice(this._snapshotVersion - status.snapVersion);
} else if (this._snapshotVersion == status.maxVersion) {
@@ -1217,14 +1227,16 @@ BookmarksSyncService.prototype = {
// FIXME: could optimize this case by caching deltas file
this._log.info("Downloading server deltas");
- this._dav.GET("bookmarks-deltas.json", cont);
- let deltasResp = yield;
- if (deltasResp.target.status < 200 || deltasResp.target.status >= 300) {
+ gen = this._dav.GET("bookmarks-deltas.json", cont);
+ resp = yield;
+ gen.close();
+
+ if (resp.status < 200 || resp.status >= 300) {
this._log.error("Could not download server deltas");
generatorDone(this, onComplete, ret)
throw 'close generator';
}
- allDeltas = eval(deltasResp.target.responseText);
+ allDeltas = eval(resp.responseText);
deltas = [];
} else { // this._snapshotVersion > status.maxVersion
@@ -1253,34 +1265,40 @@ BookmarksSyncService.prototype = {
this._snapshotVersion = 0;
this._snapshotGUID = null; // in case there are other snapshots out there
- this._dav.PUT("bookmarks-snapshot.json",
- this._mungeNodes(this._snapshot), cont);
- let snapPut = yield;
- if (snapPut.target.status < 200 || snapPut.target.status >= 300) {
+ gen = this._dav.PUT("bookmarks-snapshot.json",
+ this._mungeNodes(this._snapshot), cont);
+ resp = yield;
+ gen.close();
+
+ if (resp.status < 200 || resp.status >= 300) {
this._log.error("Could not upload snapshot to server, error code: " +
- snapPut.target.status);
+ resp.status);
generatorDone(this, onComplete, ret)
throw 'close generator';
}
- this._dav.PUT("bookmarks-deltas.json", uneval([]), cont);
- let deltasPut = yield;
- if (deltasPut.target.status < 200 || deltasPut.target.status >= 300) {
+ gen = this._dav.PUT("bookmarks-deltas.json", uneval([]), cont);
+ resp = yield;
+ gen.close();
+
+ if (resp.status < 200 || resp.status >= 300) {
this._log.error("Could not upload deltas to server, error code: " +
- deltasPut.target.status);
+ resp.status);
generatorDone(this, onComplete, ret)
throw 'close generator';
}
- this._dav.PUT("bookmarks-status.json",
- uneval({GUID: this._snapshotGUID,
- formatVersion: STORAGE_FORMAT_VERSION,
- snapVersion: this._snapshotVersion,
- maxVersion: this._snapshotVersion}), cont);
- let statusPut = yield;
- if (statusPut.target.status < 200 || statusPut.target.status >= 300) {
+ gen = this._dav.PUT("bookmarks-status.json",
+ uneval({GUID: this._snapshotGUID,
+ formatVersion: STORAGE_FORMAT_VERSION,
+ snapVersion: this._snapshotVersion,
+ maxVersion: this._snapshotVersion}), cont);
+ resp = yield;
+ gen.close();
+
+ if (resp.status < 200 || resp.status >= 300) {
this._log.error("Could not upload status file to server, error code: " +
- statusPut.target.status);
+ resp.status);
generatorDone(this, onComplete, ret)
throw 'close generator';
}
@@ -1299,7 +1317,7 @@ BookmarksSyncService.prototype = {
default:
this._log.error("Could not get bookmarks.status: unknown HTTP status code " +
- statusResp.target.status);
+ status);
break;
}
} catch (e) {
@@ -1360,24 +1378,26 @@ BookmarksSyncService.prototype = {
return;
}
- this._dav.DELETE("bookmarks-status.json", cont);
+ gen = this._dav.DELETE("bookmarks-status.json", cont);
let statusResp = yield;
- this._dav.DELETE("bookmarks-snapshot.json", cont);
+ gen.close();
+ gen = this._dav.DELETE("bookmarks-snapshot.json", cont);
let snapshotResp = yield;
- this._dav.DELETE("bookmarks-deltas.json", cont);
+ gen.close();
+ gen = this._dav.DELETE("bookmarks-deltas.json", cont);
let deltasResp = yield;
+ gen.close();
gen = this._dav.unlock.async(this._dav, cont);
let unlocked = yield;
gen.close();
- if (!(statusResp.target.status == 200 || statusResp.target.status == 404 ||
- snapshotResp.target.status == 200 || snapshotResp.target.status == 404 ||
- deltasResp.target.status == 200 || deltasResp.target.status == 404)) {
+ if (!(statusResp.status == 200 || statusResp.status == 404 ||
+ snapshotResp.status == 200 || snapshotResp.status == 404 ||
+ deltasResp.status == 200 || deltasResp.status == 404)) {
this._log.error("Could delete server data, response codes " +
- statusResp.target.status + ", " +
- snapshotResp.target.status + ", " +
- deltasResp.target.status);
+ statusResp.status + ", " + snapshotResp.status + ", " +
+ deltasResp.status);
return;
}
@@ -1608,9 +1628,9 @@ DAVCollection.prototype = {
if (this.__auth && this._userURL == this.__authURI)
return this.__auth;
- this._log.debug("Generating new authentication header");
-
try {
+ this._log.debug("Generating new authentication header");
+
this.__authURI = this._userURL;
let URI = makeURI(this._userURL);
let username = 'nobody@mozilla.com';
@@ -1666,92 +1686,115 @@ DAVCollection.prototype = {
return this._currentUser;
},
- _makeRequest: function DC__makeRequest(op, path, onComplete, headers) {
- this._log.debug("Creating " + op + " request for" + this._userURL + path);
+ _makeRequest: function DC__makeRequest(onComplete, op, path, headers, data) {
+ let cont = yield;
+ let ret;
- let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
- request = request.QueryInterface(Ci.nsIDOMEventTarget);
+ try {
+ this._log.debug("Creating " + op + " request for " + this._userURL + path);
- request.addEventListener("load", new EventListener(onComplete), false);
- request.addEventListener("error", new EventListener(onComplete), false);
- request = request.QueryInterface(Ci.nsIXMLHttpRequest);
- request.open(op, this._userURL + path, true);
-
- if (headers) {
+ let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
+ request = request.QueryInterface(Ci.nsIDOMEventTarget);
+
+ request.addEventListener("load", new EventListener(cont), false);
+ request.addEventListener("error", new EventListener(cont), false);
+ request = request.QueryInterface(Ci.nsIXMLHttpRequest);
+ request.open(op, this._userURL + path, true);
+
let key;
for (key in headers) {
+ this._log.debug("HTTP Header " + key + ": " + headers[key]);
request.setRequestHeader(key, headers[key]);
}
+
+ this._authProvider._authFailed = false;
+ request.channel.notificationCallbacks = this._authProvider;
+
+ request.send(data);
+ let event = yield;
+ ret = event.target;
+
+ if (this._authProvider._authFailed)
+ this._log.warn("_makeRequest: authentication failed");
+ if (ret.status < 200 || ret.status >= 300)
+ this._log.warn("_makeRequest: got status " + ret.status);
+
+ } catch (e) {
+ if (e != 'close generator')
+ throw e;
+
+ } finally {
+ generatorDone(this, onComplete, ret);
+ yield; // onComplete is responsible for closing the generator
}
-
- request.channel.notificationCallbacks = this._authProvider;
-
- return request;
+ this._log.warn("generator not properly closed");
},
- GET: function DC_GET(path, onComplete, headers) {
- if (!headers)
- headers = {'Content-type': 'text/plain'};
- if (this._auth)
- headers['Authorization'] = this._auth;
- if (this._token)
- headers['If'] = "<" + this._bashURL + "> (<" + this._token + ">)";
- let request = this._makeRequest("GET", path, onComplete, headers);
- request.send(null);
+ get _defaultHeaders() {
+ return {'Authorization': this._auth? this._auth : '',
+ 'Content-type': 'text/plain',
+ 'If': this._token?
+ "<" + this._userURL + "> (<" + this._token + ">)" : ''};
},
- PUT: function DC_PUT(path, data, onComplete, headers) {
- if (!headers)
- headers = {'Content-type': 'text/plain'};
- if (this._auth)
- headers['Authorization'] = this._auth;
- if (this._token)
- headers['If'] = "<" + this._bashURL + "> (<" + this._token + ">)";
- let request = this._makeRequest("PUT", path, onComplete, headers);
- request.send(data);
+ GET: function DC_GET(path, onComplete) {
+ return this._makeRequest.async(this, onComplete, "GET", path,
+ this._defaultHeaders);
},
- DELETE: function DC_DELETE(path, onComplete, headers) {
- if (!headers)
- headers = {'Content-type': 'text/plain'};
- if (this._auth)
- headers['Authorization'] = this._auth;
- if (this._token)
- headers['If'] = "<" + this._bashURL + "> (<" + this._token + ">)";
- let request = this._makeRequest("DELETE", path, onComplete, headers);
- request.send(null);
+ PUT: function DC_PUT(path, data, onComplete) {
+ return this._makeRequest.async(this, onComplete, "PUT", path,
+ this._defaultHeaders, data);
+ },
+
+ DELETE: function DC_DELETE(path, onComplete) {
+ return this._makeRequest.async(this, onComplete, "DELETE", path,
+ this._defaultHeaders);
+ },
+
+ PROPFIND: function DC_PROPFIND(path, data, onComplete) {
+ let headers = {'Content-type': 'text/xml; charset="utf-8"',
+ 'Depth': '0'};
+ headers.__proto__ = this._defaultHeaders;
+ return this._makeRequest.async(this, onComplete, "PROPFIND", path,
+ headers, data);
+ },
+
+ LOCK: function DC_LOCK(path, data, onComplete) {
+ let headers = {'Content-type': 'text/xml; charset="utf-8"',
+ 'Depth': 'infinity',
+ 'Timeout': 'Second-600'};
+ headers.__proto__ = this._defaultHeaders;
+ return this._makeRequest.async(this, onComplete, "LOCK", path, headers, data);
+ },
+
+ UNLOCK: function DC_UNLOCK(path, onComplete) {
+ let headers = {'Lock-Token': '<' + this._token + '>'};
+ headers.__proto__ = this._defaultHeaders;
+ return this._makeRequest.async(this, onComplete, "UNLOCK", path, headers);
},
// Login / Logout
login: function DC_login(onComplete) {
let cont = yield;
+
try {
if (this._loggedIn) {
this._log.debug("Login requested, but already logged in");
throw 'close generator';
}
-
- let headers = {};
- if (this._auth)
- headers['Authorization'] = this._auth;
- this._authProvider._authFailed = false;
+ this._log.info("Logging in");
// This ensures the auth header is correct, and it doubles as an
// account creation request
- let request = this._makeRequest("GET", "createAcct.php", cont, headers);
- request.send(null);
- let event = yield;
+ let gen = this.GET("createAcct.php", cont);
+ let resp = yield;
+ gen.close();
- if (this._authProvider._authFailed) {
- this._log.warn("Login authentication failed");
+ if (this._authProvider._authFailed || resp.status < 200 || resp.status >= 300)
throw 'close generator';
- }
- if (event.target.status < 200 || event.target.status >= 400) {
- this._log.warn("Login request failed, status " + event.target.status);
- throw 'close generator';
- }
let branch = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
@@ -1766,7 +1809,12 @@ DAVCollection.prototype = {
} catch (e) {
if (e != 'close generator')
throw e;
+
} finally {
+ if (this._loggedIn)
+ this._log.info("Logged in");
+ else
+ this._log.warn("Could not log in");
generatorDone(this, onComplete, this._loggedIn);
yield; // onComplete is responsible for closing the generator
}
@@ -1787,35 +1835,30 @@ DAVCollection.prototype = {
try {
this._log.info("Getting active lock token");
+ let gen = this.PROPFIND("",
+ "" +
+ "" +
+ " " +
+ "", cont);
+ let resp = yield;
+ gen.close();
- let headers = {'Content-Type': 'text/xml; charset="utf-8"',
- 'Depth': '0'};
- if (this._auth)
- headers['Authorization'] = this._auth;
-
- let request = this._makeRequest("PROPFIND", "", cont, headers);
- request.send("" +
- "" +
- " " +
- "");
- let event = yield;
-
- if (this._authProvider._authFailed) {
- this._log.warn("_getActiveLock: authentication failed");
+ if (this._authProvider._authFailed || resp.status < 200 || resp.status >= 300)
throw 'close generator';
- }
- if (event.target.status >= 400) {
- this._log.warn("_getActiveLock: got status " + event.target.status);
- throw 'close generator';
- }
- let tokens = xpath(event.target.responseXML, '//D:locktoken/D:href');
+ let tokens = xpath(resp.responseXML, '//D:locktoken/D:href');
let token = tokens.iterateNext();
ret = token.textContent;
+
} catch (e) {
if (e != 'close generator')
throw e;
+
} finally {
+ if (ret)
+ this._log.debug("Found an active lock token");
+ else
+ this._log.debug("No active lock token found");
generatorDone(this, onComplete, ret);
yield; // onComplete is responsible for closing the generator
}
@@ -1834,30 +1877,19 @@ DAVCollection.prototype = {
throw 'close generator';
}
- headers = {'Content-Type': 'text/xml; charset="utf-8"',
- 'Timeout': 'Second-600',
- 'Depth': 'infinity'};
- if (this._auth)
- headers['Authorization'] = this._auth;
+ let gen = this.LOCK("",
+ "\n" +
+ "\n" +
+ " \n" +
+ " \n" +
+ "", cont);
+ let resp = yield;
+ gen.close();
- let request = this._makeRequest("LOCK", "", cont, headers);
- request.send("\n" +
- "\n" +
- " \n" +
- " \n" +
- "");
- let event = yield;
-
- if (this._authProvider._authFailed) {
- this._log.warn("lock: authentication failed");
+ if (this._authProvider._authFailed || resp.status < 200 || resp.status >= 300)
throw 'close generator';
- }
- if (event.target.status < 200 || event.target.status >= 300) {
- this._log.warn("lock: got status " + event.target.status);
- throw 'close generator';
- }
- let tokens = xpath(event.target.responseXML, '//D:locktoken/D:href');
+ let tokens = xpath(resp.responseXML, '//D:locktoken/D:href');
let token = tokens.iterateNext();
if (token)
this._token = token.textContent;
@@ -1865,7 +1897,12 @@ DAVCollection.prototype = {
} catch (e){
if (e != 'close generator')
throw e;
+
} finally {
+ if (this._token)
+ this._log.info("Lock acquired");
+ else
+ this._log.warn("Could not acquire lock");
generatorDone(this, onComplete, this._token);
yield; // onComplete is responsible for closing the generator
}
@@ -1882,27 +1919,19 @@ DAVCollection.prototype = {
throw 'close generator';
}
- let headers = {'Lock-Token': "<" + this._token + ">"};
- if (this._auth)
- headers['Authorization'] = this._auth;
+ let gen = this.UNLOCK("", cont);
+ let resp = yield;
+ gen.close();
- let request = this._makeRequest("UNLOCK", "", cont, headers);
- request.send(null);
- let event = yield;
-
- if (this._authProvider._authFailed) {
- this._log.warn("unlock: authentication failed");
+ if (this._authProvider._authFailed || resp.status < 200 || resp.status >= 300)
throw 'close generator';
- }
- if (event.target.status < 200 || event.target.status >= 300) {
- this._log.warn("unlock: got status " + event.target.status);
- throw 'close generator';
- }
this._token = null;
+
} catch (e){
if (e != 'close generator')
throw e;
+
} finally {
if (this._token) {
this._log.info("Could not release lock");
@@ -1921,20 +1950,31 @@ DAVCollection.prototype = {
let unlocked = true;
try {
+ this._log.info("Forcibly releasing any server locks");
let gen = this._getActiveLock.async(this, cont);
this._token = yield;
gen.close();
- if (this._token) {
- gen = this.unlock.async(this, cont);
- unlocked = yield;
- gen.close();
+ if (!this._token) {
+ this._log.info("No server lock found");
+ throw 'close generator';
}
+
+ this._log.info("Server lock found, unlocking");
+ gen = this.unlock.async(this, cont);
+ unlocked = yield;
+ gen.close();
+
} catch (e){
if (e != 'close generator')
throw e;
+
} finally {
+ if (unlocked)
+ this._log.debug("Lock released");
+ else
+ this._log.debug("No lock released");
generatorDone(this, onComplete, unlocked);
yield; // onComplete is responsible for closing the generator
}
@@ -1946,7 +1986,6 @@ DAVCollection.prototype = {
let stolen = null;
try {
-
let gen = this.forceUnlock.async(this, cont);
let unlocked = yield;
gen.close();
@@ -1956,9 +1995,11 @@ DAVCollection.prototype = {
stolen = yield;
gen.close();
}
+
} catch (e){
if (e != 'close generator')
throw e;
+
} finally {
generatorDone(this, onComplete, stolen);
yield; // onComplete is responsible for closing the generator