Merge remote-tracking branch 'refs/remotes/atom/master'
This commit is contained in:
commit
582fb6f519
35 changed files with 2293 additions and 378 deletions
|
@ -7,7 +7,6 @@
|
||||||
#include "atom/common/native_mate_converters/callback.h"
|
#include "atom/common/native_mate_converters/callback.h"
|
||||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||||
#include "atom/common/native_mate_converters/value_converter.h"
|
#include "atom/common/native_mate_converters/value_converter.h"
|
||||||
#include "base/bind.h"
|
|
||||||
#include "base/time/time.h"
|
#include "base/time/time.h"
|
||||||
#include "base/values.h"
|
#include "base/values.h"
|
||||||
#include "content/public/browser/browser_context.h"
|
#include "content/public/browser/browser_context.h"
|
||||||
|
@ -20,139 +19,21 @@
|
||||||
#include "net/url_request/url_request_context.h"
|
#include "net/url_request/url_request_context.h"
|
||||||
#include "net/url_request/url_request_context_getter.h"
|
#include "net/url_request/url_request_context_getter.h"
|
||||||
|
|
||||||
using atom::api::Cookies;
|
|
||||||
using content::BrowserThread;
|
using content::BrowserThread;
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
bool GetCookieListFromStore(
|
|
||||||
net::CookieStore* cookie_store,
|
|
||||||
const std::string& url,
|
|
||||||
const net::CookieMonster::GetCookieListCallback& callback) {
|
|
||||||
DCHECK(cookie_store);
|
|
||||||
GURL gurl(url);
|
|
||||||
net::CookieMonster* monster = cookie_store->GetCookieMonster();
|
|
||||||
// Empty url will match all url cookies.
|
|
||||||
if (url.empty()) {
|
|
||||||
monster->GetAllCookiesAsync(callback);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gurl.is_valid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
monster->GetAllCookiesForURLAsync(gurl, callback);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunGetCookiesCallbackOnUIThread(v8::Isolate* isolate,
|
|
||||||
const std::string& error_message,
|
|
||||||
const net::CookieList& cookie_list,
|
|
||||||
const Cookies::CookiesCallback& callback) {
|
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
||||||
|
|
||||||
v8::Locker locker(isolate);
|
|
||||||
v8::HandleScope handle_scope(isolate);
|
|
||||||
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
v8::Local<v8::Value> error = mate::ConvertToV8(isolate, error_message);
|
|
||||||
callback.Run(error, v8::Null(isolate));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback.Run(v8::Null(isolate), mate::ConvertToV8(isolate, cookie_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunRemoveCookiesCallbackOnUIThread(
|
|
||||||
v8::Isolate* isolate,
|
|
||||||
const std::string& error_message,
|
|
||||||
const Cookies::CookiesCallback& callback) {
|
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
||||||
|
|
||||||
v8::Locker locker(isolate);
|
|
||||||
v8::HandleScope handle_scope(isolate);
|
|
||||||
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
v8::Local<v8::Value> error = mate::ConvertToV8(isolate, error_message);
|
|
||||||
callback.Run(error, v8::Null(isolate));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback.Run(v8::Null(isolate), v8::Null(isolate));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunSetCookiesCallbackOnUIThread(v8::Isolate* isolate,
|
|
||||||
const std::string& error_message,
|
|
||||||
bool set_success,
|
|
||||||
const Cookies::CookiesCallback& callback) {
|
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
||||||
|
|
||||||
v8::Locker locker(isolate);
|
|
||||||
v8::HandleScope handle_scope(isolate);
|
|
||||||
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
v8::Local<v8::Value> error = mate::ConvertToV8(isolate, error_message);
|
|
||||||
callback.Run(error, v8::Null(isolate));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!set_success) {
|
|
||||||
v8::Local<v8::Value> error = mate::ConvertToV8(
|
|
||||||
isolate, "Failed to set cookies");
|
|
||||||
callback.Run(error, v8::Null(isolate));
|
|
||||||
}
|
|
||||||
|
|
||||||
callback.Run(v8::Null(isolate), v8::Null(isolate));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MatchesDomain(const base::DictionaryValue* filter,
|
|
||||||
const std::string& cookie_domain) {
|
|
||||||
std::string filter_domain;
|
|
||||||
if (!filter->GetString("domain", &filter_domain))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Add a leading '.' character to the filter domain if it doesn't exist.
|
|
||||||
if (net::cookie_util::DomainIsHostOnly(filter_domain))
|
|
||||||
filter_domain.insert(0, ".");
|
|
||||||
|
|
||||||
std::string sub_domain(cookie_domain);
|
|
||||||
// Strip any leading '.' character from the input cookie domain.
|
|
||||||
if (!net::cookie_util::DomainIsHostOnly(sub_domain))
|
|
||||||
sub_domain = sub_domain.substr(1);
|
|
||||||
|
|
||||||
// Now check whether the domain argument is a subdomain of the filter domain.
|
|
||||||
for (sub_domain.insert(0, ".");
|
|
||||||
sub_domain.length() >= filter_domain.length();) {
|
|
||||||
if (sub_domain == filter_domain) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const size_t next_dot = sub_domain.find('.', 1); // Skip over leading dot.
|
|
||||||
sub_domain.erase(0, next_dot);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MatchesCookie(const base::DictionaryValue* filter,
|
|
||||||
const net::CanonicalCookie& cookie) {
|
|
||||||
std::string name, domain, path;
|
|
||||||
bool is_secure, session;
|
|
||||||
if (filter->GetString("name", &name) && name != cookie.Name())
|
|
||||||
return false;
|
|
||||||
if (filter->GetString("path", &path) && path != cookie.Path())
|
|
||||||
return false;
|
|
||||||
if (!MatchesDomain(filter, cookie.Domain()))
|
|
||||||
return false;
|
|
||||||
if (filter->GetBoolean("secure", &is_secure) &&
|
|
||||||
is_secure != cookie.IsSecure())
|
|
||||||
return false;
|
|
||||||
if (filter->GetBoolean("session", &session) &&
|
|
||||||
session != cookie.IsPersistent())
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace mate {
|
namespace mate {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Converter<atom::api::Cookies::Error> {
|
||||||
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
atom::api::Cookies::Error val) {
|
||||||
|
if (val == atom::api::Cookies::SUCCESS)
|
||||||
|
return v8::Null(isolate);
|
||||||
|
else
|
||||||
|
return v8::Exception::Error(StringToV8(isolate, "failed"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct Converter<net::CanonicalCookie> {
|
struct Converter<net::CanonicalCookie> {
|
||||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
@ -161,11 +42,11 @@ struct Converter<net::CanonicalCookie> {
|
||||||
dict.Set("name", val.Name());
|
dict.Set("name", val.Name());
|
||||||
dict.Set("value", val.Value());
|
dict.Set("value", val.Value());
|
||||||
dict.Set("domain", val.Domain());
|
dict.Set("domain", val.Domain());
|
||||||
dict.Set("host_only", net::cookie_util::DomainIsHostOnly(val.Domain()));
|
dict.Set("hostOnly", net::cookie_util::DomainIsHostOnly(val.Domain()));
|
||||||
dict.Set("path", val.Path());
|
dict.Set("path", val.Path());
|
||||||
dict.Set("secure", val.IsSecure());
|
dict.Set("secure", val.IsSecure());
|
||||||
dict.Set("http_only", val.IsHttpOnly());
|
dict.Set("httpOnly", val.IsHttpOnly());
|
||||||
dict.Set("session", val.IsPersistent());
|
dict.Set("session", !val.IsPersistent());
|
||||||
if (!val.IsPersistent())
|
if (!val.IsPersistent())
|
||||||
dict.Set("expirationDate", val.ExpiryDate().ToDoubleT());
|
dict.Set("expirationDate", val.ExpiryDate().ToDoubleT());
|
||||||
return dict.GetHandle();
|
return dict.GetHandle();
|
||||||
|
@ -178,121 +59,117 @@ namespace atom {
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
Cookies::Cookies(content::BrowserContext* browser_context)
|
namespace {
|
||||||
: request_context_getter_(browser_context->GetRequestContext()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Cookies::~Cookies() {
|
// Returns whether |domain| matches |filter|.
|
||||||
}
|
bool MatchesDomain(std::string filter, const std::string& domain) {
|
||||||
|
// Add a leading '.' character to the filter domain if it doesn't exist.
|
||||||
|
if (net::cookie_util::DomainIsHostOnly(filter))
|
||||||
|
filter.insert(0, ".");
|
||||||
|
|
||||||
void Cookies::Get(const base::DictionaryValue& options,
|
std::string sub_domain(domain);
|
||||||
const CookiesCallback& callback) {
|
// Strip any leading '.' character from the input cookie domain.
|
||||||
scoped_ptr<base::DictionaryValue> filter(
|
if (!net::cookie_util::DomainIsHostOnly(sub_domain))
|
||||||
options.DeepCopyWithoutEmptyChildren());
|
sub_domain = sub_domain.substr(1);
|
||||||
|
|
||||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
// Now check whether the domain argument is a subdomain of the filter domain.
|
||||||
base::Bind(&Cookies::GetCookiesOnIOThread, base::Unretained(this),
|
for (sub_domain.insert(0, "."); sub_domain.length() >= filter.length();) {
|
||||||
Passed(&filter), callback));
|
if (sub_domain == filter)
|
||||||
}
|
return true;
|
||||||
|
const size_t next_dot = sub_domain.find('.', 1); // Skip over leading dot.
|
||||||
void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
|
sub_domain.erase(0, next_dot);
|
||||||
const CookiesCallback& callback) {
|
|
||||||
std::string url;
|
|
||||||
filter->GetString("url", &url);
|
|
||||||
if (!GetCookieListFromStore(GetCookieStore(), url,
|
|
||||||
base::Bind(&Cookies::OnGetCookies, base::Unretained(this),
|
|
||||||
Passed(&filter), callback))) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
|
||||||
base::Bind(&RunGetCookiesCallbackOnUIThread, isolate(),
|
|
||||||
"URL is not valid", net::CookieList(), callback));
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cookies::OnGetCookies(scoped_ptr<base::DictionaryValue> filter,
|
// Returns whether |cookie| matches |filter|.
|
||||||
const CookiesCallback& callback,
|
bool MatchesCookie(const base::DictionaryValue* filter,
|
||||||
const net::CookieList& cookie_list) {
|
const net::CanonicalCookie& cookie) {
|
||||||
|
std::string str;
|
||||||
|
bool b;
|
||||||
|
if (filter->GetString("name", &str) && str != cookie.Name())
|
||||||
|
return false;
|
||||||
|
if (filter->GetString("path", &str) && str != cookie.Path())
|
||||||
|
return false;
|
||||||
|
if (filter->GetString("domain", &str) && !MatchesDomain(str, cookie.Domain()))
|
||||||
|
return false;
|
||||||
|
if (filter->GetBoolean("secure", &b) && b != cookie.IsSecure())
|
||||||
|
return false;
|
||||||
|
if (filter->GetBoolean("session", &b) && b != !cookie.IsPersistent())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to returns the CookieStore.
|
||||||
|
inline net::CookieStore* GetCookieStore(
|
||||||
|
scoped_refptr<net::URLRequestContextGetter> getter) {
|
||||||
|
return getter->GetURLRequestContext()->cookie_store();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run |callback| on UI thread.
|
||||||
|
void RunCallbackInUI(const base::Closure& callback) {
|
||||||
|
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove cookies from |list| not matching |filter|, and pass it to |callback|.
|
||||||
|
void FilterCookies(scoped_ptr<base::DictionaryValue> filter,
|
||||||
|
const Cookies::GetCallback& callback,
|
||||||
|
const net::CookieList& list) {
|
||||||
net::CookieList result;
|
net::CookieList result;
|
||||||
for (const auto& cookie : cookie_list) {
|
for (const auto& cookie : list) {
|
||||||
if (MatchesCookie(filter.get(), cookie))
|
if (MatchesCookie(filter.get(), cookie))
|
||||||
result.push_back(cookie);
|
result.push_back(cookie);
|
||||||
}
|
}
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
|
RunCallbackInUI(base::Bind(callback, Cookies::SUCCESS, result));
|
||||||
&RunGetCookiesCallbackOnUIThread, isolate(), "", result, callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cookies::Remove(const mate::Dictionary& details,
|
// Receives cookies matching |filter| in IO thread.
|
||||||
const CookiesCallback& callback) {
|
void GetCookiesOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||||
GURL url;
|
scoped_ptr<base::DictionaryValue> filter,
|
||||||
std::string name;
|
const Cookies::GetCallback& callback) {
|
||||||
std::string error_message;
|
|
||||||
if (!details.Get("url", &url) || !details.Get("name", &name)) {
|
|
||||||
error_message = "Details(url, name) of removing cookie are required.";
|
|
||||||
}
|
|
||||||
if (error_message.empty() && !url.is_valid()) {
|
|
||||||
error_message = "URL is not valid.";
|
|
||||||
}
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
RunRemoveCookiesCallbackOnUIThread(isolate(), error_message, callback);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&Cookies::RemoveCookiesOnIOThread, base::Unretained(this),
|
|
||||||
url, name, callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cookies::RemoveCookiesOnIOThread(const GURL& url, const std::string& name,
|
|
||||||
const CookiesCallback& callback) {
|
|
||||||
GetCookieStore()->DeleteCookieAsync(url, name,
|
|
||||||
base::Bind(&Cookies::OnRemoveCookies, base::Unretained(this), callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cookies::OnRemoveCookies(const CookiesCallback& callback) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
|
||||||
base::Bind(&RunRemoveCookiesCallbackOnUIThread, isolate(), "", callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cookies::Set(const base::DictionaryValue& options,
|
|
||||||
const CookiesCallback& callback) {
|
|
||||||
std::string url;
|
std::string url;
|
||||||
std::string error_message;
|
filter->GetString("url", &url);
|
||||||
if (!options.GetString("url", &url)) {
|
|
||||||
error_message = "The url field is required.";
|
|
||||||
}
|
|
||||||
|
|
||||||
GURL gurl(url);
|
auto filtered_callback =
|
||||||
if (error_message.empty() && !gurl.is_valid()) {
|
base::Bind(FilterCookies, base::Passed(&filter), callback);
|
||||||
error_message = "URL is not valid.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!error_message.empty()) {
|
net::CookieMonster* monster = GetCookieStore(getter)->GetCookieMonster();
|
||||||
RunSetCookiesCallbackOnUIThread(isolate(), error_message, false, callback);
|
// Empty url will match all url cookies.
|
||||||
return;
|
if (url.empty())
|
||||||
}
|
monster->GetAllCookiesAsync(filtered_callback);
|
||||||
|
else
|
||||||
scoped_ptr<base::DictionaryValue> details(
|
monster->GetAllCookiesForURLAsync(GURL(url), filtered_callback);
|
||||||
options.DeepCopyWithoutEmptyChildren());
|
|
||||||
|
|
||||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&Cookies::SetCookiesOnIOThread, base::Unretained(this),
|
|
||||||
Passed(&details), gurl, callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
// Removes cookie with |url| and |name| in IO thread.
|
||||||
const GURL& url,
|
void RemoveCookieOnIOThread(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||||
const CookiesCallback& callback) {
|
const GURL& url, const std::string& name,
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
const base::Closure& callback) {
|
||||||
|
GetCookieStore(getter)->DeleteCookieAsync(
|
||||||
|
url, name, base::Bind(RunCallbackInUI, callback));
|
||||||
|
}
|
||||||
|
|
||||||
std::string name, value, domain, path;
|
// Callback of SetCookie.
|
||||||
|
void OnSetCookie(const Cookies::SetCallback& callback, bool success) {
|
||||||
|
RunCallbackInUI(
|
||||||
|
base::Bind(callback, success ? Cookies::SUCCESS : Cookies::FAILED));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets cookie with |details| in IO thread.
|
||||||
|
void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||||
|
scoped_ptr<base::DictionaryValue> details,
|
||||||
|
const Cookies::SetCallback& callback) {
|
||||||
|
std::string url, name, value, domain, path;
|
||||||
bool secure = false;
|
bool secure = false;
|
||||||
bool http_only = false;
|
bool http_only = false;
|
||||||
double expiration_date;
|
double expiration_date;
|
||||||
|
details->GetString("url", &url);
|
||||||
details->GetString("name", &name);
|
details->GetString("name", &name);
|
||||||
details->GetString("value", &value);
|
details->GetString("value", &value);
|
||||||
details->GetString("domain", &domain);
|
details->GetString("domain", &domain);
|
||||||
details->GetString("path", &path);
|
details->GetString("path", &path);
|
||||||
details->GetBoolean("secure", &secure);
|
details->GetBoolean("secure", &secure);
|
||||||
details->GetBoolean("http_only", &http_only);
|
details->GetBoolean("httpOnly", &http_only);
|
||||||
|
|
||||||
base::Time expiration_time;
|
base::Time expiration_time;
|
||||||
if (details->GetDouble("expirationDate", &expiration_date)) {
|
if (details->GetDouble("expirationDate", &expiration_date)) {
|
||||||
|
@ -301,29 +178,44 @@ void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
||||||
base::Time::FromDoubleT(expiration_date);
|
base::Time::FromDoubleT(expiration_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetCookieStore()->GetCookieMonster()->SetCookieWithDetailsAsync(
|
GetCookieStore(getter)->GetCookieMonster()->SetCookieWithDetailsAsync(
|
||||||
url,
|
GURL(url), name, value, domain, path, expiration_time, secure, http_only,
|
||||||
name,
|
false, net::COOKIE_PRIORITY_DEFAULT, base::Bind(OnSetCookie, callback));
|
||||||
value,
|
|
||||||
domain,
|
|
||||||
path,
|
|
||||||
expiration_time,
|
|
||||||
secure,
|
|
||||||
http_only,
|
|
||||||
false,
|
|
||||||
net::COOKIE_PRIORITY_DEFAULT,
|
|
||||||
base::Bind(&Cookies::OnSetCookies, base::Unretained(this), callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cookies::OnSetCookies(const CookiesCallback& callback,
|
} // namespace
|
||||||
bool set_success) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
Cookies::Cookies(content::BrowserContext* browser_context)
|
||||||
base::Bind(&RunSetCookiesCallbackOnUIThread, isolate(), "", set_success,
|
: request_context_getter_(browser_context->GetRequestContext()) {
|
||||||
callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
net::CookieStore* Cookies::GetCookieStore() {
|
Cookies::~Cookies() {
|
||||||
return request_context_getter_->GetURLRequestContext()->cookie_store();
|
}
|
||||||
|
|
||||||
|
void Cookies::Get(const base::DictionaryValue& filter,
|
||||||
|
const GetCallback& callback) {
|
||||||
|
scoped_ptr<base::DictionaryValue> copied(filter.CreateDeepCopy());
|
||||||
|
auto getter = make_scoped_refptr(request_context_getter_);
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(GetCookiesOnIO, getter, Passed(&copied), callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cookies::Remove(const GURL& url, const std::string& name,
|
||||||
|
const base::Closure& callback) {
|
||||||
|
auto getter = make_scoped_refptr(request_context_getter_);
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(RemoveCookieOnIOThread, getter, url, name, callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cookies::Set(const base::DictionaryValue& details,
|
||||||
|
const SetCallback& callback) {
|
||||||
|
scoped_ptr<base::DictionaryValue> copied(details.CreateDeepCopy());
|
||||||
|
auto getter = make_scoped_refptr(request_context_getter_);
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(SetCookieOnIO, getter, Passed(&copied), callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
@ -20,12 +20,7 @@ namespace content {
|
||||||
class BrowserContext;
|
class BrowserContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace mate {
|
|
||||||
class Dictionary;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace net {
|
namespace net {
|
||||||
class CookieStore;
|
|
||||||
class URLRequestContextGetter;
|
class URLRequestContextGetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,9 +30,13 @@ namespace api {
|
||||||
|
|
||||||
class Cookies : public mate::TrackableObject<Cookies> {
|
class Cookies : public mate::TrackableObject<Cookies> {
|
||||||
public:
|
public:
|
||||||
// node.js style callback function(error, result)
|
enum Error {
|
||||||
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
|
SUCCESS,
|
||||||
CookiesCallback;
|
FAILED,
|
||||||
|
};
|
||||||
|
|
||||||
|
using GetCallback = base::Callback<void(Error, const net::CookieList&)>;
|
||||||
|
using SetCallback = base::Callback<void(Error)>;
|
||||||
|
|
||||||
static mate::Handle<Cookies> Create(v8::Isolate* isolate,
|
static mate::Handle<Cookies> Create(v8::Isolate* isolate,
|
||||||
content::BrowserContext* browser_context);
|
content::BrowserContext* browser_context);
|
||||||
|
@ -50,34 +49,12 @@ class Cookies : public mate::TrackableObject<Cookies> {
|
||||||
explicit Cookies(content::BrowserContext* browser_context);
|
explicit Cookies(content::BrowserContext* browser_context);
|
||||||
~Cookies();
|
~Cookies();
|
||||||
|
|
||||||
void Get(const base::DictionaryValue& options,
|
void Get(const base::DictionaryValue& filter, const GetCallback& callback);
|
||||||
const CookiesCallback& callback);
|
void Remove(const GURL& url, const std::string& name,
|
||||||
void Remove(const mate::Dictionary& details,
|
const base::Closure& callback);
|
||||||
const CookiesCallback& callback);
|
void Set(const base::DictionaryValue& details, const SetCallback& callback);
|
||||||
void Set(const base::DictionaryValue& details,
|
|
||||||
const CookiesCallback& callback);
|
|
||||||
|
|
||||||
void GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
|
|
||||||
const CookiesCallback& callback);
|
|
||||||
void OnGetCookies(scoped_ptr<base::DictionaryValue> filter,
|
|
||||||
const CookiesCallback& callback,
|
|
||||||
const net::CookieList& cookie_list);
|
|
||||||
|
|
||||||
void RemoveCookiesOnIOThread(const GURL& url,
|
|
||||||
const std::string& name,
|
|
||||||
const CookiesCallback& callback);
|
|
||||||
void OnRemoveCookies(const CookiesCallback& callback);
|
|
||||||
|
|
||||||
void SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
|
||||||
const GURL& url,
|
|
||||||
const CookiesCallback& callback);
|
|
||||||
void OnSetCookies(const CookiesCallback& callback,
|
|
||||||
bool set_success);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Must be called on IO thread.
|
|
||||||
net::CookieStore* GetCookieStore();
|
|
||||||
|
|
||||||
net::URLRequestContextGetter* request_context_getter_;
|
net::URLRequestContextGetter* request_context_getter_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Cookies);
|
DISALLOW_COPY_AND_ASSIGN(Cookies);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "atom/browser/api/atom_api_cookies.h"
|
#include "atom/browser/api/atom_api_cookies.h"
|
||||||
#include "atom/browser/api/atom_api_download_item.h"
|
#include "atom/browser/api/atom_api_download_item.h"
|
||||||
#include "atom/browser/api/atom_api_web_contents.h"
|
#include "atom/browser/api/atom_api_web_contents.h"
|
||||||
|
#include "atom/browser/api/atom_api_web_request.h"
|
||||||
#include "atom/browser/api/save_page_handler.h"
|
#include "atom/browser/api/save_page_handler.h"
|
||||||
#include "atom/browser/atom_browser_context.h"
|
#include "atom/browser/atom_browser_context.h"
|
||||||
#include "atom/browser/atom_browser_main_parts.h"
|
#include "atom/browser/atom_browser_main_parts.h"
|
||||||
|
@ -368,6 +369,14 @@ v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
|
||||||
return v8::Local<v8::Value>::New(isolate, cookies_);
|
return v8::Local<v8::Value>::New(isolate, cookies_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
|
||||||
|
if (web_request_.IsEmpty()) {
|
||||||
|
auto handle = atom::api::WebRequest::Create(isolate, browser_context());
|
||||||
|
web_request_.Reset(isolate, handle.ToV8());
|
||||||
|
}
|
||||||
|
return v8::Local<v8::Value>::New(isolate, web_request_);
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
mate::Handle<Session> Session::CreateFrom(
|
mate::Handle<Session> Session::CreateFrom(
|
||||||
v8::Isolate* isolate, AtomBrowserContext* browser_context) {
|
v8::Isolate* isolate, AtomBrowserContext* browser_context) {
|
||||||
|
@ -401,7 +410,8 @@ void Session::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
|
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
|
||||||
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
|
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
|
||||||
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
|
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
|
||||||
.SetProperty("cookies", &Session::Cookies);
|
.SetProperty("cookies", &Session::Cookies)
|
||||||
|
.SetProperty("webRequest", &Session::WebRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearWrapSession() {
|
void ClearWrapSession() {
|
||||||
|
|
|
@ -70,9 +70,11 @@ class Session: public mate::TrackableObject<Session>,
|
||||||
void DisableNetworkEmulation();
|
void DisableNetworkEmulation();
|
||||||
void SetCertVerifyProc(v8::Local<v8::Value> proc, mate::Arguments* args);
|
void SetCertVerifyProc(v8::Local<v8::Value> proc, mate::Arguments* args);
|
||||||
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
||||||
|
v8::Local<v8::Value> WebRequest(v8::Isolate* isolate);
|
||||||
|
|
||||||
// Cached object for cookies API.
|
// Cached object.
|
||||||
v8::Global<v8::Value> cookies_;
|
v8::Global<v8::Value> cookies_;
|
||||||
|
v8::Global<v8::Value> web_request_;
|
||||||
|
|
||||||
scoped_refptr<AtomBrowserContext> browser_context_;
|
scoped_refptr<AtomBrowserContext> browser_context_;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "atom/browser/api/atom_api_web_contents.h"
|
#include "atom/browser/api/atom_api_web_contents.h"
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "atom/browser/api/atom_api_session.h"
|
#include "atom/browser/api/atom_api_session.h"
|
||||||
#include "atom/browser/api/atom_api_window.h"
|
#include "atom/browser/api/atom_api_window.h"
|
||||||
|
|
119
atom/browser/api/atom_api_web_request.cc
Normal file
119
atom/browser/api/atom_api_web_request.cc
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
// Copyright (c) 2015 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "atom/browser/api/atom_api_web_request.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "atom/browser/atom_browser_context.h"
|
||||||
|
#include "atom/browser/net/atom_network_delegate.h"
|
||||||
|
#include "atom/common/native_mate_converters/callback.h"
|
||||||
|
#include "atom/common/native_mate_converters/net_converter.h"
|
||||||
|
#include "atom/common/native_mate_converters/value_converter.h"
|
||||||
|
#include "content/public/browser/browser_thread.h"
|
||||||
|
#include "native_mate/dictionary.h"
|
||||||
|
#include "native_mate/object_template_builder.h"
|
||||||
|
|
||||||
|
using content::BrowserThread;
|
||||||
|
|
||||||
|
namespace mate {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Converter<extensions::URLPattern> {
|
||||||
|
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||||
|
extensions::URLPattern* out) {
|
||||||
|
std::string pattern;
|
||||||
|
if (!ConvertFromV8(isolate, val, &pattern))
|
||||||
|
return false;
|
||||||
|
return out->Parse(pattern) == extensions::URLPattern::PARSE_SUCCESS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mate
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
WebRequest::WebRequest(AtomBrowserContext* browser_context)
|
||||||
|
: browser_context_(browser_context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
WebRequest::~WebRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<AtomNetworkDelegate::SimpleEvent type>
|
||||||
|
void WebRequest::SetSimpleListener(mate::Arguments* args) {
|
||||||
|
SetListener<AtomNetworkDelegate::SimpleListener>(
|
||||||
|
&AtomNetworkDelegate::SetSimpleListenerInIO, type, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<AtomNetworkDelegate::ResponseEvent type>
|
||||||
|
void WebRequest::SetResponseListener(mate::Arguments* args) {
|
||||||
|
SetListener<AtomNetworkDelegate::ResponseListener>(
|
||||||
|
&AtomNetworkDelegate::SetResponseListenerInIO, type, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Listener, typename Method, typename Event>
|
||||||
|
void WebRequest::SetListener(Method method, Event type, mate::Arguments* args) {
|
||||||
|
// { urls }.
|
||||||
|
URLPatterns patterns;
|
||||||
|
mate::Dictionary dict;
|
||||||
|
args->GetNext(&dict) && dict.Get("urls", &patterns);
|
||||||
|
|
||||||
|
// Function or null.
|
||||||
|
v8::Local<v8::Value> value;
|
||||||
|
Listener listener;
|
||||||
|
if (!args->GetNext(&listener) &&
|
||||||
|
!(args->GetNext(&value) && value->IsNull())) {
|
||||||
|
args->ThrowError("Must pass null or a Function");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto delegate = browser_context_->network_delegate();
|
||||||
|
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(method, base::Unretained(delegate), type,
|
||||||
|
patterns, listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
mate::Handle<WebRequest> WebRequest::Create(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
AtomBrowserContext* browser_context) {
|
||||||
|
return mate::CreateHandle(isolate, new WebRequest(browser_context));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void WebRequest::BuildPrototype(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::ObjectTemplate> prototype) {
|
||||||
|
mate::ObjectTemplateBuilder(isolate, prototype)
|
||||||
|
.SetMethod("onBeforeRequest",
|
||||||
|
&WebRequest::SetResponseListener<
|
||||||
|
AtomNetworkDelegate::kOnBeforeRequest>)
|
||||||
|
.SetMethod("onBeforeSendHeaders",
|
||||||
|
&WebRequest::SetResponseListener<
|
||||||
|
AtomNetworkDelegate::kOnBeforeSendHeaders>)
|
||||||
|
.SetMethod("onHeadersReceived",
|
||||||
|
&WebRequest::SetResponseListener<
|
||||||
|
AtomNetworkDelegate::kOnHeadersReceived>)
|
||||||
|
.SetMethod("onSendHeaders",
|
||||||
|
&WebRequest::SetSimpleListener<
|
||||||
|
AtomNetworkDelegate::kOnSendHeaders>)
|
||||||
|
.SetMethod("onBeforeRedirect",
|
||||||
|
&WebRequest::SetSimpleListener<
|
||||||
|
AtomNetworkDelegate::kOnBeforeRedirect>)
|
||||||
|
.SetMethod("onResponseStarted",
|
||||||
|
&WebRequest::SetSimpleListener<
|
||||||
|
AtomNetworkDelegate::kOnResponseStarted>)
|
||||||
|
.SetMethod("onCompleted",
|
||||||
|
&WebRequest::SetSimpleListener<
|
||||||
|
AtomNetworkDelegate::kOnCompleted>)
|
||||||
|
.SetMethod("onErrorOccurred",
|
||||||
|
&WebRequest::SetSimpleListener<
|
||||||
|
AtomNetworkDelegate::kOnErrorOccurred>);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
50
atom/browser/api/atom_api_web_request.h
Normal file
50
atom/browser/api/atom_api_web_request.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright (c) 2015 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef ATOM_BROWSER_API_ATOM_API_WEB_REQUEST_H_
|
||||||
|
#define ATOM_BROWSER_API_ATOM_API_WEB_REQUEST_H_
|
||||||
|
|
||||||
|
#include "atom/browser/api/trackable_object.h"
|
||||||
|
#include "atom/browser/net/atom_network_delegate.h"
|
||||||
|
#include "native_mate/arguments.h"
|
||||||
|
#include "native_mate/handle.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
class AtomBrowserContext;
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
class WebRequest : public mate::TrackableObject<WebRequest> {
|
||||||
|
public:
|
||||||
|
static mate::Handle<WebRequest> Create(v8::Isolate* isolate,
|
||||||
|
AtomBrowserContext* browser_context);
|
||||||
|
|
||||||
|
// mate::TrackableObject:
|
||||||
|
static void BuildPrototype(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::ObjectTemplate> prototype);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit WebRequest(AtomBrowserContext* browser_context);
|
||||||
|
~WebRequest();
|
||||||
|
|
||||||
|
// C++ can not distinguish overloaded member function.
|
||||||
|
template<AtomNetworkDelegate::SimpleEvent type>
|
||||||
|
void SetSimpleListener(mate::Arguments* args);
|
||||||
|
template<AtomNetworkDelegate::ResponseEvent type>
|
||||||
|
void SetResponseListener(mate::Arguments* args);
|
||||||
|
template<typename Listener, typename Method, typename Event>
|
||||||
|
void SetListener(Method method, Event type, mate::Arguments* args);
|
||||||
|
|
||||||
|
private:
|
||||||
|
scoped_refptr<AtomBrowserContext> browser_context_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(WebRequest);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_API_ATOM_API_WEB_REQUEST_H_
|
|
@ -6,6 +6,7 @@ PERSIST_PERFIX = 'persist:'
|
||||||
|
|
||||||
# Returns the Session from |partition| string.
|
# Returns the Session from |partition| string.
|
||||||
exports.fromPartition = (partition='') ->
|
exports.fromPartition = (partition='') ->
|
||||||
|
return exports.defaultSession if partition is ''
|
||||||
if partition.startsWith PERSIST_PERFIX
|
if partition.startsWith PERSIST_PERFIX
|
||||||
bindings.fromPartition partition.substr(PERSIST_PERFIX.length), false
|
bindings.fromPartition partition.substr(PERSIST_PERFIX.length), false
|
||||||
else
|
else
|
||||||
|
@ -14,7 +15,7 @@ exports.fromPartition = (partition='') ->
|
||||||
# Returns the default session.
|
# Returns the default session.
|
||||||
Object.defineProperty exports, 'defaultSession',
|
Object.defineProperty exports, 'defaultSession',
|
||||||
enumerable: true
|
enumerable: true
|
||||||
get: -> exports.fromPartition ''
|
get: -> bindings.fromPartition '', false
|
||||||
|
|
||||||
wrapSession = (session) ->
|
wrapSession = (session) ->
|
||||||
# session is an EventEmitter.
|
# session is an EventEmitter.
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "atom/browser/atom_download_manager_delegate.h"
|
#include "atom/browser/atom_download_manager_delegate.h"
|
||||||
#include "atom/browser/browser.h"
|
#include "atom/browser/browser.h"
|
||||||
#include "atom/browser/net/atom_cert_verifier.h"
|
#include "atom/browser/net/atom_cert_verifier.h"
|
||||||
|
#include "atom/browser/net/atom_network_delegate.h"
|
||||||
#include "atom/browser/net/atom_ssl_config_service.h"
|
#include "atom/browser/net/atom_ssl_config_service.h"
|
||||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||||
#include "atom/browser/net/asar/asar_protocol_handler.h"
|
#include "atom/browser/net/asar/asar_protocol_handler.h"
|
||||||
|
@ -63,12 +64,17 @@ AtomBrowserContext::AtomBrowserContext(const std::string& partition,
|
||||||
: brightray::BrowserContext(partition, in_memory),
|
: brightray::BrowserContext(partition, in_memory),
|
||||||
cert_verifier_(nullptr),
|
cert_verifier_(nullptr),
|
||||||
job_factory_(new AtomURLRequestJobFactory),
|
job_factory_(new AtomURLRequestJobFactory),
|
||||||
|
network_delegate_(new AtomNetworkDelegate),
|
||||||
allow_ntlm_everywhere_(false) {
|
allow_ntlm_everywhere_(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomBrowserContext::~AtomBrowserContext() {
|
AtomBrowserContext::~AtomBrowserContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
net::NetworkDelegate* AtomBrowserContext::CreateNetworkDelegate() {
|
||||||
|
return network_delegate_;
|
||||||
|
}
|
||||||
|
|
||||||
std::string AtomBrowserContext::GetUserAgent() {
|
std::string AtomBrowserContext::GetUserAgent() {
|
||||||
Browser* browser = Browser::Get();
|
Browser* browser = Browser::Get();
|
||||||
std::string name = RemoveWhitespace(browser->GetName());
|
std::string name = RemoveWhitespace(browser->GetName());
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace atom {
|
||||||
|
|
||||||
class AtomDownloadManagerDelegate;
|
class AtomDownloadManagerDelegate;
|
||||||
class AtomCertVerifier;
|
class AtomCertVerifier;
|
||||||
|
class AtomNetworkDelegate;
|
||||||
class AtomURLRequestJobFactory;
|
class AtomURLRequestJobFactory;
|
||||||
class WebViewManager;
|
class WebViewManager;
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||||
~AtomBrowserContext() override;
|
~AtomBrowserContext() override;
|
||||||
|
|
||||||
// brightray::URLRequestContextGetter::Delegate:
|
// brightray::URLRequestContextGetter::Delegate:
|
||||||
|
net::NetworkDelegate* CreateNetworkDelegate() override;
|
||||||
std::string GetUserAgent() override;
|
std::string GetUserAgent() override;
|
||||||
scoped_ptr<net::URLRequestJobFactory> CreateURLRequestJobFactory(
|
scoped_ptr<net::URLRequestJobFactory> CreateURLRequestJobFactory(
|
||||||
content::ProtocolHandlerMap* handlers,
|
content::ProtocolHandlerMap* handlers,
|
||||||
|
@ -45,6 +47,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||||
|
|
||||||
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
|
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
|
||||||
|
|
||||||
|
AtomNetworkDelegate* network_delegate() const { return network_delegate_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
scoped_ptr<AtomDownloadManagerDelegate> download_manager_delegate_;
|
scoped_ptr<AtomDownloadManagerDelegate> download_manager_delegate_;
|
||||||
scoped_ptr<WebViewManager> guest_manager_;
|
scoped_ptr<WebViewManager> guest_manager_;
|
||||||
|
@ -52,6 +56,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||||
// Managed by brightray::BrowserContext.
|
// Managed by brightray::BrowserContext.
|
||||||
AtomCertVerifier* cert_verifier_;
|
AtomCertVerifier* cert_verifier_;
|
||||||
AtomURLRequestJobFactory* job_factory_;
|
AtomURLRequestJobFactory* job_factory_;
|
||||||
|
AtomNetworkDelegate* network_delegate_;
|
||||||
|
|
||||||
bool allow_ntlm_everywhere_;
|
bool allow_ntlm_everywhere_;
|
||||||
|
|
||||||
|
|
|
@ -73,15 +73,15 @@ ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', (event, guestId) ->
|
||||||
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', (event, guestId, method, args...) ->
|
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', (event, guestId, method, args...) ->
|
||||||
BrowserWindow.fromId(guestId)?[method] args...
|
BrowserWindow.fromId(guestId)?[method] args...
|
||||||
|
|
||||||
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestId, message, targetOrigin) ->
|
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestId, message, targetOrigin, sourceOrigin) ->
|
||||||
guestContents = BrowserWindow.fromId(guestId)?.webContents
|
guestContents = BrowserWindow.fromId(guestId)?.webContents
|
||||||
if guestContents?.getURL().indexOf(targetOrigin) is 0 or targetOrigin is '*'
|
if guestContents?.getURL().indexOf(targetOrigin) is 0 or targetOrigin is '*'
|
||||||
guestContents.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', guestId, message, targetOrigin
|
guestContents?.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', guestId, message, sourceOrigin
|
||||||
|
|
||||||
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, guestId, message, targetOrigin, sourceOrigin) ->
|
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, guestId, message, targetOrigin, sourceOrigin) ->
|
||||||
embedder = v8Util.getHiddenValue event.sender, 'embedder'
|
embedder = v8Util.getHiddenValue event.sender, 'embedder'
|
||||||
if embedder?.getURL().indexOf(targetOrigin) is 0 or targetOrigin is '*'
|
if embedder?.getURL().indexOf(targetOrigin) is 0 or targetOrigin is '*'
|
||||||
embedder.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', guestId, message, sourceOrigin
|
embedder?.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', guestId, message, sourceOrigin
|
||||||
|
|
||||||
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestId, method, args...) ->
|
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestId, method, args...) ->
|
||||||
BrowserWindow.fromId(guestId)?.webContents?[method] args...
|
BrowserWindow.fromId(guestId)?.webContents?[method] args...
|
||||||
|
|
380
atom/browser/net/atom_network_delegate.cc
Normal file
380
atom/browser/net/atom_network_delegate.cc
Normal file
|
@ -0,0 +1,380 @@
|
||||||
|
// Copyright (c) 2015 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "atom/browser/net/atom_network_delegate.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "atom/common/native_mate_converters/net_converter.h"
|
||||||
|
#include "base/stl_util.h"
|
||||||
|
#include "base/strings/string_util.h"
|
||||||
|
#include "content/public/browser/browser_thread.h"
|
||||||
|
#include "content/public/browser/resource_request_info.h"
|
||||||
|
#include "net/url_request/url_request.h"
|
||||||
|
|
||||||
|
using content::BrowserThread;
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char* ResourceTypeToString(content::ResourceType type) {
|
||||||
|
switch (type) {
|
||||||
|
case content::RESOURCE_TYPE_MAIN_FRAME:
|
||||||
|
return "mainFrame";
|
||||||
|
case content::RESOURCE_TYPE_SUB_FRAME:
|
||||||
|
return "subFrame";
|
||||||
|
case content::RESOURCE_TYPE_STYLESHEET:
|
||||||
|
return "stylesheet";
|
||||||
|
case content::RESOURCE_TYPE_SCRIPT:
|
||||||
|
return "script";
|
||||||
|
case content::RESOURCE_TYPE_IMAGE:
|
||||||
|
return "image";
|
||||||
|
case content::RESOURCE_TYPE_OBJECT:
|
||||||
|
return "object";
|
||||||
|
case content::RESOURCE_TYPE_XHR:
|
||||||
|
return "xhr";
|
||||||
|
default:
|
||||||
|
return "other";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunSimpleListener(const AtomNetworkDelegate::SimpleListener& listener,
|
||||||
|
scoped_ptr<base::DictionaryValue> details) {
|
||||||
|
return listener.Run(*(details.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunResponseListener(
|
||||||
|
const AtomNetworkDelegate::ResponseListener& listener,
|
||||||
|
scoped_ptr<base::DictionaryValue> details,
|
||||||
|
const AtomNetworkDelegate::ResponseCallback& callback) {
|
||||||
|
return listener.Run(*(details.get()), callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test whether the URL of |request| matches |patterns|.
|
||||||
|
bool MatchesFilterCondition(net::URLRequest* request,
|
||||||
|
const URLPatterns& patterns) {
|
||||||
|
if (patterns.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (const auto& pattern : patterns) {
|
||||||
|
if (pattern.MatchesURL(request->url()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overloaded by multiple types to fill the |details| object.
|
||||||
|
void ToDictionary(base::DictionaryValue* details, net::URLRequest* request) {
|
||||||
|
details->SetInteger("id", request->identifier());
|
||||||
|
details->SetString("url", request->url().spec());
|
||||||
|
details->SetString("method", request->method());
|
||||||
|
details->SetDouble("timestamp", base::Time::Now().ToDoubleT() * 1000);
|
||||||
|
auto info = content::ResourceRequestInfo::ForRequest(request);
|
||||||
|
details->SetString("resourceType",
|
||||||
|
info ? ResourceTypeToString(info->GetResourceType())
|
||||||
|
: "other");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToDictionary(base::DictionaryValue* details,
|
||||||
|
const net::HttpRequestHeaders& headers) {
|
||||||
|
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
|
||||||
|
net::HttpRequestHeaders::Iterator it(headers);
|
||||||
|
while (it.GetNext())
|
||||||
|
dict->SetString(it.name(), it.value());
|
||||||
|
details->Set("requestHeaders", dict.Pass());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToDictionary(base::DictionaryValue* details,
|
||||||
|
const net::HttpResponseHeaders* headers) {
|
||||||
|
if (!headers)
|
||||||
|
return;
|
||||||
|
|
||||||
|
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
|
||||||
|
void* iter = nullptr;
|
||||||
|
std::string key;
|
||||||
|
std::string value;
|
||||||
|
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
|
||||||
|
if (dict->HasKey(key)) {
|
||||||
|
base::ListValue* values = nullptr;
|
||||||
|
if (dict->GetList(key, &values))
|
||||||
|
values->AppendString(value);
|
||||||
|
} else {
|
||||||
|
scoped_ptr<base::ListValue> values(new base::ListValue);
|
||||||
|
values->AppendString(value);
|
||||||
|
dict->Set(key, values.Pass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
details->Set("responseHeaders", dict.Pass());
|
||||||
|
details->SetString("statusLine", headers->GetStatusLine());
|
||||||
|
details->SetInteger("statusCode", headers->response_code());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToDictionary(base::DictionaryValue* details, const GURL& location) {
|
||||||
|
details->SetString("redirectURL", location.spec());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToDictionary(base::DictionaryValue* details,
|
||||||
|
const net::HostPortPair& host_port) {
|
||||||
|
if (host_port.host().empty())
|
||||||
|
details->SetString("ip", host_port.host());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToDictionary(base::DictionaryValue* details, bool from_cache) {
|
||||||
|
details->SetBoolean("fromCache", from_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToDictionary(base::DictionaryValue* details,
|
||||||
|
const net::URLRequestStatus& status) {
|
||||||
|
details->SetString("error", net::ErrorToString(status.error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to fill |details| with arbitrary |args|.
|
||||||
|
template<typename Arg>
|
||||||
|
void FillDetailsObject(base::DictionaryValue* details, Arg arg) {
|
||||||
|
ToDictionary(details, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Arg, typename... Args>
|
||||||
|
void FillDetailsObject(base::DictionaryValue* details, Arg arg, Args... args) {
|
||||||
|
ToDictionary(details, arg);
|
||||||
|
FillDetailsObject(details, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the native types with the result from the response object.
|
||||||
|
void ReadFromResponseObject(const base::DictionaryValue& response,
|
||||||
|
GURL* new_location) {
|
||||||
|
std::string url;
|
||||||
|
if (response.GetString("redirectURL", &url))
|
||||||
|
*new_location = GURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadFromResponseObject(const base::DictionaryValue& response,
|
||||||
|
net::HttpRequestHeaders* headers) {
|
||||||
|
const base::DictionaryValue* dict;
|
||||||
|
if (response.GetDictionary("requestHeaders", &dict)) {
|
||||||
|
for (base::DictionaryValue::Iterator it(*dict);
|
||||||
|
!it.IsAtEnd();
|
||||||
|
it.Advance()) {
|
||||||
|
std::string value;
|
||||||
|
if (it.value().GetAsString(&value))
|
||||||
|
headers->SetHeader(it.key(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadFromResponseObject(const base::DictionaryValue& response,
|
||||||
|
scoped_refptr<net::HttpResponseHeaders>* headers) {
|
||||||
|
const base::DictionaryValue* dict;
|
||||||
|
if (response.GetDictionary("responseHeaders", &dict)) {
|
||||||
|
*headers = new net::HttpResponseHeaders("");
|
||||||
|
for (base::DictionaryValue::Iterator it(*dict);
|
||||||
|
!it.IsAtEnd();
|
||||||
|
it.Advance()) {
|
||||||
|
const base::ListValue* list;
|
||||||
|
if (it.value().GetAsList(&list)) {
|
||||||
|
(*headers)->RemoveHeader(it.key());
|
||||||
|
for (size_t i = 0; i < list->GetSize(); ++i) {
|
||||||
|
std::string value;
|
||||||
|
if (list->GetString(i, &value))
|
||||||
|
(*headers)->AddHeader(it.key() + " : " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with the results of Listener.
|
||||||
|
template<typename T>
|
||||||
|
void OnListenerResultInIO(const net::CompletionCallback& callback,
|
||||||
|
T out,
|
||||||
|
scoped_ptr<base::DictionaryValue> response) {
|
||||||
|
ReadFromResponseObject(*response.get(), out);
|
||||||
|
|
||||||
|
bool cancel = false;
|
||||||
|
response->GetBoolean("cancel", &cancel);
|
||||||
|
callback.Run(cancel ? net::ERR_BLOCKED_BY_CLIENT : net::OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void OnListenerResultInUI(const net::CompletionCallback& callback,
|
||||||
|
T out,
|
||||||
|
const base::DictionaryValue& response) {
|
||||||
|
scoped_ptr<base::DictionaryValue> copy = response.CreateDeepCopy();
|
||||||
|
BrowserThread::PostTask(
|
||||||
|
BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(OnListenerResultInIO<T>, callback, out, base::Passed(©)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
AtomNetworkDelegate::AtomNetworkDelegate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomNetworkDelegate::~AtomNetworkDelegate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomNetworkDelegate::SetSimpleListenerInIO(
|
||||||
|
SimpleEvent type,
|
||||||
|
const URLPatterns& patterns,
|
||||||
|
const SimpleListener& callback) {
|
||||||
|
if (callback.is_null())
|
||||||
|
simple_listeners_.erase(type);
|
||||||
|
else
|
||||||
|
simple_listeners_[type] = { patterns, callback };
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomNetworkDelegate::SetResponseListenerInIO(
|
||||||
|
ResponseEvent type,
|
||||||
|
const URLPatterns& patterns,
|
||||||
|
const ResponseListener& callback) {
|
||||||
|
if (callback.is_null())
|
||||||
|
response_listeners_.erase(type);
|
||||||
|
else
|
||||||
|
response_listeners_[type] = { patterns, callback };
|
||||||
|
}
|
||||||
|
|
||||||
|
int AtomNetworkDelegate::OnBeforeURLRequest(
|
||||||
|
net::URLRequest* request,
|
||||||
|
const net::CompletionCallback& callback,
|
||||||
|
GURL* new_url) {
|
||||||
|
if (!ContainsKey(response_listeners_, kOnBeforeRequest))
|
||||||
|
return brightray::NetworkDelegate::OnBeforeURLRequest(
|
||||||
|
request, callback, new_url);
|
||||||
|
|
||||||
|
return HandleResponseEvent(kOnBeforeRequest, request, callback, new_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AtomNetworkDelegate::OnBeforeSendHeaders(
|
||||||
|
net::URLRequest* request,
|
||||||
|
const net::CompletionCallback& callback,
|
||||||
|
net::HttpRequestHeaders* headers) {
|
||||||
|
if (!ContainsKey(response_listeners_, kOnBeforeSendHeaders))
|
||||||
|
return brightray::NetworkDelegate::OnBeforeSendHeaders(
|
||||||
|
request, callback, headers);
|
||||||
|
|
||||||
|
return HandleResponseEvent(
|
||||||
|
kOnBeforeSendHeaders, request, callback, headers, *headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomNetworkDelegate::OnSendHeaders(
|
||||||
|
net::URLRequest* request,
|
||||||
|
const net::HttpRequestHeaders& headers) {
|
||||||
|
if (!ContainsKey(simple_listeners_, kOnSendHeaders)) {
|
||||||
|
brightray::NetworkDelegate::OnSendHeaders(request, headers);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleSimpleEvent(kOnSendHeaders, request, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AtomNetworkDelegate::OnHeadersReceived(
|
||||||
|
net::URLRequest* request,
|
||||||
|
const net::CompletionCallback& callback,
|
||||||
|
const net::HttpResponseHeaders* original,
|
||||||
|
scoped_refptr<net::HttpResponseHeaders>* override,
|
||||||
|
GURL* allowed) {
|
||||||
|
if (!ContainsKey(response_listeners_, kOnHeadersReceived))
|
||||||
|
return brightray::NetworkDelegate::OnHeadersReceived(
|
||||||
|
request, callback, original, override, allowed);
|
||||||
|
|
||||||
|
return HandleResponseEvent(
|
||||||
|
kOnHeadersReceived, request, callback, override, original);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
|
||||||
|
const GURL& new_location) {
|
||||||
|
if (!ContainsKey(simple_listeners_, kOnBeforeRedirect)) {
|
||||||
|
brightray::NetworkDelegate::OnBeforeRedirect(request, new_location);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleSimpleEvent(kOnBeforeRedirect, request, new_location,
|
||||||
|
request->response_headers(), request->GetSocketAddress(),
|
||||||
|
request->was_cached());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomNetworkDelegate::OnResponseStarted(net::URLRequest* request) {
|
||||||
|
if (!ContainsKey(simple_listeners_, kOnResponseStarted)) {
|
||||||
|
brightray::NetworkDelegate::OnResponseStarted(request);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->status().status() != net::URLRequestStatus::SUCCESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HandleSimpleEvent(kOnResponseStarted, request, request->response_headers(),
|
||||||
|
request->was_cached());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomNetworkDelegate::OnCompleted(net::URLRequest* request, bool started) {
|
||||||
|
if (request->status().status() == net::URLRequestStatus::FAILED ||
|
||||||
|
request->status().status() == net::URLRequestStatus::CANCELED) {
|
||||||
|
// Error event.
|
||||||
|
if (ContainsKey(simple_listeners_, kOnErrorOccurred))
|
||||||
|
OnErrorOccurred(request);
|
||||||
|
else
|
||||||
|
brightray::NetworkDelegate::OnCompleted(request, started);
|
||||||
|
return;
|
||||||
|
} else if (request->response_headers() &&
|
||||||
|
net::HttpResponseHeaders::IsRedirectResponseCode(
|
||||||
|
request->response_headers()->response_code())) {
|
||||||
|
// Redirect event.
|
||||||
|
brightray::NetworkDelegate::OnCompleted(request, started);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ContainsKey(simple_listeners_, kOnCompleted)) {
|
||||||
|
brightray::NetworkDelegate::OnCompleted(request, started);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleSimpleEvent(kOnCompleted, request, request->response_headers(),
|
||||||
|
request->was_cached());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomNetworkDelegate::OnErrorOccurred(net::URLRequest* request) {
|
||||||
|
HandleSimpleEvent(kOnErrorOccurred, request, request->was_cached(),
|
||||||
|
request->status());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Out, typename... Args>
|
||||||
|
int AtomNetworkDelegate::HandleResponseEvent(
|
||||||
|
ResponseEvent type,
|
||||||
|
net::URLRequest* request,
|
||||||
|
const net::CompletionCallback& callback,
|
||||||
|
Out out,
|
||||||
|
Args... args) {
|
||||||
|
const auto& info = response_listeners_[type];
|
||||||
|
if (!MatchesFilterCondition(request, info.url_patterns))
|
||||||
|
return net::OK;
|
||||||
|
|
||||||
|
scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue);
|
||||||
|
FillDetailsObject(details.get(), request, args...);
|
||||||
|
|
||||||
|
ResponseCallback response =
|
||||||
|
base::Bind(OnListenerResultInUI<Out>, callback, out);
|
||||||
|
BrowserThread::PostTask(
|
||||||
|
BrowserThread::UI, FROM_HERE,
|
||||||
|
base::Bind(RunResponseListener, info.listener, base::Passed(&details),
|
||||||
|
response));
|
||||||
|
return net::ERR_IO_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...Args>
|
||||||
|
void AtomNetworkDelegate::HandleSimpleEvent(
|
||||||
|
SimpleEvent type, net::URLRequest* request, Args... args) {
|
||||||
|
const auto& info = simple_listeners_[type];
|
||||||
|
if (!MatchesFilterCondition(request, info.url_patterns))
|
||||||
|
return;
|
||||||
|
|
||||||
|
scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue);
|
||||||
|
FillDetailsObject(details.get(), request, args...);
|
||||||
|
|
||||||
|
BrowserThread::PostTask(
|
||||||
|
BrowserThread::UI, FROM_HERE,
|
||||||
|
base::Bind(RunSimpleListener, info.listener, base::Passed(&details)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace atom
|
111
atom/browser/net/atom_network_delegate.h
Normal file
111
atom/browser/net/atom_network_delegate.h
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
// Copyright (c) 2015 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef ATOM_BROWSER_NET_ATOM_NETWORK_DELEGATE_H_
|
||||||
|
#define ATOM_BROWSER_NET_ATOM_NETWORK_DELEGATE_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "brightray/browser/network_delegate.h"
|
||||||
|
#include "base/callback.h"
|
||||||
|
#include "base/values.h"
|
||||||
|
#include "extensions/common/url_pattern.h"
|
||||||
|
#include "net/base/net_errors.h"
|
||||||
|
#include "net/http/http_request_headers.h"
|
||||||
|
#include "net/http/http_response_headers.h"
|
||||||
|
|
||||||
|
namespace extensions {
|
||||||
|
class URLPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
using URLPatterns = std::set<extensions::URLPattern>;
|
||||||
|
|
||||||
|
class AtomNetworkDelegate : public brightray::NetworkDelegate {
|
||||||
|
public:
|
||||||
|
using ResponseCallback = base::Callback<void(const base::DictionaryValue&)>;
|
||||||
|
using SimpleListener = base::Callback<void(const base::DictionaryValue&)>;
|
||||||
|
using ResponseListener = base::Callback<void(const base::DictionaryValue&,
|
||||||
|
const ResponseCallback&)>;
|
||||||
|
|
||||||
|
enum SimpleEvent {
|
||||||
|
kOnSendHeaders,
|
||||||
|
kOnBeforeRedirect,
|
||||||
|
kOnResponseStarted,
|
||||||
|
kOnCompleted,
|
||||||
|
kOnErrorOccurred,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ResponseEvent {
|
||||||
|
kOnBeforeRequest,
|
||||||
|
kOnBeforeSendHeaders,
|
||||||
|
kOnHeadersReceived,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SimpleListenerInfo {
|
||||||
|
URLPatterns url_patterns;
|
||||||
|
SimpleListener listener;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResponseListenerInfo {
|
||||||
|
URLPatterns url_patterns;
|
||||||
|
ResponseListener listener;
|
||||||
|
};
|
||||||
|
|
||||||
|
AtomNetworkDelegate();
|
||||||
|
~AtomNetworkDelegate() override;
|
||||||
|
|
||||||
|
void SetSimpleListenerInIO(SimpleEvent type,
|
||||||
|
const URLPatterns& patterns,
|
||||||
|
const SimpleListener& callback);
|
||||||
|
void SetResponseListenerInIO(ResponseEvent type,
|
||||||
|
const URLPatterns& patterns,
|
||||||
|
const ResponseListener& callback);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// net::NetworkDelegate:
|
||||||
|
int OnBeforeURLRequest(net::URLRequest* request,
|
||||||
|
const net::CompletionCallback& callback,
|
||||||
|
GURL* new_url) override;
|
||||||
|
int OnBeforeSendHeaders(net::URLRequest* request,
|
||||||
|
const net::CompletionCallback& callback,
|
||||||
|
net::HttpRequestHeaders* headers) override;
|
||||||
|
void OnSendHeaders(net::URLRequest* request,
|
||||||
|
const net::HttpRequestHeaders& headers) override;
|
||||||
|
int OnHeadersReceived(
|
||||||
|
net::URLRequest* request,
|
||||||
|
const net::CompletionCallback& callback,
|
||||||
|
const net::HttpResponseHeaders* original_response_headers,
|
||||||
|
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
|
||||||
|
GURL* allowed_unsafe_redirect_url) override;
|
||||||
|
void OnBeforeRedirect(net::URLRequest* request,
|
||||||
|
const GURL& new_location) override;
|
||||||
|
void OnResponseStarted(net::URLRequest* request) override;
|
||||||
|
void OnCompleted(net::URLRequest* request, bool started) override;
|
||||||
|
|
||||||
|
void OnErrorOccurred(net::URLRequest* request);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename...Args>
|
||||||
|
void HandleSimpleEvent(SimpleEvent type,
|
||||||
|
net::URLRequest* request,
|
||||||
|
Args... args);
|
||||||
|
template<typename Out, typename... Args>
|
||||||
|
int HandleResponseEvent(ResponseEvent type,
|
||||||
|
net::URLRequest* request,
|
||||||
|
const net::CompletionCallback& callback,
|
||||||
|
Out out,
|
||||||
|
Args... args);
|
||||||
|
|
||||||
|
std::map<SimpleEvent, SimpleListenerInfo> simple_listeners_;
|
||||||
|
std::map<ResponseEvent, ResponseListenerInfo> response_listeners_;;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(AtomNetworkDelegate);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_NET_ATOM_NETWORK_DELEGATE_H_
|
|
@ -17,9 +17,9 @@
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>atom.icns</string>
|
<string>atom.icns</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>0.35.4</string>
|
<string>0.36.0</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.35.4</string>
|
<string>0.36.0</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.developer-tools</string>
|
<string>public.app-category.developer-tools</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
|
|
@ -56,8 +56,8 @@ END
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 0,35,4,0
|
FILEVERSION 0,36,0,0
|
||||||
PRODUCTVERSION 0,35,4,0
|
PRODUCTVERSION 0,36,0,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -74,12 +74,12 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "GitHub, Inc."
|
VALUE "CompanyName", "GitHub, Inc."
|
||||||
VALUE "FileDescription", "Electron"
|
VALUE "FileDescription", "Electron"
|
||||||
VALUE "FileVersion", "0.35.4"
|
VALUE "FileVersion", "0.36.0"
|
||||||
VALUE "InternalName", "electron.exe"
|
VALUE "InternalName", "electron.exe"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||||
VALUE "OriginalFilename", "electron.exe"
|
VALUE "OriginalFilename", "electron.exe"
|
||||||
VALUE "ProductName", "Electron"
|
VALUE "ProductName", "Electron"
|
||||||
VALUE "ProductVersion", "0.35.4"
|
VALUE "ProductVersion", "0.36.0"
|
||||||
VALUE "SquirrelAwareVersion", "1"
|
VALUE "SquirrelAwareVersion", "1"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
#define ATOM_VERSION_H
|
#define ATOM_VERSION_H
|
||||||
|
|
||||||
#define ATOM_MAJOR_VERSION 0
|
#define ATOM_MAJOR_VERSION 0
|
||||||
#define ATOM_MINOR_VERSION 35
|
#define ATOM_MINOR_VERSION 36
|
||||||
#define ATOM_PATCH_VERSION 4
|
#define ATOM_PATCH_VERSION 0
|
||||||
|
|
||||||
#define ATOM_VERSION_IS_RELEASE 1
|
#define ATOM_VERSION_IS_RELEASE 1
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,15 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.h"
|
||||||
|
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||||
|
#include "atom/common/native_mate_converters/value_converter.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
#include "net/base/upload_bytes_element_reader.h"
|
#include "net/base/upload_bytes_element_reader.h"
|
||||||
#include "net/base/upload_data_stream.h"
|
#include "net/base/upload_data_stream.h"
|
||||||
#include "net/base/upload_element_reader.h"
|
#include "net/base/upload_element_reader.h"
|
||||||
#include "net/base/upload_file_element_reader.h"
|
#include "net/base/upload_file_element_reader.h"
|
||||||
#include "net/cert/x509_certificate.h"
|
#include "net/cert/x509_certificate.h"
|
||||||
|
#include "net/http/http_response_headers.h"
|
||||||
#include "net/url_request/url_request.h"
|
#include "net/url_request/url_request.h"
|
||||||
|
|
||||||
namespace mate {
|
namespace mate {
|
||||||
|
|
|
@ -8,9 +8,18 @@ resolveURL = (url) ->
|
||||||
|
|
||||||
# Window object returned by "window.open".
|
# Window object returned by "window.open".
|
||||||
class BrowserWindowProxy
|
class BrowserWindowProxy
|
||||||
|
@proxies: {}
|
||||||
|
|
||||||
|
@getOrCreate: (guestId) ->
|
||||||
|
@proxies[guestId] ?= new BrowserWindowProxy(guestId)
|
||||||
|
|
||||||
|
@remove: (guestId) ->
|
||||||
|
delete @proxies[guestId]
|
||||||
|
|
||||||
constructor: (@guestId) ->
|
constructor: (@guestId) ->
|
||||||
@closed = false
|
@closed = false
|
||||||
ipcRenderer.once "ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_#{@guestId}", =>
|
ipcRenderer.once "ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_#{@guestId}", =>
|
||||||
|
BrowserWindowProxy.remove(@guestId)
|
||||||
@closed = true
|
@closed = true
|
||||||
|
|
||||||
close: ->
|
close: ->
|
||||||
|
@ -23,7 +32,7 @@ class BrowserWindowProxy
|
||||||
ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', @guestId, 'blur'
|
ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', @guestId, 'blur'
|
||||||
|
|
||||||
postMessage: (message, targetOrigin='*') ->
|
postMessage: (message, targetOrigin='*') ->
|
||||||
ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', @guestId, message, targetOrigin
|
ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', @guestId, message, targetOrigin, location.origin
|
||||||
|
|
||||||
eval: (args...) ->
|
eval: (args...) ->
|
||||||
ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', @guestId, 'executeJavaScript', args...
|
ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', @guestId, 'executeJavaScript', args...
|
||||||
|
@ -60,7 +69,7 @@ window.open = (url, frameName='', features='') ->
|
||||||
|
|
||||||
guestId = ipcRenderer.sendSync 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, options
|
guestId = ipcRenderer.sendSync 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, options
|
||||||
if guestId
|
if guestId
|
||||||
new BrowserWindowProxy(guestId)
|
BrowserWindowProxy.getOrCreate(guestId)
|
||||||
else
|
else
|
||||||
null
|
null
|
||||||
|
|
||||||
|
@ -96,7 +105,7 @@ ipcRenderer.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (event, guestId, message,
|
||||||
event.initEvent 'message', false, false
|
event.initEvent 'message', false, false
|
||||||
event.data = message
|
event.data = message
|
||||||
event.origin = sourceOrigin
|
event.origin = sourceOrigin
|
||||||
event.source = new BrowserWindowProxy(guestId)
|
event.source = BrowserWindowProxy.getOrCreate(guestId)
|
||||||
window.dispatchEvent event
|
window.dispatchEvent event
|
||||||
|
|
||||||
# Forward history operations to browser.
|
# Forward history operations to browser.
|
||||||
|
|
619
chromium_src/extensions/common/url_pattern.cc
Normal file
619
chromium_src/extensions/common/url_pattern.cc
Normal file
|
@ -0,0 +1,619 @@
|
||||||
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "extensions/common/url_pattern.h"
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#include "base/strings/pattern.h"
|
||||||
|
#include "base/strings/string_number_conversions.h"
|
||||||
|
#include "base/strings/string_piece.h"
|
||||||
|
#include "base/strings/string_split.h"
|
||||||
|
#include "base/strings/string_util.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
|
#include "content/public/common/url_constants.h"
|
||||||
|
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
|
||||||
|
#include "url/gurl.h"
|
||||||
|
#include "url/url_util.h"
|
||||||
|
|
||||||
|
const char extensions::URLPattern::kAllUrlsPattern[] = "<all_urls>";
|
||||||
|
const char kExtensionScheme[] = "chrome-extension";
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// TODO(aa): What about more obscure schemes like data: and javascript: ?
|
||||||
|
// Note: keep this array in sync with kValidSchemeMasks.
|
||||||
|
const char* kValidSchemes[] = {
|
||||||
|
url::kHttpScheme,
|
||||||
|
url::kHttpsScheme,
|
||||||
|
url::kFileScheme,
|
||||||
|
url::kFtpScheme,
|
||||||
|
content::kChromeUIScheme,
|
||||||
|
kExtensionScheme,
|
||||||
|
url::kFileSystemScheme,
|
||||||
|
};
|
||||||
|
|
||||||
|
const int kValidSchemeMasks[] = {
|
||||||
|
extensions::URLPattern::SCHEME_HTTP,
|
||||||
|
extensions::URLPattern::SCHEME_HTTPS,
|
||||||
|
extensions::URLPattern::SCHEME_FILE,
|
||||||
|
extensions::URLPattern::SCHEME_FTP,
|
||||||
|
extensions::URLPattern::SCHEME_CHROMEUI,
|
||||||
|
extensions::URLPattern::SCHEME_EXTENSION,
|
||||||
|
extensions::URLPattern::SCHEME_FILESYSTEM,
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(arraysize(kValidSchemes) == arraysize(kValidSchemeMasks),
|
||||||
|
"must keep these arrays in sync");
|
||||||
|
|
||||||
|
const char kParseSuccess[] = "Success.";
|
||||||
|
const char kParseErrorMissingSchemeSeparator[] = "Missing scheme separator.";
|
||||||
|
const char kParseErrorInvalidScheme[] = "Invalid scheme.";
|
||||||
|
const char kParseErrorWrongSchemeType[] = "Wrong scheme type.";
|
||||||
|
const char kParseErrorEmptyHost[] = "Host can not be empty.";
|
||||||
|
const char kParseErrorInvalidHostWildcard[] = "Invalid host wildcard.";
|
||||||
|
const char kParseErrorEmptyPath[] = "Empty path.";
|
||||||
|
const char kParseErrorInvalidPort[] = "Invalid port.";
|
||||||
|
const char kParseErrorInvalidHost[] = "Invalid host.";
|
||||||
|
|
||||||
|
// Message explaining each URLPattern::ParseResult.
|
||||||
|
const char* const kParseResultMessages[] = {
|
||||||
|
kParseSuccess,
|
||||||
|
kParseErrorMissingSchemeSeparator,
|
||||||
|
kParseErrorInvalidScheme,
|
||||||
|
kParseErrorWrongSchemeType,
|
||||||
|
kParseErrorEmptyHost,
|
||||||
|
kParseErrorInvalidHostWildcard,
|
||||||
|
kParseErrorEmptyPath,
|
||||||
|
kParseErrorInvalidPort,
|
||||||
|
kParseErrorInvalidHost,
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(extensions::URLPattern::NUM_PARSE_RESULTS == arraysize(kParseResultMessages),
|
||||||
|
"must add message for each parse result");
|
||||||
|
|
||||||
|
const char kPathSeparator[] = "/";
|
||||||
|
|
||||||
|
bool IsStandardScheme(const std::string& scheme) {
|
||||||
|
// "*" gets the same treatment as a standard scheme.
|
||||||
|
if (scheme == "*")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return url::IsStandard(scheme.c_str(),
|
||||||
|
url::Component(0, static_cast<int>(scheme.length())));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValidPortForScheme(const std::string& scheme, const std::string& port) {
|
||||||
|
if (port == "*")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Only accept non-wildcard ports if the scheme uses ports.
|
||||||
|
if (url::DefaultPortForScheme(scheme.c_str(), scheme.length()) ==
|
||||||
|
url::PORT_UNSPECIFIED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parsed_port = url::PORT_UNSPECIFIED;
|
||||||
|
if (!base::StringToInt(port, &parsed_port))
|
||||||
|
return false;
|
||||||
|
return (parsed_port >= 0) && (parsed_port < 65536);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns |path| with the trailing wildcard stripped if one existed.
|
||||||
|
//
|
||||||
|
// The functions that rely on this (OverlapsWith and Contains) are only
|
||||||
|
// called for the patterns inside URLPatternSet. In those cases, we know that
|
||||||
|
// the path will have only a single wildcard at the end. This makes figuring
|
||||||
|
// out overlap much easier. It seems like there is probably a computer-sciency
|
||||||
|
// way to solve the general case, but we don't need that yet.
|
||||||
|
std::string StripTrailingWildcard(const std::string& path) {
|
||||||
|
size_t wildcard_index = path.find('*');
|
||||||
|
size_t path_last = path.size() - 1;
|
||||||
|
return wildcard_index == path_last ? path.substr(0, path_last) : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace extensions {
|
||||||
|
// static
|
||||||
|
bool URLPattern::IsValidSchemeForExtensions(const std::string& scheme) {
|
||||||
|
for (size_t i = 0; i < arraysize(kValidSchemes); ++i) {
|
||||||
|
if (scheme == kValidSchemes[i])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
URLPattern::URLPattern()
|
||||||
|
: valid_schemes_(SCHEME_ALL),
|
||||||
|
match_all_urls_(false),
|
||||||
|
match_subdomains_(false),
|
||||||
|
port_("*") {}
|
||||||
|
|
||||||
|
URLPattern::URLPattern(int valid_schemes)
|
||||||
|
: valid_schemes_(valid_schemes),
|
||||||
|
match_all_urls_(false),
|
||||||
|
match_subdomains_(false),
|
||||||
|
port_("*") {}
|
||||||
|
|
||||||
|
URLPattern::URLPattern(int valid_schemes, const std::string& pattern)
|
||||||
|
// Strict error checking is used, because this constructor is only
|
||||||
|
// appropriate when we know |pattern| is valid.
|
||||||
|
: valid_schemes_(valid_schemes),
|
||||||
|
match_all_urls_(false),
|
||||||
|
match_subdomains_(false),
|
||||||
|
port_("*") {
|
||||||
|
ParseResult result = Parse(pattern);
|
||||||
|
if (PARSE_SUCCESS != result)
|
||||||
|
NOTREACHED() << "URLPattern invalid: " << pattern << " result " << result;
|
||||||
|
}
|
||||||
|
|
||||||
|
URLPattern::~URLPattern() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::operator<(const URLPattern& other) const {
|
||||||
|
return GetAsString() < other.GetAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::operator>(const URLPattern& other) const {
|
||||||
|
return GetAsString() > other.GetAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::operator==(const URLPattern& other) const {
|
||||||
|
return GetAsString() == other.GetAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern) {
|
||||||
|
return out << '"' << url_pattern.GetAsString() << '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
URLPattern::ParseResult URLPattern::Parse(const std::string& pattern) {
|
||||||
|
spec_.clear();
|
||||||
|
SetMatchAllURLs(false);
|
||||||
|
SetMatchSubdomains(false);
|
||||||
|
SetPort("*");
|
||||||
|
|
||||||
|
// Special case pattern to match every valid URL.
|
||||||
|
if (pattern == kAllUrlsPattern) {
|
||||||
|
SetMatchAllURLs(true);
|
||||||
|
return PARSE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse out the scheme.
|
||||||
|
size_t scheme_end_pos = pattern.find(url::kStandardSchemeSeparator);
|
||||||
|
bool has_standard_scheme_separator = true;
|
||||||
|
|
||||||
|
// Some urls also use ':' alone as the scheme separator.
|
||||||
|
if (scheme_end_pos == std::string::npos) {
|
||||||
|
scheme_end_pos = pattern.find(':');
|
||||||
|
has_standard_scheme_separator = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scheme_end_pos == std::string::npos)
|
||||||
|
return PARSE_ERROR_MISSING_SCHEME_SEPARATOR;
|
||||||
|
|
||||||
|
if (!SetScheme(pattern.substr(0, scheme_end_pos)))
|
||||||
|
return PARSE_ERROR_INVALID_SCHEME;
|
||||||
|
|
||||||
|
bool standard_scheme = IsStandardScheme(scheme_);
|
||||||
|
if (standard_scheme != has_standard_scheme_separator)
|
||||||
|
return PARSE_ERROR_WRONG_SCHEME_SEPARATOR;
|
||||||
|
|
||||||
|
// Advance past the scheme separator.
|
||||||
|
scheme_end_pos +=
|
||||||
|
(standard_scheme ? strlen(url::kStandardSchemeSeparator) : 1);
|
||||||
|
if (scheme_end_pos >= pattern.size())
|
||||||
|
return PARSE_ERROR_EMPTY_HOST;
|
||||||
|
|
||||||
|
// Parse out the host and path.
|
||||||
|
size_t host_start_pos = scheme_end_pos;
|
||||||
|
size_t path_start_pos = 0;
|
||||||
|
|
||||||
|
if (!standard_scheme) {
|
||||||
|
path_start_pos = host_start_pos;
|
||||||
|
} else if (scheme_ == url::kFileScheme) {
|
||||||
|
size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
|
||||||
|
if (host_end_pos == std::string::npos) {
|
||||||
|
// Allow hostname omission.
|
||||||
|
// e.g. file://* is interpreted as file:///*,
|
||||||
|
// file://foo* is interpreted as file:///foo*.
|
||||||
|
path_start_pos = host_start_pos - 1;
|
||||||
|
} else {
|
||||||
|
// Ignore hostname if scheme is file://.
|
||||||
|
// e.g. file://localhost/foo is equal to file:///foo.
|
||||||
|
path_start_pos = host_end_pos;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
|
||||||
|
|
||||||
|
// Host is required.
|
||||||
|
if (host_start_pos == host_end_pos)
|
||||||
|
return PARSE_ERROR_EMPTY_HOST;
|
||||||
|
|
||||||
|
if (host_end_pos == std::string::npos)
|
||||||
|
return PARSE_ERROR_EMPTY_PATH;
|
||||||
|
|
||||||
|
host_ = pattern.substr(host_start_pos, host_end_pos - host_start_pos);
|
||||||
|
|
||||||
|
// The first component can optionally be '*' to match all subdomains.
|
||||||
|
std::vector<std::string> host_components = base::SplitString(
|
||||||
|
host_, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
|
||||||
|
|
||||||
|
// Could be empty if the host only consists of whitespace characters.
|
||||||
|
if (host_components.empty() ||
|
||||||
|
(host_components.size() == 1 && host_components[0].empty()))
|
||||||
|
return PARSE_ERROR_EMPTY_HOST;
|
||||||
|
|
||||||
|
if (host_components[0] == "*") {
|
||||||
|
match_subdomains_ = true;
|
||||||
|
host_components.erase(host_components.begin(),
|
||||||
|
host_components.begin() + 1);
|
||||||
|
}
|
||||||
|
host_ = base::JoinString(host_components, ".");
|
||||||
|
|
||||||
|
path_start_pos = host_end_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPath(pattern.substr(path_start_pos));
|
||||||
|
|
||||||
|
size_t port_pos = host_.find(':');
|
||||||
|
if (port_pos != std::string::npos) {
|
||||||
|
if (!SetPort(host_.substr(port_pos + 1)))
|
||||||
|
return PARSE_ERROR_INVALID_PORT;
|
||||||
|
host_ = host_.substr(0, port_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No other '*' can occur in the host, though. This isn't necessary, but is
|
||||||
|
// done as a convenience to developers who might otherwise be confused and
|
||||||
|
// think '*' works as a glob in the host.
|
||||||
|
if (host_.find('*') != std::string::npos)
|
||||||
|
return PARSE_ERROR_INVALID_HOST_WILDCARD;
|
||||||
|
|
||||||
|
// Null characters are not allowed in hosts.
|
||||||
|
if (host_.find('\0') != std::string::npos)
|
||||||
|
return PARSE_ERROR_INVALID_HOST;
|
||||||
|
|
||||||
|
return PARSE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void URLPattern::SetValidSchemes(int valid_schemes) {
|
||||||
|
spec_.clear();
|
||||||
|
valid_schemes_ = valid_schemes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void URLPattern::SetHost(const std::string& host) {
|
||||||
|
spec_.clear();
|
||||||
|
host_ = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
void URLPattern::SetMatchAllURLs(bool val) {
|
||||||
|
spec_.clear();
|
||||||
|
match_all_urls_ = val;
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
match_subdomains_ = true;
|
||||||
|
scheme_ = "*";
|
||||||
|
host_.clear();
|
||||||
|
SetPath("/*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void URLPattern::SetMatchSubdomains(bool val) {
|
||||||
|
spec_.clear();
|
||||||
|
match_subdomains_ = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::SetScheme(const std::string& scheme) {
|
||||||
|
spec_.clear();
|
||||||
|
scheme_ = scheme;
|
||||||
|
if (scheme_ == "*") {
|
||||||
|
valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
|
||||||
|
} else if (!IsValidScheme(scheme_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::IsValidScheme(const std::string& scheme) const {
|
||||||
|
if (valid_schemes_ == SCHEME_ALL)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arraysize(kValidSchemes); ++i) {
|
||||||
|
if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void URLPattern::SetPath(const std::string& path) {
|
||||||
|
spec_.clear();
|
||||||
|
path_ = path;
|
||||||
|
path_escaped_ = path_;
|
||||||
|
base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
|
||||||
|
base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::SetPort(const std::string& port) {
|
||||||
|
spec_.clear();
|
||||||
|
if (IsValidPortForScheme(scheme_, port)) {
|
||||||
|
port_ = port;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesURL(const GURL& test) const {
|
||||||
|
const GURL* test_url = &test;
|
||||||
|
bool has_inner_url = test.inner_url() != NULL;
|
||||||
|
|
||||||
|
if (has_inner_url) {
|
||||||
|
if (!test.SchemeIsFileSystem())
|
||||||
|
return false; // The only nested URLs we handle are filesystem URLs.
|
||||||
|
test_url = test.inner_url();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MatchesScheme(test_url->scheme()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (match_all_urls_)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::string path_for_request = test.PathForRequest();
|
||||||
|
if (has_inner_url)
|
||||||
|
path_for_request = test_url->path() + path_for_request;
|
||||||
|
|
||||||
|
return MatchesSecurityOriginHelper(*test_url) &&
|
||||||
|
MatchesPath(path_for_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
|
||||||
|
const GURL* test_url = &test;
|
||||||
|
bool has_inner_url = test.inner_url() != NULL;
|
||||||
|
|
||||||
|
if (has_inner_url) {
|
||||||
|
if (!test.SchemeIsFileSystem())
|
||||||
|
return false; // The only nested URLs we handle are filesystem URLs.
|
||||||
|
test_url = test.inner_url();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MatchesScheme(test_url->scheme()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (match_all_urls_)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return MatchesSecurityOriginHelper(*test_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesScheme(const std::string& test) const {
|
||||||
|
if (!IsValidScheme(test))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return scheme_ == "*" || test == scheme_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesHost(const std::string& host) const {
|
||||||
|
std::string test(url::kHttpScheme);
|
||||||
|
test += url::kStandardSchemeSeparator;
|
||||||
|
test += host;
|
||||||
|
test += "/";
|
||||||
|
return MatchesHost(GURL(test));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesHost(const GURL& test) const {
|
||||||
|
// If the hosts are exactly equal, we have a match.
|
||||||
|
if (test.host() == host_)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If we're matching subdomains, and we have no host in the match pattern,
|
||||||
|
// that means that we're matching all hosts, which means we have a match no
|
||||||
|
// matter what the test host is.
|
||||||
|
if (match_subdomains_ && host_.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Otherwise, we can only match if our match pattern matches subdomains.
|
||||||
|
if (!match_subdomains_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// We don't do subdomain matching against IP addresses, so we can give up now
|
||||||
|
// if the test host is an IP address.
|
||||||
|
if (test.HostIsIPAddress())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check if the test host is a subdomain of our host.
|
||||||
|
if (test.host().length() <= (host_.length() + 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (test.host().compare(test.host().length() - host_.length(),
|
||||||
|
host_.length(), host_) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return test.host()[test.host().length() - host_.length() - 1] == '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::ImpliesAllHosts() const {
|
||||||
|
// Check if it matches all urls or is a pattern like http://*/*.
|
||||||
|
if (match_all_urls_ ||
|
||||||
|
(match_subdomains_ && host_.empty() && port_ == "*" && path_ == "/*")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this doesn't even match subdomains, it can't possibly imply all hosts.
|
||||||
|
if (!match_subdomains_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If |host_| is a recognized TLD, this will be 0. We don't include private
|
||||||
|
// TLDs, so that, e.g., *.appspot.com does not imply all hosts.
|
||||||
|
size_t registry_length = net::registry_controlled_domains::GetRegistryLength(
|
||||||
|
host_,
|
||||||
|
net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
|
||||||
|
net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
|
||||||
|
// If there was more than just a TLD in the host (e.g., *.foobar.com), it
|
||||||
|
// doesn't imply all hosts.
|
||||||
|
if (registry_length > 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// At this point the host could either be just a TLD ("com") or some unknown
|
||||||
|
// TLD-like string ("notatld"). To disambiguate between them construct a
|
||||||
|
// fake URL, and check the registry. This returns 0 if the TLD is
|
||||||
|
// unrecognized, or the length of the recognized TLD.
|
||||||
|
registry_length = net::registry_controlled_domains::GetRegistryLength(
|
||||||
|
base::StringPrintf("foo.%s", host_.c_str()),
|
||||||
|
net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
|
||||||
|
net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
|
||||||
|
// If we recognized this TLD, then this is a pattern like *.com, and it
|
||||||
|
// should imply all hosts. Otherwise, this doesn't imply all hosts.
|
||||||
|
return registry_length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesSingleOrigin() const {
|
||||||
|
// Strictly speaking, the port is part of the origin, but in URLPattern it
|
||||||
|
// defaults to *. It's not very interesting anyway, so leave it out.
|
||||||
|
return !ImpliesAllHosts() && scheme_ != "*" && !match_subdomains_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesPath(const std::string& test) const {
|
||||||
|
// Make the behaviour of OverlapsWith consistent with MatchesURL, which is
|
||||||
|
// need to match hosted apps on e.g. 'google.com' also run on 'google.com/'.
|
||||||
|
if (test + "/*" == path_escaped_)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return base::MatchPattern(test, path_escaped_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& URLPattern::GetAsString() const {
|
||||||
|
if (!spec_.empty())
|
||||||
|
return spec_;
|
||||||
|
|
||||||
|
if (match_all_urls_) {
|
||||||
|
spec_ = kAllUrlsPattern;
|
||||||
|
return spec_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool standard_scheme = IsStandardScheme(scheme_);
|
||||||
|
|
||||||
|
std::string spec = scheme_ +
|
||||||
|
(standard_scheme ? url::kStandardSchemeSeparator : ":");
|
||||||
|
|
||||||
|
if (scheme_ != url::kFileScheme && standard_scheme) {
|
||||||
|
if (match_subdomains_) {
|
||||||
|
spec += "*";
|
||||||
|
if (!host_.empty())
|
||||||
|
spec += ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!host_.empty())
|
||||||
|
spec += host_;
|
||||||
|
|
||||||
|
if (port_ != "*") {
|
||||||
|
spec += ":";
|
||||||
|
spec += port_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path_.empty())
|
||||||
|
spec += path_;
|
||||||
|
|
||||||
|
spec_ = spec;
|
||||||
|
return spec_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::OverlapsWith(const URLPattern& other) const {
|
||||||
|
if (match_all_urls() || other.match_all_urls())
|
||||||
|
return true;
|
||||||
|
return (MatchesAnyScheme(other.GetExplicitSchemes()) ||
|
||||||
|
other.MatchesAnyScheme(GetExplicitSchemes()))
|
||||||
|
&& (MatchesHost(other.host()) || other.MatchesHost(host()))
|
||||||
|
&& (MatchesPortPattern(other.port()) || other.MatchesPortPattern(port()))
|
||||||
|
&& (MatchesPath(StripTrailingWildcard(other.path())) ||
|
||||||
|
other.MatchesPath(StripTrailingWildcard(path())));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::Contains(const URLPattern& other) const {
|
||||||
|
if (match_all_urls())
|
||||||
|
return true;
|
||||||
|
return MatchesAllSchemes(other.GetExplicitSchemes()) &&
|
||||||
|
MatchesHost(other.host()) &&
|
||||||
|
(!other.match_subdomains_ || match_subdomains_) &&
|
||||||
|
MatchesPortPattern(other.port()) &&
|
||||||
|
MatchesPath(StripTrailingWildcard(other.path()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesAnyScheme(
|
||||||
|
const std::vector<std::string>& schemes) const {
|
||||||
|
for (std::vector<std::string>::const_iterator i = schemes.begin();
|
||||||
|
i != schemes.end(); ++i) {
|
||||||
|
if (MatchesScheme(*i))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesAllSchemes(
|
||||||
|
const std::vector<std::string>& schemes) const {
|
||||||
|
for (std::vector<std::string>::const_iterator i = schemes.begin();
|
||||||
|
i != schemes.end(); ++i) {
|
||||||
|
if (!MatchesScheme(*i))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
|
||||||
|
// Ignore hostname if scheme is file://.
|
||||||
|
if (scheme_ != url::kFileScheme && !MatchesHost(test))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!MatchesPortPattern(base::IntToString(test.EffectiveIntPort())))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool URLPattern::MatchesPortPattern(const std::string& port) const {
|
||||||
|
return port_ == "*" || port_ == port;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> URLPattern::GetExplicitSchemes() const {
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
|
||||||
|
result.push_back(scheme_);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arraysize(kValidSchemes); ++i) {
|
||||||
|
if (MatchesScheme(kValidSchemes[i])) {
|
||||||
|
result.push_back(kValidSchemes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<URLPattern> URLPattern::ConvertToExplicitSchemes() const {
|
||||||
|
std::vector<std::string> explicit_schemes = GetExplicitSchemes();
|
||||||
|
std::vector<URLPattern> result;
|
||||||
|
|
||||||
|
for (std::vector<std::string>::const_iterator i = explicit_schemes.begin();
|
||||||
|
i != explicit_schemes.end(); ++i) {
|
||||||
|
URLPattern temp = *this;
|
||||||
|
temp.SetScheme(*i);
|
||||||
|
temp.SetMatchAllURLs(false);
|
||||||
|
result.push_back(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
const char* URLPattern::GetParseResultString(
|
||||||
|
URLPattern::ParseResult parse_result) {
|
||||||
|
return kParseResultMessages[parse_result];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extensions
|
264
chromium_src/extensions/common/url_pattern.h
Normal file
264
chromium_src/extensions/common/url_pattern.h
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
#ifndef EXTENSIONS_COMMON_URL_PATTERN_H_
|
||||||
|
#define EXTENSIONS_COMMON_URL_PATTERN_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class GURL;
|
||||||
|
|
||||||
|
namespace extensions {
|
||||||
|
// A pattern that can be used to match URLs. A URLPattern is a very restricted
|
||||||
|
// subset of URL syntax:
|
||||||
|
//
|
||||||
|
// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
|
||||||
|
// <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' |
|
||||||
|
// 'chrome-extension' | 'filesystem'
|
||||||
|
// <host> := '*' | '*.' <anychar except '/' and '*'>+
|
||||||
|
// <port> := [':' ('*' | <port number between 0 and 65535>)]
|
||||||
|
// <path> := '/' <any chars>
|
||||||
|
//
|
||||||
|
// * Host is not used when the scheme is 'file'.
|
||||||
|
// * The path can have embedded '*' characters which act as glob wildcards.
|
||||||
|
// * '<all_urls>' is a special pattern that matches any URL that contains a
|
||||||
|
// valid scheme (as specified by valid_schemes_).
|
||||||
|
// * The '*' scheme pattern excludes file URLs.
|
||||||
|
//
|
||||||
|
// Examples of valid patterns:
|
||||||
|
// - http://*/*
|
||||||
|
// - http://*/foo*
|
||||||
|
// - https://*.google.com/foo*bar
|
||||||
|
// - file://monkey*
|
||||||
|
// - http://127.0.0.1/*
|
||||||
|
//
|
||||||
|
// Examples of invalid patterns:
|
||||||
|
// - http://* -- path not specified
|
||||||
|
// - http://*foo/bar -- * not allowed as substring of host component
|
||||||
|
// - http://foo.*.bar/baz -- * must be first component
|
||||||
|
// - http:/bar -- scheme separator not found
|
||||||
|
// - foo://* -- invalid scheme
|
||||||
|
// - chrome:// -- we don't support chrome internal URLs
|
||||||
|
class URLPattern {
|
||||||
|
public:
|
||||||
|
// A collection of scheme bitmasks for use with valid_schemes.
|
||||||
|
enum SchemeMasks {
|
||||||
|
SCHEME_NONE = 0,
|
||||||
|
SCHEME_HTTP = 1 << 0,
|
||||||
|
SCHEME_HTTPS = 1 << 1,
|
||||||
|
SCHEME_FILE = 1 << 2,
|
||||||
|
SCHEME_FTP = 1 << 3,
|
||||||
|
SCHEME_CHROMEUI = 1 << 4,
|
||||||
|
SCHEME_EXTENSION = 1 << 5,
|
||||||
|
SCHEME_FILESYSTEM = 1 << 6,
|
||||||
|
|
||||||
|
// IMPORTANT!
|
||||||
|
// SCHEME_ALL will match every scheme, including chrome://, chrome-
|
||||||
|
// extension://, about:, etc. Because this has lots of security
|
||||||
|
// implications, third-party extensions should usually not be able to get
|
||||||
|
// access to URL patterns initialized this way. If there is a reason
|
||||||
|
// for violating this general rule, document why this it safe.
|
||||||
|
SCHEME_ALL = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Error codes returned from Parse().
|
||||||
|
enum ParseResult {
|
||||||
|
PARSE_SUCCESS = 0,
|
||||||
|
PARSE_ERROR_MISSING_SCHEME_SEPARATOR,
|
||||||
|
PARSE_ERROR_INVALID_SCHEME,
|
||||||
|
PARSE_ERROR_WRONG_SCHEME_SEPARATOR,
|
||||||
|
PARSE_ERROR_EMPTY_HOST,
|
||||||
|
PARSE_ERROR_INVALID_HOST_WILDCARD,
|
||||||
|
PARSE_ERROR_EMPTY_PATH,
|
||||||
|
PARSE_ERROR_INVALID_PORT,
|
||||||
|
PARSE_ERROR_INVALID_HOST,
|
||||||
|
NUM_PARSE_RESULTS
|
||||||
|
};
|
||||||
|
|
||||||
|
// The <all_urls> string pattern.
|
||||||
|
static const char kAllUrlsPattern[];
|
||||||
|
|
||||||
|
// Returns true if the given |scheme| is considered valid for extensions.
|
||||||
|
static bool IsValidSchemeForExtensions(const std::string& scheme);
|
||||||
|
|
||||||
|
explicit URLPattern(int valid_schemes);
|
||||||
|
|
||||||
|
// Convenience to construct a URLPattern from a string. If the string is not
|
||||||
|
// known ahead of time, use Parse() instead, which returns success or failure.
|
||||||
|
URLPattern(int valid_schemes, const std::string& pattern);
|
||||||
|
|
||||||
|
URLPattern();
|
||||||
|
~URLPattern();
|
||||||
|
|
||||||
|
bool operator<(const URLPattern& other) const;
|
||||||
|
bool operator>(const URLPattern& other) const;
|
||||||
|
bool operator==(const URLPattern& other) const;
|
||||||
|
|
||||||
|
// Initializes this instance by parsing the provided string. Returns
|
||||||
|
// URLPattern::PARSE_SUCCESS on success, or an error code otherwise. On
|
||||||
|
// failure, this instance will have some intermediate values and is in an
|
||||||
|
// invalid state.
|
||||||
|
ParseResult Parse(const std::string& pattern_str);
|
||||||
|
|
||||||
|
// Gets the bitmask of valid schemes.
|
||||||
|
int valid_schemes() const { return valid_schemes_; }
|
||||||
|
void SetValidSchemes(int valid_schemes);
|
||||||
|
|
||||||
|
// Gets the host the pattern matches. This can be an empty string if the
|
||||||
|
// pattern matches all hosts (the input was <scheme>://*/<whatever>).
|
||||||
|
const std::string& host() const { return host_; }
|
||||||
|
void SetHost(const std::string& host);
|
||||||
|
|
||||||
|
// Gets whether to match subdomains of host().
|
||||||
|
bool match_subdomains() const { return match_subdomains_; }
|
||||||
|
void SetMatchSubdomains(bool val);
|
||||||
|
|
||||||
|
// Gets the path the pattern matches with the leading slash. This can have
|
||||||
|
// embedded asterisks which are interpreted using glob rules.
|
||||||
|
const std::string& path() const { return path_; }
|
||||||
|
void SetPath(const std::string& path);
|
||||||
|
|
||||||
|
// Returns true if this pattern matches all urls.
|
||||||
|
bool match_all_urls() const { return match_all_urls_; }
|
||||||
|
void SetMatchAllURLs(bool val);
|
||||||
|
|
||||||
|
// Sets the scheme for pattern matches. This can be a single '*' if the
|
||||||
|
// pattern matches all valid schemes (as defined by the valid_schemes_
|
||||||
|
// property). Returns false on failure (if the scheme is not valid).
|
||||||
|
bool SetScheme(const std::string& scheme);
|
||||||
|
// Note: You should use MatchesScheme() instead of this getter unless you
|
||||||
|
// absolutely need the exact scheme. This is exposed for testing.
|
||||||
|
const std::string& scheme() const { return scheme_; }
|
||||||
|
|
||||||
|
// Returns true if the specified scheme can be used in this URL pattern, and
|
||||||
|
// false otherwise. Uses valid_schemes_ to determine validity.
|
||||||
|
bool IsValidScheme(const std::string& scheme) const;
|
||||||
|
|
||||||
|
// Returns true if this instance matches the specified URL.
|
||||||
|
bool MatchesURL(const GURL& test) const;
|
||||||
|
|
||||||
|
// Returns true if this instance matches the specified security origin.
|
||||||
|
bool MatchesSecurityOrigin(const GURL& test) const;
|
||||||
|
|
||||||
|
// Returns true if |test| matches our scheme.
|
||||||
|
// Note that if test is "filesystem", this may fail whereas MatchesURL
|
||||||
|
// may succeed. MatchesURL is smart enough to look at the inner_url instead
|
||||||
|
// of the outer "filesystem:" part.
|
||||||
|
bool MatchesScheme(const std::string& test) const;
|
||||||
|
|
||||||
|
// Returns true if |test| matches our host.
|
||||||
|
bool MatchesHost(const std::string& test) const;
|
||||||
|
bool MatchesHost(const GURL& test) const;
|
||||||
|
|
||||||
|
// Returns true if |test| matches our path.
|
||||||
|
bool MatchesPath(const std::string& test) const;
|
||||||
|
|
||||||
|
// Returns true if the pattern is vague enough that it implies all hosts,
|
||||||
|
// such as *://*/*.
|
||||||
|
// This is an expensive method, and should be used sparingly!
|
||||||
|
// You should probably use URLPatternSet::ShouldWarnAllHosts(), which is
|
||||||
|
// cached.
|
||||||
|
bool ImpliesAllHosts() const;
|
||||||
|
|
||||||
|
// Returns true if the pattern only matches a single origin. The pattern may
|
||||||
|
// include a path.
|
||||||
|
bool MatchesSingleOrigin() const;
|
||||||
|
|
||||||
|
// Sets the port. Returns false if the port is invalid.
|
||||||
|
bool SetPort(const std::string& port);
|
||||||
|
const std::string& port() const { return port_; }
|
||||||
|
|
||||||
|
// Returns a string representing this instance.
|
||||||
|
const std::string& GetAsString() const;
|
||||||
|
|
||||||
|
// Determines whether there is a URL that would match this instance and
|
||||||
|
// another instance. This method is symmetrical: Calling
|
||||||
|
// other.OverlapsWith(this) would result in the same answer.
|
||||||
|
bool OverlapsWith(const URLPattern& other) const;
|
||||||
|
|
||||||
|
// Returns true if this pattern matches all possible URLs that |other| can
|
||||||
|
// match. For example, http://*.google.com encompasses http://www.google.com.
|
||||||
|
bool Contains(const URLPattern& other) const;
|
||||||
|
|
||||||
|
// Converts this URLPattern into an equivalent set of URLPatterns that don't
|
||||||
|
// use a wildcard in the scheme component. If this URLPattern doesn't use a
|
||||||
|
// wildcard scheme, then the returned set will contain one element that is
|
||||||
|
// equivalent to this instance.
|
||||||
|
std::vector<URLPattern> ConvertToExplicitSchemes() const;
|
||||||
|
|
||||||
|
static bool EffectiveHostCompare(const URLPattern& a, const URLPattern& b) {
|
||||||
|
if (a.match_all_urls_ && b.match_all_urls_)
|
||||||
|
return false;
|
||||||
|
return a.host_.compare(b.host_) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for origin comparisons in a std::set.
|
||||||
|
class EffectiveHostCompareFunctor {
|
||||||
|
public:
|
||||||
|
bool operator()(const URLPattern& a, const URLPattern& b) const {
|
||||||
|
return EffectiveHostCompare(a, b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get an error string for a ParseResult.
|
||||||
|
static const char* GetParseResultString(URLPattern::ParseResult parse_result);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Returns true if any of the |schemes| items matches our scheme.
|
||||||
|
bool MatchesAnyScheme(const std::vector<std::string>& schemes) const;
|
||||||
|
|
||||||
|
// Returns true if all of the |schemes| items matches our scheme.
|
||||||
|
bool MatchesAllSchemes(const std::vector<std::string>& schemes) const;
|
||||||
|
|
||||||
|
bool MatchesSecurityOriginHelper(const GURL& test) const;
|
||||||
|
|
||||||
|
// Returns true if our port matches the |port| pattern (it may be "*").
|
||||||
|
bool MatchesPortPattern(const std::string& port) const;
|
||||||
|
|
||||||
|
// If the URLPattern contains a wildcard scheme, returns a list of
|
||||||
|
// equivalent literal schemes, otherwise returns the current scheme.
|
||||||
|
std::vector<std::string> GetExplicitSchemes() const;
|
||||||
|
|
||||||
|
// A bitmask containing the schemes which are considered valid for this
|
||||||
|
// pattern. Parse() uses this to decide whether a pattern contains a valid
|
||||||
|
// scheme.
|
||||||
|
int valid_schemes_;
|
||||||
|
|
||||||
|
// True if this is a special-case "<all_urls>" pattern.
|
||||||
|
bool match_all_urls_;
|
||||||
|
|
||||||
|
// The scheme for the pattern.
|
||||||
|
std::string scheme_;
|
||||||
|
|
||||||
|
// The host without any leading "*" components.
|
||||||
|
std::string host_;
|
||||||
|
|
||||||
|
// Whether we should match subdomains of the host. This is true if the first
|
||||||
|
// component of the pattern's host was "*".
|
||||||
|
bool match_subdomains_;
|
||||||
|
|
||||||
|
// The port.
|
||||||
|
std::string port_;
|
||||||
|
|
||||||
|
// The path to match. This is everything after the host of the URL, or
|
||||||
|
// everything after the scheme in the case of file:// URLs.
|
||||||
|
std::string path_;
|
||||||
|
|
||||||
|
// The path with "?" and "\" characters escaped for use with the
|
||||||
|
// MatchPattern() function.
|
||||||
|
std::string path_escaped_;
|
||||||
|
|
||||||
|
// A string representing this URLPattern.
|
||||||
|
mutable std::string spec_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern);
|
||||||
|
|
||||||
|
typedef std::vector<URLPattern> URLPatternList;
|
||||||
|
|
||||||
|
} // namespace extensions
|
||||||
|
|
||||||
|
#endif // EXTENSIONS_COMMON_URL_PATTERN_H_
|
|
@ -4,8 +4,12 @@ The `BrowserWindow` class gives you the ability to create a browser window. For
|
||||||
example:
|
example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
// In the main process.
|
||||||
const BrowserWindow = require('electron').BrowserWindow;
|
const BrowserWindow = require('electron').BrowserWindow;
|
||||||
|
|
||||||
|
// Or in the renderer process.
|
||||||
|
const BrowserWindow = require('electron').remote.BrowserWindow;
|
||||||
|
|
||||||
var win = new BrowserWindow({ width: 800, height: 600, show: false });
|
var win = new BrowserWindow({ width: 800, height: 600, show: false });
|
||||||
win.on('closed', function() {
|
win.on('closed', function() {
|
||||||
win = null;
|
win = null;
|
||||||
|
|
|
@ -12,7 +12,7 @@ const BrowserWindow = require('electron').BrowserWindow;
|
||||||
var win = new BrowserWindow({ width: 800, height: 600 });
|
var win = new BrowserWindow({ width: 800, height: 600 });
|
||||||
win.loadURL("http://github.com");
|
win.loadURL("http://github.com");
|
||||||
|
|
||||||
var ses = win.webContents.session
|
var ses = win.webContents.session;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
@ -63,7 +63,7 @@ Emitted when Electron is about to download `item` in `webContents`.
|
||||||
Calling `event.preventDefault()` will cancel the download.
|
Calling `event.preventDefault()` will cancel the download.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
session.on('will-download', function(event, item, webContents) {
|
session.defaultSession.on('will-download', function(event, item, webContents) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
require('request')(item.getURL(), function(data) {
|
require('request')(item.getURL(), function(data) {
|
||||||
require('fs').writeFileSync('/somewhere', data);
|
require('fs').writeFileSync('/somewhere', data);
|
||||||
|
@ -80,91 +80,84 @@ The following methods are available on instances of `Session`:
|
||||||
The `cookies` gives you ability to query and modify cookies. For example:
|
The `cookies` gives you ability to query and modify cookies. For example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const BrowserWindow = require('electron').BrowserWindow;
|
// Query all cookies.
|
||||||
|
session.defaultSession.cookies.get({}, function(error, cookies) {
|
||||||
|
console.log(cookies);
|
||||||
|
});
|
||||||
|
|
||||||
var win = new BrowserWindow({ width: 800, height: 600 });
|
// Query all cookies associated with a specific url.
|
||||||
|
session.defaultSession.cookies.get({ url : "http://www.github.com" }, function(error, cookies) {
|
||||||
|
console.log(cookies);
|
||||||
|
});
|
||||||
|
|
||||||
win.loadURL('https://github.com');
|
// Set a cookie with the given cookie data;
|
||||||
|
// may overwrite equivalent cookies if they exist.
|
||||||
win.webContents.on('did-finish-load', function() {
|
var cookie = { url : "http://www.github.com", name : "dummy_name", value : "dummy" };
|
||||||
// Query all cookies.
|
session.defaultSession.cookies.set(cookie, function(error) {
|
||||||
win.webContents.session.cookies.get({}, function(error, cookies) {
|
if (error)
|
||||||
if (error) throw error;
|
console.error(error);
|
||||||
console.log(cookies);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Query all cookies associated with a specific url.
|
|
||||||
win.webContents.session.cookies.get({ url : "http://www.github.com" },
|
|
||||||
function(error, cookies) {
|
|
||||||
if (error) throw error;
|
|
||||||
console.log(cookies);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set a cookie with the given cookie data;
|
|
||||||
// may overwrite equivalent cookies if they exist.
|
|
||||||
win.webContents.session.cookies.set(
|
|
||||||
{ url : "http://www.github.com", name : "dummy_name", value : "dummy"},
|
|
||||||
function(error, cookies) {
|
|
||||||
if (error) throw error;
|
|
||||||
console.log(cookies);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `ses.cookies.get(details, callback)`
|
#### `ses.cookies.get(filter, callback)`
|
||||||
|
|
||||||
`details` Object, properties:
|
* `filter` Object
|
||||||
|
* `url` String __optional__ - Retrieves cookies which are associated with
|
||||||
|
`url`. Empty implies retrieving cookies of all urls.
|
||||||
|
* `name` String __optional__ - Filters cookies by name.
|
||||||
|
* `domain` String __optional__ - Retrieves cookies whose domains match or are
|
||||||
|
subdomains of `domains`
|
||||||
|
* `path` String __optional__ - Retrieves cookies whose path matches `path`.
|
||||||
|
* `secure` Boolean __optional__ - Filters cookies by their Secure property.
|
||||||
|
* `session` Boolean __optional__ - Filters out session or persistent cookies.
|
||||||
|
* `callback` Function
|
||||||
|
|
||||||
* `url` String - Retrieves cookies which are associated with `url`.
|
Sends a request to get all cookies matching `details`, `callback` will be called
|
||||||
Empty implies retrieving cookies of all urls.
|
with `callback(error, cookies)` on complete.
|
||||||
* `name` String - Filters cookies by name
|
|
||||||
* `domain` String - Retrieves cookies whose domains match or are subdomains of
|
`cookies` is an Array of `cookie` objects.
|
||||||
`domains`
|
|
||||||
* `path` String - Retrieves cookies whose path matches `path`
|
* `cookie` Object
|
||||||
* `secure` Boolean - Filters cookies by their Secure property
|
|
||||||
* `session` Boolean - Filters out session or persistent cookies.
|
|
||||||
* `callback` Function - function(error, cookies)
|
|
||||||
* `error` Error
|
|
||||||
* `cookies` Array - array of `cookie` objects, properties:
|
|
||||||
* `name` String - The name of the cookie.
|
* `name` String - The name of the cookie.
|
||||||
* `value` String - The value of the cookie.
|
* `value` String - The value of the cookie.
|
||||||
* `domain` String - The domain of the cookie.
|
* `domain` String - The domain of the cookie.
|
||||||
* `host_only` String - Whether the cookie is a host-only cookie.
|
* `hostOnly` String - Whether the cookie is a host-only cookie.
|
||||||
* `path` String - The path of the cookie.
|
* `path` String - The path of the cookie.
|
||||||
* `secure` Boolean - Whether the cookie is marked as Secure (typically HTTPS).
|
* `secure` Boolean - Whether the cookie is marked as secure.
|
||||||
* `http_only` Boolean - Whether the cookie is marked as HttpOnly.
|
* `httpOnly` Boolean - Whether the cookie is marked as HTTP only.
|
||||||
* `session` Boolean - Whether the cookie is a session cookie or a persistent
|
* `session` Boolean - Whether the cookie is a session cookie or a persistent
|
||||||
cookie with an expiration date.
|
cookie with an expiration date.
|
||||||
* `expirationDate` Double - (Option) The expiration date of the cookie as
|
* `expirationDate` Double __optional__ - The expiration date of the cookie as
|
||||||
the number of seconds since the UNIX epoch. Not provided for session
|
the number of seconds since the UNIX epoch. Not provided for session
|
||||||
cookies.
|
cookies.
|
||||||
|
|
||||||
#### `ses.cookies.set(details, callback)`
|
#### `ses.cookies.set(details, callback)`
|
||||||
|
|
||||||
`details` Object, properties:
|
|
||||||
|
|
||||||
* `url` String - Retrieves cookies which are associated with `url`
|
|
||||||
* `name` String - The name of the cookie. Empty by default if omitted.
|
|
||||||
* `value` String - The value of the cookie. Empty by default if omitted.
|
|
||||||
* `domain` String - The domain of the cookie. Empty by default if omitted.
|
|
||||||
* `path` String - The path of the cookie. Empty by default if omitted.
|
|
||||||
* `secure` Boolean - Whether the cookie should be marked as Secure. Defaults to
|
|
||||||
false.
|
|
||||||
* `session` Boolean - Whether the cookie should be marked as HttpOnly. Defaults
|
|
||||||
to false.
|
|
||||||
* `expirationDate` Double - The expiration date of the cookie as the number of
|
|
||||||
seconds since the UNIX epoch. If omitted, the cookie becomes a session cookie.
|
|
||||||
|
|
||||||
* `callback` Function - function(error)
|
|
||||||
* `error` Error
|
|
||||||
|
|
||||||
#### `ses.cookies.remove(details, callback)`
|
|
||||||
|
|
||||||
* `details` Object
|
* `details` Object
|
||||||
* `url` String - The URL associated with the cookie
|
* `url` String - Retrieves cookies which are associated with `url`
|
||||||
* `name` String - The name of cookie to remove
|
* `name` String - The name of the cookie. Empty by default if omitted.
|
||||||
* `callback` Function - function(error)
|
* `value` String - The value of the cookie. Empty by default if omitted.
|
||||||
* `error` Error
|
* `domain` String - The domain of the cookie. Empty by default if omitted.
|
||||||
|
* `path` String - The path of the cookie. Empty by default if omitted.
|
||||||
|
* `secure` Boolean - Whether the cookie should be marked as Secure. Defaults to
|
||||||
|
false.
|
||||||
|
* `session` Boolean - Whether the cookie should be marked as HttpOnly. Defaults
|
||||||
|
to false.
|
||||||
|
* `expirationDate` Double - The expiration date of the cookie as the number of
|
||||||
|
seconds since the UNIX epoch. If omitted, the cookie becomes a session cookie.
|
||||||
|
* `callback` Function
|
||||||
|
|
||||||
|
Sets the cookie with `details`, `callback` will be called with `callback(error)`
|
||||||
|
on complete.
|
||||||
|
|
||||||
|
#### `ses.cookies.remove(url, name, callback)`
|
||||||
|
|
||||||
|
* `url` String - The URL associated with the cookie.
|
||||||
|
* `name` String - The name of cookie to remove.
|
||||||
|
* `callback` Function
|
||||||
|
|
||||||
|
Removes the cookies matching `url` and `name`, `callback` will called with
|
||||||
|
`callback()` on complete.
|
||||||
|
|
||||||
#### `ses.clearCache(callback)`
|
#### `ses.clearCache(callback)`
|
||||||
|
|
||||||
|
@ -286,3 +279,197 @@ myWindow.webContents.session.setCertificateVerifyProc(function(hostname, cert, c
|
||||||
callback(false);
|
callback(false);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `ses.webRequest`
|
||||||
|
|
||||||
|
The `webRequest` API set allows to intercept and modify contents of a request at
|
||||||
|
various stages of its lifetime.
|
||||||
|
|
||||||
|
Each API accepts an optional `filter` and a `listener`, the `listener` will be
|
||||||
|
called with `listener(details)` when the API's event has happened, the `details`
|
||||||
|
is an object that describes the request. Passing `null` as `listener` will
|
||||||
|
unsubscribe from the event.
|
||||||
|
|
||||||
|
The `filter` is an object that has an `urls` property, which is an Array of URL
|
||||||
|
patterns that will be used to filter out the requests that do not match the URL
|
||||||
|
patterns. If the `filter` is omitted then all requests will be matched.
|
||||||
|
|
||||||
|
For certain events the `listener` is passed with a `callback`, which should be
|
||||||
|
called with an `response` object when `listener` has done its work.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Modify the user agent for all requests to the following urls.
|
||||||
|
var filter = {
|
||||||
|
urls: ["https://*.github.com/*", "*://electron.github.io"]
|
||||||
|
};
|
||||||
|
|
||||||
|
session.defaultSession.webRequest.onBeforeSendHeaders(filter, function(details, callback) {
|
||||||
|
details.requestHeaders['User-Agent'] = "MyAgent";
|
||||||
|
callback({cancel: false, requestHeaders: details.requestHeaders});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `ses.webRequest.onBeforeRequest([filter, ]listener)`
|
||||||
|
|
||||||
|
* `filter` Object
|
||||||
|
* `listener` Function
|
||||||
|
|
||||||
|
The `listener` will be called with `listener(details, callback)` when a request
|
||||||
|
is about to occur.
|
||||||
|
|
||||||
|
* `details` Object
|
||||||
|
* `id` Integer
|
||||||
|
* `url` String
|
||||||
|
* `method` String
|
||||||
|
* `resourceType` String
|
||||||
|
* `timestamp` Double
|
||||||
|
|
||||||
|
The `callback` has to be called with an `response` object:
|
||||||
|
|
||||||
|
* `response` Object
|
||||||
|
* `cancel` Boolean __optional__
|
||||||
|
* `redirectURL` String __optional__ - The original request is prevented from
|
||||||
|
being sent or completed, and is instead redirected to the given URL.
|
||||||
|
|
||||||
|
#### `ses.webRequest.onBeforeSendHeaders([filter, ]listener)`
|
||||||
|
|
||||||
|
* `filter` Object
|
||||||
|
* `listener` Function
|
||||||
|
|
||||||
|
The `listener` will be called with `listener(details, callback)` before sending
|
||||||
|
an HTTP request, once the request headers are available. This may occur after a
|
||||||
|
TCP connection is made to the server, but before any http data is sent.
|
||||||
|
|
||||||
|
* `details` Object
|
||||||
|
* `id` Integer
|
||||||
|
* `url` String
|
||||||
|
* `method` String
|
||||||
|
* `resourceType` String
|
||||||
|
* `timestamp` Double
|
||||||
|
* `requestHeaders` Object
|
||||||
|
|
||||||
|
The `callback` has to be called with an `response` object:
|
||||||
|
|
||||||
|
* `response` Object
|
||||||
|
* `cancel` Boolean __optional__
|
||||||
|
* `requestHeaders` Object __optional__ - When provided, request will be made
|
||||||
|
with these headers.
|
||||||
|
|
||||||
|
#### `ses.webRequest.onSendHeaders([filter, ]listener)`
|
||||||
|
|
||||||
|
* `filter` Object
|
||||||
|
* `listener` Function
|
||||||
|
|
||||||
|
The `listener` will be called with `listener(details)` just before a request is
|
||||||
|
going to be sent to the server, modifications of previous `onBeforeSendHeaders`
|
||||||
|
response are visible by the time this listener is fired.
|
||||||
|
|
||||||
|
* `details` Object
|
||||||
|
* `id` Integer
|
||||||
|
* `url` String
|
||||||
|
* `method` String
|
||||||
|
* `resourceType` String
|
||||||
|
* `timestamp` Double
|
||||||
|
* `requestHeaders` Object
|
||||||
|
|
||||||
|
#### `ses.webRequest.onHeadersReceived([filter,] listener)`
|
||||||
|
|
||||||
|
* `filter` Object
|
||||||
|
* `listener` Function
|
||||||
|
|
||||||
|
The `listener` will be called with `listener(details, callback)` when HTTP
|
||||||
|
response headers of a request have been received.
|
||||||
|
|
||||||
|
* `details` Object
|
||||||
|
* `id` String
|
||||||
|
* `url` String
|
||||||
|
* `method` String
|
||||||
|
* `resourceType` String
|
||||||
|
* `timestamp` Double
|
||||||
|
* `statusLine` String
|
||||||
|
* `statusCode` Integer
|
||||||
|
* `responseHeaders` Object
|
||||||
|
|
||||||
|
The `callback` has to be called with an `response` object:
|
||||||
|
|
||||||
|
* `response` Object
|
||||||
|
* `cancel` Boolean
|
||||||
|
* `responseHeaders` Object __optional__ - When provided, the server is assumed
|
||||||
|
to have responded with these headers.
|
||||||
|
|
||||||
|
#### `ses.webRequest.onResponseStarted([filter, ]listener)`
|
||||||
|
|
||||||
|
* `filter` Object
|
||||||
|
* `listener` Function
|
||||||
|
|
||||||
|
The `listener` will be called with `listener(details)` when first byte of the
|
||||||
|
response body is received. For HTTP requests, this means that the status line
|
||||||
|
and response headers are available.
|
||||||
|
|
||||||
|
* `details` Object
|
||||||
|
* `id` Integer
|
||||||
|
* `url` String
|
||||||
|
* `method` String
|
||||||
|
* `resourceType` String
|
||||||
|
* `timestamp` Double
|
||||||
|
* `responseHeaders` Object
|
||||||
|
* `fromCache` Boolean - Indicates whether the response was fetched from disk
|
||||||
|
cache.
|
||||||
|
* `statusCode` Integer
|
||||||
|
* `statusLine` String
|
||||||
|
|
||||||
|
#### `ses.webRequest.onBeforeRedirect([filter, ]listener)`
|
||||||
|
|
||||||
|
* `filter` Object
|
||||||
|
* `listener` Function
|
||||||
|
|
||||||
|
The `listener` will be called with `listener(details)` when a server initiated
|
||||||
|
redirect is about to occur.
|
||||||
|
|
||||||
|
* `details` Object
|
||||||
|
* `id` String
|
||||||
|
* `url` String
|
||||||
|
* `method` String
|
||||||
|
* `resourceType` String
|
||||||
|
* `timestamp` Double
|
||||||
|
* `redirectURL` String
|
||||||
|
* `statusCode` Integer
|
||||||
|
* `ip` String __optional__ - The server IP address that the request was
|
||||||
|
actually sent to.
|
||||||
|
* `fromCache` Boolean
|
||||||
|
* `responseHeaders` Object
|
||||||
|
|
||||||
|
#### `ses.webRequest.onCompleted([filter, ]listener)`
|
||||||
|
|
||||||
|
* `filter` Object
|
||||||
|
* `listener` Function
|
||||||
|
|
||||||
|
The `listener` will be called with `listener(details)` when a request is
|
||||||
|
completed.
|
||||||
|
|
||||||
|
* `details` Object
|
||||||
|
* `id` Integer
|
||||||
|
* `url` String
|
||||||
|
* `method` String
|
||||||
|
* `resourceType` String
|
||||||
|
* `timestamp` Double
|
||||||
|
* `responseHeaders` Object
|
||||||
|
* `fromCache` Boolean
|
||||||
|
* `statusCode` Integer
|
||||||
|
* `statusLine` String
|
||||||
|
|
||||||
|
#### `ses.webRequest.onErrorOccurred([filter, ]listener)`
|
||||||
|
|
||||||
|
* `filter` Object
|
||||||
|
* `listener` Function
|
||||||
|
|
||||||
|
The `listener` will be called with `listener(details)` when an error occurs.
|
||||||
|
|
||||||
|
* `details` Object
|
||||||
|
* `id` Integer
|
||||||
|
* `url` String
|
||||||
|
* `method` String
|
||||||
|
* `resourceType` String
|
||||||
|
* `timestamp` Double
|
||||||
|
* `fromCache` Boolean
|
||||||
|
* `error` String - The error description.
|
||||||
|
|
|
@ -110,6 +110,8 @@
|
||||||
'atom/browser/api/atom_api_tray.h',
|
'atom/browser/api/atom_api_tray.h',
|
||||||
'atom/browser/api/atom_api_web_contents.cc',
|
'atom/browser/api/atom_api_web_contents.cc',
|
||||||
'atom/browser/api/atom_api_web_contents.h',
|
'atom/browser/api/atom_api_web_contents.h',
|
||||||
|
'atom/browser/api/atom_api_web_request.cc',
|
||||||
|
'atom/browser/api/atom_api_web_request.h',
|
||||||
'atom/browser/api/atom_api_web_view_manager.cc',
|
'atom/browser/api/atom_api_web_view_manager.cc',
|
||||||
'atom/browser/api/atom_api_window.cc',
|
'atom/browser/api/atom_api_window.cc',
|
||||||
'atom/browser/api/atom_api_window.h',
|
'atom/browser/api/atom_api_window.h',
|
||||||
|
@ -178,6 +180,8 @@
|
||||||
'atom/browser/net/asar/url_request_asar_job.h',
|
'atom/browser/net/asar/url_request_asar_job.h',
|
||||||
'atom/browser/net/atom_cert_verifier.cc',
|
'atom/browser/net/atom_cert_verifier.cc',
|
||||||
'atom/browser/net/atom_cert_verifier.h',
|
'atom/browser/net/atom_cert_verifier.h',
|
||||||
|
'atom/browser/net/atom_network_delegate.cc',
|
||||||
|
'atom/browser/net/atom_network_delegate.h',
|
||||||
'atom/browser/net/atom_ssl_config_service.cc',
|
'atom/browser/net/atom_ssl_config_service.cc',
|
||||||
'atom/browser/net/atom_ssl_config_service.h',
|
'atom/browser/net/atom_ssl_config_service.h',
|
||||||
'atom/browser/net/atom_url_request_job_factory.cc',
|
'atom/browser/net/atom_url_request_job_factory.cc',
|
||||||
|
@ -472,6 +476,8 @@
|
||||||
'chromium_src/chrome/utility/utility_message_handler.h',
|
'chromium_src/chrome/utility/utility_message_handler.h',
|
||||||
'chromium_src/extensions/browser/app_window/size_constraints.cc',
|
'chromium_src/extensions/browser/app_window/size_constraints.cc',
|
||||||
'chromium_src/extensions/browser/app_window/size_constraints.h',
|
'chromium_src/extensions/browser/app_window/size_constraints.h',
|
||||||
|
'chromium_src/extensions/common/url_pattern.cc',
|
||||||
|
'chromium_src/extensions/common/url_pattern.h',
|
||||||
'chromium_src/library_loaders/libspeechd_loader.cc',
|
'chromium_src/library_loaders/libspeechd_loader.cc',
|
||||||
'chromium_src/library_loaders/libspeechd.h',
|
'chromium_src/library_loaders/libspeechd.h',
|
||||||
'chromium_src/net/test/embedded_test_server/stream_listen_socket.cc',
|
'chromium_src/net/test/embedded_test_server/stream_listen_socket.cc',
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "node -e 'process.exit(0)'"
|
"preinstall": "node -e 'process.exit(0)'",
|
||||||
|
"test": "python ./script/test.py"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import sys
|
||||||
|
|
||||||
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
|
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
|
||||||
'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent'
|
'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent'
|
||||||
LIBCHROMIUMCONTENT_COMMIT = 'cfbe8ec7e14af4cabd1474386f54e197db1f7ac1'
|
LIBCHROMIUMCONTENT_COMMIT = '66bd8d1c705b7258f76c82436e4b16e82afbbd33'
|
||||||
|
|
||||||
PLATFORM = {
|
PLATFORM = {
|
||||||
'cygwin': 'win32',
|
'cygwin': 'win32',
|
||||||
|
|
|
@ -8,7 +8,7 @@ os = require 'os'
|
||||||
{remote, screen} = require 'electron'
|
{remote, screen} = require 'electron'
|
||||||
{ipcMain, BrowserWindow} = remote.require 'electron'
|
{ipcMain, BrowserWindow} = remote.require 'electron'
|
||||||
|
|
||||||
isCI = remote.process.argv[2] == '--ci'
|
isCI = remote.getGlobal('isCi')
|
||||||
|
|
||||||
describe 'browser-window module', ->
|
describe 'browser-window module', ->
|
||||||
fixtures = path.resolve __dirname, 'fixtures'
|
fixtures = path.resolve __dirname, 'fixtures'
|
||||||
|
|
|
@ -18,7 +18,7 @@ describe 'crash-reporter module', ->
|
||||||
return if process.mas
|
return if process.mas
|
||||||
|
|
||||||
# The crash-reporter test is not reliable on CI machine.
|
# The crash-reporter test is not reliable on CI machine.
|
||||||
isCI = remote.process.argv[2] == '--ci'
|
isCI = remote.getGlobal('isCi')
|
||||||
return if isCI
|
return if isCI
|
||||||
|
|
||||||
it 'should send minidump when renderer crashes', (done) ->
|
it 'should send minidump when renderer crashes', (done) ->
|
||||||
|
|
|
@ -49,12 +49,11 @@ describe 'session module', ->
|
||||||
it 'should remove cookies', (done) ->
|
it 'should remove cookies', (done) ->
|
||||||
session.defaultSession.cookies.set {url: url, name: '2', value: '2'}, (error) ->
|
session.defaultSession.cookies.set {url: url, name: '2', value: '2'}, (error) ->
|
||||||
return done(error) if error
|
return done(error) if error
|
||||||
session.defaultSession.cookies.remove {url: url, name: '2'}, (error) ->
|
session.defaultSession.cookies.remove url, '2', ->
|
||||||
return done(error) if error
|
|
||||||
session.defaultSession.cookies.get {url: url}, (error, list) ->
|
session.defaultSession.cookies.get {url: url}, (error, list) ->
|
||||||
return done(error) if error
|
return done(error) if error
|
||||||
for cookie in list when cookie.name is '2'
|
for cookie in list when cookie.name is '2'
|
||||||
return done('Cookie not deleted')
|
return done('Cookie not deleted')
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe 'session.clearStorageData(options)', ->
|
describe 'session.clearStorageData(options)', ->
|
||||||
|
|
232
spec/api-web-request-spec.coffee
Normal file
232
spec/api-web-request-spec.coffee
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
assert = require 'assert'
|
||||||
|
http = require 'http'
|
||||||
|
|
||||||
|
{remote} = require 'electron'
|
||||||
|
{session} = remote
|
||||||
|
|
||||||
|
describe 'webRequest module', ->
|
||||||
|
ses = session.defaultSession
|
||||||
|
server = http.createServer (req, res) ->
|
||||||
|
res.setHeader('Custom', ['Header'])
|
||||||
|
content = req.url
|
||||||
|
if req.headers.accept is '*/*;test/header'
|
||||||
|
content += 'header/received'
|
||||||
|
res.end content
|
||||||
|
defaultURL = null
|
||||||
|
|
||||||
|
before (done) ->
|
||||||
|
server.listen 0, '127.0.0.1', ->
|
||||||
|
{port} = server.address()
|
||||||
|
defaultURL = "http://127.0.0.1:#{port}/"
|
||||||
|
done()
|
||||||
|
after ->
|
||||||
|
server.close()
|
||||||
|
|
||||||
|
describe 'webRequest.onBeforeRequest', ->
|
||||||
|
afterEach ->
|
||||||
|
ses.webRequest.onBeforeRequest null
|
||||||
|
|
||||||
|
it 'can cancel the request', (done) ->
|
||||||
|
ses.webRequest.onBeforeRequest (details, callback) ->
|
||||||
|
callback(cancel: true)
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data) -> done('unexpected success')
|
||||||
|
error: (xhr, errorType, error) -> done()
|
||||||
|
|
||||||
|
it 'can filter URLs', (done) ->
|
||||||
|
filter = urls: ["#{defaultURL}filter/*"]
|
||||||
|
ses.webRequest.onBeforeRequest filter, (details, callback) ->
|
||||||
|
callback(cancel: true)
|
||||||
|
$.ajax
|
||||||
|
url: "#{defaultURL}nofilter/test"
|
||||||
|
success: (data) ->
|
||||||
|
assert.equal data, '/nofilter/test'
|
||||||
|
$.ajax
|
||||||
|
url: "#{defaultURL}filter/test"
|
||||||
|
success: (data) -> done('unexpected success')
|
||||||
|
error: (xhr, errorType, error) -> done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
it 'receives details object', (done) ->
|
||||||
|
ses.webRequest.onBeforeRequest (details, callback) ->
|
||||||
|
assert.equal typeof details.id, 'number'
|
||||||
|
assert.equal typeof details.timestamp, 'number'
|
||||||
|
assert.equal details.url, defaultURL
|
||||||
|
assert.equal details.method, 'GET'
|
||||||
|
assert.equal details.resourceType, 'xhr'
|
||||||
|
callback({})
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data) ->
|
||||||
|
assert.equal data, '/'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
it 'can redirect the request', (done) ->
|
||||||
|
ses.webRequest.onBeforeRequest (details, callback) ->
|
||||||
|
if details.url is defaultURL
|
||||||
|
callback(redirectURL: "#{defaultURL}redirect")
|
||||||
|
else
|
||||||
|
callback({})
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data) ->
|
||||||
|
assert.equal data, '/redirect'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
describe 'webRequest.onBeforeSendHeaders', ->
|
||||||
|
afterEach ->
|
||||||
|
ses.webRequest.onBeforeSendHeaders null
|
||||||
|
|
||||||
|
it 'receives details object', (done) ->
|
||||||
|
ses.webRequest.onBeforeSendHeaders (details, callback) ->
|
||||||
|
assert.equal typeof details.requestHeaders, 'object'
|
||||||
|
callback({})
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data) ->
|
||||||
|
assert.equal data, '/'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
it 'can change the request headers', (done) ->
|
||||||
|
ses.webRequest.onBeforeSendHeaders (details, callback) ->
|
||||||
|
{requestHeaders} = details
|
||||||
|
requestHeaders.Accept = '*/*;test/header'
|
||||||
|
callback({requestHeaders})
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data, textStatus, request) ->
|
||||||
|
assert.equal data, '/header/received'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
describe 'webRequest.onSendHeaders', ->
|
||||||
|
afterEach ->
|
||||||
|
ses.webRequest.onSendHeaders null
|
||||||
|
|
||||||
|
it 'receives details object', (done) ->
|
||||||
|
ses.webRequest.onSendHeaders (details, callback) ->
|
||||||
|
assert.equal typeof details.requestHeaders, 'object'
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data) ->
|
||||||
|
assert.equal data, '/'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
describe 'webRequest.onHeadersReceived', ->
|
||||||
|
afterEach ->
|
||||||
|
ses.webRequest.onHeadersReceived null
|
||||||
|
|
||||||
|
it 'receives details object', (done) ->
|
||||||
|
ses.webRequest.onHeadersReceived (details, callback) ->
|
||||||
|
assert.equal details.statusLine, 'HTTP/1.1 200 OK'
|
||||||
|
assert.equal details.statusCode, 200
|
||||||
|
assert.equal details.responseHeaders['Custom'], 'Header'
|
||||||
|
callback({})
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data) ->
|
||||||
|
assert.equal data, '/'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
it 'can change the response header', (done) ->
|
||||||
|
ses.webRequest.onHeadersReceived (details, callback) ->
|
||||||
|
{responseHeaders} = details
|
||||||
|
responseHeaders['Custom'] = ['Changed']
|
||||||
|
callback({responseHeaders})
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data, status, xhr) ->
|
||||||
|
assert.equal xhr.getResponseHeader('Custom'), 'Changed'
|
||||||
|
assert.equal data, '/'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
it 'does not change header by default', (done) ->
|
||||||
|
ses.webRequest.onHeadersReceived (details, callback) ->
|
||||||
|
callback({})
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data, status, xhr) ->
|
||||||
|
assert.equal xhr.getResponseHeader('Custom'), 'Header'
|
||||||
|
assert.equal data, '/'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
describe 'webRequest.onResponseStarted', ->
|
||||||
|
afterEach ->
|
||||||
|
ses.webRequest.onResponseStarted null
|
||||||
|
|
||||||
|
it 'receives details object', (done) ->
|
||||||
|
ses.webRequest.onResponseStarted (details) ->
|
||||||
|
assert.equal typeof details.fromCache, 'boolean'
|
||||||
|
assert.equal details.statusLine, 'HTTP/1.1 200 OK'
|
||||||
|
assert.equal details.statusCode, 200
|
||||||
|
assert.equal details.responseHeaders['Custom'], 'Header'
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data, status, xhr) ->
|
||||||
|
assert.equal xhr.getResponseHeader('Custom'), 'Header'
|
||||||
|
assert.equal data, '/'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
describe 'webRequest.onBeforeRedirect', ->
|
||||||
|
afterEach ->
|
||||||
|
ses.webRequest.onBeforeRedirect null
|
||||||
|
ses.webRequest.onBeforeRequest null
|
||||||
|
|
||||||
|
it 'receives details object', (done) ->
|
||||||
|
redirectURL = "#{defaultURL}redirect"
|
||||||
|
ses.webRequest.onBeforeRequest (details, callback) ->
|
||||||
|
if details.url is defaultURL
|
||||||
|
callback({redirectURL})
|
||||||
|
else
|
||||||
|
callback({})
|
||||||
|
ses.webRequest.onBeforeRedirect (details) ->
|
||||||
|
assert.equal typeof details.fromCache, 'boolean'
|
||||||
|
assert.equal details.statusLine, 'HTTP/1.1 307 Internal Redirect'
|
||||||
|
assert.equal details.statusCode, 307
|
||||||
|
assert.equal details.redirectURL, redirectURL
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data, status, xhr) ->
|
||||||
|
assert.equal data, '/redirect'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
describe 'webRequest.onCompleted', ->
|
||||||
|
afterEach ->
|
||||||
|
ses.webRequest.onCompleted null
|
||||||
|
|
||||||
|
it 'receives details object', (done) ->
|
||||||
|
ses.webRequest.onCompleted (details) ->
|
||||||
|
assert.equal typeof details.fromCache, 'boolean'
|
||||||
|
assert.equal details.statusLine, 'HTTP/1.1 200 OK'
|
||||||
|
assert.equal details.statusCode, 200
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data, status, xhr) ->
|
||||||
|
assert.equal data, '/'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) -> done(errorType)
|
||||||
|
|
||||||
|
describe 'webRequest.onErrorOccurred', ->
|
||||||
|
afterEach ->
|
||||||
|
ses.webRequest.onErrorOccurred null
|
||||||
|
ses.webRequest.onBeforeRequest null
|
||||||
|
|
||||||
|
it 'receives details object', (done) ->
|
||||||
|
ses.webRequest.onBeforeRequest (details, callback) ->
|
||||||
|
callback(cancel: true)
|
||||||
|
ses.webRequest.onErrorOccurred (details) ->
|
||||||
|
assert.equal details.error, 'net::ERR_BLOCKED_BY_CLIENT'
|
||||||
|
done()
|
||||||
|
$.ajax
|
||||||
|
url: defaultURL
|
||||||
|
success: (data) -> done('unexpected success')
|
|
@ -45,7 +45,7 @@ describe 'chromium feature', ->
|
||||||
done()
|
done()
|
||||||
w.loadURL url
|
w.loadURL url
|
||||||
|
|
||||||
describe 'navigator.webkitGetUserMedia', ->
|
xdescribe 'navigator.webkitGetUserMedia', ->
|
||||||
it 'calls its callbacks', (done) ->
|
it 'calls its callbacks', (done) ->
|
||||||
@timeout 5000
|
@timeout 5000
|
||||||
navigator.webkitGetUserMedia audio: true, video: false,
|
navigator.webkitGetUserMedia audio: true, video: false,
|
||||||
|
@ -115,12 +115,25 @@ describe 'chromium feature', ->
|
||||||
window.addEventListener 'message', listener
|
window.addEventListener 'message', listener
|
||||||
b = window.open url, '', 'show=no'
|
b = window.open url, '', 'show=no'
|
||||||
|
|
||||||
|
describe 'window.postMessage', ->
|
||||||
|
it 'sets the origin correctly', (done) ->
|
||||||
|
listener = (event) ->
|
||||||
|
window.removeEventListener 'message', listener
|
||||||
|
b.close()
|
||||||
|
assert.equal event.data, 'file://testing'
|
||||||
|
assert.equal event.origin, 'file://'
|
||||||
|
done()
|
||||||
|
window.addEventListener 'message', listener
|
||||||
|
b = window.open "file://#{fixtures}/pages/window-open-postMessage.html", '', 'show=no'
|
||||||
|
BrowserWindow.fromId(b.guestId).webContents.once 'did-finish-load', ->
|
||||||
|
b.postMessage('testing', '*')
|
||||||
|
|
||||||
describe 'window.opener.postMessage', ->
|
describe 'window.opener.postMessage', ->
|
||||||
it 'sets source and origin correctly', (done) ->
|
it 'sets source and origin correctly', (done) ->
|
||||||
listener = (event) ->
|
listener = (event) ->
|
||||||
window.removeEventListener 'message', listener
|
window.removeEventListener 'message', listener
|
||||||
b.close()
|
b.close()
|
||||||
assert.equal event.source.guestId, b.guestId
|
assert.equal event.source, b
|
||||||
assert.equal event.origin, 'file://'
|
assert.equal event.origin, 'file://'
|
||||||
done()
|
done()
|
||||||
window.addEventListener 'message', listener
|
window.addEventListener 'message', listener
|
||||||
|
@ -210,7 +223,7 @@ describe 'chromium feature', ->
|
||||||
setImmediate ->
|
setImmediate ->
|
||||||
called = false
|
called = false
|
||||||
Promise.resolve().then ->
|
Promise.resolve().then ->
|
||||||
done(if called then undefined else new Error('wrong sequnce'))
|
done(if called then undefined else new Error('wrong sequence'))
|
||||||
document.createElement 'x-element'
|
document.createElement 'x-element'
|
||||||
called = true
|
called = true
|
||||||
|
|
||||||
|
@ -224,6 +237,6 @@ describe 'chromium feature', ->
|
||||||
remote.getGlobal('setImmediate') ->
|
remote.getGlobal('setImmediate') ->
|
||||||
called = false
|
called = false
|
||||||
Promise.resolve().then ->
|
Promise.resolve().then ->
|
||||||
done(if called then undefined else new Error('wrong sequnce'))
|
done(if called then undefined else new Error('wrong sequence'))
|
||||||
document.createElement 'y-element'
|
document.createElement 'y-element'
|
||||||
called = true
|
called = true
|
||||||
|
|
9
spec/fixtures/pages/window-open-postMessage.html
vendored
Normal file
9
spec/fixtures/pages/window-open-postMessage.html
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
window.addEventListener('message', function (e) {
|
||||||
|
window.opener.postMessage(e.origin + e.data, '*');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -5,13 +5,14 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"basic-auth": "^1.0.0",
|
"basic-auth": "^1.0.0",
|
||||||
"multiparty": "4.1.2",
|
|
||||||
"graceful-fs": "3.0.5",
|
"graceful-fs": "3.0.5",
|
||||||
"mocha": "2.1.0",
|
"mocha": "2.1.0",
|
||||||
|
"multiparty": "4.1.2",
|
||||||
"q": "0.9.7",
|
"q": "0.9.7",
|
||||||
"temp": "0.8.1",
|
"temp": "0.8.1",
|
||||||
"walkdir": "0.0.7",
|
"walkdir": "0.0.7",
|
||||||
"ws": "0.7.2"
|
"ws": "0.7.2",
|
||||||
|
"yargs": "^3.31.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"ffi": "2.0.0",
|
"ffi": "2.0.0",
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
var remote = electron.remote;
|
var remote = electron.remote;
|
||||||
var ipcRenderer = electron.ipcRenderer;
|
var ipcRenderer = electron.ipcRenderer;
|
||||||
|
|
||||||
var argv = remote.process.argv;
|
var isCi = remote.getGlobal('isCi')
|
||||||
var isCi = argv[2] == '--ci';
|
|
||||||
|
|
||||||
if (!isCi) {
|
if (!isCi) {
|
||||||
var win = remote.getCurrentWindow();
|
var win = remote.getCurrentWindow();
|
||||||
|
|
|
@ -5,6 +5,13 @@ const dialog = electron.dialog;
|
||||||
const BrowserWindow = electron.BrowserWindow;
|
const BrowserWindow = electron.BrowserWindow;
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const url = require('url');
|
||||||
|
|
||||||
|
var argv = require('yargs')
|
||||||
|
.boolean('ci')
|
||||||
|
.string('g').alias('g', 'grep')
|
||||||
|
.boolean('i').alias('i', 'invert')
|
||||||
|
.argv;
|
||||||
|
|
||||||
var window = null;
|
var window = null;
|
||||||
process.port = 0; // will be used by crash-reporter spec.
|
process.port = 0; // will be used by crash-reporter spec.
|
||||||
|
@ -42,7 +49,8 @@ ipcMain.on('echo', function(event, msg) {
|
||||||
event.returnValue = msg;
|
event.returnValue = msg;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (process.argv[2] == '--ci') {
|
global.isCi = !!argv.ci;
|
||||||
|
if (global.isCi) {
|
||||||
process.removeAllListeners('uncaughtException');
|
process.removeAllListeners('uncaughtException');
|
||||||
process.on('uncaughtException', function(error) {
|
process.on('uncaughtException', function(error) {
|
||||||
console.error(error, error.stack);
|
console.error(error, error.stack);
|
||||||
|
@ -67,7 +75,14 @@ app.on('ready', function() {
|
||||||
javascript: true // Test whether web-preferences crashes.
|
javascript: true // Test whether web-preferences crashes.
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
window.loadURL('file://' + __dirname + '/index.html');
|
window.loadURL(url.format({
|
||||||
|
pathname: __dirname + '/index.html',
|
||||||
|
protocol: 'file',
|
||||||
|
query: {
|
||||||
|
grep: argv.grep,
|
||||||
|
invert: argv.invert ? 'true': ''
|
||||||
|
}
|
||||||
|
}));
|
||||||
window.on('unresponsive', function() {
|
window.on('unresponsive', function() {
|
||||||
var chosen = dialog.showMessageBox(window, {
|
var chosen = dialog.showMessageBox(window, {
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
|
|
2
vendor/native_mate
vendored
2
vendor/native_mate
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 5e70868fd0c005dc2c43bea15ca6e93da0b68741
|
Subproject commit a3dcf8ced663e974ac94ad5e50a1d25a43995a9d
|
Loading…
Reference in a new issue