Merge pull request #8061 from deepak1556/resume_download_api
session: api to resume canceled downloads from previous session
This commit is contained in:
commit
952e3bac2c
9 changed files with 245 additions and 15 deletions
|
@ -146,6 +146,10 @@ const GURL& DownloadItem::GetURL() const {
|
||||||
return download_item_->GetURL();
|
return download_item_->GetURL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<GURL>& DownloadItem::GetURLChain() const {
|
||||||
|
return download_item_->GetUrlChain();
|
||||||
|
}
|
||||||
|
|
||||||
content::DownloadItem::DownloadState DownloadItem::GetState() const {
|
content::DownloadItem::DownloadState DownloadItem::GetState() const {
|
||||||
return download_item_->GetState();
|
return download_item_->GetState();
|
||||||
}
|
}
|
||||||
|
@ -162,6 +166,18 @@ base::FilePath DownloadItem::GetSavePath() const {
|
||||||
return save_path_;
|
return save_path_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string DownloadItem::GetLastModifiedTime() const {
|
||||||
|
return download_item_->GetLastModifiedTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DownloadItem::GetETag() const {
|
||||||
|
return download_item_->GetETag();
|
||||||
|
}
|
||||||
|
|
||||||
|
double DownloadItem::GetStartTime() const {
|
||||||
|
return download_item_->GetStartTime().ToDoubleT();
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void DownloadItem::BuildPrototype(v8::Isolate* isolate,
|
void DownloadItem::BuildPrototype(v8::Isolate* isolate,
|
||||||
v8::Local<v8::FunctionTemplate> prototype) {
|
v8::Local<v8::FunctionTemplate> prototype) {
|
||||||
|
@ -180,10 +196,14 @@ void DownloadItem::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("getFilename", &DownloadItem::GetFilename)
|
.SetMethod("getFilename", &DownloadItem::GetFilename)
|
||||||
.SetMethod("getContentDisposition", &DownloadItem::GetContentDisposition)
|
.SetMethod("getContentDisposition", &DownloadItem::GetContentDisposition)
|
||||||
.SetMethod("getURL", &DownloadItem::GetURL)
|
.SetMethod("getURL", &DownloadItem::GetURL)
|
||||||
|
.SetMethod("getURLChain", &DownloadItem::GetURLChain)
|
||||||
.SetMethod("getState", &DownloadItem::GetState)
|
.SetMethod("getState", &DownloadItem::GetState)
|
||||||
.SetMethod("isDone", &DownloadItem::IsDone)
|
.SetMethod("isDone", &DownloadItem::IsDone)
|
||||||
.SetMethod("setSavePath", &DownloadItem::SetSavePath)
|
.SetMethod("setSavePath", &DownloadItem::SetSavePath)
|
||||||
.SetMethod("getSavePath", &DownloadItem::GetSavePath);
|
.SetMethod("getSavePath", &DownloadItem::GetSavePath)
|
||||||
|
.SetMethod("getLastModifiedTime", &DownloadItem::GetLastModifiedTime)
|
||||||
|
.SetMethod("getETag", &DownloadItem::GetETag)
|
||||||
|
.SetMethod("getStartTime", &DownloadItem::GetStartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
|
#define ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "atom/browser/api/trackable_object.h"
|
#include "atom/browser/api/trackable_object.h"
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
|
@ -38,10 +39,14 @@ class DownloadItem : public mate::TrackableObject<DownloadItem>,
|
||||||
std::string GetFilename() const;
|
std::string GetFilename() const;
|
||||||
std::string GetContentDisposition() const;
|
std::string GetContentDisposition() const;
|
||||||
const GURL& GetURL() const;
|
const GURL& GetURL() const;
|
||||||
|
const std::vector<GURL>& GetURLChain() const;
|
||||||
content::DownloadItem::DownloadState GetState() const;
|
content::DownloadItem::DownloadState GetState() const;
|
||||||
bool IsDone() const;
|
bool IsDone() const;
|
||||||
void SetSavePath(const base::FilePath& path);
|
void SetSavePath(const base::FilePath& path);
|
||||||
base::FilePath GetSavePath() const;
|
base::FilePath GetSavePath() const;
|
||||||
|
std::string GetLastModifiedTime() const;
|
||||||
|
std::string GetETag() const;
|
||||||
|
double GetStartTime() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DownloadItem(v8::Isolate* isolate, content::DownloadItem* download_item);
|
DownloadItem(v8::Isolate* isolate, content::DownloadItem* download_item);
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "chrome/common/pref_names.h"
|
#include "chrome/common/pref_names.h"
|
||||||
#include "components/prefs/pref_service.h"
|
#include "components/prefs/pref_service.h"
|
||||||
#include "content/public/browser/browser_thread.h"
|
#include "content/public/browser/browser_thread.h"
|
||||||
|
#include "content/public/browser/download_manager_delegate.h"
|
||||||
#include "content/public/browser/storage_partition.h"
|
#include "content/public/browser/storage_partition.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
#include "native_mate/object_template_builder.h"
|
#include "native_mate/object_template_builder.h"
|
||||||
|
@ -331,6 +332,25 @@ void OnClearStorageDataDone(const base::Closure& callback) {
|
||||||
callback.Run();
|
callback.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DownloadIdCallback(content::DownloadManager* download_manager,
|
||||||
|
const base::FilePath& path,
|
||||||
|
const std::vector<GURL>& url_chain,
|
||||||
|
const std::string& mime_type,
|
||||||
|
int64_t offset,
|
||||||
|
int64_t length,
|
||||||
|
const std::string& last_modified,
|
||||||
|
const std::string& etag,
|
||||||
|
const base::Time& start_time,
|
||||||
|
uint32_t id) {
|
||||||
|
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(),
|
||||||
|
content::DownloadItem::INTERRUPTED,
|
||||||
|
content::DownloadDangerType::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
|
||||||
|
content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT, false);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context)
|
Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context)
|
||||||
|
@ -357,10 +377,10 @@ void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||||
|
|
||||||
v8::Locker locker(isolate());
|
v8::Locker locker(isolate());
|
||||||
v8::HandleScope handle_scope(isolate());
|
v8::HandleScope handle_scope(isolate());
|
||||||
bool prevent_default = Emit(
|
auto handle = DownloadItem::Create(isolate(), item);
|
||||||
"will-download",
|
if (item->GetState() == content::DownloadItem::INTERRUPTED)
|
||||||
DownloadItem::Create(isolate(), item),
|
handle->SetSavePath(item->GetTargetFilePath());
|
||||||
item->GetWebContents());
|
bool prevent_default = Emit("will-download", handle, item->GetWebContents());
|
||||||
if (prevent_default) {
|
if (prevent_default) {
|
||||||
item->Cancel(true);
|
item->Cancel(true);
|
||||||
item->Remove();
|
item->Remove();
|
||||||
|
@ -520,6 +540,37 @@ void Session::GetBlobData(
|
||||||
callback));
|
callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::CreateInterruptedDownload(const mate::Dictionary& options) {
|
||||||
|
int64_t offset = 0, length = 0;
|
||||||
|
double start_time = 0.0;
|
||||||
|
std::string mime_type, last_modified, etag;
|
||||||
|
base::FilePath path;
|
||||||
|
std::vector<GURL> url_chain;
|
||||||
|
options.Get("path", &path);
|
||||||
|
options.Get("urlChain", &url_chain);
|
||||||
|
options.Get("mimeType", &mime_type);
|
||||||
|
options.Get("offset", &offset);
|
||||||
|
options.Get("length", &length);
|
||||||
|
options.Get("lastModified", &last_modified);
|
||||||
|
options.Get("eTag", &etag);
|
||||||
|
options.Get("startTime", &start_time);
|
||||||
|
if (path.empty() || url_chain.empty() || length == 0) {
|
||||||
|
isolate()->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||||
|
isolate(), "Must pass non-empty path, urlChain and length.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (offset >= length) {
|
||||||
|
isolate()->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||||
|
isolate(), "Must pass an offset value less than length.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto download_manager =
|
||||||
|
content::BrowserContext::GetDownloadManager(browser_context());
|
||||||
|
download_manager->GetDelegate()->GetNextId(base::Bind(
|
||||||
|
&DownloadIdCallback, download_manager, path, url_chain, mime_type, offset,
|
||||||
|
length, last_modified, etag, base::Time::FromDoubleT(start_time)));
|
||||||
|
}
|
||||||
|
|
||||||
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
|
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
|
||||||
if (cookies_.IsEmpty()) {
|
if (cookies_.IsEmpty()) {
|
||||||
auto handle = Cookies::Create(isolate, browser_context());
|
auto handle = Cookies::Create(isolate, browser_context());
|
||||||
|
@ -603,6 +654,8 @@ void Session::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("setUserAgent", &Session::SetUserAgent)
|
.SetMethod("setUserAgent", &Session::SetUserAgent)
|
||||||
.SetMethod("getUserAgent", &Session::GetUserAgent)
|
.SetMethod("getUserAgent", &Session::GetUserAgent)
|
||||||
.SetMethod("getBlobData", &Session::GetBlobData)
|
.SetMethod("getBlobData", &Session::GetBlobData)
|
||||||
|
.SetMethod("createInterruptedDownload",
|
||||||
|
&Session::CreateInterruptedDownload)
|
||||||
.SetProperty("cookies", &Session::Cookies)
|
.SetProperty("cookies", &Session::Cookies)
|
||||||
.SetProperty("protocol", &Session::Protocol)
|
.SetProperty("protocol", &Session::Protocol)
|
||||||
.SetProperty("webRequest", &Session::WebRequest);
|
.SetProperty("webRequest", &Session::WebRequest);
|
||||||
|
|
|
@ -79,6 +79,7 @@ class Session: public mate::TrackableObject<Session>,
|
||||||
std::string GetUserAgent();
|
std::string GetUserAgent();
|
||||||
void GetBlobData(const std::string& uuid,
|
void GetBlobData(const std::string& uuid,
|
||||||
const AtomBlobReader::CompletionCallback& callback);
|
const AtomBlobReader::CompletionCallback& callback);
|
||||||
|
void CreateInterruptedDownload(const mate::Dictionary& options);
|
||||||
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
||||||
v8::Local<v8::Value> Protocol(v8::Isolate* isolate);
|
v8::Local<v8::Value> Protocol(v8::Isolate* isolate);
|
||||||
v8::Local<v8::Value> WebRequest(v8::Isolate* isolate);
|
v8::Local<v8::Value> WebRequest(v8::Isolate* isolate);
|
||||||
|
|
|
@ -146,3 +146,23 @@ header.
|
||||||
#### `downloadItem.getState()`
|
#### `downloadItem.getState()`
|
||||||
|
|
||||||
Returns `String` - The current state. Can be `progressing`, `completed`, `cancelled` or `interrupted`.
|
Returns `String` - The current state. Can be `progressing`, `completed`, `cancelled` or `interrupted`.
|
||||||
|
|
||||||
|
**Note:** The following methods are useful specifically to resume a
|
||||||
|
`cancelled` item when session is restarted.
|
||||||
|
|
||||||
|
#### `downloadItem.getURLChain()`
|
||||||
|
|
||||||
|
Returns `String[]` - The complete url chain of the item including any redirects.
|
||||||
|
|
||||||
|
#### `downloadItem.getLastModifiedTime()`
|
||||||
|
|
||||||
|
Returns `String` - Last-Modified header value.
|
||||||
|
|
||||||
|
#### `downloadItem.getETag()`
|
||||||
|
|
||||||
|
Returns `String` - ETag header value.
|
||||||
|
|
||||||
|
#### `downloadItem.getStartTime()`
|
||||||
|
|
||||||
|
Returns `Double` - Number of seconds since the UNIX epoch when the download was
|
||||||
|
started.
|
||||||
|
|
|
@ -344,6 +344,25 @@ Returns `String` - The user agent for this session.
|
||||||
|
|
||||||
Returns `Blob` - The blob data associated with the `identifier`.
|
Returns `Blob` - The blob data associated with the `identifier`.
|
||||||
|
|
||||||
|
#### `ses.createInterruptedDownload(options)`
|
||||||
|
|
||||||
|
* `options` Object
|
||||||
|
* `path` String - Absolute path of the download.
|
||||||
|
* `urlChain` String[] - Complete URL chain for the download.
|
||||||
|
* `mimeType` String (optional)
|
||||||
|
* `offset` Integer - Start range for the download.
|
||||||
|
* `length` Integer - Total length of the download.
|
||||||
|
* `lastModified` String - Last-Modified header value.
|
||||||
|
* `eTag` String - ETag header value.
|
||||||
|
* `startTime` Double (optional) - Time when download was started in
|
||||||
|
number of seconds since UNIX epoch.
|
||||||
|
|
||||||
|
Allows resuming `cancelled` or `interrupted` downloads from previous `Session`.
|
||||||
|
The API will generate a [DownloadItem](download-item.md) that can be accessed with the [will-download](#event-will-download)
|
||||||
|
event. The [DownloadItem](download-item.md) will not have any `WebContents` associated with it and
|
||||||
|
the initial state will be `interrupted`. The download will start only when the
|
||||||
|
`resume` API is called on the [DownloadItem](download-item.md).
|
||||||
|
|
||||||
### Instance Properties
|
### Instance Properties
|
||||||
|
|
||||||
The following properties are available on instances of `Session`:
|
The following properties are available on instances of `Session`:
|
||||||
|
|
|
@ -3,6 +3,7 @@ const http = require('http')
|
||||||
const https = require('https')
|
const https = require('https')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
const send = require('send')
|
||||||
const {closeWindow} = require('./window-helpers')
|
const {closeWindow} = require('./window-helpers')
|
||||||
|
|
||||||
const {ipcRenderer, remote} = require('electron')
|
const {ipcRenderer, remote} = require('electron')
|
||||||
|
@ -288,7 +289,9 @@ describe('session module', function () {
|
||||||
res.end(mockPDF)
|
res.end(mockPDF)
|
||||||
downloadServer.close()
|
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(state, 'completed')
|
||||||
assert.equal(filename, 'mock.pdf')
|
assert.equal(filename, 'mock.pdf')
|
||||||
assert.equal(savePath, path.join(__dirname, 'fixtures', 'mock.pdf'))
|
assert.equal(savePath, path.join(__dirname, 'fixtures', 'mock.pdf'))
|
||||||
|
@ -306,8 +309,12 @@ describe('session module', function () {
|
||||||
var port = downloadServer.address().port
|
var port = downloadServer.address().port
|
||||||
ipcRenderer.sendSync('set-download-option', false, false)
|
ipcRenderer.sendSync('set-download-option', false, false)
|
||||||
w.loadURL(url + ':' + port)
|
w.loadURL(url + ':' + port)
|
||||||
ipcRenderer.once('download-done', function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, savePath) {
|
ipcRenderer.once('download-done', function (event, state, url,
|
||||||
assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port, savePath)
|
mimeType, receivedBytes,
|
||||||
|
totalBytes, disposition,
|
||||||
|
filename, savePath) {
|
||||||
|
assertDownload(event, state, url, mimeType, receivedBytes,
|
||||||
|
totalBytes, disposition, filename, port, savePath)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -322,8 +329,12 @@ describe('session module', function () {
|
||||||
webview.addEventListener('did-finish-load', function () {
|
webview.addEventListener('did-finish-load', function () {
|
||||||
webview.downloadURL(url + ':' + port + '/')
|
webview.downloadURL(url + ':' + port + '/')
|
||||||
})
|
})
|
||||||
ipcRenderer.once('download-done', function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, savePath) {
|
ipcRenderer.once('download-done', function (event, state, url,
|
||||||
assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port, savePath)
|
mimeType, receivedBytes,
|
||||||
|
totalBytes, disposition,
|
||||||
|
filename, savePath) {
|
||||||
|
assertDownload(event, state, url, mimeType, receivedBytes,
|
||||||
|
totalBytes, disposition, filename, port, savePath)
|
||||||
document.body.removeChild(webview)
|
document.body.removeChild(webview)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
@ -336,7 +347,10 @@ describe('session module', function () {
|
||||||
var port = downloadServer.address().port
|
var port = downloadServer.address().port
|
||||||
ipcRenderer.sendSync('set-download-option', true, false)
|
ipcRenderer.sendSync('set-download-option', true, false)
|
||||||
w.loadURL(url + ':' + port + '/')
|
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(state, 'cancelled')
|
||||||
assert.equal(filename, 'mock.pdf')
|
assert.equal(filename, 'mock.pdf')
|
||||||
assert.equal(mimeType, 'application/pdf')
|
assert.equal(mimeType, 'application/pdf')
|
||||||
|
@ -356,7 +370,10 @@ describe('session module', function () {
|
||||||
var port = downloadServer.address().port
|
var port = downloadServer.address().port
|
||||||
ipcRenderer.sendSync('set-download-option', true, false)
|
ipcRenderer.sendSync('set-download-option', true, false)
|
||||||
w.loadURL(url + ':' + port + '/?testFilename')
|
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(state, 'cancelled')
|
||||||
assert.equal(filename, 'download.pdf')
|
assert.equal(filename, 'download.pdf')
|
||||||
assert.equal(mimeType, 'application/pdf')
|
assert.equal(mimeType, 'application/pdf')
|
||||||
|
@ -565,4 +582,83 @@ describe('session module', function () {
|
||||||
w.loadURL(url)
|
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 options = {
|
||||||
|
path: filePath,
|
||||||
|
urlChain: ['http://127.0.0.1/'],
|
||||||
|
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.deepEqual(urlChain, ['http://127.0.0.1/'])
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"mocha": "^3.1.0",
|
"mocha": "^3.1.0",
|
||||||
"multiparty": "^4.1.2",
|
"multiparty": "^4.1.2",
|
||||||
"q": "^1.4.1",
|
"q": "^1.4.1",
|
||||||
|
"send": "^0.14.1",
|
||||||
"temp": "^0.8.3",
|
"temp": "^0.8.3",
|
||||||
"walkdir": "0.0.11",
|
"walkdir": "0.0.11",
|
||||||
"ws": "^1.1.1",
|
"ws": "^1.1.1",
|
||||||
|
|
|
@ -137,8 +137,16 @@ app.on('ready', function () {
|
||||||
// For session's download test, listen 'will-download' event in browser, and
|
// For session's download test, listen 'will-download' event in browser, and
|
||||||
// reply the result to renderer for verifying
|
// reply the result to renderer for verifying
|
||||||
var downloadFilePath = path.join(__dirname, '..', 'fixtures', 'mock.pdf')
|
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.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) {
|
if (preventDefault) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const url = item.getURL()
|
const url = item.getURL()
|
||||||
|
@ -151,7 +159,11 @@ app.on('ready', function () {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
item.setSavePath(downloadFilePath)
|
if (item.getState() === 'interrupted' && !needCancel) {
|
||||||
|
item.resume()
|
||||||
|
} else {
|
||||||
|
item.setSavePath(filePath)
|
||||||
|
}
|
||||||
item.on('done', function (e, state) {
|
item.on('done', function (e, state) {
|
||||||
window.webContents.send('download-done',
|
window.webContents.send('download-done',
|
||||||
state,
|
state,
|
||||||
|
@ -161,7 +173,10 @@ app.on('ready', function () {
|
||||||
item.getTotalBytes(),
|
item.getTotalBytes(),
|
||||||
item.getContentDisposition(),
|
item.getContentDisposition(),
|
||||||
item.getFilename(),
|
item.getFilename(),
|
||||||
item.getSavePath())
|
item.getSavePath(),
|
||||||
|
item.getURLChain(),
|
||||||
|
item.getLastModifiedTime(),
|
||||||
|
item.getETag())
|
||||||
})
|
})
|
||||||
if (needCancel) item.cancel()
|
if (needCancel) item.cancel()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue