feat: allow customizing browser data location (#33554)

* feat: redirect Electron/Chromium cache location

* fix: network services should also use browserData

* test: browserData

* chore: no need to explicitly create dir

* feat: browserData => sessionData

* test: check existings of specific items

* docs: add background on userData and sessionData

Co-authored-by: emmanuel.kimmerlin@thomsonreuters.com <emmanuel.kimmerlin@thomsonreuters.com>
This commit is contained in:
Cheng Zhao 2022-05-09 23:26:57 +09:00 коммит произвёл GitHub
Родитель 03e68e2efe
Коммит 9483e714c4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 128 добавлений и 18 удалений

Просмотреть файл

@ -635,8 +635,18 @@ Returns `string` - The current application directory.
* `%APPDATA%` on Windows
* `$XDG_CONFIG_HOME` or `~/.config` on Linux
* `~/Library/Application Support` on macOS
* `userData` The directory for storing your app's configuration files, which by
default it is the `appData` directory appended with your app's name.
* `userData` The directory for storing your app's configuration files, which
by default is the `appData` directory appended with your app's name. By
convention files storing user data should be written to this directory, and
it is not recommended to write large files here because some environments
may backup this directory to cloud storage.
* `sessionData` The directory for storing data generated by `Session`, such
as localStorage, cookies, disk cache, downloaded dictionaries, network
state, devtools files. By default this points to `userData`. Chromium may
write very large disk cache here, so if your app does not rely on browser
storage like localStorage or cookies to save user data, it is recommended
to set this directory to other locations to avoid polluting the `userData`
directory.
* `temp` Temporary directory.
* `exe` The current executable file.
* `module` The `libchromiumcontent` library.
@ -686,9 +696,9 @@ In that case, the directory should be created with `fs.mkdirSync` or similar.
You can only override paths of a `name` defined in `app.getPath`.
By default, web pages' cookies and caches will be stored under the `userData`
By default, web pages' cookies and caches will be stored under the `sessionData`
directory. If you want to change this location, you have to override the
`userData` path before the `ready` event of the `app` module is emitted.
`sessionData` path before the `ready` event of the `app` module is emitted.
### `app.getVersion()`

Просмотреть файл

@ -134,11 +134,14 @@ bool ElectronPathProvider(int key, base::FilePath* result) {
break;
case chrome::DIR_APP_DICTIONARIES:
// TODO(nornagon): can we just default to using Chrome's logic here?
if (!base::PathService::Get(chrome::DIR_USER_DATA, &cur))
if (!base::PathService::Get(DIR_SESSION_DATA, &cur))
return false;
cur = cur.Append(base::FilePath::FromUTF8Unsafe("Dictionaries"));
create_dir = true;
break;
case DIR_SESSION_DATA:
// By default and for backward, equivalent to DIR_USER_DATA.
return base::PathService::Get(chrome::DIR_USER_DATA, result);
case DIR_USER_CACHE: {
#if BUILDFLAG(IS_POSIX)
int parent_key = base::DIR_CACHE;

Просмотреть файл

@ -473,6 +473,8 @@ IconLoader::IconSize GetIconSizeByString(const std::string& size) {
int GetPathConstant(const std::string& name) {
if (name == "appData")
return DIR_APP_DATA;
else if (name == "sessionData")
return DIR_SESSION_DATA;
else if (name == "userData")
return chrome::DIR_USER_DATA;
else if (name == "cache")

Просмотреть файл

@ -110,7 +110,7 @@ void BrowserProcessImpl::PostEarlyInitialization() {
// Only use a persistent prefs store when cookie encryption is enabled as that
// is the only key that needs it
base::FilePath prefs_path;
CHECK(base::PathService::Get(chrome::DIR_USER_DATA, &prefs_path));
CHECK(base::PathService::Get(electron::DIR_SESSION_DATA, &prefs_path));
prefs_path = prefs_path.Append(FILE_PATH_LITERAL("Local State"));
base::ThreadRestrictions::ScopedAllowIO allow_io;
scoped_refptr<JsonPrefStore> user_pref_store =

Просмотреть файл

@ -1139,11 +1139,11 @@ void ElectronBrowserClient::OnNetworkServiceCreated(
std::vector<base::FilePath>
ElectronBrowserClient::GetNetworkContextsParentDirectory() {
base::FilePath user_data_dir;
base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
DCHECK(!user_data_dir.empty());
base::FilePath session_data;
base::PathService::Get(DIR_SESSION_DATA, &session_data);
DCHECK(!session_data.empty());
return {user_data_dir};
return {session_data};
}
std::string ElectronBrowserClient::GetProduct() {

Просмотреть файл

@ -120,8 +120,7 @@ ElectronBrowserContext::ElectronBrowserContext(const std::string& partition,
base::StringToInt(command_line->GetSwitchValueASCII(switches::kDiskCacheSize),
&max_cache_size_);
CHECK(base::PathService::Get(chrome::DIR_USER_DATA, &path_));
base::PathService::Get(DIR_SESSION_DATA, &path_);
if (!in_memory && !partition.empty())
path_ = path_.Append(FILE_PATH_LITERAL("Partitions"))
.Append(base::FilePath::FromUTF8Unsafe(

Просмотреть файл

@ -501,7 +501,7 @@ void ElectronBrowserMainParts::PostCreateMainMessageLoop() {
// https://source.chromium.org/chromium/chromium/src/+/master:chrome/common/chrome_switches.cc;l=689;drc=9d82515060b9b75fa941986f5db7390299669ef1
config->should_use_preference =
command_line.HasSwitch(::switches::kEnableEncryptionSelection);
base::PathService::Get(chrome::DIR_USER_DATA, &config->user_data_path);
base::PathService::Get(DIR_SESSION_DATA, &config->user_data_path);
OSCrypt::SetConfig(std::move(config));
#endif
#if BUILDFLAG(IS_POSIX)

Просмотреть файл

@ -91,10 +91,10 @@ const char kBrowserCloseMethod[] = "Browser.close";
// static
void DevToolsManagerDelegate::StartHttpHandler() {
base::FilePath user_dir;
base::PathService::Get(chrome::DIR_USER_DATA, &user_dir);
base::FilePath session_data;
base::PathService::Get(DIR_SESSION_DATA, &session_data);
content::DevToolsAgentHost::StartRemoteDebuggingServer(
CreateSocketFactory(), user_dir, base::FilePath());
CreateSocketFactory(), session_data, base::FilePath());
}
DevToolsManagerDelegate::DevToolsManagerDelegate() = default;

Просмотреть файл

@ -23,7 +23,8 @@ enum {
PATH_START = 11000,
DIR_USER_CACHE = PATH_START, // Directory where user cache can be written.
DIR_APP_LOGS, // Directory where app logs live
DIR_APP_LOGS, // Directory where app logs live.
DIR_SESSION_DATA, // Where cookies, localStorage are stored.
#if BUILDFLAG(IS_WIN)
DIR_RECENT, // Directory where recent files live

Просмотреть файл

@ -3,7 +3,7 @@ import * as cp from 'child_process';
import * as https from 'https';
import * as http from 'http';
import * as net from 'net';
import * as fs from 'fs';
import * as fs from 'fs-extra';
import * as path from 'path';
import { promisify } from 'util';
import { app, BrowserWindow, Menu, session, net as electronNet } from 'electron/main';
@ -1078,6 +1078,54 @@ describe('app module', () => {
expect(() => { app.getPath(badPath as any); }).to.throw();
});
describe('sessionData', () => {
const appPath = path.join(__dirname, 'fixtures', 'apps', 'set-path');
const appName = fs.readJsonSync(path.join(appPath, 'package.json')).name;
const userDataPath = path.join(app.getPath('appData'), appName);
const tempBrowserDataPath = path.join(app.getPath('temp'), appName);
const sessionFiles = [
'Preferences',
'Code Cache',
'Local Storage',
'IndexedDB',
'Service Worker'
];
const hasSessionFiles = (dir: string) => {
for (const file of sessionFiles) {
if (!fs.existsSync(path.join(dir, file))) {
return false;
}
}
return true;
};
beforeEach(() => {
fs.removeSync(userDataPath);
fs.removeSync(tempBrowserDataPath);
});
it('writes to userData by default', () => {
expect(hasSessionFiles(userDataPath)).to.equal(false);
cp.spawnSync(process.execPath, [appPath]);
expect(hasSessionFiles(userDataPath)).to.equal(true);
});
it('can be changed', () => {
expect(hasSessionFiles(userDataPath)).to.equal(false);
cp.spawnSync(process.execPath, [appPath, 'sessionData', tempBrowserDataPath]);
expect(hasSessionFiles(userDataPath)).to.equal(false);
expect(hasSessionFiles(tempBrowserDataPath)).to.equal(true);
});
it('changing userData affects default sessionData', () => {
expect(hasSessionFiles(userDataPath)).to.equal(false);
cp.spawnSync(process.execPath, [appPath, 'userData', tempBrowserDataPath]);
expect(hasSessionFiles(userDataPath)).to.equal(false);
expect(hasSessionFiles(tempBrowserDataPath)).to.equal(true);
});
});
});
describe('setAppLogsPath(path)', () => {

Просмотреть файл

@ -0,0 +1,43 @@
const http = require('http');
const { app, ipcMain, BrowserWindow } = require('electron');
if (process.argv.length > 3) {
app.setPath(process.argv[2], process.argv[3]);
}
const html = `
<script>
async function main() {
localStorage.setItem('myCat', 'Tom')
const db = indexedDB.open('db-name', 1)
await new Promise(resolve => db.onsuccess = resolve)
await navigator.serviceWorker.register('sw.js', {scope: './'})
}
main().then(() => {
require('electron').ipcRenderer.send('success')
})
</script>
`;
const js = 'console.log("From service worker")';
app.once('ready', () => {
ipcMain.on('success', () => {
app.quit();
});
const server = http.createServer((request, response) => {
if (request.url === '/') {
response.writeHead(200, { 'Content-Type': 'text/html' });
response.end(html);
} else if (request.url === '/sw.js') {
response.writeHead(200, { 'Content-Type': 'text/javascript' });
response.end(js);
}
}).listen(0, '127.0.0.1', () => {
const serverUrl = 'http://127.0.0.1:' + server.address().port;
const mainWindow = new BrowserWindow({ show: false, webPreferences: { webSecurity: true, nodeIntegration: true, contextIsolation: false } });
mainWindow.loadURL(serverUrl);
});
});

Просмотреть файл

@ -0,0 +1,4 @@
{
"name": "electron-test-set-path",
"main": "main.js"
}