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 93557f30..9badea1b 100644 --- a/plugins/c9.vfs.client/vfs_client.js +++ b/plugins/c9.vfs.client/vfs_client.js @@ -198,7 +198,8 @@ define(function(require, exports, module) { } window.open(vfsUrl(path) + extraPaths + "?download" - + (filename ? "=" + escape(filename) : "") + // Escape '+', otherwise it gets interpreted as a space. + + (filename ? "=" + escape(filename) : "").replace(/\+/g, "%2B") + (isfile ? "&isfile=1" : "")); } diff --git a/plugins/c9.vfs.server/download.js b/plugins/c9.vfs.server/download.js index b1dbea6f..b259713e 100644 --- a/plugins/c9.vfs.server/download.js +++ b/plugins/c9.vfs.server/download.js @@ -44,11 +44,11 @@ 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; + var proc; req.on("close", function() { - if (process) process.kill(); + if (proc) proc.kill(); }); if (req.uri.query.isfile) { @@ -113,24 +113,26 @@ 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, '/'); + 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.replace(/"/g, "") + '"'; } 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; @@ -139,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;