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
|
* `%APPDATA%` on Windows
|
||||||
* `$XDG_CONFIG_HOME` or `~/.config` on Linux
|
* `$XDG_CONFIG_HOME` or `~/.config` on Linux
|
||||||
* `~/Library/Application Support` on macOS
|
* `~/Library/Application Support` on macOS
|
||||||
* `userData` The directory for storing your app's configuration files, which by
|
* `userData` The directory for storing your app's configuration files, which
|
||||||
default it is the `appData` directory appended with your app's name.
|
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.
|
* `temp` Temporary directory.
|
||||||
* `exe` The current executable file.
|
* `exe` The current executable file.
|
||||||
* `module` The `libchromiumcontent` library.
|
* `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`.
|
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
|
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()`
|
### `app.getVersion()`
|
||||||
|
|
||||||
|
|
|
@ -134,11 +134,14 @@ bool ElectronPathProvider(int key, base::FilePath* result) {
|
||||||
break;
|
break;
|
||||||
case chrome::DIR_APP_DICTIONARIES:
|
case chrome::DIR_APP_DICTIONARIES:
|
||||||
// TODO(nornagon): can we just default to using Chrome's logic here?
|
// 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;
|
return false;
|
||||||
cur = cur.Append(base::FilePath::FromUTF8Unsafe("Dictionaries"));
|
cur = cur.Append(base::FilePath::FromUTF8Unsafe("Dictionaries"));
|
||||||
create_dir = true;
|
create_dir = true;
|
||||||
break;
|
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: {
|
case DIR_USER_CACHE: {
|
||||||
#if BUILDFLAG(IS_POSIX)
|
#if BUILDFLAG(IS_POSIX)
|
||||||
int parent_key = base::DIR_CACHE;
|
int parent_key = base::DIR_CACHE;
|
||||||
|
|
|
@ -473,6 +473,8 @@ IconLoader::IconSize GetIconSizeByString(const std::string& size) {
|
||||||
int GetPathConstant(const std::string& name) {
|
int GetPathConstant(const std::string& name) {
|
||||||
if (name == "appData")
|
if (name == "appData")
|
||||||
return DIR_APP_DATA;
|
return DIR_APP_DATA;
|
||||||
|
else if (name == "sessionData")
|
||||||
|
return DIR_SESSION_DATA;
|
||||||
else if (name == "userData")
|
else if (name == "userData")
|
||||||
return chrome::DIR_USER_DATA;
|
return chrome::DIR_USER_DATA;
|
||||||
else if (name == "cache")
|
else if (name == "cache")
|
||||||
|
|
|
@ -110,7 +110,7 @@ void BrowserProcessImpl::PostEarlyInitialization() {
|
||||||
// Only use a persistent prefs store when cookie encryption is enabled as that
|
// Only use a persistent prefs store when cookie encryption is enabled as that
|
||||||
// is the only key that needs it
|
// is the only key that needs it
|
||||||
base::FilePath prefs_path;
|
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"));
|
prefs_path = prefs_path.Append(FILE_PATH_LITERAL("Local State"));
|
||||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||||
scoped_refptr<JsonPrefStore> user_pref_store =
|
scoped_refptr<JsonPrefStore> user_pref_store =
|
||||||
|
|
|
@ -1139,11 +1139,11 @@ void ElectronBrowserClient::OnNetworkServiceCreated(
|
||||||
|
|
||||||
std::vector<base::FilePath>
|
std::vector<base::FilePath>
|
||||||
ElectronBrowserClient::GetNetworkContextsParentDirectory() {
|
ElectronBrowserClient::GetNetworkContextsParentDirectory() {
|
||||||
base::FilePath user_data_dir;
|
base::FilePath session_data;
|
||||||
base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
|
base::PathService::Get(DIR_SESSION_DATA, &session_data);
|
||||||
DCHECK(!user_data_dir.empty());
|
DCHECK(!session_data.empty());
|
||||||
|
|
||||||
return {user_data_dir};
|
return {session_data};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ElectronBrowserClient::GetProduct() {
|
std::string ElectronBrowserClient::GetProduct() {
|
||||||
|
|
|
@ -120,8 +120,7 @@ ElectronBrowserContext::ElectronBrowserContext(const std::string& partition,
|
||||||
base::StringToInt(command_line->GetSwitchValueASCII(switches::kDiskCacheSize),
|
base::StringToInt(command_line->GetSwitchValueASCII(switches::kDiskCacheSize),
|
||||||
&max_cache_size_);
|
&max_cache_size_);
|
||||||
|
|
||||||
CHECK(base::PathService::Get(chrome::DIR_USER_DATA, &path_));
|
base::PathService::Get(DIR_SESSION_DATA, &path_);
|
||||||
|
|
||||||
if (!in_memory && !partition.empty())
|
if (!in_memory && !partition.empty())
|
||||||
path_ = path_.Append(FILE_PATH_LITERAL("Partitions"))
|
path_ = path_.Append(FILE_PATH_LITERAL("Partitions"))
|
||||||
.Append(base::FilePath::FromUTF8Unsafe(
|
.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
|
// https://source.chromium.org/chromium/chromium/src/+/master:chrome/common/chrome_switches.cc;l=689;drc=9d82515060b9b75fa941986f5db7390299669ef1
|
||||||
config->should_use_preference =
|
config->should_use_preference =
|
||||||
command_line.HasSwitch(::switches::kEnableEncryptionSelection);
|
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));
|
OSCrypt::SetConfig(std::move(config));
|
||||||
#endif
|
#endif
|
||||||
#if BUILDFLAG(IS_POSIX)
|
#if BUILDFLAG(IS_POSIX)
|
||||||
|
|
|
@ -91,10 +91,10 @@ const char kBrowserCloseMethod[] = "Browser.close";
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void DevToolsManagerDelegate::StartHttpHandler() {
|
void DevToolsManagerDelegate::StartHttpHandler() {
|
||||||
base::FilePath user_dir;
|
base::FilePath session_data;
|
||||||
base::PathService::Get(chrome::DIR_USER_DATA, &user_dir);
|
base::PathService::Get(DIR_SESSION_DATA, &session_data);
|
||||||
content::DevToolsAgentHost::StartRemoteDebuggingServer(
|
content::DevToolsAgentHost::StartRemoteDebuggingServer(
|
||||||
CreateSocketFactory(), user_dir, base::FilePath());
|
CreateSocketFactory(), session_data, base::FilePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
DevToolsManagerDelegate::DevToolsManagerDelegate() = default;
|
DevToolsManagerDelegate::DevToolsManagerDelegate() = default;
|
||||||
|
|
|
@ -23,7 +23,8 @@ enum {
|
||||||
PATH_START = 11000,
|
PATH_START = 11000,
|
||||||
|
|
||||||
DIR_USER_CACHE = PATH_START, // Directory where user cache can be written.
|
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)
|
#if BUILDFLAG(IS_WIN)
|
||||||
DIR_RECENT, // Directory where recent files live
|
DIR_RECENT, // Directory where recent files live
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as cp from 'child_process';
|
||||||
import * as https from 'https';
|
import * as https from 'https';
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
import * as net from 'net';
|
import * as net from 'net';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs-extra';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
import { app, BrowserWindow, Menu, session, net as electronNet } from 'electron/main';
|
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();
|
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)', () => {
|
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