Skip to content

Commit 2ee8b6d

Browse files
committed
implement Window.cookies.get
1 parent 1ba4c5a commit 2ee8b6d

File tree

4 files changed

+165
-20
lines changed

4 files changed

+165
-20
lines changed

src/api/app/app.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class Shell;
3535
}
3636

3737
namespace api {
38-
38+
3939
class App {
4040
public:
4141
static void Call(const std::string& method,
@@ -60,9 +60,9 @@ class App {
6060
static void EmitReopenEvent();
6161

6262
static void ClearCache(content::RenderProcessHost* render_view_host);
63+
6364
private:
6465
App();
65-
6666
DISALLOW_COPY_AND_ASSIGN(App);
6767
};
6868

src/api/window/window.cc

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,39 @@
2121
#include "content/nw/src/api/window/window.h"
2222

2323
#include "base/values.h"
24+
#include "base/strings/utf_string_conversions.h"
2425
#include "content/nw/src/api/dispatcher_host.h"
2526
#include "content/nw/src/api/menu/menu.h"
2627
#include "content/nw/src/browser/native_window.h"
2728
#include "content/nw/src/nw_shell.h"
29+
#include "content/nw/src/shell_browser_context.h"
30+
#include "content/public/browser/browser_thread.h"
31+
#include "content/public/browser/render_view_host.h"
32+
#include "net/cookies/canonical_cookie.h"
33+
#include "net/cookies/cookie_constants.h"
34+
#include "net/cookies/cookie_monster.h"
35+
#include "net/cookies/cookie_util.h"
36+
#include "net/url_request/url_request_context.h"
37+
#include "url/gurl.h"
38+
39+
using content::BrowserThread;
40+
41+
namespace {
42+
43+
void GetCookieListFromStore(
44+
net::CookieStore* cookie_store, const GURL& url,
45+
const net::CookieMonster::GetCookieListCallback& callback) {
46+
DCHECK(cookie_store);
47+
net::CookieMonster* monster = cookie_store->GetCookieMonster();
48+
if (!url.is_empty()) {
49+
DCHECK(url.is_valid());
50+
monster->GetAllCookiesForURLAsync(url, callback);
51+
} else {
52+
monster->GetAllCookiesAsync(callback);
53+
}
54+
}
55+
56+
} // namespace
2857

2958
namespace api {
3059

@@ -130,6 +159,8 @@ void Window::Call(const std::string& method,
130159
std::string image_format_str;
131160
if (arguments.GetString(0, &image_format_str))
132161
shell_->window()->CapturePage(image_format_str);
162+
} else if (method == "CookieGet") {
163+
CookieGet(arguments);
133164
} else {
134165
NOTREACHED() << "Invalid call to Window method:" << method
135166
<< " arguments:" << arguments;
@@ -159,4 +190,87 @@ void Window::CallSync(const std::string& method,
159190
}
160191
}
161192

193+
194+
void Window::CookieGet(const base::ListValue& arguments) {
195+
content::RenderProcessHost* render_process_host =
196+
dispatcher_host()->render_view_host()->GetProcess();
197+
net::URLRequestContextGetter* context_getter =
198+
render_process_host->GetBrowserContext()->
199+
GetRequestContextForRenderProcess(render_process_host->GetID());
200+
201+
const base::DictionaryValue* details = NULL;
202+
std::string url;
203+
204+
store_context_ = context_getter;
205+
if (details) {
206+
details_.reset(details->DeepCopyWithoutEmptyChildren());
207+
details->GetString("url", &url);
208+
}
209+
url_ = GURL(url);
210+
211+
bool rv = BrowserThread::PostTask(
212+
BrowserThread::IO, FROM_HERE,
213+
base::Bind(&Window::GetCookieOnIOThread, base::Unretained(this)));
214+
DCHECK(rv);
215+
}
216+
217+
void Window::GetCookieOnIOThread() {
218+
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
219+
net::CookieStore* cookie_store =
220+
store_context_->GetURLRequestContext()->cookie_store();
221+
GetCookieListFromStore(
222+
cookie_store, url_,
223+
base::Bind(&Window::GetCookieCallback, base::Unretained(this)));
224+
}
225+
226+
void Window::GetCookieCallback(const net::CookieList& cookie_list) {
227+
net::CookieList::const_iterator it;
228+
std::string name;
229+
details_->GetString("name", &name);
230+
231+
if (!result_)
232+
result_.reset(new base::DictionaryValue);
233+
result_->Clear();
234+
235+
for (it = cookie_list.begin(); it != cookie_list.end(); ++it) {
236+
// Return the first matching cookie. Relies on the fact that the
237+
// CookieMonster returns them in canonical order (longest path, then
238+
// earliest creation time).
239+
240+
if (it->Name() == name) {
241+
const net::CanonicalCookie& canonical_cookie = *it;
242+
// A cookie is a raw byte sequence. By explicitly parsing it as UTF-8, we
243+
// apply error correction, so the string can be safely passed to the renderer.
244+
result_->SetString("name", UTF16ToUTF8(UTF8ToUTF16(canonical_cookie.Name())));
245+
result_->SetString("value", UTF16ToUTF8(UTF8ToUTF16(canonical_cookie.Value())));
246+
result_->SetString("domain", canonical_cookie.Domain());
247+
result_->SetBoolean("host_only", net::cookie_util::DomainIsHostOnly(
248+
canonical_cookie.Domain()));
249+
// A non-UTF8 path is invalid, so we just replace it with an empty string.
250+
result_->SetString("path", IsStringUTF8(canonical_cookie.Path()) ? canonical_cookie.Path()
251+
: std::string());
252+
result_->SetBoolean("secure", canonical_cookie.IsSecure());
253+
result_->SetBoolean("http_only", canonical_cookie.IsHttpOnly());
254+
result_->SetBoolean("session", !canonical_cookie.IsPersistent());
255+
if (canonical_cookie.IsPersistent()) {
256+
result_->SetDouble("expiration_date",
257+
canonical_cookie.ExpiryDate().ToDoubleT());
258+
}
259+
break;
260+
}
261+
}
262+
263+
bool rv = BrowserThread::PostTask(
264+
BrowserThread::UI, FROM_HERE,
265+
base::Bind(&Window::RespondOnUIThread, base::Unretained(this)));
266+
DCHECK(rv);
267+
}
268+
269+
void Window::RespondOnUIThread() {
270+
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271+
base::ListValue args;
272+
args.Append(result_.release());
273+
dispatcher_host()->SendEvent(this, "__nw_gotcookie", args);
274+
}
275+
162276
} // namespace api

src/api/window/window.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@
2222
#define CONTENT_NW_SRC_API_WINDOW_WINDOW_H_
2323

2424
#include "base/compiler_specific.h"
25+
#include "base/values.h"
2526
#include "content/nw/src/api/base/base.h"
27+
#include "content/public/browser/render_process_host.h"
28+
#include "net/cookies/canonical_cookie.h"
29+
#include "net/url_request/url_request_context_getter.h"
30+
#include "url/gurl.h"
31+
2632

2733
namespace content {
2834
class Shell;
@@ -42,8 +48,19 @@ class Window : public Base {
4248
virtual void CallSync(const std::string& method,
4349
const base::ListValue& arguments,
4450
base::ListValue* result) OVERRIDE;
51+
52+
void CookieGet(const base::ListValue& arguments);
53+
void GetCookieOnIOThread();
54+
void GetCookieCallback(const net::CookieList& cookie_list);
55+
void RespondOnUIThread();
56+
4557
private:
58+
4659
content::Shell* shell_;
60+
net::URLRequestContextGetter* store_context_;
61+
scoped_ptr<base::DictionaryValue> details_;
62+
scoped_ptr<base::DictionaryValue> result_;
63+
GURL url_;
4764

4865
DISALLOW_COPY_AND_ASSIGN(Window);
4966
};

src/api/window_bindings.js

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
function Window(routing_id, nobind) {
2-
// Get and set id.
3-
var id = global.__nwObjectsRegistry.allocateId();
4-
Object.defineProperty(this, 'id', {
5-
value: id,
6-
writable: false
7-
});
8-
9-
// Store routing id (need for IPC since we are in node's context).
10-
this.routing_id = routing_id;
11-
12-
// Store myself in node's context.
13-
global.__nwWindowsStore[id] = this;
14-
global.__nwObjectsRegistry.set(id, this);
2+
// Get and set id.
3+
native function CallObjectMethod();
4+
native function CallObjectMethodSync();
5+
var id = global.__nwObjectsRegistry.allocateId();
6+
Object.defineProperty(this, 'id', {
7+
value: id,
8+
writable: false
9+
});
1510

16-
// Tell Shell I'm the js delegate of it.
17-
native function BindToShell();
18-
if (!nobind)
19-
BindToShell(this.routing_id, this.id);
11+
// Store routing id (need for IPC since we are in node's context).
12+
this.routing_id = routing_id;
13+
14+
// Store myself in node's context.
15+
global.__nwWindowsStore[id] = this;
16+
global.__nwObjectsRegistry.set(id, this);
17+
18+
// Tell Shell I'm the js delegate of it.
19+
native function BindToShell();
20+
if (!nobind)
21+
BindToShell(this.routing_id, this.id);
22+
23+
var that = this;
24+
this.cookies = {
25+
get : function(details, cb) {
26+
CallObjectMethod(that, 'CookieGet', [ details ]);
27+
if (typeof cb == 'function') {
28+
that.once('__nw_gotcookie', function(cookie) {
29+
cb(cookie);
30+
});
31+
}
32+
}
33+
}
2034
}
2135

2236
// Window will inherit EventEmitter in "third_party/node/src/node.js", do
@@ -52,7 +66,7 @@ Window.prototype.handleEvent = function(ev) {
5266
for (var i = 0; i < listeners_copy.length; ++i) {
5367
var original_closure = v8_util.getCreationContext(listeners_copy[i]);
5468

55-
// Skip for node context.
69+
// Skip for node context.
5670
if (v8_util.getConstructorName(original_closure) != 'Window')
5771
continue;
5872

0 commit comments

Comments
 (0)