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:
parent
03e68e2efe
commit
9483e714c4
12 changed files with 128 additions and 18 deletions
|
@ -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)', () => {
|
||||
|
|
43
spec-main/fixtures/apps/set-path/main.js
Normal file
43
spec-main/fixtures/apps/set-path/main.js
Normal file
|
@ -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);
|
||||
});
|
||||
});
|
4
spec-main/fixtures/apps/set-path/package.json
Normal file
4
spec-main/fixtures/apps/set-path/package.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "electron-test-set-path",
|
||||
"main": "main.js"
|
||||
}
|
Loading…
Reference in a new issue