From fd96fc8f0143f724362363fa0629e5b558641b26 Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Tue, 17 May 2016 14:40:29 +0100 Subject: [PATCH 1/7] When downloading several files or folders, name the archive 'item1[+n].zip', and ensure that filenames are encoded correctly --- package.json | 1 + plugins/c9.ide.download/download.js | 14 ++++++++++---- plugins/c9.vfs.client/vfs_client.js | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 4317d547..157706fd 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ ], "c9plugins": { "c9.ide.language": "#79bcb2fe06", + "c9.ide.language.core": "#undefined", "c9.ide.language.css": "#be07d72209", "c9.ide.language.generic": "#3949510863", "c9.ide.language.html": "#22fdc74869", diff --git a/plugins/c9.ide.download/download.js b/plugins/c9.ide.download/download.js index dd6a585f..ab8e5280 100644 --- a/plugins/c9.ide.download/download.js +++ b/plugins/c9.ide.download/download.js @@ -91,24 +91,30 @@ define(function(require, exports, module) { } function downloadProject() { - vfs.download("/", info.getWorkspace().name + getArchiveFileExtension()); + vfs.download("/", makeArchiveFilename(info.getWorkspace().name)); } function downloadPaths(paths) { - vfs.download(paths, info.getWorkspace().name + getArchiveFileExtension()); + var lastPart = paths[0].match(/([^\/]*)\/?$/)[1]; + var filename = lastPart ? (lastPart + "[+" + (paths.length - 1) + "]") : info.getWorkspace().name; + vfs.download(paths, makeArchiveFilename(filename)); } function downloadFolder(path) { var withTrailingSlash = path.replace(/\/*$/, "/"); var parts = withTrailingSlash.split("/"); - var lastPart = parts[parts.length - 2]; - vfs.download(withTrailingSlash, lastPart + getArchiveFileExtension()); + var folderName = parts[parts.length - 2]; + vfs.download(withTrailingSlash, makeArchiveFilename(folderName)); } function downloadFile(path) { vfs.download(path.replace(/\/*$/, ""), null, true); } + function makeArchiveFilename(filename) { + return filename + getArchiveFileExtension(); + } + function getArchiveFileExtension() { var downloadFilesAs = settings.get(SETTING_PATH); if (downloadFilesAs === 'auto' || !downloadFilesAs) { diff --git a/plugins/c9.vfs.client/vfs_client.js b/plugins/c9.vfs.client/vfs_client.js index 0fd09d42..44f3b1a1 100644 --- a/plugins/c9.vfs.client/vfs_client.js +++ b/plugins/c9.vfs.client/vfs_client.js @@ -193,12 +193,12 @@ define(function(require, exports, module) { extraPaths = path; path = path[0]; extraPaths = "," + extraPaths.map(function(p) { - return p[0] == path[0] && p != path ? escape(p) : ""; + return p[0] == path[0] && p != path ? encodeURI(p) : ""; }).filter(Boolean).join(","); } window.open(vfsUrl(path) + extraPaths + "?download" - + (filename ? "=" + escape(filename) : "") + + (filename ? "=" + encodeURIComponent(filename) : "") + (isfile ? "&isfile=1" : "")); } From 31ad443da504a5a51d756553a23c6b3de644236b Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Tue, 17 May 2016 15:25:13 +0100 Subject: [PATCH 2/7] Another filename encoding fix --- plugins/c9.vfs.server/download.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/c9.vfs.server/download.js b/plugins/c9.vfs.server/download.js index b1dbea6f..ec26e2ca 100644 --- a/plugins/c9.vfs.server/download.js +++ b/plugins/c9.vfs.server/download.js @@ -113,10 +113,8 @@ define(function(require, exports, module) { paths.forEach(function(path) { if (!path) return; path = Path.relative(cwd, path); - // tar misinterprets the Windows path separator as an escape sequence, so use forward slash. - if (Path.sep === '\\') { - path = path.replace(/\\/g, '/'); - } + // Single quote the path to escape unusual characters, and manually escape single quotes. + path = "'" + path.replace(/'/, "'\\''") + "'"; args.push(path); }); From 5cad3449c3782f9ac6c4e520eafadc18c87f2af7 Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Thu, 2 Jun 2016 09:25:44 +0100 Subject: [PATCH 3/7] URI-encode commas in filenames explicitly, because they are used as a separator --- plugins/c9.vfs.client/vfs_client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/c9.vfs.client/vfs_client.js b/plugins/c9.vfs.client/vfs_client.js index 44f3b1a1..eade1caf 100644 --- a/plugins/c9.vfs.client/vfs_client.js +++ b/plugins/c9.vfs.client/vfs_client.js @@ -193,7 +193,7 @@ define(function(require, exports, module) { extraPaths = path; path = path[0]; extraPaths = "," + extraPaths.map(function(p) { - return p[0] == path[0] && p != path ? encodeURI(p) : ""; + return p[0] == path[0] && p != path ? encodeURI(p).replace(/,/g, "%2C") : ""; }).filter(Boolean).join(","); } window.open(vfsUrl(path) + extraPaths From 0dc707ec6556bad9e64f6f20a0f4fcd2be9f1227 Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Mon, 6 Jun 2016 15:35:12 +0100 Subject: [PATCH 4/7] Use escape instead of encodeURI and encodeURIComponent, so that problematic filename characters are escaped correctly --- plugins/c9.vfs.client/vfs_client.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/c9.vfs.client/vfs_client.js b/plugins/c9.vfs.client/vfs_client.js index eade1caf..51d7736c 100644 --- a/plugins/c9.vfs.client/vfs_client.js +++ b/plugins/c9.vfs.client/vfs_client.js @@ -193,12 +193,13 @@ define(function(require, exports, module) { extraPaths = path; path = path[0]; extraPaths = "," + extraPaths.map(function(p) { - return p[0] == path[0] && p != path ? encodeURI(p).replace(/,/g, "%2C") : ""; + return p[0] == path[0] && p != path ? escape(p) : ""; }).filter(Boolean).join(","); } window.open(vfsUrl(path) + extraPaths + "?download" - + (filename ? "=" + encodeURIComponent(filename) : "") + // Escape '+', otherwise it gets interpreted as a space. + + (filename ? "=" + escape(filename) : "").replace(/\+/g, "%2B") + (isfile ? "&isfile=1" : "")); } From dbf1d72d1c3bacdf85feaa9abb5eaeed86149fbe Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Mon, 6 Jun 2016 15:36:46 +0100 Subject: [PATCH 5/7] Use escape instead of encodeURIComponent so that download filenames are encoded correctly (e.g., filenames containing a single quote) --- plugins/c9.vfs.server/download.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/c9.vfs.server/download.js b/plugins/c9.vfs.server/download.js index ec26e2ca..c064dce6 100644 --- a/plugins/c9.vfs.server/download.js +++ b/plugins/c9.vfs.server/download.js @@ -44,7 +44,7 @@ define(function(require, exports, module) { filename += (paths.length > 1 ? "[+" + (paths.length - 1) + "]" : "") + ".tar.gz"; } } - var filenameHeader = "attachment; filename*=utf-8''" + encodeURIComponent(filename); + var filenameHeader = "attachment; filename*=utf-8''" + escape(filename); var process; req.on("close", function() { From 6440ef1eb86fd646856fd1a3b1c659a74c180be1 Mon Sep 17 00:00:00 2001 From: Chris Brown Date: Mon, 6 Jun 2016 15:37:32 +0100 Subject: [PATCH 6/7] Escape the filename arguments to zip and tar correctly on Windows --- plugins/c9.vfs.server/download.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/plugins/c9.vfs.server/download.js b/plugins/c9.vfs.server/download.js index c064dce6..5246be18 100644 --- a/plugins/c9.vfs.server/download.js +++ b/plugins/c9.vfs.server/download.js @@ -46,9 +46,9 @@ define(function(require, exports, module) { } var filenameHeader = "attachment; filename*=utf-8''" + escape(filename); - var process; + var proc; req.on("close", function() { - if (process) process.kill(); + if (proc) proc.kill(); }); if (req.uri.query.isfile) { @@ -113,22 +113,26 @@ define(function(require, exports, module) { paths.forEach(function(path) { if (!path) return; path = Path.relative(cwd, path); - // Single quote the path to escape unusual characters, and manually escape single quotes. - path = "'" + path.replace(/'/, "'\\''") + "'"; + if (/win/.test(process.platform)) { + // Quote the path to escape unusual characters and spaces. + // NB: Double quotes are illegal within the actual path on Windows. + path = '"' + path + '"'; + } args.push(path); }); vfs.spawn(executable, { args: args, - cwd: cwd + cwd: cwd, + windowsVerbatimArguments: true // Prevents Node from escaping the double quotes added above. }, function (err, meta) { if (err) return next(err); - process = meta.process; + proc = meta.process; // once we receive data on stdout pipe it to the response - process.stdout.once("data", function (data) { + proc.stdout.once("data", function (data) { if (res.headerSent) return; @@ -137,15 +141,15 @@ define(function(require, exports, module) { "Content-Disposition": filenameHeader }); res.write(data); - process.stdout.pipe(res); + proc.stdout.pipe(res); }); var stderr = ""; - process.stderr.on("data", function (data) { + proc.stderr.on("data", function (data) { stderr += data; }); - process.on("exit", function(code, signal) { + proc.on("exit", function(code, signal) { if (res.headerSent) return; From 60e4de8ec9ea90e26fdafebb276d1f6165cd546d Mon Sep 17 00:00:00 2001 From: nightwing Date: Thu, 9 Jun 2016 13:48:05 +0400 Subject: [PATCH 7/7] do not treat darwin as win32 --- plugins/c9.vfs.server/download.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/c9.vfs.server/download.js b/plugins/c9.vfs.server/download.js index 5246be18..b259713e 100644 --- a/plugins/c9.vfs.server/download.js +++ b/plugins/c9.vfs.server/download.js @@ -113,10 +113,10 @@ define(function(require, exports, module) { paths.forEach(function(path) { if (!path) return; path = Path.relative(cwd, path); - if (/win/.test(process.platform)) { + if (process.platform == "win32") { // Quote the path to escape unusual characters and spaces. // NB: Double quotes are illegal within the actual path on Windows. - path = '"' + path + '"'; + path = '"' + path.replace(/"/g, "") + '"'; } args.push(path); });