atom_api_session.cc 32 KB

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