Run Tizen Webapps in single process mode
[platform/framework/web/crosswalk-tizen.git] / atom / browser / api / atom_api_session.cc
1 // Copyright (c) 2015 GitHub, Inc.
2 // Use of this source code is governed by the MIT license that can be
3 // found in the LICENSE file.
4
5 #include "atom/browser/api/atom_api_session.h"
6
7 #include <map>
8 #include <string>
9 #include <vector>
10
11 #include "atom/browser/api/atom_api_cookies.h"
12 #include "atom/browser/api/atom_api_download_item.h"
13 #include "atom/browser/api/atom_api_protocol.h"
14 #include "atom/browser/api/atom_api_web_request.h"
15 #include "atom/browser/atom_browser_context.h"
16 #include "atom/browser/atom_browser_main_parts.h"
17 #include "atom/browser/atom_permission_manager.h"
18 #include "atom/browser/browser.h"
19 #include "atom/browser/net/atom_cert_verifier.h"
20 #include "atom/common/native_mate_converters/callback.h"
21 #include "atom/common/native_mate_converters/content_converter.h"
22 #include "atom/common/native_mate_converters/file_path_converter.h"
23 #include "atom/common/native_mate_converters/gurl_converter.h"
24 #include "atom/common/native_mate_converters/net_converter.h"
25 #include "atom/common/native_mate_converters/value_converter.h"
26 #include "atom/common/node_includes.h"
27 #include "base/files/file_path.h"
28 #include "base/guid.h"
29 #include "base/strings/string_number_conversions.h"
30 #include "base/strings/string_util.h"
31 #include "base/threading/thread_task_runner_handle.h"
32 #include "brightray/browser/media/media_device_id_salt.h"
33 #include "brightray/browser/net/devtools_network_conditions.h"
34 #include "brightray/browser/net/devtools_network_controller_handle.h"
35 #include "chrome/common/pref_names.h"
36 #include "components/prefs/pref_service.h"
37 #include "content/public/browser/browser_thread.h"
38 #include "content/public/browser/download_manager_delegate.h"
39 #include "content/public/browser/storage_partition.h"
40 #include "native_mate/dictionary.h"
41 #include "native_mate/object_template_builder.h"
42 #include "net/base/load_flags.h"
43 #include "net/disk_cache/disk_cache.h"
44 #include "net/dns/host_cache.h"
45 #include "net/http/http_auth_handler_factory.h"
46 #include "net/http/http_auth_preferences.h"
47 #include "net/proxy/proxy_config_service_fixed.h"
48 #include "net/proxy/proxy_service.h"
49 #include "net/url_request/static_http_user_agent_settings.h"
50 #include "net/url_request/url_request_context.h"
51 #include "net/url_request/url_request_context_getter.h"
52 #include "tizen/common/env_variables.h"
53 #include "ui/base/l10n/l10n_util.h"
54
55 using atom::api::Cookies;
56 using content::BrowserThread;
57 using content::StoragePartition;
58
59 namespace {
60
61 struct ClearStorageDataOptions {
62   GURL origin;
63   uint32_t storage_types = StoragePartition::REMOVE_DATA_MASK_ALL;
64   uint32_t quota_types = StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL;
65 };
66
67 struct ClearAuthCacheOptions {
68   std::string type;
69   GURL origin;
70   std::string realm;
71   base::string16 username;
72   base::string16 password;
73   net::HttpAuth::Scheme auth_scheme;
74 };
75
76 uint32_t GetStorageMask(const std::vector<std::string>& storage_types) {
77   uint32_t storage_mask = 0;
78   for (const auto& it : storage_types) {
79     auto type = base::ToLowerASCII(it);
80     if (type == "appcache")
81       storage_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE;
82     else if (type == "cookies")
83       storage_mask |= StoragePartition::REMOVE_DATA_MASK_COOKIES;
84     else if (type == "filesystem")
85       storage_mask |= StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
86     else if (type == "indexdb")
87       storage_mask |= StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
88     else if (type == "localstorage")
89       storage_mask |= StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
90     else if (type == "shadercache")
91       storage_mask |= StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE;
92     else if (type == "websql")
93       storage_mask |= StoragePartition::REMOVE_DATA_MASK_WEBSQL;
94     else if (type == "serviceworkers")
95       storage_mask |= StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS;
96   }
97   return storage_mask;
98 }
99
100 uint32_t GetQuotaMask(const std::vector<std::string>& quota_types) {
101   uint32_t quota_mask = 0;
102   for (const auto& it : quota_types) {
103     auto type = base::ToLowerASCII(it);
104     if (type == "temporary")
105       quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY;
106     else if (type == "persistent")
107       quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT;
108     else if (type == "syncable")
109       quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_SYNCABLE;
110   }
111   return quota_mask;
112 }
113
114 net::HttpAuth::Scheme GetAuthSchemeFromString(const std::string& scheme) {
115   if (scheme == "basic")
116     return net::HttpAuth::AUTH_SCHEME_BASIC;
117   if (scheme == "digest")
118     return net::HttpAuth::AUTH_SCHEME_DIGEST;
119   if (scheme == "ntlm")
120     return net::HttpAuth::AUTH_SCHEME_NTLM;
121   if (scheme == "negotiate")
122     return net::HttpAuth::AUTH_SCHEME_NEGOTIATE;
123   return net::HttpAuth::AUTH_SCHEME_MAX;
124 }
125
126 void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
127                       const std::string& accept_lang,
128                       const std::string& user_agent) {
129   getter->GetURLRequestContext()->set_http_user_agent_settings(
130       new net::StaticHttpUserAgentSettings(
131           net::HttpUtil::GenerateAcceptLanguageHeader(accept_lang),
132           user_agent));
133 }
134
135 }  // namespace
136
137 namespace mate {
138
139 template<>
140 struct Converter<ClearStorageDataOptions> {
141   static bool FromV8(v8::Isolate* isolate,
142                      v8::Local<v8::Value> val,
143                      ClearStorageDataOptions* out) {
144     mate::Dictionary options;
145     if (!ConvertFromV8(isolate, val, &options))
146       return false;
147     options.Get("origin", &out->origin);
148     std::vector<std::string> types;
149     if (options.Get("storages", &types))
150       out->storage_types = GetStorageMask(types);
151     if (options.Get("quotas", &types))
152       out->quota_types = GetQuotaMask(types);
153     return true;
154   }
155 };
156
157 template <>
158 struct Converter<ClearAuthCacheOptions> {
159   static bool FromV8(v8::Isolate* isolate,
160                      v8::Local<v8::Value> val,
161                      ClearAuthCacheOptions* out) {
162     mate::Dictionary options;
163     if (!ConvertFromV8(isolate, val, &options))
164       return false;
165     options.Get("type", &out->type);
166     options.Get("origin", &out->origin);
167     options.Get("realm", &out->realm);
168     options.Get("username", &out->username);
169     options.Get("password", &out->password);
170     std::string scheme;
171     if (options.Get("scheme", &scheme))
172       out->auth_scheme = GetAuthSchemeFromString(scheme);
173     return true;
174   }
175 };
176
177 template <>
178 struct Converter<net::ProxyConfig> {
179   static bool FromV8(v8::Isolate* isolate,
180                      v8::Local<v8::Value> val,
181                      net::ProxyConfig* out) {
182     std::string proxy_rules, proxy_bypass_rules;
183     GURL pac_url;
184     mate::Dictionary options;
185     // Fallback to previous API when passed String.
186     // https://git.io/vuhjj
187     if (ConvertFromV8(isolate, val, &proxy_rules)) {
188       pac_url = GURL(proxy_rules);  // Assume it is PAC script if it is URL.
189     } else if (ConvertFromV8(isolate, val, &options)) {
190       options.Get("pacScript", &pac_url);
191       options.Get("proxyRules", &proxy_rules);
192       options.Get("proxyBypassRules", &proxy_bypass_rules);
193     } else {
194       return false;
195     }
196
197     // pacScript takes precedence over proxyRules.
198     if (!pac_url.is_empty() && pac_url.is_valid()) {
199       out->set_pac_url(pac_url);
200     } else {
201       out->proxy_rules().ParseFromString(proxy_rules);
202       out->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_rules);
203     }
204     return true;
205   }
206 };
207
208 template<>
209 struct Converter<atom::VerifyRequestParams> {
210   static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
211                                    atom::VerifyRequestParams val) {
212     mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
213     dict.Set("hostname", val.hostname);
214     dict.Set("certificate", val.certificate);
215     dict.Set("verificationResult", val.default_result);
216     return dict.GetHandle();
217   }
218 };
219
220 }  // namespace mate
221
222 namespace atom {
223
224 namespace api {
225
226 namespace {
227
228 const char kPersistPrefix[] = "persist:";
229
230 // Referenced session objects.
231 std::map<uint32_t, v8::Global<v8::Object>> g_sessions;
232
233 class ResolveProxyHelper {
234  public:
235   ResolveProxyHelper(AtomBrowserContext* browser_context,
236                      const GURL& url,
237                      const Session::ResolveProxyCallback& callback)
238       : callback_(callback),
239         original_thread_(base::ThreadTaskRunnerHandle::Get()) {
240     scoped_refptr<net::URLRequestContextGetter> context_getter =
241         browser_context->url_request_context_getter();
242     context_getter->GetNetworkTaskRunner()->PostTask(
243         FROM_HERE,
244         base::Bind(&ResolveProxyHelper::ResolveProxy,
245                    base::Unretained(this), context_getter, url));
246   }
247
248   void OnResolveProxyCompleted(int result) {
249     std::string proxy;
250     if (result == net::OK)
251       proxy = proxy_info_.ToPacString();
252     original_thread_->PostTask(FROM_HERE,
253                                base::Bind(callback_, proxy));
254     delete this;
255   }
256
257  private:
258   void ResolveProxy(scoped_refptr<net::URLRequestContextGetter> context_getter,
259                     const GURL& url) {
260     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
261
262     net::ProxyService* proxy_service =
263         context_getter->GetURLRequestContext()->proxy_service();
264     net::CompletionCallback completion_callback =
265         base::Bind(&ResolveProxyHelper::OnResolveProxyCompleted,
266                    base::Unretained(this));
267
268     // Start the request.
269     int result = proxy_service->ResolveProxy(
270         url, "GET", &proxy_info_, completion_callback, &pac_req_, nullptr,
271         net::NetLogWithSource());
272
273     // Completed synchronously.
274     if (result != net::ERR_IO_PENDING)
275       completion_callback.Run(result);
276   }
277
278   Session::ResolveProxyCallback callback_;
279   net::ProxyInfo proxy_info_;
280   net::ProxyService::PacRequest* pac_req_;
281   scoped_refptr<base::SingleThreadTaskRunner> original_thread_;
282
283   DISALLOW_COPY_AND_ASSIGN(ResolveProxyHelper);
284 };
285
286 // Runs the callback in UI thread.
287 void RunCallbackInUI(const base::Callback<void()>& callback) {
288   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
289 }
290 template<typename ...T>
291 void RunCallbackInUI(const base::Callback<void(T...)>& callback, T... result) {
292   BrowserThread::PostTask(
293       BrowserThread::UI, FROM_HERE, base::Bind(callback, result...));
294 }
295
296 // Callback of HttpCache::GetBackend.
297 void OnGetBackend(disk_cache::Backend** backend_ptr,
298                   Session::CacheAction action,
299                   const net::CompletionCallback& callback,
300                   int result) {
301   if (result != net::OK) {
302     RunCallbackInUI(callback, result);
303   } else if (backend_ptr && *backend_ptr) {
304     if (action == Session::CacheAction::CLEAR) {
305       (*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI<int>,
306                                                 callback));
307     } else if (action == Session::CacheAction::STATS) {
308       base::StringPairs stats;
309       (*backend_ptr)->GetStats(&stats);
310       for (const auto& stat : stats) {
311         if (stat.first == "Current size") {
312           int current_size;
313           base::StringToInt(stat.second, &current_size);
314           RunCallbackInUI(callback, current_size);
315           break;
316         }
317       }
318     }
319   } else {
320     RunCallbackInUI<int>(callback, net::ERR_FAILED);
321   }
322 }
323
324 void DoCacheActionInIO(
325     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
326     Session::CacheAction action,
327     const net::CompletionCallback& callback) {
328   auto request_context = context_getter->GetURLRequestContext();
329   auto http_cache = request_context->http_transaction_factory()->GetCache();
330   if (!http_cache)
331     RunCallbackInUI<int>(callback, net::ERR_FAILED);
332
333   // Call GetBackend and make the backend's ptr accessable in OnGetBackend.
334   using BackendPtr = disk_cache::Backend*;
335   auto* backend_ptr = new BackendPtr(nullptr);
336   net::CompletionCallback on_get_backend =
337       base::Bind(&OnGetBackend, base::Owned(backend_ptr), action, callback);
338   int rv = http_cache->GetBackend(backend_ptr, on_get_backend);
339   if (rv != net::ERR_IO_PENDING)
340     on_get_backend.Run(net::OK);
341 }
342
343 void SetProxyInIO(net::URLRequestContextGetter* getter,
344                   const net::ProxyConfig& config,
345                   const base::Closure& callback) {
346   auto proxy_service = getter->GetURLRequestContext()->proxy_service();
347   proxy_service->ResetConfigService(base::WrapUnique(
348       new net::ProxyConfigServiceFixed(config)));
349   // Refetches and applies the new pac script if provided.
350   proxy_service->ForceReloadProxyConfig();
351   RunCallbackInUI(callback);
352 }
353
354 void SetCertVerifyProcInIO(
355     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
356     const AtomCertVerifier::VerifyProc& proc) {
357   auto request_context = context_getter->GetURLRequestContext();
358   static_cast<AtomCertVerifier*>(request_context->cert_verifier())->
359       SetVerifyProc(proc);
360 }
361
362 void ClearHostResolverCacheInIO(
363     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
364     const base::Closure& callback) {
365   auto request_context = context_getter->GetURLRequestContext();
366   auto cache = request_context->host_resolver()->GetHostCache();
367   if (cache) {
368     cache->clear();
369     DCHECK_EQ(0u, cache->size());
370     if (!callback.is_null())
371       RunCallbackInUI(callback);
372   }
373 }
374
375 void ClearAuthCacheInIO(
376     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
377     const ClearAuthCacheOptions& options,
378     const base::Closure& callback) {
379   auto request_context = context_getter->GetURLRequestContext();
380   auto network_session =
381       request_context->http_transaction_factory()->GetSession();
382   if (network_session) {
383     if (options.type == "password") {
384       auto auth_cache = network_session->http_auth_cache();
385       if (!options.origin.is_empty()) {
386         auth_cache->Remove(
387             options.origin, options.realm, options.auth_scheme,
388             net::AuthCredentials(options.username, options.password));
389       } else {
390         auth_cache->ClearEntriesAddedWithin(base::TimeDelta::Max());
391       }
392     } else if (options.type == "clientCertificate") {
393       auto client_auth_cache = network_session->ssl_client_auth_cache();
394       client_auth_cache->Remove(net::HostPortPair::FromURL(options.origin));
395     }
396     network_session->CloseAllConnections();
397   }
398   if (!callback.is_null())
399     RunCallbackInUI(callback);
400 }
401
402 void AllowNTLMCredentialsForDomainsInIO(
403     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
404     const std::string& domains) {
405   auto request_context = context_getter->GetURLRequestContext();
406   auto auth_handler = request_context->http_auth_handler_factory();
407   if (auth_handler) {
408     auto auth_preferences = const_cast<net::HttpAuthPreferences*>(
409         auth_handler->http_auth_preferences());
410     if (auth_preferences)
411       auth_preferences->set_server_whitelist(domains);
412   }
413 }
414
415 void OnClearStorageDataDone(const base::Closure& callback) {
416   if (!callback.is_null())
417     callback.Run();
418 }
419
420 void DownloadIdCallback(content::DownloadManager* download_manager,
421                         const base::FilePath& path,
422                         const std::vector<GURL>& url_chain,
423                         const std::string& mime_type,
424                         int64_t offset,
425                         int64_t length,
426                         const std::string& last_modified,
427                         const std::string& etag,
428                         const base::Time& start_time,
429                         uint32_t id) {
430   download_manager->CreateDownloadItem(
431       base::GenerateGUID(), id, path, path, url_chain, GURL(), GURL(), GURL(),
432       GURL(), mime_type, mime_type, start_time, base::Time(), etag,
433       last_modified, offset, length, std::string(),
434       content::DownloadItem::INTERRUPTED,
435       content::DownloadDangerType::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
436       content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT, false);
437 }
438
439 }  // namespace
440
441 Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context)
442     : devtools_network_emulation_client_id_(base::GenerateGUID()),
443       browser_context_(browser_context) {
444   // Observe DownloadManager to get download notifications.
445   content::BrowserContext::GetDownloadManager(browser_context)->
446       AddObserver(this);
447
448   Init(isolate);
449   AttachAsUserData(browser_context);
450 }
451
452 Session::~Session() {
453   content::BrowserContext::GetDownloadManager(browser_context())->
454       RemoveObserver(this);
455   g_sessions.erase(weak_map_id());
456 }
457
458 void Session::OnDownloadCreated(content::DownloadManager* manager,
459                                 content::DownloadItem* item) {
460   if (item->IsSavePackageDownload())
461     return;
462
463   if (!::tizen::is_single_process)
464     v8::Locker locker(isolate());
465   v8::HandleScope handle_scope(isolate());
466   auto handle = DownloadItem::Create(isolate(), item);
467   if (item->GetState() == content::DownloadItem::INTERRUPTED)
468     handle->SetSavePath(item->GetTargetFilePath());
469   bool prevent_default = Emit("will-download", handle, item->GetWebContents());
470   if (prevent_default) {
471     item->Cancel(true);
472     item->Remove();
473   }
474 }
475
476 void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
477   new ResolveProxyHelper(browser_context(), url, callback);
478 }
479
480 template<Session::CacheAction action>
481 void Session::DoCacheAction(const net::CompletionCallback& callback) {
482   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
483       base::Bind(&DoCacheActionInIO,
484                  make_scoped_refptr(browser_context_->GetRequestContext()),
485                  action,
486                  callback));
487 }
488
489 void Session::ClearStorageData(mate::Arguments* args) {
490   // clearStorageData([options, callback])
491   ClearStorageDataOptions options;
492   base::Closure callback;
493   args->GetNext(&options);
494   args->GetNext(&callback);
495
496   auto storage_partition =
497       content::BrowserContext::GetStoragePartition(browser_context(), nullptr);
498   if (options.storage_types & StoragePartition::REMOVE_DATA_MASK_COOKIES) {
499     // Reset media device id salt when cookies are cleared.
500     // https://w3c.github.io/mediacapture-main/#dom-mediadeviceinfo-deviceid
501     brightray::MediaDeviceIDSalt::Reset(browser_context()->prefs());
502   }
503   storage_partition->ClearData(
504       options.storage_types, options.quota_types, options.origin,
505       content::StoragePartition::OriginMatcherFunction(),
506       base::Time(), base::Time::Max(),
507       base::Bind(&OnClearStorageDataDone, callback));
508 }
509
510 void Session::FlushStorageData() {
511   auto storage_partition =
512       content::BrowserContext::GetStoragePartition(browser_context(), nullptr);
513   storage_partition->Flush();
514 }
515
516 void Session::SetProxy(const net::ProxyConfig& config,
517                        const base::Closure& callback) {
518   auto getter = browser_context_->GetRequestContext();
519   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
520       base::Bind(&SetProxyInIO, base::Unretained(getter), config, callback));
521 }
522
523 void Session::SetDownloadPath(const base::FilePath& path) {
524   browser_context_->prefs()->SetFilePath(
525       prefs::kDownloadDefaultDirectory, path);
526 }
527
528 void Session::EnableNetworkEmulation(const mate::Dictionary& options) {
529   std::unique_ptr<brightray::DevToolsNetworkConditions> conditions;
530   bool offline = false;
531   double latency = 0.0, download_throughput = 0.0, upload_throughput = 0.0;
532   if (options.Get("offline", &offline) && offline) {
533     conditions.reset(new brightray::DevToolsNetworkConditions(offline));
534   } else {
535     options.Get("latency", &latency);
536     options.Get("downloadThroughput", &download_throughput);
537     options.Get("uploadThroughput", &upload_throughput);
538     conditions.reset(
539         new brightray::DevToolsNetworkConditions(false,
540                                                  latency,
541                                                  download_throughput,
542                                                  upload_throughput));
543   }
544
545   browser_context_->network_controller_handle()->SetNetworkState(
546       devtools_network_emulation_client_id_, std::move(conditions));
547   browser_context_->network_delegate()->SetDevToolsNetworkEmulationClientId(
548       devtools_network_emulation_client_id_);
549 }
550
551 void Session::DisableNetworkEmulation() {
552   std::unique_ptr<brightray::DevToolsNetworkConditions> conditions;
553   browser_context_->network_controller_handle()->SetNetworkState(
554       devtools_network_emulation_client_id_, std::move(conditions));
555   browser_context_->network_delegate()->SetDevToolsNetworkEmulationClientId(
556       std::string());
557 }
558
559 void Session::SetCertVerifyProc(v8::Local<v8::Value> val,
560                                 mate::Arguments* args) {
561   AtomCertVerifier::VerifyProc proc;
562   if (!(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &proc))) {
563     args->ThrowError("Must pass null or function");
564     return;
565   }
566
567   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
568       base::Bind(&SetCertVerifyProcInIO,
569                  make_scoped_refptr(browser_context_->GetRequestContext()),
570                  proc));
571 }
572
573 void Session::SetPermissionRequestHandler(v8::Local<v8::Value> val,
574                                           mate::Arguments* args) {
575   AtomPermissionManager::RequestHandler handler;
576   if (!(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &handler))) {
577     args->ThrowError("Must pass null or function");
578     return;
579   }
580   auto permission_manager = static_cast<AtomPermissionManager*>(
581       browser_context()->GetPermissionManager());
582   permission_manager->SetPermissionRequestHandler(handler);
583 }
584
585 void Session::ClearHostResolverCache(mate::Arguments* args) {
586   base::Closure callback;
587   args->GetNext(&callback);
588
589   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
590       base::Bind(&ClearHostResolverCacheInIO,
591                  make_scoped_refptr(browser_context_->GetRequestContext()),
592                  callback));
593 }
594
595 void Session::ClearAuthCache(mate::Arguments* args) {
596   ClearAuthCacheOptions options;
597   if (!args->GetNext(&options)) {
598     args->ThrowError("Must specify options object");
599     return;
600   }
601   base::Closure callback;
602   args->GetNext(&callback);
603
604   BrowserThread::PostTask(
605       BrowserThread::IO, FROM_HERE,
606       base::Bind(&ClearAuthCacheInIO,
607                  make_scoped_refptr(browser_context_->GetRequestContext()),
608                  options, callback));
609 }
610
611 void Session::AllowNTLMCredentialsForDomains(const std::string& domains) {
612   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
613       base::Bind(&AllowNTLMCredentialsForDomainsInIO,
614                  make_scoped_refptr(browser_context_->GetRequestContext()),
615                  domains));
616 }
617
618 void Session::SetUserAgent(const std::string& user_agent,
619                            mate::Arguments* args) {
620   browser_context_->SetUserAgent(user_agent);
621
622   std::string accept_lang = l10n_util::GetApplicationLocale("");
623   args->GetNext(&accept_lang);
624
625   auto getter = browser_context_->GetRequestContext();
626   getter->GetNetworkTaskRunner()->PostTask(
627       FROM_HERE,
628       base::Bind(&SetUserAgentInIO, getter, accept_lang, user_agent));
629 }
630
631 std::string Session::GetUserAgent() {
632   return browser_context_->GetUserAgent();
633 }
634
635 void Session::GetBlobData(
636     const std::string& uuid,
637     const AtomBlobReader::CompletionCallback& callback) {
638   if (callback.is_null())
639     return;
640
641   AtomBlobReader* blob_reader =
642       browser_context()->GetBlobReader();
643   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
644       base::Bind(&AtomBlobReader::StartReading,
645                  base::Unretained(blob_reader),
646                  uuid,
647                  callback));
648 }
649
650 void Session::CreateInterruptedDownload(const mate::Dictionary& options) {
651   int64_t offset = 0, length = 0;
652   double start_time = 0.0;
653   std::string mime_type, last_modified, etag;
654   base::FilePath path;
655   std::vector<GURL> url_chain;
656   options.Get("path", &path);
657   options.Get("urlChain", &url_chain);
658   options.Get("mimeType", &mime_type);
659   options.Get("offset", &offset);
660   options.Get("length", &length);
661   options.Get("lastModified", &last_modified);
662   options.Get("eTag", &etag);
663   options.Get("startTime", &start_time);
664   if (path.empty() || url_chain.empty() || length == 0) {
665     isolate()->ThrowException(v8::Exception::Error(mate::StringToV8(
666         isolate(), "Must pass non-empty path, urlChain and length.")));
667     return;
668   }
669   if (offset >= length) {
670     isolate()->ThrowException(v8::Exception::Error(mate::StringToV8(
671         isolate(), "Must pass an offset value less than length.")));
672     return;
673   }
674   auto download_manager =
675       content::BrowserContext::GetDownloadManager(browser_context());
676   download_manager->GetDelegate()->GetNextId(base::Bind(
677       &DownloadIdCallback, download_manager, path, url_chain, mime_type, offset,
678       length, last_modified, etag, base::Time::FromDoubleT(start_time)));
679 }
680
681 v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
682   if (cookies_.IsEmpty()) {
683     auto handle = Cookies::Create(isolate, browser_context());
684     cookies_.Reset(isolate, handle.ToV8());
685   }
686   return v8::Local<v8::Value>::New(isolate, cookies_);
687 }
688
689 v8::Local<v8::Value> Session::Protocol(v8::Isolate* isolate) {
690   if (protocol_.IsEmpty()) {
691     auto handle = atom::api::Protocol::Create(isolate, browser_context());
692     protocol_.Reset(isolate, handle.ToV8());
693   }
694   return v8::Local<v8::Value>::New(isolate, protocol_);
695 }
696
697 v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
698   if (web_request_.IsEmpty()) {
699     auto handle = atom::api::WebRequest::Create(isolate, browser_context());
700     web_request_.Reset(isolate, handle.ToV8());
701   }
702   return v8::Local<v8::Value>::New(isolate, web_request_);
703 }
704
705 // static
706 mate::Handle<Session> Session::CreateFrom(
707     v8::Isolate* isolate, AtomBrowserContext* browser_context) {
708   auto existing = TrackableObject::FromWrappedClass(isolate, browser_context);
709   if (existing)
710     return mate::CreateHandle(isolate, static_cast<Session*>(existing));
711
712   auto handle = mate::CreateHandle(
713       isolate, new Session(isolate, browser_context));
714
715   // The Sessions should never be garbage collected, since the common pattern is
716   // to use partition strings, instead of using the Session object directly.
717   g_sessions[handle->weak_map_id()] =
718       v8::Global<v8::Object>(isolate, handle.ToV8());
719
720   return handle;
721 }
722
723 // static
724 mate::Handle<Session> Session::FromPartition(
725     v8::Isolate* isolate, const std::string& partition,
726     const base::DictionaryValue& options) {
727   scoped_refptr<AtomBrowserContext> browser_context;
728   if (partition.empty()) {
729     browser_context = AtomBrowserContext::From("", false, options);
730   } else if (base::StartsWith(partition, kPersistPrefix,
731                               base::CompareCase::SENSITIVE)) {
732     std::string name = partition.substr(8);
733     browser_context = AtomBrowserContext::From(name, false, options);
734   } else {
735     browser_context = AtomBrowserContext::From(partition, true, options);
736   }
737   return CreateFrom(isolate, browser_context.get());
738 }
739
740 // static
741 void Session::BuildPrototype(v8::Isolate* isolate,
742                              v8::Local<v8::FunctionTemplate> prototype) {
743   prototype->SetClassName(mate::StringToV8(isolate, "Session"));
744   mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
745       .MakeDestroyable()
746       .SetMethod("resolveProxy", &Session::ResolveProxy)
747       .SetMethod("getCacheSize", &Session::DoCacheAction<CacheAction::STATS>)
748       .SetMethod("clearCache", &Session::DoCacheAction<CacheAction::CLEAR>)
749       .SetMethod("clearStorageData", &Session::ClearStorageData)
750       .SetMethod("flushStorageData", &Session::FlushStorageData)
751       .SetMethod("setProxy", &Session::SetProxy)
752       .SetMethod("setDownloadPath", &Session::SetDownloadPath)
753       .SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
754       .SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
755       .SetMethod("_setCertificateVerifyProc", &Session::SetCertVerifyProc)
756       .SetMethod("setPermissionRequestHandler",
757                  &Session::SetPermissionRequestHandler)
758       .SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache)
759       .SetMethod("clearAuthCache", &Session::ClearAuthCache)
760       .SetMethod("allowNTLMCredentialsForDomains",
761                  &Session::AllowNTLMCredentialsForDomains)
762       .SetMethod("setUserAgent", &Session::SetUserAgent)
763       .SetMethod("getUserAgent", &Session::GetUserAgent)
764       .SetMethod("getBlobData", &Session::GetBlobData)
765       .SetMethod("createInterruptedDownload",
766                  &Session::CreateInterruptedDownload)
767       .SetProperty("cookies", &Session::Cookies)
768       .SetProperty("protocol", &Session::Protocol)
769       .SetProperty("webRequest", &Session::WebRequest);
770 }
771
772 }  // namespace api
773
774 }  // namespace atom
775
776 namespace {
777
778 using atom::api::Session;
779
780 v8::Local<v8::Value> FromPartition(
781     const std::string& partition, mate::Arguments* args) {
782   if (!atom::Browser::Get()->is_ready()) {
783     args->ThrowError("Session can only be received when app is ready");
784     return v8::Null(args->isolate());
785   }
786   base::DictionaryValue options;
787   args->GetNext(&options);
788   return Session::FromPartition(args->isolate(), partition, options).ToV8();
789 }
790
791 void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
792                 v8::Local<v8::Context> context, void* priv) {
793   v8::Isolate* isolate = context->GetIsolate();
794   mate::Dictionary dict(isolate, exports);
795   dict.Set("Session", Session::GetConstructor(isolate)->GetFunction());
796   dict.Set("Cookies", Cookies::GetConstructor(isolate)->GetFunction());
797   dict.SetMethod("fromPartition", &FromPartition);
798 }
799
800 }  // namespace
801
802 NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_session, Initialize)