diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index ae59619402a1..8ed76e994a16 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -342,7 +342,7 @@ void DownloadIdCallback(content::DownloadManager* download_manager, const std::string& etag, const base::Time& start_time, uint32_t id) { - content::DownloadItem* item = download_manager->CreateDownloadItem( + download_manager->CreateDownloadItem( base::GenerateGUID(), id, path, path, url_chain, GURL(), GURL(), GURL(), GURL(), mime_type, mime_type, start_time, base::Time(), etag, last_modified, offset, length, std::string(), @@ -554,7 +554,7 @@ void Session::CreateInterruptedDownload(const mate::Dictionary& options) { options.Get("lastModified", &last_modified); options.Get("eTag", &etag); options.Get("startTime", &start_time); - if (path.empty() || length == 0 || offset >= length) + if (path.empty() || url_chain.empty() || length == 0 || offset >= length) return; auto download_manager = content::BrowserContext::GetDownloadManager(browser_context()); diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index 1a75fa333a4a..dfb2db5dedd3 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -3,6 +3,7 @@ const http = require('http') const https = require('https') const path = require('path') const fs = require('fs') +const send = require('send') const {closeWindow} = require('./window-helpers') const {ipcRenderer, remote} = require('electron') @@ -288,7 +289,9 @@ describe('session module', function () { res.end(mockPDF) downloadServer.close() }) - var assertDownload = function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port, savePath) { + var assertDownload = function (event, state, url, mimeType, + receivedBytes, totalBytes, disposition, + filename, port, savePath) { assert.equal(state, 'completed') assert.equal(filename, 'mock.pdf') assert.equal(savePath, path.join(__dirname, 'fixtures', 'mock.pdf')) @@ -306,8 +309,12 @@ describe('session module', function () { var port = downloadServer.address().port ipcRenderer.sendSync('set-download-option', false, false) w.loadURL(url + ':' + port) - ipcRenderer.once('download-done', function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, savePath) { - assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port, savePath) + ipcRenderer.once('download-done', function (event, state, url, + mimeType, receivedBytes, + totalBytes, disposition, + filename, savePath) { + assertDownload(event, state, url, mimeType, receivedBytes, + totalBytes, disposition, filename, port, savePath) done() }) }) @@ -322,8 +329,12 @@ describe('session module', function () { webview.addEventListener('did-finish-load', function () { webview.downloadURL(url + ':' + port + '/') }) - ipcRenderer.once('download-done', function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, savePath) { - assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port, savePath) + ipcRenderer.once('download-done', function (event, state, url, + mimeType, receivedBytes, + totalBytes, disposition, + filename, savePath) { + assertDownload(event, state, url, mimeType, receivedBytes, + totalBytes, disposition, filename, port, savePath) document.body.removeChild(webview) done() }) @@ -336,7 +347,10 @@ describe('session module', function () { var port = downloadServer.address().port ipcRenderer.sendSync('set-download-option', true, false) w.loadURL(url + ':' + port + '/') - ipcRenderer.once('download-done', function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) { + ipcRenderer.once('download-done', function (event, state, url, + mimeType, receivedBytes, + totalBytes, disposition, + filename) { assert.equal(state, 'cancelled') assert.equal(filename, 'mock.pdf') assert.equal(mimeType, 'application/pdf') @@ -356,7 +370,10 @@ describe('session module', function () { var port = downloadServer.address().port ipcRenderer.sendSync('set-download-option', true, false) w.loadURL(url + ':' + port + '/?testFilename') - ipcRenderer.once('download-done', function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) { + ipcRenderer.once('download-done', function (event, state, url, + mimeType, receivedBytes, + totalBytes, disposition, + filename) { assert.equal(state, 'cancelled') assert.equal(filename, 'download.pdf') assert.equal(mimeType, 'application/pdf') @@ -565,4 +582,84 @@ describe('session module', function () { w.loadURL(url) }) }) + + describe('ses.createInterruptedDownload(options)', function () { + it('can create an interrupted download item', function (done) { + ipcRenderer.sendSync('set-download-option', true, false) + const filePath = path.join(__dirname, 'fixtures', 'mock.pdf') + const urlChain = ['http://127.0.0.1/'] + const options = { + path: filePath, + urlChain: urlChain, + mimeType: 'application/pdf', + offset: 0, + length: 5242880 + } + w.webContents.session.createInterruptedDownload(options) + ipcRenderer.once('download-created', function (event, state, urlChain, + mimeType, receivedBytes, + totalBytes, filename, + savePath) { + assert.equal(state, 'interrupted') + assert.equal(urlChain, urlChain) + assert.equal(mimeType, 'application/pdf') + assert.equal(receivedBytes, 0) + assert.equal(totalBytes, 5242880) + assert.equal(savePath, filePath) + done() + }) + }) + + it('can be resumed', function (done) { + const fixtures = path.join(__dirname, 'fixtures') + const downloadFilePath = path.join(fixtures, 'logo.png') + const rangeServer = http.createServer(function (req, res) { + let options = { + root: fixtures + } + send(req, req.url, options) + .on('error', function (error) { + done(error) + }).pipe(res) + }) + ipcRenderer.sendSync('set-download-option', true, false, downloadFilePath) + rangeServer.listen(0, '127.0.0.1', function () { + const port = rangeServer.address().port + const downloadUrl = `http://127.0.0.1:${port}/assets/logo.png` + const callback = function (event, state, url, mimeType, + receivedBytes, totalBytes, disposition, + filename, savePath, urlChain, + lastModifiedTime, eTag) { + if (state === 'cancelled') { + const options = { + path: savePath, + urlChain: urlChain, + mimeType: mimeType, + offset: receivedBytes, + length: totalBytes, + lastModified: lastModifiedTime, + eTag: eTag + } + ipcRenderer.sendSync('set-download-option', false, false, downloadFilePath) + w.webContents.session.createInterruptedDownload(options) + } else { + assert.equal(state, 'completed') + assert.equal(filename, 'logo.png') + assert.equal(savePath, downloadFilePath) + assert.equal(url, downloadUrl) + assert.equal(mimeType, 'image/png') + assert.equal(receivedBytes, 14022) + assert.equal(totalBytes, 14022) + assert(fs.existsSync(downloadFilePath)) + fs.unlinkSync(downloadFilePath) + rangeServer.close() + ipcRenderer.removeListener('download-done', callback) + done() + } + } + ipcRenderer.on('download-done', callback) + w.webContents.downloadURL(downloadUrl) + }) + }) + }) }) diff --git a/spec/package.json b/spec/package.json index 8cc1614a27ec..a3b1ba7b26a6 100644 --- a/spec/package.json +++ b/spec/package.json @@ -10,6 +10,7 @@ "mocha": "^3.1.0", "multiparty": "^4.1.2", "q": "^1.4.1", + "send": "^0.14.1", "temp": "^0.8.3", "walkdir": "0.0.11", "ws": "^1.1.1", diff --git a/spec/static/main.js b/spec/static/main.js index ffc13e39a8ee..f29cbebeeb1e 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -137,8 +137,16 @@ app.on('ready', function () { // For session's download test, listen 'will-download' event in browser, and // reply the result to renderer for verifying var downloadFilePath = path.join(__dirname, '..', 'fixtures', 'mock.pdf') - ipcMain.on('set-download-option', function (event, needCancel, preventDefault) { + ipcMain.on('set-download-option', function (event, needCancel, preventDefault, filePath = downloadFilePath) { window.webContents.session.once('will-download', function (e, item) { + window.webContents.send('download-created', + item.getState(), + item.getURLChain(), + item.getMimeType(), + item.getReceivedBytes(), + item.getTotalBytes(), + item.getFilename(), + item.getSavePath()) if (preventDefault) { e.preventDefault() const url = item.getURL() @@ -151,7 +159,11 @@ app.on('ready', function () { } }) } else { - item.setSavePath(downloadFilePath) + if (item.getState() === 'interrupted' && !needCancel) { + item.resume() + } else { + item.setSavePath(filePath) + } item.on('done', function (e, state) { window.webContents.send('download-done', state, @@ -161,7 +173,10 @@ app.on('ready', function () { item.getTotalBytes(), item.getContentDisposition(), item.getFilename(), - item.getSavePath()) + item.getSavePath(), + item.getURLChain(), + item.getLastModifiedTime(), + item.getETag()) }) if (needCancel) item.cancel() }