Merge pull request #1981 from atom/cookies-api

Implement Cookies api
This commit is contained in:
Cheng Zhao 2015-06-23 10:04:42 +08:00
commit 19963bfcd1
9 changed files with 702 additions and 0 deletions

View file

@ -0,0 +1,351 @@
// 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_cookies.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 "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
#include "net/cookies/cookie_util.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "atom/common/node_includes.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(const std::string& error_message,
const net::CookieList& cookie_list,
const Cookies::CookiesCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (!error_message.empty()) {
v8::Local<v8::String> error = v8::String::NewFromUtf8(isolate,
error_message.c_str());
callback.Run(error, v8::Null(isolate));
return;
}
callback.Run(v8::Null(isolate), mate::ConvertToV8(isolate, cookie_list));
}
void RunRemoveCookiesCallbackOnUIThread(
const std::string& error_message,
const Cookies::CookiesCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (!error_message.empty()) {
v8::Local<v8::String> error = v8::String::NewFromUtf8(isolate,
error_message.c_str());
callback.Run(error, v8::Null(isolate));
return;
}
callback.Run(v8::Null(isolate), v8::Null(isolate));
}
void RunSetCookiesCallbackOnUIThread(const std::string& error_message,
bool set_success,
const Cookies::CookiesCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (!error_message.empty()) {
v8::Local<v8::String> error = v8::String::NewFromUtf8(isolate,
error_message.c_str());
callback.Run(error, v8::Null(isolate));
return;
}
if (!set_success) {
v8::Local<v8::String> error = v8::String::NewFromUtf8(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<net::CanonicalCookie> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const net::CanonicalCookie& val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
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("path", val.Path());
dict.Set("secure", val.IsSecure());
dict.Set("http_only", val.IsHttpOnly());
dict.Set("session", val.IsPersistent());
if (!val.IsPersistent())
dict.Set("expirationDate", val.ExpiryDate().ToDoubleT());
return dict.GetHandle();
}
};
} // namespace mate
namespace atom {
namespace api {
Cookies::Cookies(content::BrowserContext* browser_context) :
browser_context_(browser_context) {
}
Cookies::~Cookies() {
}
void Cookies::Get(const base::DictionaryValue& options,
const CookiesCallback& callback) {
scoped_ptr<base::DictionaryValue> filter(
options.DeepCopyWithoutEmptyChildren());
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) {
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
->GetURLRequestContext()->cookie_store();
std::string url;
filter->GetString("url", &url);
if (!GetCookieListFromStore(cookie_store, url,
base::Bind(&Cookies::OnGetCookies, base::Unretained(this),
Passed(&filter), callback))) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&RunGetCookiesCallbackOnUIThread, "Url is not valid",
net::CookieList(), callback));
}
}
void Cookies::OnGetCookies(scoped_ptr<base::DictionaryValue> filter,
const CookiesCallback& callback,
const net::CookieList& cookie_list) {
net::CookieList result;
for (const auto& cookie : cookie_list) {
if (MatchesCookie(filter.get(), cookie))
result.push_back(cookie);
}
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
&RunGetCookiesCallbackOnUIThread, "", result, callback));
}
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(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) {
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
->GetURLRequestContext()->cookie_store();
cookie_store->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, "", callback));
}
void Cookies::Set(const base::DictionaryValue& options,
const CookiesCallback& callback) {
std::string url;
std::string error_message;
if (!options.GetString("url", &url)) {
error_message = "The url field is required.";
}
GURL gurl(url);
if (error_message.empty() && !gurl.is_valid()) {
error_message = "Url is not valid.";
}
if (!error_message.empty()) {
RunSetCookiesCallbackOnUIThread(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));
}
void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
const GURL& url,
const CookiesCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
->GetURLRequestContext()->cookie_store();
std::string name, value, domain, path;
bool secure = false;
bool http_only = false;
double expiration_date;
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);
base::Time expiration_time;
if (details->GetDouble("expirationDate", &expiration_date)) {
expiration_time = (expiration_date == 0) ?
base::Time::UnixEpoch() :
base::Time::FromDoubleT(expiration_date);
}
cookie_store->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));
}
void Cookies::OnSetCookies(const CookiesCallback& callback,
bool set_success) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&RunSetCookiesCallbackOnUIThread, "", set_success, callback));
}
mate::ObjectTemplateBuilder Cookies::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("get", &Cookies::Get)
.SetMethod("remove", &Cookies::Remove)
.SetMethod("set", &Cookies::Set);
}
// static
mate::Handle<Cookies> Cookies::Create(
v8::Isolate* isolate,
content::BrowserContext* browser_context) {
return CreateHandle(isolate, new Cookies(browser_context));
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,78 @@
// 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_COOKIES_H_
#define ATOM_BROWSER_API_ATOM_API_COOKIES_H_
#include <string>
#include "base/callback.h"
#include "base/values.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h"
#include "native_mate/dictionary.h"
#include "net/cookies/canonical_cookie.h"
namespace content {
class BrowserContext;
}
namespace atom {
namespace api {
class Cookies : public mate::Wrappable {
public:
// node.js style callback function(error, result)
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
CookiesCallback;
static mate::Handle<Cookies> Create(v8::Isolate* isolate,
content::BrowserContext* browser_context);
protected:
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);
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
content::BrowserContext* browser_context_;
DISALLOW_COPY_AND_ASSIGN(Cookies);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_COOKIES_H_

View file

@ -0,0 +1,49 @@
// 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_session.h"
#include "atom/browser/api/atom_api_cookies.h"
#include "content/public/browser/browser_context.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace api {
Session::Session(content::BrowserContext* browser_context):
browser_context_(browser_context) {
}
Session::~Session() {
}
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
if (cookies_.IsEmpty()) {
auto handle = atom::api::Cookies::Create(isolate, browser_context_);
cookies_.Reset(isolate, handle.ToV8());
}
return v8::Local<v8::Value>::New(isolate, cookies_);
}
mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetProperty("cookies", &Session::Cookies);
}
// static
mate::Handle<Session> Session::Create(
v8::Isolate* isolate,
content::BrowserContext* browser_context) {
return CreateHandle(isolate, new Session(browser_context));
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,47 @@
// 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_SESSION_H_
#define ATOM_BROWSER_API_ATOM_API_SESSION_H_
#include "native_mate/handle.h"
#include "native_mate/wrappable.h"
namespace content {
class BrowserContext;
}
namespace atom {
namespace api {
class Session: public mate::Wrappable {
public:
static mate::Handle<Session> Create(v8::Isolate* isolate,
content::BrowserContext* browser_context);
protected:
explicit Session(content::BrowserContext* browser_context);
~Session();
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
v8::Global<v8::Value> cookies_;
// The webContents which owns the Sesssion.
content::BrowserContext* browser_context_;
DISALLOW_COPY_AND_ASSIGN(Session);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_SESSION_H_

View file

@ -6,6 +6,7 @@
#include <set> #include <set>
#include "atom/browser/api/atom_api_session.h"
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.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"
@ -584,6 +585,14 @@ void WebContents::InspectServiceWorker() {
} }
} }
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
if (session_.IsEmpty()) {
auto handle = Session::Create(isolate, web_contents()->GetBrowserContext());
session_.Reset(isolate, handle.ToV8());
}
return v8::Local<v8::Value>::New(isolate, session_);
}
void WebContents::HasServiceWorker( void WebContents::HasServiceWorker(
const base::Callback<void(bool)>& callback) { const base::Callback<void(bool)>& callback) {
auto context = GetServiceWorkerContext(web_contents()); auto context = GetServiceWorkerContext(web_contents());
@ -804,6 +813,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker) .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("print", &WebContents::Print) .SetMethod("print", &WebContents::Print)
.SetMethod("_printToPDF", &WebContents::PrintToPDF) .SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetProperty("session", &WebContents::Session)
.Build()); .Build());
return mate::ObjectTemplateBuilder( return mate::ObjectTemplateBuilder(

View file

@ -89,6 +89,7 @@ class WebContents : public mate::EventEmitter,
void ToggleDevTools(); void ToggleDevTools();
void InspectElement(int x, int y); void InspectElement(int x, int y);
void InspectServiceWorker(); void InspectServiceWorker();
v8::Local<v8::Value> Session(v8::Isolate* isolate);
void HasServiceWorker(const base::Callback<void(bool)>&); void HasServiceWorker(const base::Callback<void(bool)>&);
void UnregisterServiceWorker(const base::Callback<void(bool)>&); void UnregisterServiceWorker(const base::Callback<void(bool)>&);
void SetAudioMuted(bool muted); void SetAudioMuted(bool muted);
@ -239,6 +240,9 @@ class WebContents : public mate::EventEmitter,
// Returns the default size of the guestview. // Returns the default size of the guestview.
gfx::Size GetDefaultSize() const; gfx::Size GetDefaultSize() const;
v8::Global<v8::Value> session_;
// Stores whether the contents of the guest can be transparent. // Stores whether the contents of the guest can be transparent.
bool guest_opaque_; bool guest_opaque_;

View file

@ -1024,3 +1024,90 @@ app.on('ready', function() {
is different from the handlers on the main process. is different from the handlers on the main process.
2. There is no way to send synchronous messages from the main process to a 2. There is no way to send synchronous messages from the main process to a
renderer process, because it would be very easy to cause dead locks. renderer process, because it would be very easy to cause dead locks.
## Class: WebContents.session.cookies
The `cookies` gives you ability to query and modify cookies, an example is:
```javascipt
var BrowserWindow = require('browser-window');
var win = new BrowserWindow({ width: 800, height: 600 });
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 that are 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);
});
});
```
### WebContents.session.cookies.get(details, callback)
* `details` Object
* `url` String - Retrieves cookies which are associated with `url`.
Empty imples 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.
* `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
* `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
* `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
the number of seconds since the UNIX epoch. Not provided for session cookies.
### WebContents.session.cookies.set(details, callback)
* `details` Object
* `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
### WebContents.session.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

View file

@ -69,6 +69,8 @@
'atom/browser/api/atom_api_auto_updater.cc', 'atom/browser/api/atom_api_auto_updater.cc',
'atom/browser/api/atom_api_auto_updater.h', 'atom/browser/api/atom_api_auto_updater.h',
'atom/browser/api/atom_api_content_tracing.cc', 'atom/browser/api/atom_api_content_tracing.cc',
'atom/browser/api/atom_api_cookies.cc',
'atom/browser/api/atom_api_cookies.h',
'atom/browser/api/atom_api_dialog.cc', 'atom/browser/api/atom_api_dialog.cc',
'atom/browser/api/atom_api_global_shortcut.cc', 'atom/browser/api/atom_api_global_shortcut.cc',
'atom/browser/api/atom_api_global_shortcut.h', 'atom/browser/api/atom_api_global_shortcut.h',
@ -84,6 +86,8 @@
'atom/browser/api/atom_api_protocol.h', 'atom/browser/api/atom_api_protocol.h',
'atom/browser/api/atom_api_screen.cc', 'atom/browser/api/atom_api_screen.cc',
'atom/browser/api/atom_api_screen.h', 'atom/browser/api/atom_api_screen.h',
'atom/browser/api/atom_api_session.cc',
'atom/browser/api/atom_api_session.h',
'atom/browser/api/atom_api_tray.cc', 'atom/browser/api/atom_api_tray.cc',
'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',

View file

@ -0,0 +1,72 @@
assert = require 'assert'
remote = require 'remote'
http = require 'http'
path = require 'path'
BrowserWindow = remote.require 'browser-window'
describe 'cookies module', ->
fixtures = path.resolve __dirname, 'fixtures'
w = null
url = "http://127.0.0.1"
beforeEach -> w = new BrowserWindow(show: true)
afterEach -> w.destroy()
it 'should get cookies', (done) ->
server = http.createServer (req, res) ->
console.log req
res.setHeader('Set-Cookie', ['type=dummy'])
res.end('finished')
server.close()
port = remote.process.port
server.listen port, '127.0.0.1', ->
{port} = server.address()
w.loadUrl "#{url}:#{port}"
w.webContents.on 'did-finish-load', ()->
w.webContents.session.cookies.get {url: url}, (error, cookies) ->
throw error if error
assert.equal 1, cookies.length
assert.equal 'type', cookies[0].name
assert.equal 'dummy', cookies[0].value
done()
it 'should overwrite the existent cookie', (done) ->
w.loadUrl 'file://' + path.join(fixtures, 'page', 'a.html')
w.webContents.on 'did-finish-load', ()->
w.webContents.session.cookies.set {url: url, name: 'type', value: 'dummy2'}, (error) ->
throw error if error
w.webContents.session.cookies.get {url: url}, (error, cookies_list) ->
throw error if error
assert.equal 1, cookies_list.length
assert.equal 'type', cookies_list[0].name
assert.equal 'dummy2', cookies_list[0].value
done()
it 'should set new cookie', (done) ->
w.loadUrl 'file://' + path.join(fixtures, 'page', 'a.html')
w.webContents.on 'did-finish-load', ()->
w.webContents.session.cookies.set {url: url, name: 'key', value: 'dummy2'}, (error) ->
throw error if error
w.webContents.session.cookies.get {url: url}, (error, cookies_list) ->
throw error if error
assert.equal 2, cookies_list.length
for cookie in cookies_list
if cookie.name is 'key'
assert.equal 'dummy2', cookie.value
done();
it 'should remove cookies', (done) ->
w.loadUrl 'file://' + path.join(fixtures, 'page', 'a.html')
w.webContents.on 'did-finish-load', ()->
w.webContents.session.cookies.get {url: url}, (error, cookies_list) ->
count = 0
for cookie in cookies_list
w.webContents.session.cookies.remove {url: url, name: cookie.name}, (error) ->
throw error if error
++count
if count == cookies_list.length
w.webContents.session.cookies.get {url: url}, (error, cookies_list) ->
throw error if error
assert.equal 0, cookies_list.length
done()