Fx60: Fix snapshot filenames

nsIURL doesn't seem to work anymore, so add Zotero.Utilities.parseURL(),
which uses the `url` package from NPM and adds fileName, fileExtension,
and fileBaseName.
This commit is contained in:
Dan Stillman 2018-02-25 15:07:33 -05:00
parent c07379fe33
commit 8c59df435f
6 changed files with 84 additions and 28 deletions

View file

@ -2426,53 +2426,43 @@ Zotero.Attachments = new function(){
this._getFileNameFromURL = function(url, contentType) { this._getFileNameFromURL = function(url, contentType) {
var nsIURL = Components.classes["@mozilla.org/network/standard-url;1"] url = Zotero.Utilities.parseURL(url);
.createInstance(Components.interfaces.nsIURL);
nsIURL.spec = url;
var ext = Zotero.MIME.getPrimaryExtension(contentType, nsIURL.fileExtension); var fileBaseName = url.fileBaseName;
var fileExt = Zotero.MIME.getPrimaryExtension(contentType, url.fileExtension);
if (!nsIURL.fileName) { if (!fileBaseName) {
var matches = nsIURL.directory.match(/\/([^\/]+)\/$/); let matches = url.pathname.match(/\/([^\/]+)\/$/);
// If no filename, use the last part of the path if there is one // If no filename, use the last part of the path if there is one
if (matches) { if (matches) {
nsIURL.fileName = matches[1]; fileBaseName = matches[1];
} }
// Or just use the host // Or just use the host
else { else {
nsIURL.fileName = nsIURL.host; fileBaseName = url.hostname;
var tld = nsIURL.fileExtension;
} }
} }
// If we found a better extension, use that
if (ext && (!nsIURL.fileExtension || nsIURL.fileExtension != ext)) {
nsIURL.fileExtension = ext;
}
// If we replaced the TLD (which would've been interpreted as the extension), add it back
if (tld && tld != nsIURL.fileExtension) {
nsIURL.fileBaseName = nsIURL.fileBaseName + '.' + tld;
}
// Test unencoding fileBaseName // Test unencoding fileBaseName
try { try {
decodeURIComponent(nsIURL.fileBaseName); decodeURIComponent(fileBaseName);
} }
catch (e) { catch (e) {
if (e.name == 'URIError') { if (e.name == 'URIError') {
// If we got a 'malformed URI sequence' while decoding, // If we got a 'malformed URI sequence' while decoding,
// use MD5 of fileBaseName // use MD5 of fileBaseName
nsIURL.fileBaseName = Zotero.Utilities.Internal.md5(nsIURL.fileBaseName, false); fileBaseName = Zotero.Utilities.Internal.md5(fileBaseName, false);
} }
else { else {
throw e; throw e;
} }
} }
var fileName = fileBaseName + (fileExt ? '.' + fileExt : '');
// Pass unencoded name to getValidFileName() so that percent-encoded // Pass unencoded name to getValidFileName() so that percent-encoded
// characters aren't stripped to just numbers // characters aren't stripped to just numbers
return Zotero.File.getValidFileName(decodeURIComponent(nsIURL.fileName)); return Zotero.File.getValidFileName(decodeURIComponent(fileName));
} }

View file

@ -1913,6 +1913,21 @@ Zotero.Utilities = {
} }
}, },
parseURL: function (url) {
var parts = require('url').parse(url);
// fileName
parts.fileName = parts.pathname.split('/').pop();
// fileExtension
var pos = parts.fileName.lastIndexOf('.');
parts.fileExtension = pos == -1 ? '' : parts.fileName.substr(pos + 1);
// fileBaseName
parts.fileBaseName = parts.fileName
// filename up to the period before the file extension, if there is one
.substr(0, parts.fileName.length - (parts.fileExtension ? parts.fileExtension.length + 1 : 0));
return parts;
},
/** /**
* Get the real target URL from an intermediate URL * Get the real target URL from an intermediate URL
*/ */

7
package-lock.json generated
View file

@ -5398,8 +5398,7 @@
"querystring": { "querystring": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
"dev": true
}, },
"querystring-es3": { "querystring-es3": {
"version": "0.2.1", "version": "0.2.1",
@ -6686,7 +6685,6 @@
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
"integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
"dev": true,
"requires": { "requires": {
"punycode": "1.3.2", "punycode": "1.3.2",
"querystring": "0.2.0" "querystring": "0.2.0"
@ -6695,8 +6693,7 @@
"punycode": { "punycode": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
"dev": true
} }
} }
}, },

View file

@ -20,7 +20,8 @@
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^16.8.6", "react": "^16.8.6",
"react-dom": "^16.8.6", "react-dom": "^16.8.6",
"react-intl": "^2.7.2" "react-intl": "^2.7.2",
"url": "^0.11.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/cli": "^7.2.3", "@babel/cli": "^7.2.3",

View file

@ -38,6 +38,13 @@ const symlinkFiles = [
// these files will be browserified during the build // these files will be browserified during the build
const browserifyConfigs = [ const browserifyConfigs = [
{
src: 'node_modules/url/url.js',
dest: 'resource/url.js',
config: {
standalone: 'url'
}
},
{ {
src: 'node_modules/sinon/lib/sinon.js', src: 'node_modules/sinon/lib/sinon.js',
dest: 'test/resource/sinon.js', dest: 'test/resource/sinon.js',

View file

@ -477,6 +477,52 @@ describe("Zotero.Utilities", function() {
}) })
}); });
describe("#parseURL()", function () {
var f;
before(() => {
f = Zotero.Utilities.parseURL;
});
describe("#fileName", function () {
it("should contain filename", function () {
assert.propertyVal(f('http://example.com/abc/def.html?foo=bar'), 'fileName', 'def.html');
});
it("should be empty if no filename", function () {
assert.propertyVal(f('http://example.com/abc/'), 'fileName', '');
});
});
describe("#fileExtension", function () {
it("should contain extension", function () {
assert.propertyVal(f('http://example.com/abc/def.html?foo=bar'), 'fileExtension', 'html');
});
it("should be empty if no extension", function () {
assert.propertyVal(f('http://example.com/abc/def'), 'fileExtension', '');
});
it("should be empty if no filename", function () {
assert.propertyVal(f('http://example.com/abc/'), 'fileExtension', '');
});
});
describe("#fileBaseName", function () {
it("should contain base name", function () {
assert.propertyVal(f('http://example.com/abc/def.html?foo=bar'), 'fileBaseName', 'def');
});
it("should equal filename if no extension", function () {
assert.propertyVal(f('http://example.com/abc/def'), 'fileBaseName', 'def');
});
it("should be empty if no filename", function () {
assert.propertyVal(f('http://example.com/abc/'), 'fileBaseName', '');
});
});
});
describe("#ellipsize()", function () { describe("#ellipsize()", function () {
describe("with wordBoundary", function () { describe("with wordBoundary", function () {
it("should truncate at word boundary", function* () { it("should truncate at word boundary", function* () {