Fix file upload error when remote attachment has no stored hash
This commit is contained in:
parent
90a3013802
commit
c9694e93b0
2 changed files with 112 additions and 29 deletions
|
@ -374,33 +374,49 @@ Zotero.Sync.Storage.Mode.ZFS.prototype = {
|
|||
}
|
||||
body = body.join('&');
|
||||
|
||||
try {
|
||||
var req = yield this.apiClient.makeRequest(
|
||||
"POST",
|
||||
uri,
|
||||
{
|
||||
body,
|
||||
headers,
|
||||
// This should include all errors in _handleUploadAuthorizationFailure()
|
||||
successCodes: [200, 201, 204, 403, 404, 412, 413],
|
||||
debug: true
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
|
||||
let msg = "Unexpected status code " + e.status + " in " + funcName
|
||||
+ " (" + item.libraryKey + ")";
|
||||
Zotero.logError(msg);
|
||||
Zotero.debug(e.xmlhttp.getAllResponseHeaders());
|
||||
throw new Error(Zotero.Sync.Storage.defaultError);
|
||||
var req;
|
||||
while (true) {
|
||||
try {
|
||||
req = yield this.apiClient.makeRequest(
|
||||
"POST",
|
||||
uri,
|
||||
{
|
||||
body,
|
||||
headers,
|
||||
// This should include all errors in _handleUploadAuthorizationFailure()
|
||||
successCodes: [200, 201, 204, 403, 404, 412, 413],
|
||||
debug: true
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
|
||||
let msg = "Unexpected status code " + e.status + " in " + funcName
|
||||
+ " (" + item.libraryKey + ")";
|
||||
Zotero.logError(msg);
|
||||
Zotero.debug(e.xmlhttp.getAllResponseHeaders());
|
||||
throw new Error(Zotero.Sync.Storage.defaultError);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
let result = yield this._handleUploadAuthorizationFailure(req, item);
|
||||
if (result instanceof Zotero.Sync.Storage.Result) {
|
||||
return result;
|
||||
}
|
||||
// If remote attachment exists but has no hash (which can happen for an old (pre-4.0?)
|
||||
// attachment with just an mtime, or after a storage purge), send again with If-None-Match
|
||||
else if (result == "ERROR_412_WITHOUT_VERSION") {
|
||||
if (headers["If-None-Match"]) {
|
||||
throw new Error("412 returned for request with If-None-Match");
|
||||
}
|
||||
delete headers["If-Match"];
|
||||
headers["If-None-Match"] = "*";
|
||||
Zotero.debug("Retrying with If-None-Match");
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
var result = yield this._handleUploadAuthorizationFailure(req, item);
|
||||
if (result instanceof Zotero.Sync.Storage.Result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -468,10 +484,9 @@ Zotero.Sync.Storage.Mode.ZFS.prototype = {
|
|||
throw new Error(Zotero.Sync.Storage.defaultError);
|
||||
}
|
||||
else if (req.status == 412) {
|
||||
Zotero.debug("412 BUT WE'RE COOL");
|
||||
let version = req.getResponseHeader('Last-Modified-Version');
|
||||
if (!version) {
|
||||
throw new Error("Last-Modified-Version header not provided");
|
||||
return "ERROR_412_WITHOUT_VERSION";
|
||||
}
|
||||
if (version > item.version) {
|
||||
return new Zotero.Sync.Storage.Result({
|
||||
|
|
|
@ -817,7 +817,75 @@ describe("Zotero.Sync.Storage.Mode.ZFS", function () {
|
|||
assert.isFalse(result.localChanges);
|
||||
assert.isFalse(result.remoteChanges);
|
||||
assert.isTrue(result.syncRequired);
|
||||
})
|
||||
});
|
||||
|
||||
it("should retry with If-None-Match on 412 with missing remote hash", function* () {
|
||||
var { engine, client, caller } = yield setup();
|
||||
var zfs = new Zotero.Sync.Storage.Mode.ZFS({
|
||||
apiClient: client
|
||||
})
|
||||
|
||||
var file = getTestDataDirectory();
|
||||
file.append('test.png');
|
||||
var item = yield Zotero.Attachments.importFromFile({ file });
|
||||
item.version = 5;
|
||||
item.synced = true;
|
||||
item.attachmentSyncedModificationTime = Date.now();
|
||||
item.attachmentSyncedHash = 'bd4c33e03798a7e8bc0b46f8bda74fac'
|
||||
yield item.saveTx();
|
||||
|
||||
var contentType = 'image/png';
|
||||
var prefix = Zotero.Utilities.randomString();
|
||||
var suffix = Zotero.Utilities.randomString();
|
||||
var uploadKey = Zotero.Utilities.randomString(32, 'abcdef0123456789');
|
||||
|
||||
var called = 0;
|
||||
server.respond(function (req) {
|
||||
if (req.method == "POST"
|
||||
&& req.url == `${baseURL}users/1/items/${item.key}/file`
|
||||
&& !req.requestBody.includes('upload=')
|
||||
&& req.requestHeaders["If-Match"] == item.attachmentSyncedHash) {
|
||||
called++;
|
||||
req.respond(
|
||||
412,
|
||||
{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"If-Match set but file does not exist"
|
||||
);
|
||||
}
|
||||
else if (req.method == "POST"
|
||||
&& req.url == `${baseURL}users/1/items/${item.key}/file`
|
||||
&& !req.requestBody.includes('upload=')
|
||||
&& req.requestHeaders["If-None-Match"] == "*") {
|
||||
assert.equal(called++, 1)
|
||||
req.respond(
|
||||
200,
|
||||
{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
JSON.stringify({
|
||||
url: baseURL + "pretend-s3/1",
|
||||
contentType: contentType,
|
||||
prefix: prefix,
|
||||
suffix: suffix,
|
||||
uploadKey: uploadKey
|
||||
})
|
||||
);
|
||||
}
|
||||
})
|
||||
|
||||
var stub = sinon.stub(zfs, "_uploadFile");
|
||||
|
||||
yield zfs._processUploadFile({
|
||||
name: item.libraryKey
|
||||
});
|
||||
|
||||
assert.equal(called, 2);
|
||||
assert.ok(stub.called);
|
||||
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should handle 413 on quota limit", function* () {
|
||||
var { engine, client, caller } = yield setup();
|
||||
|
|
Loading…
Reference in a new issue