atom_api_session.cc 31 KB

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