Merge pull request #3789 from atom/template-web-request
Cleanup the webRequest and cookies code
This commit is contained in:
commit
84cea1b494
15 changed files with 956 additions and 852 deletions
|
@ -7,7 +7,6 @@
|
|||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/values.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_getter.h"
|
||||
|
||||
using atom::api::Cookies;
|
||||
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 {
|
||||
|
||||
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<>
|
||||
struct Converter<net::CanonicalCookie> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
|
@ -161,11 +42,11 @@ struct Converter<net::CanonicalCookie> {
|
|||
dict.Set("name", val.Name());
|
||||
dict.Set("value", val.Value());
|
||||
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("secure", val.IsSecure());
|
||||
dict.Set("http_only", val.IsHttpOnly());
|
||||
dict.Set("session", val.IsPersistent());
|
||||
dict.Set("httpOnly", val.IsHttpOnly());
|
||||
dict.Set("session", !val.IsPersistent());
|
||||
if (!val.IsPersistent())
|
||||
dict.Set("expirationDate", val.ExpiryDate().ToDoubleT());
|
||||
return dict.GetHandle();
|
||||
|
@ -178,121 +59,117 @@ namespace atom {
|
|||
|
||||
namespace api {
|
||||
|
||||
Cookies::Cookies(content::BrowserContext* browser_context)
|
||||
: request_context_getter_(browser_context->GetRequestContext()) {
|
||||
}
|
||||
namespace {
|
||||
|
||||
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,
|
||||
const CookiesCallback& callback) {
|
||||
scoped_ptr<base::DictionaryValue> filter(
|
||||
options.DeepCopyWithoutEmptyChildren());
|
||||
std::string sub_domain(domain);
|
||||
// Strip any leading '.' character from the input cookie domain.
|
||||
if (!net::cookie_util::DomainIsHostOnly(sub_domain))
|
||||
sub_domain = sub_domain.substr(1);
|
||||
|
||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Cookies::GetCookiesOnIOThread, base::Unretained(this),
|
||||
Passed(&filter), callback));
|
||||
}
|
||||
|
||||
void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
|
||||
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));
|
||||
// Now check whether the domain argument is a subdomain of the filter domain.
|
||||
for (sub_domain.insert(0, "."); sub_domain.length() >= filter.length();) {
|
||||
if (sub_domain == filter)
|
||||
return true;
|
||||
const size_t next_dot = sub_domain.find('.', 1); // Skip over leading dot.
|
||||
sub_domain.erase(0, next_dot);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Cookies::OnGetCookies(scoped_ptr<base::DictionaryValue> filter,
|
||||
const CookiesCallback& callback,
|
||||
const net::CookieList& cookie_list) {
|
||||
// Returns whether |cookie| matches |filter|.
|
||||
bool MatchesCookie(const base::DictionaryValue* filter,
|
||||
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;
|
||||
for (const auto& cookie : cookie_list) {
|
||||
for (const auto& cookie : list) {
|
||||
if (MatchesCookie(filter.get(), cookie))
|
||||
result.push_back(cookie);
|
||||
}
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
|
||||
&RunGetCookiesCallbackOnUIThread, isolate(), "", result, callback));
|
||||
RunCallbackInUI(base::Bind(callback, Cookies::SUCCESS, result));
|
||||
}
|
||||
|
||||
void Cookies::Remove(const mate::Dictionary& details,
|
||||
const CookiesCallback& callback) {
|
||||
GURL url;
|
||||
std::string name;
|
||||
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) {
|
||||
// Receives cookies matching |filter| in IO thread.
|
||||
void GetCookiesOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
scoped_ptr<base::DictionaryValue> filter,
|
||||
const Cookies::GetCallback& callback) {
|
||||
std::string url;
|
||||
std::string error_message;
|
||||
if (!options.GetString("url", &url)) {
|
||||
error_message = "The url field is required.";
|
||||
}
|
||||
filter->GetString("url", &url);
|
||||
|
||||
GURL gurl(url);
|
||||
if (error_message.empty() && !gurl.is_valid()) {
|
||||
error_message = "URL is not valid.";
|
||||
}
|
||||
auto filtered_callback =
|
||||
base::Bind(FilterCookies, base::Passed(&filter), callback);
|
||||
|
||||
if (!error_message.empty()) {
|
||||
RunSetCookiesCallbackOnUIThread(isolate(), error_message, false, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_ptr<base::DictionaryValue> details(
|
||||
options.DeepCopyWithoutEmptyChildren());
|
||||
|
||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Cookies::SetCookiesOnIOThread, base::Unretained(this),
|
||||
Passed(&details), gurl, callback));
|
||||
net::CookieMonster* monster = GetCookieStore(getter)->GetCookieMonster();
|
||||
// Empty url will match all url cookies.
|
||||
if (url.empty())
|
||||
monster->GetAllCookiesAsync(filtered_callback);
|
||||
else
|
||||
monster->GetAllCookiesForURLAsync(GURL(url), filtered_callback);
|
||||
}
|
||||
|
||||
void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
||||
const GURL& url,
|
||||
const CookiesCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
// Removes cookie with |url| and |name| in IO thread.
|
||||
void RemoveCookieOnIOThread(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
const GURL& url, const std::string& name,
|
||||
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 http_only = false;
|
||||
double expiration_date;
|
||||
|
||||
details->GetString("url", &url);
|
||||
details->GetString("name", &name);
|
||||
details->GetString("value", &value);
|
||||
details->GetString("domain", &domain);
|
||||
details->GetString("path", &path);
|
||||
details->GetBoolean("secure", &secure);
|
||||
details->GetBoolean("http_only", &http_only);
|
||||
details->GetBoolean("httpOnly", &http_only);
|
||||
|
||||
base::Time expiration_time;
|
||||
if (details->GetDouble("expirationDate", &expiration_date)) {
|
||||
|
@ -301,29 +178,44 @@ void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
|||
base::Time::FromDoubleT(expiration_date);
|
||||
}
|
||||
|
||||
GetCookieStore()->GetCookieMonster()->SetCookieWithDetailsAsync(
|
||||
url,
|
||||
name,
|
||||
value,
|
||||
domain,
|
||||
path,
|
||||
expiration_time,
|
||||
secure,
|
||||
http_only,
|
||||
false,
|
||||
net::COOKIE_PRIORITY_DEFAULT,
|
||||
base::Bind(&Cookies::OnSetCookies, base::Unretained(this), callback));
|
||||
GetCookieStore(getter)->GetCookieMonster()->SetCookieWithDetailsAsync(
|
||||
GURL(url), name, value, domain, path, expiration_time, secure, http_only,
|
||||
false, net::COOKIE_PRIORITY_DEFAULT, base::Bind(OnSetCookie, callback));
|
||||
}
|
||||
|
||||
void Cookies::OnSetCookies(const CookiesCallback& callback,
|
||||
bool set_success) {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&RunSetCookiesCallbackOnUIThread, isolate(), "", set_success,
|
||||
callback));
|
||||
} // namespace
|
||||
|
||||
Cookies::Cookies(content::BrowserContext* browser_context)
|
||||
: request_context_getter_(browser_context->GetRequestContext()) {
|
||||
}
|
||||
|
||||
net::CookieStore* Cookies::GetCookieStore() {
|
||||
return request_context_getter_->GetURLRequestContext()->cookie_store();
|
||||
Cookies::~Cookies() {
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -20,12 +20,7 @@ namespace content {
|
|||
class BrowserContext;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
class Dictionary;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class CookieStore;
|
||||
class URLRequestContextGetter;
|
||||
}
|
||||
|
||||
|
@ -35,9 +30,13 @@ namespace api {
|
|||
|
||||
class Cookies : public mate::TrackableObject<Cookies> {
|
||||
public:
|
||||
// node.js style callback function(error, result)
|
||||
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
|
||||
CookiesCallback;
|
||||
enum Error {
|
||||
SUCCESS,
|
||||
FAILED,
|
||||
};
|
||||
|
||||
using GetCallback = base::Callback<void(Error, const net::CookieList&)>;
|
||||
using SetCallback = base::Callback<void(Error)>;
|
||||
|
||||
static mate::Handle<Cookies> Create(v8::Isolate* isolate,
|
||||
content::BrowserContext* browser_context);
|
||||
|
@ -50,34 +49,12 @@ class Cookies : public mate::TrackableObject<Cookies> {
|
|||
explicit Cookies(content::BrowserContext* browser_context);
|
||||
~Cookies();
|
||||
|
||||
void Get(const base::DictionaryValue& options,
|
||||
const CookiesCallback& callback);
|
||||
void Remove(const mate::Dictionary& details,
|
||||
const CookiesCallback& 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);
|
||||
void Get(const base::DictionaryValue& filter, const GetCallback& callback);
|
||||
void Remove(const GURL& url, const std::string& name,
|
||||
const base::Closure& callback);
|
||||
void Set(const base::DictionaryValue& details, const SetCallback& callback);
|
||||
|
||||
private:
|
||||
// Must be called on IO thread.
|
||||
net::CookieStore* GetCookieStore();
|
||||
|
||||
net::URLRequestContextGetter* request_context_getter_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Cookies);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/atom_api_session.h"
|
||||
#include "atom/browser/api/atom_api_window.h"
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#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"
|
||||
|
@ -15,6 +17,21 @@
|
|||
|
||||
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 {
|
||||
|
@ -26,23 +43,38 @@ WebRequest::WebRequest(AtomBrowserContext* browser_context)
|
|||
WebRequest::~WebRequest() {
|
||||
}
|
||||
|
||||
template<AtomNetworkDelegate::EventTypes type>
|
||||
void WebRequest::SetListener(mate::Arguments* args) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
template<AtomNetworkDelegate::SimpleEvent type>
|
||||
void WebRequest::SetSimpleListener(mate::Arguments* args) {
|
||||
SetListener<AtomNetworkDelegate::SimpleListener>(
|
||||
&AtomNetworkDelegate::SetSimpleListenerInIO, type, args);
|
||||
}
|
||||
|
||||
scoped_ptr<base::DictionaryValue> filter(new base::DictionaryValue());
|
||||
args->GetNext(filter.get());
|
||||
AtomNetworkDelegate::Listener callback;
|
||||
if (!args->GetNext(&callback)) {
|
||||
args->ThrowError("Must pass null or a function");
|
||||
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(&AtomNetworkDelegate::SetListenerInIO,
|
||||
base::Unretained(delegate),
|
||||
type, base::Passed(&filter), callback));
|
||||
base::Bind(method, base::Unretained(delegate), type,
|
||||
patterns, listener));
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -57,28 +89,28 @@ void WebRequest::BuildPrototype(v8::Isolate* isolate,
|
|||
v8::Local<v8::ObjectTemplate> prototype) {
|
||||
mate::ObjectTemplateBuilder(isolate, prototype)
|
||||
.SetMethod("onBeforeRequest",
|
||||
&WebRequest::SetListener<
|
||||
&WebRequest::SetResponseListener<
|
||||
AtomNetworkDelegate::kOnBeforeRequest>)
|
||||
.SetMethod("onBeforeSendHeaders",
|
||||
&WebRequest::SetListener<
|
||||
&WebRequest::SetResponseListener<
|
||||
AtomNetworkDelegate::kOnBeforeSendHeaders>)
|
||||
.SetMethod("onSendHeaders",
|
||||
&WebRequest::SetListener<
|
||||
AtomNetworkDelegate::kOnSendHeaders>)
|
||||
.SetMethod("onHeadersReceived",
|
||||
&WebRequest::SetListener<
|
||||
&WebRequest::SetResponseListener<
|
||||
AtomNetworkDelegate::kOnHeadersReceived>)
|
||||
.SetMethod("onSendHeaders",
|
||||
&WebRequest::SetSimpleListener<
|
||||
AtomNetworkDelegate::kOnSendHeaders>)
|
||||
.SetMethod("onBeforeRedirect",
|
||||
&WebRequest::SetListener<
|
||||
&WebRequest::SetSimpleListener<
|
||||
AtomNetworkDelegate::kOnBeforeRedirect>)
|
||||
.SetMethod("onResponseStarted",
|
||||
&WebRequest::SetListener<
|
||||
&WebRequest::SetSimpleListener<
|
||||
AtomNetworkDelegate::kOnResponseStarted>)
|
||||
.SetMethod("onCompleted",
|
||||
&WebRequest::SetListener<
|
||||
&WebRequest::SetSimpleListener<
|
||||
AtomNetworkDelegate::kOnCompleted>)
|
||||
.SetMethod("onErrorOccurred",
|
||||
&WebRequest::SetListener<
|
||||
&WebRequest::SetSimpleListener<
|
||||
AtomNetworkDelegate::kOnErrorOccurred>);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#ifndef ATOM_BROWSER_API_ATOM_API_WEB_REQUEST_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_WEB_REQUEST_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/net/atom_network_delegate.h"
|
||||
#include "native_mate/arguments.h"
|
||||
|
@ -31,8 +29,13 @@ class WebRequest : public mate::TrackableObject<WebRequest> {
|
|||
explicit WebRequest(AtomBrowserContext* browser_context);
|
||||
~WebRequest();
|
||||
|
||||
template<AtomNetworkDelegate::EventTypes Event>
|
||||
void SetListener(mate::Arguments* args);
|
||||
// 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_;
|
||||
|
|
|
@ -6,6 +6,7 @@ PERSIST_PERFIX = 'persist:'
|
|||
|
||||
# Returns the Session from |partition| string.
|
||||
exports.fromPartition = (partition='') ->
|
||||
return exports.defaultSession if partition is ''
|
||||
if partition.startsWith PERSIST_PERFIX
|
||||
bindings.fromPartition partition.substr(PERSIST_PERFIX.length), false
|
||||
else
|
||||
|
@ -14,7 +15,7 @@ exports.fromPartition = (partition='') ->
|
|||
# Returns the default session.
|
||||
Object.defineProperty exports, 'defaultSession',
|
||||
enumerable: true
|
||||
get: -> exports.fromPartition 'persist:'
|
||||
get: -> bindings.fromPartition '', false
|
||||
|
||||
wrapSession = (session) ->
|
||||
# session is an EventEmitter.
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
#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"
|
||||
|
@ -15,7 +19,7 @@ namespace atom {
|
|||
|
||||
namespace {
|
||||
|
||||
std::string ResourceTypeToString(content::ResourceType type) {
|
||||
const char* ResourceTypeToString(content::ResourceType type) {
|
||||
switch (type) {
|
||||
case content::RESOURCE_TYPE_MAIN_FRAME:
|
||||
return "mainFrame";
|
||||
|
@ -36,98 +40,171 @@ std::string ResourceTypeToString(content::ResourceType type) {
|
|||
}
|
||||
}
|
||||
|
||||
AtomNetworkDelegate::BlockingResponse RunListener(
|
||||
const AtomNetworkDelegate::Listener& callback,
|
||||
scoped_ptr<base::DictionaryValue> details) {
|
||||
return callback.Run(*(details.get()));
|
||||
void RunSimpleListener(const AtomNetworkDelegate::SimpleListener& listener,
|
||||
scoped_ptr<base::DictionaryValue> details) {
|
||||
return listener.Run(*(details.get()));
|
||||
}
|
||||
|
||||
bool MatchesFilterCondition(
|
||||
net::URLRequest* request,
|
||||
const AtomNetworkDelegate::ListenerInfo& info) {
|
||||
if (!info.url_patterns.empty()) {
|
||||
auto url = request->url();
|
||||
for (auto& pattern : info.url_patterns)
|
||||
if (pattern.MatchesURL(url))
|
||||
return true;
|
||||
return false;
|
||||
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 true;
|
||||
return false;
|
||||
}
|
||||
|
||||
scoped_ptr<base::DictionaryValue> ExtractRequestInfo(net::URLRequest* request) {
|
||||
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
|
||||
dict->SetInteger("id", request->identifier());
|
||||
dict->SetString("url", request->url().spec());
|
||||
dict->SetString("method", request->method());
|
||||
content::ResourceType resourceType = content::RESOURCE_TYPE_LAST_TYPE;
|
||||
// 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);
|
||||
if (info)
|
||||
resourceType = info->GetResourceType();
|
||||
dict->SetString("resourceType", ResourceTypeToString(resourceType));
|
||||
dict->SetDouble("timestamp", base::Time::Now().ToDoubleT() * 1000);
|
||||
|
||||
return dict.Pass();
|
||||
details->SetString("resourceType",
|
||||
info ? ResourceTypeToString(info->GetResourceType())
|
||||
: "other");
|
||||
}
|
||||
|
||||
scoped_ptr<base::DictionaryValue> GetRequestHeadersDict(
|
||||
const net::HttpRequestHeaders& headers) {
|
||||
scoped_ptr<base::DictionaryValue> header_dict(new base::DictionaryValue());
|
||||
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())
|
||||
header_dict->SetString(it.name(), it.value());
|
||||
return header_dict.Pass();
|
||||
dict->SetString(it.name(), it.value());
|
||||
details->Set("requestHeaders", dict.Pass());
|
||||
}
|
||||
|
||||
scoped_ptr<base::DictionaryValue> GetResponseHeadersDict(
|
||||
const net::HttpResponseHeaders* headers) {
|
||||
scoped_ptr<base::DictionaryValue> header_dict(new base::DictionaryValue());
|
||||
if (headers) {
|
||||
void* iter = nullptr;
|
||||
std::string key;
|
||||
std::string value;
|
||||
while (headers->EnumerateHeaderLines(&iter, &key, &value))
|
||||
header_dict->SetString(key, value);
|
||||
}
|
||||
return header_dict.Pass();
|
||||
}
|
||||
void ToDictionary(base::DictionaryValue* details,
|
||||
const net::HttpResponseHeaders* headers) {
|
||||
if (!headers)
|
||||
return;
|
||||
|
||||
void OnBeforeURLRequestResponse(
|
||||
const net::CompletionCallback& callback,
|
||||
GURL* new_url,
|
||||
const AtomNetworkDelegate::BlockingResponse& result) {
|
||||
if (!result.redirect_url.is_empty())
|
||||
*new_url = result.redirect_url;
|
||||
callback.Run(result.Code());
|
||||
}
|
||||
|
||||
void OnBeforeSendHeadersResponse(
|
||||
const net::CompletionCallback& callback,
|
||||
net::HttpRequestHeaders* headers,
|
||||
const AtomNetworkDelegate::BlockingResponse& result) {
|
||||
if (!result.request_headers.IsEmpty())
|
||||
*headers = result.request_headers;
|
||||
callback.Run(result.Code());
|
||||
}
|
||||
|
||||
void OnHeadersReceivedResponse(
|
||||
const net::CompletionCallback& callback,
|
||||
const net::HttpResponseHeaders* original_response_headers,
|
||||
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
|
||||
const AtomNetworkDelegate::BlockingResponse& result) {
|
||||
if (result.response_headers.get()) {
|
||||
*override_response_headers = new net::HttpResponseHeaders(
|
||||
original_response_headers->raw_headers());
|
||||
void* iter = nullptr;
|
||||
std::string key;
|
||||
std::string value;
|
||||
while (result.response_headers->EnumerateHeaderLines(&iter, &key, &value)) {
|
||||
(*override_response_headers)->RemoveHeader(key);
|
||||
(*override_response_headers)->AddHeader(key + ": " + value);
|
||||
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());
|
||||
}
|
||||
}
|
||||
callback.Run(result.Code());
|
||||
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
|
||||
|
@ -138,256 +215,166 @@ AtomNetworkDelegate::AtomNetworkDelegate() {
|
|||
AtomNetworkDelegate::~AtomNetworkDelegate() {
|
||||
}
|
||||
|
||||
void AtomNetworkDelegate::SetListenerInIO(
|
||||
EventTypes type,
|
||||
scoped_ptr<base::DictionaryValue> filter,
|
||||
const Listener& callback) {
|
||||
if (callback.is_null()) {
|
||||
event_listener_map_.erase(type);
|
||||
return;
|
||||
}
|
||||
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 };
|
||||
}
|
||||
|
||||
ListenerInfo info;
|
||||
info.callback = callback;
|
||||
|
||||
const base::ListValue* url_list = nullptr;
|
||||
if (filter->GetList("urls", &url_list)) {
|
||||
for (size_t i = 0; i < url_list->GetSize(); ++i) {
|
||||
std::string url;
|
||||
extensions::URLPattern pattern;
|
||||
if (url_list->GetString(i, &url) &&
|
||||
pattern.Parse(url) == extensions::URLPattern::PARSE_SUCCESS) {
|
||||
info.url_patterns.insert(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event_listener_map_[type] = info;
|
||||
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) {
|
||||
auto listener_info = event_listener_map_.find(kOnBeforeRequest);
|
||||
if (listener_info != event_listener_map_.end()) {
|
||||
if (!MatchesFilterCondition(request, listener_info->second))
|
||||
return net::OK;
|
||||
if (!ContainsKey(response_listeners_, kOnBeforeRequest))
|
||||
return brightray::NetworkDelegate::OnBeforeURLRequest(
|
||||
request, callback, new_url);
|
||||
|
||||
auto wrapped_callback = listener_info->second.callback;
|
||||
auto details = ExtractRequestInfo(request);
|
||||
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&RunListener, wrapped_callback, base::Passed(&details)),
|
||||
base::Bind(&OnBeforeURLRequestResponse,
|
||||
callback, new_url));
|
||||
|
||||
return net::ERR_IO_PENDING;
|
||||
}
|
||||
|
||||
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) {
|
||||
auto listener_info = event_listener_map_.find(kOnBeforeSendHeaders);
|
||||
if (listener_info != event_listener_map_.end()) {
|
||||
if (!MatchesFilterCondition(request, listener_info->second))
|
||||
return net::OK;
|
||||
if (!ContainsKey(response_listeners_, kOnBeforeSendHeaders))
|
||||
return brightray::NetworkDelegate::OnBeforeSendHeaders(
|
||||
request, callback, headers);
|
||||
|
||||
auto wrapped_callback = listener_info->second.callback;
|
||||
auto details = ExtractRequestInfo(request);
|
||||
details->Set("requestHeaders", GetRequestHeadersDict(*headers).release());
|
||||
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&RunListener, wrapped_callback, base::Passed(&details)),
|
||||
base::Bind(&OnBeforeSendHeadersResponse,
|
||||
callback, headers));
|
||||
|
||||
return net::ERR_IO_PENDING;
|
||||
}
|
||||
|
||||
return brightray::NetworkDelegate::OnBeforeSendHeaders(request,
|
||||
callback,
|
||||
headers);
|
||||
return HandleResponseEvent(
|
||||
kOnBeforeSendHeaders, request, callback, headers, *headers);
|
||||
}
|
||||
|
||||
void AtomNetworkDelegate::OnSendHeaders(
|
||||
net::URLRequest* request,
|
||||
const net::HttpRequestHeaders& headers) {
|
||||
auto listener_info = event_listener_map_.find(kOnSendHeaders);
|
||||
if (listener_info != event_listener_map_.end()) {
|
||||
if (!MatchesFilterCondition(request, listener_info->second))
|
||||
return;
|
||||
|
||||
auto wrapped_callback = listener_info->second.callback;
|
||||
auto details = ExtractRequestInfo(request);
|
||||
details->Set("requestHeaders", GetRequestHeadersDict(headers).release());
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(base::IgnoreResult(&RunListener),
|
||||
wrapped_callback,
|
||||
base::Passed(&details)));
|
||||
} else {
|
||||
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_response_headers,
|
||||
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
|
||||
GURL* allowed_unsafe_redirect_url) {
|
||||
auto listener_info = event_listener_map_.find(kOnHeadersReceived);
|
||||
if (listener_info != event_listener_map_.end()) {
|
||||
if (!MatchesFilterCondition(request, listener_info->second))
|
||||
return net::OK;
|
||||
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);
|
||||
|
||||
auto wrapped_callback = listener_info->second.callback;
|
||||
auto details = ExtractRequestInfo(request);
|
||||
details->SetString("statusLine",
|
||||
original_response_headers->GetStatusLine());
|
||||
details->SetInteger("statusCode",
|
||||
original_response_headers->response_code());
|
||||
details->Set("responseHeaders",
|
||||
GetResponseHeadersDict(original_response_headers).release());
|
||||
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&RunListener, wrapped_callback, base::Passed(&details)),
|
||||
base::Bind(&OnHeadersReceivedResponse,
|
||||
callback,
|
||||
original_response_headers,
|
||||
override_response_headers));
|
||||
|
||||
return net::ERR_IO_PENDING;
|
||||
}
|
||||
|
||||
return brightray::NetworkDelegate::OnHeadersReceived(
|
||||
request, callback, original_response_headers, override_response_headers,
|
||||
allowed_unsafe_redirect_url);
|
||||
return HandleResponseEvent(
|
||||
kOnHeadersReceived, request, callback, override, original);
|
||||
}
|
||||
|
||||
void AtomNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
|
||||
const GURL& new_location) {
|
||||
auto listener_info = event_listener_map_.find(kOnBeforeRedirect);
|
||||
if (listener_info != event_listener_map_.end()) {
|
||||
if (!MatchesFilterCondition(request, listener_info->second))
|
||||
return;
|
||||
|
||||
auto wrapped_callback = listener_info->second.callback;
|
||||
auto details = ExtractRequestInfo(request);
|
||||
details->SetString("redirectURL", new_location.spec());
|
||||
details->SetInteger("statusCode", request->GetResponseCode());
|
||||
auto ip = request->GetSocketAddress().host();
|
||||
if (!ip.empty())
|
||||
details->SetString("ip", ip);
|
||||
details->SetBoolean("fromCache", request->was_cached());
|
||||
details->Set("responseHeaders",
|
||||
GetResponseHeadersDict(request->response_headers()).release());
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(base::IgnoreResult(&RunListener),
|
||||
wrapped_callback,
|
||||
base::Passed(&details)));
|
||||
} else {
|
||||
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) {
|
||||
auto listener_info = event_listener_map_.find(kOnResponseStarted);
|
||||
if (listener_info != event_listener_map_.end()) {
|
||||
if (request->status().status() != net::URLRequestStatus::SUCCESS)
|
||||
return;
|
||||
|
||||
if (!MatchesFilterCondition(request, listener_info->second))
|
||||
return;
|
||||
|
||||
auto wrapped_callback = listener_info->second.callback;
|
||||
auto details = ExtractRequestInfo(request);
|
||||
details->Set("responseHeaders",
|
||||
GetResponseHeadersDict(request->response_headers()).release());
|
||||
details->SetBoolean("fromCache", request->was_cached());
|
||||
|
||||
auto response_headers = request->response_headers();
|
||||
details->SetInteger("statusCode",
|
||||
response_headers ?
|
||||
response_headers->response_code() : 200);
|
||||
details->SetString("statusLine",
|
||||
response_headers ?
|
||||
response_headers->GetStatusLine() : std::string());
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(base::IgnoreResult(&RunListener),
|
||||
wrapped_callback,
|
||||
base::Passed(&details)));
|
||||
} else {
|
||||
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) {
|
||||
auto listener_info = event_listener_map_.find(kOnCompleted);
|
||||
if (listener_info != event_listener_map_.end()) {
|
||||
if (request->status().status() == net::URLRequestStatus::FAILED ||
|
||||
request->status().status() == net::URLRequestStatus::CANCELED) {
|
||||
if (request->status().status() == net::URLRequestStatus::FAILED ||
|
||||
request->status().status() == net::URLRequestStatus::CANCELED) {
|
||||
// Error event.
|
||||
if (ContainsKey(simple_listeners_, kOnErrorOccurred))
|
||||
OnErrorOccurred(request);
|
||||
return;
|
||||
} else {
|
||||
bool is_redirect = request->response_headers() &&
|
||||
net::HttpResponseHeaders::IsRedirectResponseCode(
|
||||
request->response_headers()->response_code());
|
||||
if (is_redirect)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MatchesFilterCondition(request, listener_info->second))
|
||||
return;
|
||||
|
||||
auto wrapped_callback = listener_info->second.callback;
|
||||
auto details = ExtractRequestInfo(request);
|
||||
details->Set("responseHeaders",
|
||||
GetResponseHeadersDict(request->response_headers()).release());
|
||||
details->SetBoolean("fromCache", request->was_cached());
|
||||
|
||||
auto response_headers = request->response_headers();
|
||||
details->SetInteger("statusCode",
|
||||
response_headers ?
|
||||
response_headers->response_code() : 200);
|
||||
details->SetString("statusLine",
|
||||
response_headers ?
|
||||
response_headers->GetStatusLine() : std::string());
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(base::IgnoreResult(&RunListener),
|
||||
wrapped_callback,
|
||||
base::Passed(&details)));
|
||||
} else {
|
||||
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) {
|
||||
auto listener_info = event_listener_map_.find(kOnErrorOccurred);
|
||||
if (listener_info != event_listener_map_.end()) {
|
||||
if (!MatchesFilterCondition(request, listener_info->second))
|
||||
return;
|
||||
HandleSimpleEvent(kOnErrorOccurred, request, request->was_cached(),
|
||||
request->status());
|
||||
}
|
||||
|
||||
auto wrapped_callback = listener_info->second.callback;
|
||||
auto details = ExtractRequestInfo(request);
|
||||
details->SetBoolean("fromCache", request->was_cached());
|
||||
details->SetString("error", net::ErrorToString(request->status().error()));
|
||||
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;
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(base::IgnoreResult(&RunListener),
|
||||
wrapped_callback,
|
||||
base::Passed(&details)));
|
||||
}
|
||||
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
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "brightray/browser/network_delegate.h"
|
||||
#include "base/callback.h"
|
||||
|
@ -23,53 +22,50 @@ class URLPattern;
|
|||
|
||||
namespace atom {
|
||||
|
||||
using URLPatterns = std::set<extensions::URLPattern>;
|
||||
|
||||
class AtomNetworkDelegate : public brightray::NetworkDelegate {
|
||||
public:
|
||||
struct BlockingResponse;
|
||||
using Listener =
|
||||
base::Callback<BlockingResponse(const base::DictionaryValue&)>;
|
||||
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 EventTypes {
|
||||
kInvalidEvent = 0,
|
||||
kOnBeforeRequest = 1 << 0,
|
||||
kOnBeforeSendHeaders = 1 << 1,
|
||||
kOnSendHeaders = 1 << 2,
|
||||
kOnHeadersReceived = 1 << 3,
|
||||
kOnBeforeRedirect = 1 << 4,
|
||||
kOnResponseStarted = 1 << 5,
|
||||
kOnCompleted = 1 << 6,
|
||||
kOnErrorOccurred = 1 << 7,
|
||||
enum SimpleEvent {
|
||||
kOnSendHeaders,
|
||||
kOnBeforeRedirect,
|
||||
kOnResponseStarted,
|
||||
kOnCompleted,
|
||||
kOnErrorOccurred,
|
||||
};
|
||||
|
||||
struct ListenerInfo {
|
||||
std::set<extensions::URLPattern> url_patterns;
|
||||
AtomNetworkDelegate::Listener callback;
|
||||
enum ResponseEvent {
|
||||
kOnBeforeRequest,
|
||||
kOnBeforeSendHeaders,
|
||||
kOnHeadersReceived,
|
||||
};
|
||||
|
||||
struct BlockingResponse {
|
||||
BlockingResponse() : cancel(false) {}
|
||||
~BlockingResponse() {}
|
||||
struct SimpleListenerInfo {
|
||||
URLPatterns url_patterns;
|
||||
SimpleListener listener;
|
||||
};
|
||||
|
||||
int Code() const {
|
||||
return cancel ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
|
||||
}
|
||||
|
||||
bool cancel;
|
||||
GURL redirect_url;
|
||||
net::HttpRequestHeaders request_headers;
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers;
|
||||
struct ResponseListenerInfo {
|
||||
URLPatterns url_patterns;
|
||||
ResponseListener listener;
|
||||
};
|
||||
|
||||
AtomNetworkDelegate();
|
||||
~AtomNetworkDelegate() override;
|
||||
|
||||
void SetListenerInIO(EventTypes type,
|
||||
scoped_ptr<base::DictionaryValue> filter,
|
||||
const Listener& callback);
|
||||
void SetSimpleListenerInIO(SimpleEvent type,
|
||||
const URLPatterns& patterns,
|
||||
const SimpleListener& callback);
|
||||
void SetResponseListenerInIO(ResponseEvent type,
|
||||
const URLPatterns& patterns,
|
||||
const ResponseListener& callback);
|
||||
|
||||
protected:
|
||||
void OnErrorOccurred(net::URLRequest* request);
|
||||
|
||||
// net::NetworkDelegate:
|
||||
int OnBeforeURLRequest(net::URLRequest* request,
|
||||
const net::CompletionCallback& callback,
|
||||
|
@ -90,8 +86,22 @@ class AtomNetworkDelegate : public brightray::NetworkDelegate {
|
|||
void OnResponseStarted(net::URLRequest* request) override;
|
||||
void OnCompleted(net::URLRequest* request, bool started) override;
|
||||
|
||||
void OnErrorOccurred(net::URLRequest* request);
|
||||
|
||||
private:
|
||||
std::map<EventTypes, ListenerInfo> event_listener_map_;
|
||||
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);
|
||||
};
|
||||
|
|
|
@ -82,38 +82,4 @@ v8::Local<v8::Value> Converter<scoped_refptr<net::X509Certificate>>::ToV8(
|
|||
return dict.GetHandle();
|
||||
}
|
||||
|
||||
// static
|
||||
bool Converter<atom::AtomNetworkDelegate::BlockingResponse>::FromV8(
|
||||
v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||
atom::AtomNetworkDelegate::BlockingResponse* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
if (!dict.Get("cancel", &(out->cancel)))
|
||||
return false;
|
||||
dict.Get("redirectURL", &(out->redirect_url));
|
||||
base::DictionaryValue request_headers;
|
||||
if (dict.Get("requestHeaders", &request_headers)) {
|
||||
for (base::DictionaryValue::Iterator it(request_headers);
|
||||
!it.IsAtEnd();
|
||||
it.Advance()) {
|
||||
std::string value;
|
||||
CHECK(it.value().GetAsString(&value));
|
||||
out->request_headers.SetHeader(it.key(), value);
|
||||
}
|
||||
}
|
||||
base::DictionaryValue response_headers;
|
||||
if (dict.Get("responseHeaders", &response_headers)) {
|
||||
out->response_headers = new net::HttpResponseHeaders("");
|
||||
for (base::DictionaryValue::Iterator it(response_headers);
|
||||
!it.IsAtEnd();
|
||||
it.Advance()) {
|
||||
std::string value;
|
||||
CHECK(it.value().GetAsString(&value));
|
||||
out->response_headers->AddHeader(it.key() + " : " + value);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_
|
||||
|
||||
#include "atom/browser/net/atom_network_delegate.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
|
@ -35,13 +34,6 @@ struct Converter<scoped_refptr<net::X509Certificate>> {
|
|||
const scoped_refptr<net::X509Certificate>& val);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<atom::AtomNetworkDelegate::BlockingResponse> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
atom::AtomNetworkDelegate::BlockingResponse* out);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_
|
||||
|
|
|
@ -12,7 +12,7 @@ const BrowserWindow = require('electron').BrowserWindow;
|
|||
var win = new BrowserWindow({ width: 800, height: 600 });
|
||||
win.loadURL("http://github.com");
|
||||
|
||||
var ses = win.webContents.session
|
||||
var ses = win.webContents.session;
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
@ -63,7 +63,7 @@ Emitted when Electron is about to download `item` in `webContents`.
|
|||
Calling `event.preventDefault()` will cancel the download.
|
||||
|
||||
```javascript
|
||||
session.on('will-download', function(event, item, webContents) {
|
||||
session.defaultSession.on('will-download', function(event, item, webContents) {
|
||||
event.preventDefault();
|
||||
require('request')(item.getURL(), function(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:
|
||||
|
||||
```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');
|
||||
|
||||
win.webContents.on('did-finish-load', function() {
|
||||
// Query all cookies.
|
||||
win.webContents.session.cookies.get({}, function(error, cookies) {
|
||||
if (error) throw 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);
|
||||
});
|
||||
// Set a cookie with the given cookie data;
|
||||
// may overwrite equivalent cookies if they exist.
|
||||
var cookie = { url : "http://www.github.com", name : "dummy_name", value : "dummy" };
|
||||
session.defaultSession.cookies.set(cookie, function(error) {
|
||||
if (error)
|
||||
console.error(error);
|
||||
});
|
||||
```
|
||||
|
||||
#### `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`.
|
||||
Empty implies retrieving cookies of all urls.
|
||||
* `name` String - Filters cookies by name
|
||||
* `domain` String - Retrieves cookies whose domains match or are subdomains of
|
||||
`domains`
|
||||
* `path` String - Retrieves cookies whose path matches `path`
|
||||
* `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:
|
||||
Sends a request to get all cookies matching `details`, `callback` will be called
|
||||
with `callback(error, cookies)` on complete.
|
||||
|
||||
`cookies` is an Array of `cookie` objects.
|
||||
|
||||
* `cookie` Object
|
||||
* `name` String - The name of the cookie.
|
||||
* `value` String - The value 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.
|
||||
* `secure` Boolean - Whether the cookie is marked as Secure (typically HTTPS).
|
||||
* `http_only` Boolean - Whether the cookie is marked as HttpOnly.
|
||||
* `secure` Boolean - Whether the cookie is marked as secure.
|
||||
* `httpOnly` Boolean - Whether the cookie is marked as HTTP only.
|
||||
* `session` Boolean - Whether the cookie is a session cookie or a persistent
|
||||
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
|
||||
cookies.
|
||||
|
||||
#### `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
|
||||
* `url` String - The URL associated with the cookie
|
||||
* `name` String - The name of cookie to remove
|
||||
* `callback` Function - function(error)
|
||||
* `error` Error
|
||||
* `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
|
||||
|
||||
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)`
|
||||
|
||||
|
@ -289,175 +282,194 @@ myWindow.webContents.session.setCertificateVerifyProc(function(hostname, cert, c
|
|||
|
||||
#### `ses.webRequest`
|
||||
|
||||
The `webRequest` api allows to intercept and modify contents of a request at various
|
||||
stages of its lifetime.
|
||||
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"]
|
||||
}
|
||||
};
|
||||
|
||||
myWindow.webContents.session.webRequest.onBeforeSendHeaders(filter, function(details) {
|
||||
session.defaultSession.webRequest.onBeforeSendHeaders(filter, function(details, callback) {
|
||||
details.requestHeaders['User-Agent'] = "MyAgent";
|
||||
return {cancel: false, requestHeaders: details.requestHeaders};
|
||||
})
|
||||
callback({cancel: false, requestHeaders: details.requestHeaders});
|
||||
});
|
||||
```
|
||||
|
||||
#### `ses.webRequest.onBeforeRequest([filter,] listener)`
|
||||
#### `ses.webRequest.onBeforeRequest([filter, ]listener)`
|
||||
|
||||
* `filter` Object
|
||||
* `urls` Array - A list of URLs or URL patterns. Request that cannot match any of the URLs
|
||||
will be filtered out.
|
||||
* `listener` Function
|
||||
* `details` Object
|
||||
* `id` String - Request id.
|
||||
* `url` String
|
||||
* `method` String
|
||||
* `resourceType` String
|
||||
* `timestamp` Double
|
||||
* `blockingResponse` Object
|
||||
* `cancel` Boolean - Whether to continue or block the request.
|
||||
* `redirectURL` String **optional** - The original request is prevented from being sent or
|
||||
completed, and is instead redirected to the given URL.
|
||||
|
||||
Fired when a request is about to occur. Should return a `blockingResponse`.
|
||||
The `listener` will be called with `listener(details, callback)` when a request
|
||||
is about to occur.
|
||||
|
||||
#### `ses.webRequest.onBeforeSendHeaders([filter,] listener)`
|
||||
* `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
|
||||
* `urls` Array - A list of URLs or URL patterns. Request that cannot match any of the URLs
|
||||
will be filtered out.
|
||||
* `listener` Function
|
||||
* `details` Object
|
||||
* `id` String - Request id.
|
||||
* `url` String
|
||||
* `method` String
|
||||
* `resourceType` String
|
||||
* `timestamp` Double
|
||||
* `requestHeaders` Object
|
||||
* `blockingResponse` Object
|
||||
* `cancel` Boolean - Whether to continue or block the request.
|
||||
* `requestHeaders` Object **optional** - When provided, request will be made with these
|
||||
headers.
|
||||
|
||||
Fired 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.
|
||||
Should return a `blockingResponse`.
|
||||
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.
|
||||
|
||||
#### `ses.webRequest.onSendHeaders([filter,] listener)`
|
||||
* `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
|
||||
* `urls` Array - A list of URLs or URL patterns. Request that cannot match any of the URLs
|
||||
will be filtered out.
|
||||
* `listener` Function
|
||||
* `details` Object
|
||||
* `id` String - Request id.
|
||||
* `url` String
|
||||
* `method` String
|
||||
* `resourceType` String
|
||||
* `timestamp` Double
|
||||
* `requestHeaders` Object
|
||||
|
||||
Fired 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.
|
||||
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
|
||||
* `urls` Array - A list of URLs or URL patterns. Request that cannot match any of the URLs
|
||||
will be filtered out.
|
||||
* `listener` Function
|
||||
* `details` Object
|
||||
* `id` String - Request id.
|
||||
* `url` String
|
||||
* `method` String
|
||||
* `resourceType` String
|
||||
* `timestamp` Double
|
||||
* `statusLine` String
|
||||
* `statusCode` Integer
|
||||
* `responseHeaders` Object
|
||||
* `blockingResponse` Object
|
||||
* `cancel` Boolean - Whether to continue or block the request.
|
||||
* `responseHeaders` Object **optional** - When provided, the server is assumed to have
|
||||
responded with these headers.
|
||||
|
||||
Fired when HTTP response headers of a request have been received. Should return a
|
||||
`blockingResponse`.
|
||||
The `listener` will be called with `listener(details, callback)` when HTTP
|
||||
response headers of a request have been received.
|
||||
|
||||
#### `ses.webRequest.onResponseStarted([filter,] listener)`
|
||||
* `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
|
||||
* `urls` Array - A list of URLs or URL patterns. Request that cannot match any of the URLs
|
||||
will be filtered out.
|
||||
* `listener` Function
|
||||
* `details` Object
|
||||
* `id` String - Request id.
|
||||
* `url` String
|
||||
* `method` String
|
||||
* `resourceType` String
|
||||
* `timestamp` Double
|
||||
* `responseHeaders` Object
|
||||
* `fromCache` Boolean
|
||||
* `statusCode` Integer
|
||||
* `statusLine` String
|
||||
|
||||
Fired when first byte of the response body is received. For HTTP requests, this means that the
|
||||
status line and response headers are available.
|
||||
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.
|
||||
|
||||
#### `ses.webRequest.onBeforeRedirect([filter,] listener)`
|
||||
* `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
|
||||
* `urls` Array - A list of URLs or URL patterns. Request that cannot match any of the URLs
|
||||
will be filtered out.
|
||||
* `listener` Function
|
||||
* `details` Object
|
||||
* `id` String - Request id.
|
||||
* `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
|
||||
|
||||
Fired when a server initiated redirect is about to occur.
|
||||
The `listener` will be called with `listener(details)` when a server initiated
|
||||
redirect is about to occur.
|
||||
|
||||
#### `ses.webRequest.onCompleted([filter,] listener)`
|
||||
* `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
|
||||
* `urls` Array - A list of URLs or URL patterns. Request that cannot match any of the URLs
|
||||
will be filtered out.
|
||||
* `listener` Function
|
||||
* `details` Object
|
||||
* `id` String - Request id.
|
||||
* `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
|
||||
|
||||
Fired when a request is completed.
|
||||
The `listener` will be called with `listener(details)` when a request is
|
||||
completed.
|
||||
|
||||
#### `ses.webRequest.onErrorOccurred([filter,] listener)`
|
||||
* `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
|
||||
* `urls` Array - A list of URLs or URL patterns. Request that cannot match any of the URLs
|
||||
will be filtered out.
|
||||
* `listener` Function
|
||||
* `details` Object
|
||||
* `id` String - Request id.
|
||||
* `url` String
|
||||
* `method` String
|
||||
* `resourceType` String
|
||||
* `timestamp` Double
|
||||
* `fromCache` Boolean - Indicates whether the response was fetched from disk cache.
|
||||
* `error` String - The error description.
|
||||
|
||||
Fired when an error occurs.
|
||||
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.
|
||||
|
|
|
@ -49,12 +49,11 @@ describe 'session module', ->
|
|||
it 'should remove cookies', (done) ->
|
||||
session.defaultSession.cookies.set {url: url, name: '2', value: '2'}, (error) ->
|
||||
return done(error) if error
|
||||
session.defaultSession.cookies.remove {url: url, name: '2'}, (error) ->
|
||||
return done(error) if error
|
||||
session.defaultSession.cookies.remove url, '2', ->
|
||||
session.defaultSession.cookies.get {url: url}, (error, list) ->
|
||||
return done(error) if error
|
||||
for cookie in list when cookie.name is '2'
|
||||
return done('Cookie not deleted')
|
||||
return done('Cookie not deleted')
|
||||
done()
|
||||
|
||||
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()
|
||||
w.loadURL url
|
||||
|
||||
describe 'navigator.webkitGetUserMedia', ->
|
||||
xdescribe 'navigator.webkitGetUserMedia', ->
|
||||
it 'calls its callbacks', (done) ->
|
||||
@timeout 5000
|
||||
navigator.webkitGetUserMedia audio: true, video: false,
|
||||
|
|
2
vendor/native_mate
vendored
2
vendor/native_mate
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 5e70868fd0c005dc2c43bea15ca6e93da0b68741
|
||||
Subproject commit a3dcf8ced663e974ac94ad5e50a1d25a43995a9d
|
Loading…
Reference in a new issue