atom_api_session.cc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  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 "shell/browser/api/atom_api_session.h"
  5. #include <algorithm>
  6. #include <map>
  7. #include <memory>
  8. #include <string>
  9. #include <utility>
  10. #include <vector>
  11. #include "base/command_line.h"
  12. #include "base/files/file_path.h"
  13. #include "base/guid.h"
  14. #include "base/strings/string_number_conversions.h"
  15. #include "base/strings/string_util.h"
  16. #include "base/task/post_task.h"
  17. #include "chrome/browser/browser_process.h"
  18. #include "chrome/common/pref_names.h"
  19. #include "components/download/public/common/download_danger_type.h"
  20. #include "components/prefs/pref_service.h"
  21. #include "components/prefs/value_map_pref_store.h"
  22. #include "components/proxy_config/proxy_config_dictionary.h"
  23. #include "components/proxy_config/proxy_config_pref_names.h"
  24. #include "content/public/browser/browser_task_traits.h"
  25. #include "content/public/browser/browser_thread.h"
  26. #include "content/public/browser/download_item_utils.h"
  27. #include "content/public/browser/download_manager_delegate.h"
  28. #include "content/public/browser/network_service_instance.h"
  29. #include "content/public/browser/storage_partition.h"
  30. #include "mojo/public/cpp/bindings/pending_remote.h"
  31. #include "mojo/public/cpp/bindings/self_owned_receiver.h"
  32. #include "native_mate/dictionary.h"
  33. #include "native_mate/object_template_builder.h"
  34. #include "net/base/completion_repeating_callback.h"
  35. #include "net/base/load_flags.h"
  36. #include "net/http/http_auth_handler_factory.h"
  37. #include "net/http/http_auth_preferences.h"
  38. #include "net/http/http_cache.h"
  39. #include "services/network/network_service.h"
  40. #include "services/network/public/cpp/features.h"
  41. #include "shell/browser/api/atom_api_cookies.h"
  42. #include "shell/browser/api/atom_api_data_pipe_holder.h"
  43. #include "shell/browser/api/atom_api_download_item.h"
  44. #include "shell/browser/api/atom_api_net_log.h"
  45. #include "shell/browser/api/atom_api_protocol_ns.h"
  46. #include "shell/browser/api/atom_api_web_request_ns.h"
  47. #include "shell/browser/atom_browser_context.h"
  48. #include "shell/browser/atom_browser_main_parts.h"
  49. #include "shell/browser/atom_permission_manager.h"
  50. #include "shell/browser/browser.h"
  51. #include "shell/browser/media/media_device_id_salt.h"
  52. #include "shell/browser/net/cert_verifier_client.h"
  53. #include "shell/browser/session_preferences.h"
  54. #include "shell/common/native_mate_converters/callback.h"
  55. #include "shell/common/native_mate_converters/content_converter.h"
  56. #include "shell/common/native_mate_converters/file_path_converter.h"
  57. #include "shell/common/native_mate_converters/gurl_converter.h"
  58. #include "shell/common/native_mate_converters/net_converter.h"
  59. #include "shell/common/native_mate_converters/value_converter.h"
  60. #include "shell/common/node_includes.h"
  61. #include "shell/common/options_switches.h"
  62. #include "ui/base/l10n/l10n_util.h"
  63. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  64. #include "shell/browser/extensions/atom_extension_system.h"
  65. #endif
  66. using content::BrowserThread;
  67. using content::StoragePartition;
  68. namespace {
  69. struct ClearStorageDataOptions {
  70. GURL origin;
  71. uint32_t storage_types = StoragePartition::REMOVE_DATA_MASK_ALL;
  72. uint32_t quota_types = StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL;
  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. } // namespace
  113. namespace mate {
  114. template <>
  115. struct Converter<ClearStorageDataOptions> {
  116. static bool FromV8(v8::Isolate* isolate,
  117. v8::Local<v8::Value> val,
  118. ClearStorageDataOptions* out) {
  119. mate::Dictionary options;
  120. if (!ConvertFromV8(isolate, val, &options))
  121. return false;
  122. options.Get("origin", &out->origin);
  123. std::vector<std::string> types;
  124. if (options.Get("storages", &types))
  125. out->storage_types = GetStorageMask(types);
  126. if (options.Get("quotas", &types))
  127. out->quota_types = GetQuotaMask(types);
  128. return true;
  129. }
  130. };
  131. } // namespace mate
  132. namespace electron {
  133. namespace api {
  134. namespace {
  135. const char kPersistPrefix[] = "persist:";
  136. // Referenced session objects.
  137. std::map<uint32_t, v8::Global<v8::Object>> g_sessions;
  138. void DownloadIdCallback(content::DownloadManager* download_manager,
  139. const base::FilePath& path,
  140. const std::vector<GURL>& url_chain,
  141. const std::string& mime_type,
  142. int64_t offset,
  143. int64_t length,
  144. const std::string& last_modified,
  145. const std::string& etag,
  146. const base::Time& start_time,
  147. uint32_t id) {
  148. download_manager->CreateDownloadItem(
  149. base::GenerateGUID(), id, path, path, url_chain, GURL(), GURL(), GURL(),
  150. GURL(), base::nullopt, mime_type, mime_type, start_time, base::Time(),
  151. etag, last_modified, offset, length, std::string(),
  152. download::DownloadItem::INTERRUPTED,
  153. download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
  154. download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT, false, base::Time(),
  155. false, std::vector<download::DownloadItem::ReceivedSlice>());
  156. }
  157. void DestroyGlobalHandle(v8::Isolate* isolate,
  158. const v8::Global<v8::Value>& global_handle) {
  159. v8::Locker locker(isolate);
  160. v8::HandleScope handle_scope(isolate);
  161. if (!global_handle.IsEmpty()) {
  162. v8::Local<v8::Value> local_handle = global_handle.Get(isolate);
  163. v8::Local<v8::Object> object;
  164. if (local_handle->IsObject() &&
  165. local_handle->ToObject(isolate->GetCurrentContext()).ToLocal(&object)) {
  166. void* ptr = object->GetAlignedPointerFromInternalField(0);
  167. if (!ptr)
  168. return;
  169. delete static_cast<mate::WrappableBase*>(ptr);
  170. object->SetAlignedPointerInInternalField(0, nullptr);
  171. }
  172. }
  173. }
  174. } // namespace
  175. Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context)
  176. : network_emulation_token_(base::UnguessableToken::Create()),
  177. browser_context_(browser_context) {
  178. // Observe DownloadManager to get download notifications.
  179. content::BrowserContext::GetDownloadManager(browser_context)
  180. ->AddObserver(this);
  181. new SessionPreferences(browser_context);
  182. Init(isolate);
  183. AttachAsUserData(browser_context);
  184. }
  185. Session::~Session() {
  186. content::BrowserContext::GetDownloadManager(browser_context())
  187. ->RemoveObserver(this);
  188. // TODO(zcbenz): Now since URLRequestContextGetter is gone, is this still
  189. // needed?
  190. // Refs https://github.com/electron/electron/pull/12305.
  191. DestroyGlobalHandle(isolate(), cookies_);
  192. DestroyGlobalHandle(isolate(), protocol_);
  193. DestroyGlobalHandle(isolate(), net_log_);
  194. g_sessions.erase(weak_map_id());
  195. }
  196. void Session::OnDownloadCreated(content::DownloadManager* manager,
  197. download::DownloadItem* item) {
  198. if (item->IsSavePackageDownload())
  199. return;
  200. v8::Locker locker(isolate());
  201. v8::HandleScope handle_scope(isolate());
  202. auto handle = DownloadItem::Create(isolate(), item);
  203. if (item->GetState() == download::DownloadItem::INTERRUPTED)
  204. handle->SetSavePath(item->GetTargetFilePath());
  205. content::WebContents* web_contents =
  206. content::DownloadItemUtils::GetWebContents(item);
  207. bool prevent_default = Emit("will-download", handle, web_contents);
  208. if (prevent_default) {
  209. item->Cancel(true);
  210. item->Remove();
  211. }
  212. }
  213. v8::Local<v8::Promise> Session::ResolveProxy(mate::Arguments* args) {
  214. v8::Isolate* isolate = args->isolate();
  215. util::Promise promise(isolate);
  216. v8::Local<v8::Promise> handle = promise.GetHandle();
  217. GURL url;
  218. args->GetNext(&url);
  219. browser_context_->GetResolveProxyHelper()->ResolveProxy(
  220. url, base::BindOnce(util::Promise::ResolvePromise<std::string>,
  221. std::move(promise)));
  222. return handle;
  223. }
  224. v8::Local<v8::Promise> Session::GetCacheSize() {
  225. auto* isolate = v8::Isolate::GetCurrent();
  226. auto promise = util::Promise(isolate);
  227. auto handle = promise.GetHandle();
  228. content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
  229. ->GetNetworkContext()
  230. ->ComputeHttpCacheSize(base::Time(), base::Time::Max(),
  231. base::BindOnce(
  232. [](util::Promise promise, bool is_upper_bound,
  233. int64_t size_or_error) {
  234. if (size_or_error < 0) {
  235. promise.RejectWithErrorMessage(
  236. net::ErrorToString(size_or_error));
  237. } else {
  238. promise.Resolve(size_or_error);
  239. }
  240. },
  241. std::move(promise)));
  242. return handle;
  243. }
  244. v8::Local<v8::Promise> Session::ClearCache() {
  245. auto* isolate = v8::Isolate::GetCurrent();
  246. auto promise = util::Promise(isolate);
  247. auto handle = promise.GetHandle();
  248. content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
  249. ->GetNetworkContext()
  250. ->ClearHttpCache(base::Time(), base::Time::Max(), nullptr,
  251. base::BindOnce(util::Promise::ResolveEmptyPromise,
  252. std::move(promise)));
  253. return handle;
  254. }
  255. v8::Local<v8::Promise> Session::ClearStorageData(mate::Arguments* args) {
  256. v8::Isolate* isolate = args->isolate();
  257. util::Promise promise(isolate);
  258. v8::Local<v8::Promise> handle = promise.GetHandle();
  259. ClearStorageDataOptions options;
  260. args->GetNext(&options);
  261. auto* storage_partition =
  262. content::BrowserContext::GetStoragePartition(browser_context(), nullptr);
  263. if (options.storage_types & StoragePartition::REMOVE_DATA_MASK_COOKIES) {
  264. // Reset media device id salt when cookies are cleared.
  265. // https://w3c.github.io/mediacapture-main/#dom-mediadeviceinfo-deviceid
  266. MediaDeviceIDSalt::Reset(browser_context()->prefs());
  267. }
  268. storage_partition->ClearData(
  269. options.storage_types, options.quota_types, options.origin, base::Time(),
  270. base::Time::Max(),
  271. base::BindOnce(util::Promise::ResolveEmptyPromise, std::move(promise)));
  272. return handle;
  273. }
  274. void Session::FlushStorageData() {
  275. auto* storage_partition =
  276. content::BrowserContext::GetStoragePartition(browser_context(), nullptr);
  277. storage_partition->Flush();
  278. }
  279. v8::Local<v8::Promise> Session::SetProxy(mate::Arguments* args) {
  280. v8::Isolate* isolate = args->isolate();
  281. util::Promise promise(isolate);
  282. v8::Local<v8::Promise> handle = promise.GetHandle();
  283. mate::Dictionary options;
  284. args->GetNext(&options);
  285. if (!browser_context_->in_memory_pref_store()) {
  286. promise.Resolve();
  287. return handle;
  288. }
  289. std::string proxy_rules, bypass_list, pac_url;
  290. options.Get("pacScript", &pac_url);
  291. options.Get("proxyRules", &proxy_rules);
  292. options.Get("proxyBypassRules", &bypass_list);
  293. // pacScript takes precedence over proxyRules.
  294. if (!pac_url.empty()) {
  295. browser_context_->in_memory_pref_store()->SetValue(
  296. proxy_config::prefs::kProxy,
  297. std::make_unique<base::Value>(ProxyConfigDictionary::CreatePacScript(
  298. pac_url, true /* pac_mandatory */)),
  299. WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
  300. } else {
  301. browser_context_->in_memory_pref_store()->SetValue(
  302. proxy_config::prefs::kProxy,
  303. std::make_unique<base::Value>(ProxyConfigDictionary::CreateFixedServers(
  304. proxy_rules, bypass_list)),
  305. WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
  306. }
  307. base::ThreadTaskRunnerHandle::Get()->PostTask(
  308. FROM_HERE,
  309. base::BindOnce(util::Promise::ResolveEmptyPromise, std::move(promise)));
  310. return handle;
  311. }
  312. void Session::SetDownloadPath(const base::FilePath& path) {
  313. browser_context_->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
  314. path);
  315. }
  316. void Session::EnableNetworkEmulation(const mate::Dictionary& options) {
  317. auto conditions = network::mojom::NetworkConditions::New();
  318. options.Get("offline", &conditions->offline);
  319. options.Get("downloadThroughput", &conditions->download_throughput);
  320. options.Get("uploadThroughput", &conditions->upload_throughput);
  321. double latency = 0.0;
  322. if (options.Get("latency", &latency) && latency) {
  323. conditions->latency = base::TimeDelta::FromMillisecondsD(latency);
  324. }
  325. auto* network_context = content::BrowserContext::GetDefaultStoragePartition(
  326. browser_context_.get())
  327. ->GetNetworkContext();
  328. network_context->SetNetworkConditions(network_emulation_token_,
  329. std::move(conditions));
  330. }
  331. void Session::DisableNetworkEmulation() {
  332. auto* network_context = content::BrowserContext::GetDefaultStoragePartition(
  333. browser_context_.get())
  334. ->GetNetworkContext();
  335. network_context->SetNetworkConditions(
  336. network_emulation_token_, network::mojom::NetworkConditions::New());
  337. }
  338. void Session::SetCertVerifyProc(v8::Local<v8::Value> val,
  339. mate::Arguments* args) {
  340. CertVerifierClient::CertVerifyProc proc;
  341. if (!(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &proc))) {
  342. args->ThrowError("Must pass null or function");
  343. return;
  344. }
  345. mojo::PendingRemote<network::mojom::CertVerifierClient>
  346. cert_verifier_client_remote;
  347. if (proc) {
  348. mojo::MakeSelfOwnedReceiver(
  349. std::make_unique<CertVerifierClient>(proc),
  350. cert_verifier_client_remote.InitWithNewPipeAndPassReceiver());
  351. }
  352. content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
  353. ->GetNetworkContext()
  354. ->SetCertVerifierClient(std::move(cert_verifier_client_remote));
  355. // This causes the cert verifier cache to be cleared.
  356. content::GetNetworkService()->OnCertDBChanged();
  357. }
  358. void Session::SetPermissionRequestHandler(v8::Local<v8::Value> val,
  359. mate::Arguments* args) {
  360. auto* permission_manager = static_cast<AtomPermissionManager*>(
  361. browser_context()->GetPermissionControllerDelegate());
  362. if (val->IsNull()) {
  363. permission_manager->SetPermissionRequestHandler(
  364. AtomPermissionManager::RequestHandler());
  365. return;
  366. }
  367. auto handler = std::make_unique<AtomPermissionManager::RequestHandler>();
  368. if (!mate::ConvertFromV8(args->isolate(), val, handler.get())) {
  369. args->ThrowError("Must pass null or function");
  370. return;
  371. }
  372. permission_manager->SetPermissionRequestHandler(base::BindRepeating(
  373. [](AtomPermissionManager::RequestHandler* handler,
  374. content::WebContents* web_contents,
  375. content::PermissionType permission_type,
  376. AtomPermissionManager::StatusCallback callback,
  377. const base::Value& details) {
  378. handler->Run(web_contents, permission_type,
  379. base::AdaptCallbackForRepeating(std::move(callback)),
  380. details);
  381. },
  382. base::Owned(std::move(handler))));
  383. }
  384. void Session::SetPermissionCheckHandler(v8::Local<v8::Value> val,
  385. mate::Arguments* args) {
  386. AtomPermissionManager::CheckHandler handler;
  387. if (!(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &handler))) {
  388. args->ThrowError("Must pass null or function");
  389. return;
  390. }
  391. auto* permission_manager = static_cast<AtomPermissionManager*>(
  392. browser_context()->GetPermissionControllerDelegate());
  393. permission_manager->SetPermissionCheckHandler(handler);
  394. }
  395. v8::Local<v8::Promise> Session::ClearHostResolverCache(mate::Arguments* args) {
  396. v8::Isolate* isolate = args->isolate();
  397. util::Promise promise(isolate);
  398. v8::Local<v8::Promise> handle = promise.GetHandle();
  399. content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
  400. ->GetNetworkContext()
  401. ->ClearHostCache(nullptr,
  402. base::BindOnce(util::Promise::ResolveEmptyPromise,
  403. std::move(promise)));
  404. return handle;
  405. }
  406. v8::Local<v8::Promise> Session::ClearAuthCache() {
  407. auto* isolate = v8::Isolate::GetCurrent();
  408. util::Promise promise(isolate);
  409. v8::Local<v8::Promise> handle = promise.GetHandle();
  410. content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
  411. ->GetNetworkContext()
  412. ->ClearHttpAuthCache(base::Time(),
  413. base::BindOnce(util::Promise::ResolveEmptyPromise,
  414. std::move(promise)));
  415. return handle;
  416. }
  417. void Session::AllowNTLMCredentialsForDomains(const std::string& domains) {
  418. network::mojom::HttpAuthDynamicParamsPtr auth_dynamic_params =
  419. network::mojom::HttpAuthDynamicParams::New();
  420. auth_dynamic_params->server_allowlist = domains;
  421. auth_dynamic_params->enable_negotiate_port =
  422. base::CommandLine::ForCurrentProcess()->HasSwitch(
  423. electron::switches::kEnableAuthNegotiatePort);
  424. content::GetNetworkService()->ConfigureHttpAuthPrefs(
  425. std::move(auth_dynamic_params));
  426. }
  427. void Session::SetUserAgent(const std::string& user_agent,
  428. mate::Arguments* args) {
  429. browser_context_->SetUserAgent(user_agent);
  430. content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
  431. ->GetNetworkContext()
  432. ->SetUserAgent(user_agent);
  433. }
  434. std::string Session::GetUserAgent() {
  435. return browser_context_->GetUserAgent();
  436. }
  437. v8::Local<v8::Promise> Session::GetBlobData(v8::Isolate* isolate,
  438. const std::string& uuid) {
  439. gin::Handle<DataPipeHolder> holder = DataPipeHolder::From(isolate, uuid);
  440. if (holder.IsEmpty()) {
  441. util::Promise promise(isolate);
  442. promise.RejectWithErrorMessage("Could not get blob data handle");
  443. return promise.GetHandle();
  444. }
  445. return holder->ReadAll(isolate);
  446. }
  447. void Session::CreateInterruptedDownload(const mate::Dictionary& options) {
  448. int64_t offset = 0, length = 0;
  449. double start_time = 0.0;
  450. std::string mime_type, last_modified, etag;
  451. base::FilePath path;
  452. std::vector<GURL> url_chain;
  453. options.Get("path", &path);
  454. options.Get("urlChain", &url_chain);
  455. options.Get("mimeType", &mime_type);
  456. options.Get("offset", &offset);
  457. options.Get("length", &length);
  458. options.Get("lastModified", &last_modified);
  459. options.Get("eTag", &etag);
  460. options.Get("startTime", &start_time);
  461. if (path.empty() || url_chain.empty() || length == 0) {
  462. isolate()->ThrowException(v8::Exception::Error(mate::StringToV8(
  463. isolate(), "Must pass non-empty path, urlChain and length.")));
  464. return;
  465. }
  466. if (offset >= length) {
  467. isolate()->ThrowException(v8::Exception::Error(mate::StringToV8(
  468. isolate(), "Must pass an offset value less than length.")));
  469. return;
  470. }
  471. auto* download_manager =
  472. content::BrowserContext::GetDownloadManager(browser_context());
  473. download_manager->GetDelegate()->GetNextId(base::BindRepeating(
  474. &DownloadIdCallback, download_manager, path, url_chain, mime_type, offset,
  475. length, last_modified, etag, base::Time::FromDoubleT(start_time)));
  476. }
  477. void Session::SetPreloads(
  478. const std::vector<base::FilePath::StringType>& preloads) {
  479. auto* prefs = SessionPreferences::FromBrowserContext(browser_context());
  480. DCHECK(prefs);
  481. prefs->set_preloads(preloads);
  482. }
  483. std::vector<base::FilePath::StringType> Session::GetPreloads() const {
  484. auto* prefs = SessionPreferences::FromBrowserContext(browser_context());
  485. DCHECK(prefs);
  486. return prefs->preloads();
  487. }
  488. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  489. void Session::LoadChromeExtension(const base::FilePath extension_path) {
  490. auto* extension_system = static_cast<extensions::AtomExtensionSystem*>(
  491. extensions::ExtensionSystem::Get(browser_context()));
  492. extension_system->LoadExtension(extension_path);
  493. }
  494. #endif
  495. v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
  496. if (cookies_.IsEmpty()) {
  497. auto handle = Cookies::Create(isolate, browser_context());
  498. cookies_.Reset(isolate, handle.ToV8());
  499. }
  500. return v8::Local<v8::Value>::New(isolate, cookies_);
  501. }
  502. v8::Local<v8::Value> Session::Protocol(v8::Isolate* isolate) {
  503. if (protocol_.IsEmpty()) {
  504. v8::Local<v8::Value> handle;
  505. handle = ProtocolNS::Create(isolate, browser_context()).ToV8();
  506. protocol_.Reset(isolate, handle);
  507. }
  508. return v8::Local<v8::Value>::New(isolate, protocol_);
  509. }
  510. v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
  511. if (web_request_.IsEmpty()) {
  512. v8::Local<v8::Value> handle;
  513. handle = WebRequestNS::Create(isolate, browser_context()).ToV8();
  514. web_request_.Reset(isolate, handle);
  515. }
  516. return v8::Local<v8::Value>::New(isolate, web_request_);
  517. }
  518. v8::Local<v8::Value> Session::NetLog(v8::Isolate* isolate) {
  519. if (net_log_.IsEmpty()) {
  520. auto handle = electron::api::NetLog::Create(isolate, browser_context());
  521. net_log_.Reset(isolate, handle.ToV8());
  522. }
  523. return v8::Local<v8::Value>::New(isolate, net_log_);
  524. }
  525. static void StartPreconnectOnUI(
  526. scoped_refptr<AtomBrowserContext> browser_context,
  527. const GURL& url,
  528. int num_sockets_to_preconnect) {
  529. std::vector<predictors::PreconnectRequest> requests = {
  530. {url.GetOrigin(), num_sockets_to_preconnect, net::NetworkIsolationKey()}};
  531. browser_context->GetPreconnectManager()->Start(url, requests);
  532. }
  533. void Session::Preconnect(const mate::Dictionary& options,
  534. mate::Arguments* args) {
  535. GURL url;
  536. if (!options.Get("url", &url) || !url.is_valid()) {
  537. args->ThrowError("Must pass non-empty valid url to session.preconnect.");
  538. return;
  539. }
  540. int num_sockets_to_preconnect = 1;
  541. if (options.Get("numSockets", &num_sockets_to_preconnect)) {
  542. const int kMinSocketsToPreconnect = 1;
  543. const int kMaxSocketsToPreconnect = 6;
  544. if (num_sockets_to_preconnect < kMinSocketsToPreconnect ||
  545. num_sockets_to_preconnect > kMaxSocketsToPreconnect) {
  546. args->ThrowError(
  547. base::StringPrintf("numSocketsToPreconnect is outside range [%d,%d]",
  548. kMinSocketsToPreconnect, kMaxSocketsToPreconnect));
  549. return;
  550. }
  551. }
  552. DCHECK_GT(num_sockets_to_preconnect, 0);
  553. base::PostTaskWithTraits(
  554. FROM_HERE, {content::BrowserThread::UI},
  555. base::BindOnce(&StartPreconnectOnUI, base::RetainedRef(browser_context_),
  556. url, num_sockets_to_preconnect));
  557. }
  558. // static
  559. mate::Handle<Session> Session::CreateFrom(v8::Isolate* isolate,
  560. AtomBrowserContext* browser_context) {
  561. auto* existing = TrackableObject::FromWrappedClass(isolate, browser_context);
  562. if (existing)
  563. return mate::CreateHandle(isolate, static_cast<Session*>(existing));
  564. auto handle =
  565. mate::CreateHandle(isolate, new Session(isolate, browser_context));
  566. // The Sessions should never be garbage collected, since the common pattern is
  567. // to use partition strings, instead of using the Session object directly.
  568. g_sessions[handle->weak_map_id()] =
  569. v8::Global<v8::Object>(isolate, handle.ToV8());
  570. return handle;
  571. }
  572. // static
  573. mate::Handle<Session> Session::FromPartition(
  574. v8::Isolate* isolate,
  575. const std::string& partition,
  576. const base::DictionaryValue& options) {
  577. scoped_refptr<AtomBrowserContext> browser_context;
  578. if (partition.empty()) {
  579. browser_context = AtomBrowserContext::From("", false, options);
  580. } else if (base::StartsWith(partition, kPersistPrefix,
  581. base::CompareCase::SENSITIVE)) {
  582. std::string name = partition.substr(8);
  583. browser_context = AtomBrowserContext::From(name, false, options);
  584. } else {
  585. browser_context = AtomBrowserContext::From(partition, true, options);
  586. }
  587. return CreateFrom(isolate, browser_context.get());
  588. }
  589. // static
  590. void Session::BuildPrototype(v8::Isolate* isolate,
  591. v8::Local<v8::FunctionTemplate> prototype) {
  592. prototype->SetClassName(mate::StringToV8(isolate, "Session"));
  593. mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
  594. .MakeDestroyable()
  595. .SetMethod("resolveProxy", &Session::ResolveProxy)
  596. .SetMethod("getCacheSize", &Session::GetCacheSize)
  597. .SetMethod("clearCache", &Session::ClearCache)
  598. .SetMethod("clearStorageData", &Session::ClearStorageData)
  599. .SetMethod("flushStorageData", &Session::FlushStorageData)
  600. .SetMethod("setProxy", &Session::SetProxy)
  601. .SetMethod("setDownloadPath", &Session::SetDownloadPath)
  602. .SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
  603. .SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
  604. .SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
  605. .SetMethod("setPermissionRequestHandler",
  606. &Session::SetPermissionRequestHandler)
  607. .SetMethod("setPermissionCheckHandler",
  608. &Session::SetPermissionCheckHandler)
  609. .SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache)
  610. .SetMethod("clearAuthCache", &Session::ClearAuthCache)
  611. .SetMethod("allowNTLMCredentialsForDomains",
  612. &Session::AllowNTLMCredentialsForDomains)
  613. .SetMethod("setUserAgent", &Session::SetUserAgent)
  614. .SetMethod("getUserAgent", &Session::GetUserAgent)
  615. .SetMethod("getBlobData", &Session::GetBlobData)
  616. .SetMethod("createInterruptedDownload",
  617. &Session::CreateInterruptedDownload)
  618. .SetMethod("setPreloads", &Session::SetPreloads)
  619. .SetMethod("getPreloads", &Session::GetPreloads)
  620. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  621. .SetMethod("loadChromeExtension", &Session::LoadChromeExtension)
  622. #endif
  623. .SetMethod("preconnect", &Session::Preconnect)
  624. .SetProperty("cookies", &Session::Cookies)
  625. .SetProperty("netLog", &Session::NetLog)
  626. .SetProperty("protocol", &Session::Protocol)
  627. .SetProperty("webRequest", &Session::WebRequest);
  628. }
  629. } // namespace api
  630. } // namespace electron
  631. namespace {
  632. using electron::api::Cookies;
  633. using electron::api::NetLog;
  634. using electron::api::ProtocolNS;
  635. using electron::api::Session;
  636. v8::Local<v8::Value> FromPartition(const std::string& partition,
  637. mate::Arguments* args) {
  638. if (!electron::Browser::Get()->is_ready()) {
  639. args->ThrowError("Session can only be received when app is ready");
  640. return v8::Null(args->isolate());
  641. }
  642. base::DictionaryValue options;
  643. args->GetNext(&options);
  644. return Session::FromPartition(args->isolate(), partition, options).ToV8();
  645. }
  646. void Initialize(v8::Local<v8::Object> exports,
  647. v8::Local<v8::Value> unused,
  648. v8::Local<v8::Context> context,
  649. void* priv) {
  650. v8::Isolate* isolate = context->GetIsolate();
  651. mate::Dictionary dict(isolate, exports);
  652. dict.Set(
  653. "Session",
  654. Session::GetConstructor(isolate)->GetFunction(context).ToLocalChecked());
  655. dict.Set(
  656. "Cookies",
  657. Cookies::GetConstructor(isolate)->GetFunction(context).ToLocalChecked());
  658. dict.Set(
  659. "NetLog",
  660. NetLog::GetConstructor(isolate)->GetFunction(context).ToLocalChecked());
  661. dict.Set("Protocol", ProtocolNS::GetConstructor(isolate)
  662. ->GetFunction(context)
  663. .ToLocalChecked());
  664. dict.SetMethod("fromPartition", &FromPartition);
  665. }
  666. } // namespace
  667. NODE_LINKED_MODULE_CONTEXT_AWARE(atom_browser_session, Initialize)