mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de625bfb65 | ||
|
|
c751d42d1a | ||
|
|
198f5f237f | ||
|
|
dc5b27069a | ||
|
|
6a829e0179 | ||
|
|
4085ba309a | ||
|
|
975d677f55 | ||
|
|
21be9a3309 | ||
|
|
7456b9ae17 | ||
|
|
35349643af | ||
|
|
952e3bac2c | ||
|
|
d705f4cbac | ||
|
|
5d94221c61 | ||
|
|
f124732431 | ||
|
|
d944219b28 | ||
|
|
86961d0f44 | ||
|
|
54d27a390b | ||
|
|
ba44dca34a | ||
|
|
61d91579df | ||
|
|
32ae3a52b8 | ||
|
|
e198b6945c | ||
|
|
9adb232d99 |
@@ -146,6 +146,10 @@ const GURL& DownloadItem::GetURL() const {
|
||||
return download_item_->GetURL();
|
||||
}
|
||||
|
||||
const std::vector<GURL>& DownloadItem::GetURLChain() const {
|
||||
return download_item_->GetUrlChain();
|
||||
}
|
||||
|
||||
content::DownloadItem::DownloadState DownloadItem::GetState() const {
|
||||
return download_item_->GetState();
|
||||
}
|
||||
@@ -162,6 +166,18 @@ base::FilePath DownloadItem::GetSavePath() const {
|
||||
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
|
||||
void DownloadItem::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype) {
|
||||
@@ -180,10 +196,14 @@ void DownloadItem::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("getFilename", &DownloadItem::GetFilename)
|
||||
.SetMethod("getContentDisposition", &DownloadItem::GetContentDisposition)
|
||||
.SetMethod("getURL", &DownloadItem::GetURL)
|
||||
.SetMethod("getURLChain", &DownloadItem::GetURLChain)
|
||||
.SetMethod("getState", &DownloadItem::GetState)
|
||||
.SetMethod("isDone", &DownloadItem::IsDone)
|
||||
.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
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "base/files/file_path.h"
|
||||
@@ -38,10 +39,14 @@ class DownloadItem : public mate::TrackableObject<DownloadItem>,
|
||||
std::string GetFilename() const;
|
||||
std::string GetContentDisposition() const;
|
||||
const GURL& GetURL() const;
|
||||
const std::vector<GURL>& GetURLChain() const;
|
||||
content::DownloadItem::DownloadState GetState() const;
|
||||
bool IsDone() const;
|
||||
void SetSavePath(const base::FilePath& path);
|
||||
base::FilePath GetSavePath() const;
|
||||
std::string GetLastModifiedTime() const;
|
||||
std::string GetETag() const;
|
||||
double GetStartTime() const;
|
||||
|
||||
protected:
|
||||
DownloadItem(v8::Isolate* isolate, content::DownloadItem* download_item);
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/download_manager_delegate.h"
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
@@ -61,6 +62,15 @@ struct ClearStorageDataOptions {
|
||||
uint32_t quota_types = StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL;
|
||||
};
|
||||
|
||||
struct ClearAuthCacheOptions {
|
||||
std::string type;
|
||||
GURL origin;
|
||||
std::string realm;
|
||||
base::string16 username;
|
||||
base::string16 password;
|
||||
net::HttpAuth::Scheme auth_scheme;
|
||||
};
|
||||
|
||||
uint32_t GetStorageMask(const std::vector<std::string>& storage_types) {
|
||||
uint32_t storage_mask = 0;
|
||||
for (const auto& it : storage_types) {
|
||||
@@ -99,6 +109,18 @@ uint32_t GetQuotaMask(const std::vector<std::string>& quota_types) {
|
||||
return quota_mask;
|
||||
}
|
||||
|
||||
net::HttpAuth::Scheme GetAuthSchemeFromString(const std::string& scheme) {
|
||||
if (scheme == "basic")
|
||||
return net::HttpAuth::AUTH_SCHEME_BASIC;
|
||||
if (scheme == "digest")
|
||||
return net::HttpAuth::AUTH_SCHEME_DIGEST;
|
||||
if (scheme == "ntlm")
|
||||
return net::HttpAuth::AUTH_SCHEME_NTLM;
|
||||
if (scheme == "negotiate")
|
||||
return net::HttpAuth::AUTH_SCHEME_NEGOTIATE;
|
||||
return net::HttpAuth::AUTH_SCHEME_MAX;
|
||||
}
|
||||
|
||||
void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
const std::string& accept_lang,
|
||||
const std::string& user_agent) {
|
||||
@@ -130,7 +152,27 @@ struct Converter<ClearStorageDataOptions> {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
template <>
|
||||
struct Converter<ClearAuthCacheOptions> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
ClearAuthCacheOptions* out) {
|
||||
mate::Dictionary options;
|
||||
if (!ConvertFromV8(isolate, val, &options))
|
||||
return false;
|
||||
options.Get("type", &out->type);
|
||||
options.Get("origin", &out->origin);
|
||||
options.Get("realm", &out->realm);
|
||||
options.Get("username", &out->username);
|
||||
options.Get("password", &out->password);
|
||||
std::string scheme;
|
||||
if (options.Get("scheme", &scheme))
|
||||
out->auth_scheme = GetAuthSchemeFromString(scheme);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<net::ProxyConfig> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
@@ -313,6 +355,33 @@ void ClearHostResolverCacheInIO(
|
||||
}
|
||||
}
|
||||
|
||||
void ClearAuthCacheInIO(
|
||||
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
|
||||
const ClearAuthCacheOptions& options,
|
||||
const base::Closure& callback) {
|
||||
auto request_context = context_getter->GetURLRequestContext();
|
||||
auto network_session =
|
||||
request_context->http_transaction_factory()->GetSession();
|
||||
if (network_session) {
|
||||
if (options.type == "password") {
|
||||
auto auth_cache = network_session->http_auth_cache();
|
||||
if (!options.origin.is_empty()) {
|
||||
auth_cache->Remove(
|
||||
options.origin, options.realm, options.auth_scheme,
|
||||
net::AuthCredentials(options.username, options.password));
|
||||
} else {
|
||||
auth_cache->Clear();
|
||||
}
|
||||
} else if (options.type == "clientCertificate") {
|
||||
auto client_auth_cache = network_session->ssl_client_auth_cache();
|
||||
client_auth_cache->Remove(net::HostPortPair::FromURL(options.origin));
|
||||
}
|
||||
network_session->CloseAllConnections();
|
||||
}
|
||||
if (!callback.is_null())
|
||||
RunCallbackInUI(callback);
|
||||
}
|
||||
|
||||
void AllowNTLMCredentialsForDomainsInIO(
|
||||
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
|
||||
const std::string& domains) {
|
||||
@@ -331,6 +400,25 @@ void OnClearStorageDataDone(const base::Closure& callback) {
|
||||
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
|
||||
|
||||
Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context)
|
||||
@@ -357,10 +445,10 @@ void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
bool prevent_default = Emit(
|
||||
"will-download",
|
||||
DownloadItem::Create(isolate(), item),
|
||||
item->GetWebContents());
|
||||
auto handle = DownloadItem::Create(isolate(), item);
|
||||
if (item->GetState() == content::DownloadItem::INTERRUPTED)
|
||||
handle->SetSavePath(item->GetTargetFilePath());
|
||||
bool prevent_default = Emit("will-download", handle, item->GetWebContents());
|
||||
if (prevent_default) {
|
||||
item->Cancel(true);
|
||||
item->Remove();
|
||||
@@ -481,6 +569,22 @@ void Session::ClearHostResolverCache(mate::Arguments* args) {
|
||||
callback));
|
||||
}
|
||||
|
||||
void Session::ClearAuthCache(mate::Arguments* args) {
|
||||
ClearAuthCacheOptions options;
|
||||
if (!args->GetNext(&options)) {
|
||||
args->ThrowError("Must specify options object");
|
||||
return;
|
||||
}
|
||||
base::Closure callback;
|
||||
args->GetNext(&callback);
|
||||
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&ClearAuthCacheInIO,
|
||||
make_scoped_refptr(browser_context_->GetRequestContext()),
|
||||
options, callback));
|
||||
}
|
||||
|
||||
void Session::AllowNTLMCredentialsForDomains(const std::string& domains) {
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AllowNTLMCredentialsForDomainsInIO,
|
||||
@@ -520,6 +624,37 @@ void Session::GetBlobData(
|
||||
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) {
|
||||
if (cookies_.IsEmpty()) {
|
||||
auto handle = Cookies::Create(isolate, browser_context());
|
||||
@@ -598,11 +733,14 @@ void Session::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("setPermissionRequestHandler",
|
||||
&Session::SetPermissionRequestHandler)
|
||||
.SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache)
|
||||
.SetMethod("clearAuthCache", &Session::ClearAuthCache)
|
||||
.SetMethod("allowNTLMCredentialsForDomains",
|
||||
&Session::AllowNTLMCredentialsForDomains)
|
||||
.SetMethod("setUserAgent", &Session::SetUserAgent)
|
||||
.SetMethod("getUserAgent", &Session::GetUserAgent)
|
||||
.SetMethod("getBlobData", &Session::GetBlobData)
|
||||
.SetMethod("createInterruptedDownload",
|
||||
&Session::CreateInterruptedDownload)
|
||||
.SetProperty("cookies", &Session::Cookies)
|
||||
.SetProperty("protocol", &Session::Protocol)
|
||||
.SetProperty("webRequest", &Session::WebRequest);
|
||||
|
||||
@@ -74,11 +74,13 @@ class Session: public mate::TrackableObject<Session>,
|
||||
void SetPermissionRequestHandler(v8::Local<v8::Value> val,
|
||||
mate::Arguments* args);
|
||||
void ClearHostResolverCache(mate::Arguments* args);
|
||||
void ClearAuthCache(mate::Arguments* args);
|
||||
void AllowNTLMCredentialsForDomains(const std::string& domains);
|
||||
void SetUserAgent(const std::string& user_agent, mate::Arguments* args);
|
||||
std::string GetUserAgent();
|
||||
void GetBlobData(const std::string& uuid,
|
||||
const AtomBlobReader::CompletionCallback& callback);
|
||||
void CreateInterruptedDownload(const mate::Dictionary& options);
|
||||
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
||||
v8::Local<v8::Value> Protocol(v8::Isolate* isolate);
|
||||
v8::Local<v8::Value> WebRequest(v8::Isolate* isolate);
|
||||
|
||||
@@ -176,6 +176,7 @@ void URLRequest::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("setExtraHeader", &URLRequest::SetExtraHeader)
|
||||
.SetMethod("removeExtraHeader", &URLRequest::RemoveExtraHeader)
|
||||
.SetMethod("setChunkedUpload", &URLRequest::SetChunkedUpload)
|
||||
.SetMethod("_setLoadFlags", &URLRequest::SetLoadFlags)
|
||||
.SetProperty("notStarted", &URLRequest::NotStarted)
|
||||
.SetProperty("finished", &URLRequest::Finished)
|
||||
// Response APi
|
||||
@@ -292,6 +293,18 @@ void URLRequest::SetChunkedUpload(bool is_chunked_upload) {
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequest::SetLoadFlags(int flags) {
|
||||
// State must be equal to not started.
|
||||
if (!request_state_.NotStarted()) {
|
||||
// Cannot change load flags after start.
|
||||
return;
|
||||
}
|
||||
DCHECK(atom_request_);
|
||||
if (atom_request_) {
|
||||
atom_request_->SetLoadFlags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequest::OnAuthenticationRequired(
|
||||
scoped_refptr<const net::AuthChallengeInfo> auth_info) {
|
||||
if (request_state_.Canceled() || request_state_.Closed()) {
|
||||
|
||||
@@ -173,6 +173,7 @@ class URLRequest : public mate::EventEmitter<URLRequest> {
|
||||
bool SetExtraHeader(const std::string& name, const std::string& value);
|
||||
void RemoveExtraHeader(const std::string& name);
|
||||
void SetChunkedUpload(bool is_chunked_upload);
|
||||
void SetLoadFlags(int flags);
|
||||
|
||||
int StatusCode() const;
|
||||
std::string StatusMessage() const;
|
||||
|
||||
@@ -177,6 +177,13 @@ void AtomURLRequest::PassLoginInformation(
|
||||
}
|
||||
}
|
||||
|
||||
void AtomURLRequest::SetLoadFlags(int flags) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AtomURLRequest::DoSetLoadFlags, this, flags));
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoWriteBuffer(
|
||||
scoped_refptr<const net::IOBufferWithSize> buffer,
|
||||
bool is_last) {
|
||||
@@ -244,6 +251,7 @@ void AtomURLRequest::DoSetExtraHeader(const std::string& name,
|
||||
}
|
||||
request_->SetExtraRequestHeaderByName(name, value, true);
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoRemoveExtraHeader(const std::string& name) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_) {
|
||||
@@ -278,6 +286,14 @@ void AtomURLRequest::DoCancelWithError(const std::string& error,
|
||||
isRequestError));
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoSetLoadFlags(int flags) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_) {
|
||||
return;
|
||||
}
|
||||
request_->SetLoadFlags(request_->load_flags() | flags);
|
||||
}
|
||||
|
||||
void AtomURLRequest::OnAuthRequired(net::URLRequest* request,
|
||||
net::AuthChallengeInfo* auth_info) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
|
||||
@@ -40,6 +40,7 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
|
||||
void RemoveExtraHeader(const std::string& name) const;
|
||||
void PassLoginInformation(const base::string16& username,
|
||||
const base::string16& password) const;
|
||||
void SetLoadFlags(int flags) const;
|
||||
|
||||
protected:
|
||||
// Overrides of net::URLRequest::Delegate
|
||||
@@ -71,6 +72,7 @@ class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
|
||||
const base::string16& password) const;
|
||||
void DoCancelAuth() const;
|
||||
void DoCancelWithError(const std::string& error, bool isRequestError);
|
||||
void DoSetLoadFlags(int flags) const;
|
||||
|
||||
void ReadResponse();
|
||||
bool CopyAndPostBuffer(int bytes_read);
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>electron.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.4.11</string>
|
||||
<string>1.4.12</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.4.11</string>
|
||||
<string>1.4.12</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -56,8 +56,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,4,11,0
|
||||
PRODUCTVERSION 1,4,11,0
|
||||
FILEVERSION 1,4,12,0
|
||||
PRODUCTVERSION 1,4,12,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -74,12 +74,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "1.4.11"
|
||||
VALUE "FileVersion", "1.4.12"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "1.4.11"
|
||||
VALUE "ProductVersion", "1.4.12"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#define ATOM_MAJOR_VERSION 1
|
||||
#define ATOM_MINOR_VERSION 4
|
||||
#define ATOM_PATCH_VERSION 11
|
||||
#define ATOM_PATCH_VERSION 12
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ child.once('ready-to-show', () => {
|
||||
|
||||
### Platform notices
|
||||
|
||||
* On macOS modal windows will be displayed as sheets attached to the parent window.
|
||||
* On macOS the child windows will keep the relative position to parent window
|
||||
when parent window moves, while on Windows and Linux child windows will not
|
||||
move.
|
||||
@@ -1004,6 +1005,19 @@ let url = require('url').format({
|
||||
win.loadURL(url)
|
||||
```
|
||||
|
||||
You can load a URL using a `POST` request with URL-encoded data by doing
|
||||
the following:
|
||||
|
||||
```javascript
|
||||
win.loadURL('http://localhost:8000/post', {
|
||||
postData: [{
|
||||
type: 'rawData',
|
||||
bytes: Buffer.from('hello=world')
|
||||
}],
|
||||
extraHeaders: 'Content-Type: application/x-www-form-urlencoded'
|
||||
})
|
||||
```
|
||||
|
||||
#### `win.reload()`
|
||||
|
||||
Same as `webContents.reload`.
|
||||
|
||||
@@ -41,6 +41,8 @@ The `dialog` module has the following methods:
|
||||
Returns `String[]`, an array of file paths chosen by the user,
|
||||
if the callback is provided it returns `undefined`.
|
||||
|
||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||
|
||||
The `filters` specifies an array of file types that can be displayed or
|
||||
selected when you want to limit the user to a specific type. For example:
|
||||
|
||||
@@ -82,6 +84,8 @@ shown.
|
||||
Returns `String`, the path of the file chosen by the user,
|
||||
if a callback is provided it returns `undefined`.
|
||||
|
||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||
|
||||
The `filters` specifies an array of file types that can be displayed, see
|
||||
`dialog.showOpenDialog` for an example.
|
||||
|
||||
@@ -122,6 +126,8 @@ it returns undefined.
|
||||
Shows a message box, it will block the process until the message box is closed.
|
||||
It returns the index of the clicked button.
|
||||
|
||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||
|
||||
If a `callback` is passed, the API call will be asynchronous and the result
|
||||
will be passed via `callback(response)`.
|
||||
|
||||
|
||||
@@ -146,3 +146,23 @@ header.
|
||||
#### `downloadItem.getState()`
|
||||
|
||||
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,32 @@ Returns `String` - The user agent for this session.
|
||||
|
||||
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).
|
||||
|
||||
#### `ses.clearAuthCache(options[, callback])`
|
||||
|
||||
* `options` ([RemovePassword](structures/remove-password.md) | [RemoveClientCertificate](structures/remove-client-certificate.md))
|
||||
* `callback` Function (optional) - Called when operation is done
|
||||
|
||||
Clears the session’s HTTP authentication cache.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
The following properties are available on instances of `Session`:
|
||||
|
||||
5
docs/api/structures/remove-client-certificate.md
Normal file
5
docs/api/structures/remove-client-certificate.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# RemoveClientCertificate Object
|
||||
|
||||
* `type` String - `clientCertificate`.
|
||||
* `origin` String - Origin of the server whose associated client certificate
|
||||
must be removed from the cache.
|
||||
15
docs/api/structures/remove-password.md
Normal file
15
docs/api/structures/remove-password.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# RemovePassword Object
|
||||
|
||||
* `type` String - `password`.
|
||||
* `origin` String (optional) - When provided, the authentication info
|
||||
related to the origin will only be removed otherwise the entire cache
|
||||
will be cleared.
|
||||
* `scheme` String (optional) - Scheme of the authentication.
|
||||
Can be `basic`, `digest`, `ntlm`, `negotiate`. Must be provided if
|
||||
removing by `origin`.
|
||||
* `realm` String (optional) - Realm of the authentication. Must be provided if
|
||||
removing by `origin`.
|
||||
* `username` String (optional) - Credentials of the authentication. Must be
|
||||
provided if removing by `origin`.
|
||||
* `password` String (optional) - Credentials of the authentication. Must be
|
||||
provided if removing by `origin`.
|
||||
@@ -4,7 +4,7 @@
|
||||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '1.4.11',
|
||||
'version%': '1.4.12',
|
||||
'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c',
|
||||
},
|
||||
'includes': [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "1.4.11",
|
||||
"version": "1.4.12",
|
||||
"devDependencies": {
|
||||
"asar": "^0.11.0",
|
||||
"browserify": "^13.1.0",
|
||||
|
||||
@@ -9,7 +9,7 @@ import sys
|
||||
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
|
||||
'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent'
|
||||
LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \
|
||||
'd59491fbd40f98ae72dfa575fd2b477c061ce613'
|
||||
'2c8173b64b7fbc50e7190a6982e6db6b3eda0582'
|
||||
|
||||
PLATFORM = {
|
||||
'cygwin': 'win32',
|
||||
|
||||
@@ -3,10 +3,12 @@ const http = require('http')
|
||||
const https = require('https')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const send = require('send')
|
||||
const auth = require('basic-auth')
|
||||
const {closeWindow} = require('./window-helpers')
|
||||
|
||||
const {ipcRenderer, remote} = require('electron')
|
||||
const {ipcMain, session, BrowserWindow} = remote
|
||||
const {ipcMain, session, BrowserWindow, net} = remote
|
||||
|
||||
describe('session module', function () {
|
||||
var fixtures = path.resolve(__dirname, 'fixtures')
|
||||
@@ -288,7 +290,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 +310,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 +330,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 +348,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 +371,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 +583,139 @@ 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 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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('ses.clearAuthCache(options[, callback])', function () {
|
||||
it('can clear http auth info from cache', function (done) {
|
||||
const ses = session.fromPartition('auth-cache')
|
||||
const server = http.createServer(function (req, res) {
|
||||
var credentials = auth(req)
|
||||
if (!credentials || credentials.name !== 'test' || credentials.pass !== 'test') {
|
||||
res.statusCode = 401
|
||||
res.setHeader('WWW-Authenticate', 'Basic realm="Restricted"')
|
||||
res.end()
|
||||
} else {
|
||||
res.end('authenticated')
|
||||
}
|
||||
})
|
||||
server.listen(0, '127.0.0.1', function () {
|
||||
const port = server.address().port
|
||||
function issueLoginRequest (attempt = 1) {
|
||||
if (attempt > 2) {
|
||||
server.close()
|
||||
return done()
|
||||
}
|
||||
const request = net.request({
|
||||
url: `http://127.0.0.1:${port}`,
|
||||
session: ses
|
||||
})
|
||||
request.on('login', function (info, callback) {
|
||||
attempt++
|
||||
assert.equal(info.scheme, 'basic')
|
||||
assert.equal(info.realm, 'Restricted')
|
||||
callback('test', 'test')
|
||||
})
|
||||
request.on('response', function (response) {
|
||||
let data = ''
|
||||
response.pause()
|
||||
response.on('data', function (chunk) {
|
||||
data += chunk
|
||||
})
|
||||
response.on('end', function () {
|
||||
assert.equal(data, 'authenticated')
|
||||
ses.clearAuthCache({type: 'password'}, function () {
|
||||
issueLoginRequest(attempt)
|
||||
})
|
||||
})
|
||||
response.on('error', function (error) {
|
||||
done(error)
|
||||
})
|
||||
response.resume()
|
||||
})
|
||||
// Internal api to bypass cache for testing.
|
||||
request.urlRequest._setLoadFlags(1 << 1)
|
||||
request.end()
|
||||
}
|
||||
issueLoginRequest()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user