feat: Session#clearData API (#40983)
		
	* WIP: Session.clearBrowsingData API * impl API method * clean up * tidy types and comments * add docs * add barebones test * forgot a `#` :( * tidy: address review comments * use format macro for cross-platform build * add another test * amend docs to disambiguate * Rename to `clearData`
This commit is contained in:
		
					parent
					
						
							
								e95673b052
							
						
					
				
			
			
				commit
				
					
						12d7a8ff66
					
				
			
		
					 4 changed files with 106 additions and 0 deletions
				
			
		| 
						 | 
					@ -1424,6 +1424,26 @@ is emitted.
 | 
				
			||||||
Returns `string | null` - The absolute file system path where data for this
 | 
					Returns `string | null` - The absolute file system path where data for this
 | 
				
			||||||
session is persisted on disk.  For in memory sessions this returns `null`.
 | 
					session is persisted on disk.  For in memory sessions this returns `null`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `ses.clearData()`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Returns `Promise<void>` - resolves when all data has been cleared.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This method clears many different types of data, inlcuding:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Cache
 | 
				
			||||||
 | 
					* Cookies
 | 
				
			||||||
 | 
					* Downloads
 | 
				
			||||||
 | 
					* IndexedDB
 | 
				
			||||||
 | 
					* Local Storage
 | 
				
			||||||
 | 
					* Service Workers
 | 
				
			||||||
 | 
					* And more...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This method clears more types of data and is more thourough than the
 | 
				
			||||||
 | 
					`clearStorageData` method, however it is currently less configurable than that
 | 
				
			||||||
 | 
					method.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For more information, refer to Chromium's [`BrowsingDataRemover` interface](https://source.chromium.org/chromium/chromium/src/+/main:content/public/browser/browsing_data_remover.h).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Instance Properties
 | 
					### Instance Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The following properties are available on instances of `Session`:
 | 
					The following properties are available on instances of `Session`:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@
 | 
				
			||||||
#include "base/files/file_path.h"
 | 
					#include "base/files/file_path.h"
 | 
				
			||||||
#include "base/files/file_util.h"
 | 
					#include "base/files/file_util.h"
 | 
				
			||||||
#include "base/memory/raw_ptr.h"
 | 
					#include "base/memory/raw_ptr.h"
 | 
				
			||||||
 | 
					#include "base/scoped_observation.h"
 | 
				
			||||||
#include "base/strings/string_util.h"
 | 
					#include "base/strings/string_util.h"
 | 
				
			||||||
#include "base/strings/stringprintf.h"
 | 
					#include "base/strings/stringprintf.h"
 | 
				
			||||||
#include "base/uuid.h"
 | 
					#include "base/uuid.h"
 | 
				
			||||||
| 
						 | 
					@ -32,6 +33,7 @@
 | 
				
			||||||
#include "content/browser/code_cache/generated_code_cache_context.h"  // nogncheck
 | 
					#include "content/browser/code_cache/generated_code_cache_context.h"  // nogncheck
 | 
				
			||||||
#include "content/public/browser/browser_task_traits.h"
 | 
					#include "content/public/browser/browser_task_traits.h"
 | 
				
			||||||
#include "content/public/browser/browser_thread.h"
 | 
					#include "content/public/browser/browser_thread.h"
 | 
				
			||||||
 | 
					#include "content/public/browser/browsing_data_remover.h"
 | 
				
			||||||
#include "content/public/browser/download_item_utils.h"
 | 
					#include "content/public/browser/download_item_utils.h"
 | 
				
			||||||
#include "content/public/browser/download_manager_delegate.h"
 | 
					#include "content/public/browser/download_manager_delegate.h"
 | 
				
			||||||
#include "content/public/browser/network_service_instance.h"
 | 
					#include "content/public/browser/network_service_instance.h"
 | 
				
			||||||
| 
						 | 
					@ -77,6 +79,7 @@
 | 
				
			||||||
#include "shell/common/gin_converters/value_converter.h"
 | 
					#include "shell/common/gin_converters/value_converter.h"
 | 
				
			||||||
#include "shell/common/gin_helper/dictionary.h"
 | 
					#include "shell/common/gin_helper/dictionary.h"
 | 
				
			||||||
#include "shell/common/gin_helper/object_template_builder.h"
 | 
					#include "shell/common/gin_helper/object_template_builder.h"
 | 
				
			||||||
 | 
					#include "shell/common/gin_helper/promise.h"
 | 
				
			||||||
#include "shell/common/node_includes.h"
 | 
					#include "shell/common/node_includes.h"
 | 
				
			||||||
#include "shell/common/options_switches.h"
 | 
					#include "shell/common/options_switches.h"
 | 
				
			||||||
#include "shell/common/process_util.h"
 | 
					#include "shell/common/process_util.h"
 | 
				
			||||||
| 
						 | 
					@ -149,6 +152,40 @@ uint32_t GetQuotaMask(const std::vector<std::string>& quota_types) {
 | 
				
			||||||
  return quota_mask;
 | 
					  return quota_mask;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr content::BrowsingDataRemover::DataType kClearDataTypeAll = ~0ULL;
 | 
				
			||||||
 | 
					constexpr content::BrowsingDataRemover::OriginType kClearOriginTypeAll =
 | 
				
			||||||
 | 
					    content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
 | 
				
			||||||
 | 
					    content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Observes the BrowsingDataRemover that backs the `clearData` method and
 | 
				
			||||||
 | 
					// fulfills that API's promise once it's done. This type manages its own
 | 
				
			||||||
 | 
					// lifetime, deleting itself once it's done.
 | 
				
			||||||
 | 
					class ClearDataObserver : public content::BrowsingDataRemover::Observer {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  ClearDataObserver(gin_helper::Promise<void> promise,
 | 
				
			||||||
 | 
					                    content::BrowsingDataRemover* remover)
 | 
				
			||||||
 | 
					      : promise_(std::move(promise)) {
 | 
				
			||||||
 | 
					    observation_.Observe(remover);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void OnBrowsingDataRemoverDone(
 | 
				
			||||||
 | 
					      content::BrowsingDataRemover::DataType failed_data_types) override {
 | 
				
			||||||
 | 
					    if (failed_data_types == 0ULL) {
 | 
				
			||||||
 | 
					      promise_.Resolve();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      promise_.RejectWithErrorMessage(base::StringPrintf(
 | 
				
			||||||
 | 
					          "Failed to clear browsing data (%" PRIu64 ")", failed_data_types));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    delete this;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  gin_helper::Promise<void> promise_;
 | 
				
			||||||
 | 
					  base::ScopedObservation<content::BrowsingDataRemover,
 | 
				
			||||||
 | 
					                          content::BrowsingDataRemover::Observer>
 | 
				
			||||||
 | 
					      observation_{this};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
base::Value::Dict createProxyConfig(ProxyPrefs::ProxyMode proxy_mode,
 | 
					base::Value::Dict createProxyConfig(ProxyPrefs::ProxyMode proxy_mode,
 | 
				
			||||||
                                    std::string const& pac_url,
 | 
					                                    std::string const& pac_url,
 | 
				
			||||||
                                    std::string const& proxy_server,
 | 
					                                    std::string const& proxy_server,
 | 
				
			||||||
| 
						 | 
					@ -1101,6 +1138,21 @@ v8::Local<v8::Promise> Session::ClearCodeCaches(
 | 
				
			||||||
  return handle;
 | 
					  return handle;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v8::Local<v8::Promise> Session::ClearData(gin::Arguments* args) {
 | 
				
			||||||
 | 
					  auto* isolate = JavascriptEnvironment::GetIsolate();
 | 
				
			||||||
 | 
					  gin_helper::Promise<void> promise(isolate);
 | 
				
			||||||
 | 
					  v8::Local<v8::Promise> promise_handle = promise.GetHandle();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  content::BrowsingDataRemover* remover =
 | 
				
			||||||
 | 
					      browser_context_->GetBrowsingDataRemover();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto* observer = new ClearDataObserver(std::move(promise), remover);
 | 
				
			||||||
 | 
					  remover->RemoveAndReply(base::Time::Min(), base::Time::Max(),
 | 
				
			||||||
 | 
					                          kClearDataTypeAll, kClearOriginTypeAll, observer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return promise_handle;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
 | 
					#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
 | 
				
			||||||
base::Value Session::GetSpellCheckerLanguages() {
 | 
					base::Value Session::GetSpellCheckerLanguages() {
 | 
				
			||||||
  return browser_context_->prefs()
 | 
					  return browser_context_->prefs()
 | 
				
			||||||
| 
						 | 
					@ -1370,6 +1422,7 @@ void Session::FillObjectTemplate(v8::Isolate* isolate,
 | 
				
			||||||
      .SetMethod("getStoragePath", &Session::GetPath)
 | 
					      .SetMethod("getStoragePath", &Session::GetPath)
 | 
				
			||||||
      .SetMethod("setCodeCachePath", &Session::SetCodeCachePath)
 | 
					      .SetMethod("setCodeCachePath", &Session::SetCodeCachePath)
 | 
				
			||||||
      .SetMethod("clearCodeCaches", &Session::ClearCodeCaches)
 | 
					      .SetMethod("clearCodeCaches", &Session::ClearCodeCaches)
 | 
				
			||||||
 | 
					      .SetMethod("clearData", &Session::ClearData)
 | 
				
			||||||
      .SetProperty("cookies", &Session::Cookies)
 | 
					      .SetProperty("cookies", &Session::Cookies)
 | 
				
			||||||
      .SetProperty("netLog", &Session::NetLog)
 | 
					      .SetProperty("netLog", &Session::NetLog)
 | 
				
			||||||
      .SetProperty("protocol", &Session::Protocol)
 | 
					      .SetProperty("protocol", &Session::Protocol)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,6 +147,7 @@ class Session : public gin::Wrappable<Session>,
 | 
				
			||||||
  v8::Local<v8::Value> GetPath(v8::Isolate* isolate);
 | 
					  v8::Local<v8::Value> GetPath(v8::Isolate* isolate);
 | 
				
			||||||
  void SetCodeCachePath(gin::Arguments* args);
 | 
					  void SetCodeCachePath(gin::Arguments* args);
 | 
				
			||||||
  v8::Local<v8::Promise> ClearCodeCaches(const gin_helper::Dictionary& options);
 | 
					  v8::Local<v8::Promise> ClearCodeCaches(const gin_helper::Dictionary& options);
 | 
				
			||||||
 | 
					  v8::Local<v8::Promise> ClearData(gin::Arguments* args);
 | 
				
			||||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
 | 
					#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
 | 
				
			||||||
  base::Value GetSpellCheckerLanguages();
 | 
					  base::Value GetSpellCheckerLanguages();
 | 
				
			||||||
  void SetSpellCheckerLanguages(gin_helper::ErrorThrower thrower,
 | 
					  void SetSpellCheckerLanguages(gin_helper::ErrorThrower thrower,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1607,4 +1607,36 @@ describe('session module', () => {
 | 
				
			||||||
      await expect(request()).to.be.rejectedWith(/ERR_SSL_VERSION_OR_CIPHER_MISMATCH/);
 | 
					      await expect(request()).to.be.rejectedWith(/ERR_SSL_VERSION_OR_CIPHER_MISMATCH/);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('ses.clearData()', () => {
 | 
				
			||||||
 | 
					    afterEach(closeAllWindows);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // NOTE: This API clears more than localStorage, but localStorage is a
 | 
				
			||||||
 | 
					    // convenient test target for this API
 | 
				
			||||||
 | 
					    it('clears localstorage data', async () => {
 | 
				
			||||||
 | 
					      const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
 | 
				
			||||||
 | 
					      await w.loadFile(path.join(fixtures, 'api', 'localstorage.html'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(await w.webContents.executeJavaScript('localStorage.length')).to.be.greaterThan(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await w.webContents.session.clearData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(await w.webContents.executeJavaScript('localStorage.length')).to.equal(0);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('clears localstorage data when called twice in parallel', async () => {
 | 
				
			||||||
 | 
					      const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
 | 
				
			||||||
 | 
					      await w.loadFile(path.join(fixtures, 'api', 'localstorage.html'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(await w.webContents.executeJavaScript('localStorage.length')).to.be.greaterThan(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // This first call is not awaited immediately
 | 
				
			||||||
 | 
					      const clearDataPromise = w.webContents.session.clearData();
 | 
				
			||||||
 | 
					      await w.webContents.session.clearData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(await w.webContents.executeJavaScript('localStorage.length')).to.equal(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Await the first promise so it doesn't creep into another test
 | 
				
			||||||
 | 
					      await clearDataPromise;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue