feat: Allow usage of an absolute path for partitions used in a session (#37604)

* Allow an absolute path to be used for creating sessions

Allows an absolute path to be used for creating sessions
by adding the session.fromPath() API.

* Fixup! Clarify that an emptry string is not permitted as a parameter to fromPath()
This commit is contained in:
George Joseph 2023-03-20 14:34:49 +00:00 committed by GitHub
parent eb613ef3d4
commit e0c348a2f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 153 additions and 18 deletions

View file

@ -12,7 +12,9 @@
#include <vector>
#include "base/command_line.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/guid.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@ -1206,6 +1208,30 @@ gin::Handle<Session> Session::FromPartition(v8::Isolate* isolate,
return CreateFrom(isolate, browser_context);
}
// static
absl::optional<gin::Handle<Session>> Session::FromPath(
v8::Isolate* isolate,
const base::FilePath& path,
base::Value::Dict options) {
ElectronBrowserContext* browser_context;
if (path.empty()) {
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
promise.RejectWithErrorMessage("An empty path was specified");
return absl::nullopt;
}
if (!path.IsAbsolute()) {
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
promise.RejectWithErrorMessage("An absolute path was not provided");
return absl::nullopt;
}
browser_context =
ElectronBrowserContext::FromPath(std::move(path), std::move(options));
return CreateFrom(isolate, browser_context);
}
// static
gin::Handle<Session> Session::New() {
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
@ -1311,6 +1337,23 @@ v8::Local<v8::Value> FromPartition(const std::string& partition,
.ToV8();
}
v8::Local<v8::Value> FromPath(const base::FilePath& path,
gin::Arguments* args) {
if (!electron::Browser::Get()->is_ready()) {
args->ThrowTypeError("Session can only be received when app is ready");
return v8::Null(args->isolate());
}
base::Value::Dict options;
args->GetNext(&options);
absl::optional<gin::Handle<Session>> session_handle =
Session::FromPath(args->isolate(), path, std::move(options));
if (session_handle)
return session_handle.value().ToV8();
else
return v8::Null(args->isolate());
}
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
@ -1319,6 +1362,7 @@ void Initialize(v8::Local<v8::Object> exports,
gin_helper::Dictionary dict(isolate, exports);
dict.Set("Session", Session::GetConstructor(context));
dict.SetMethod("fromPartition", &FromPartition);
dict.SetMethod("fromPath", &FromPath);
}
} // namespace

View file

@ -82,6 +82,12 @@ class Session : public gin::Wrappable<Session>,
const std::string& partition,
base::Value::Dict options = {});
// Gets the Session based on |path|.
static absl::optional<gin::Handle<Session>> FromPath(
v8::Isolate* isolate,
const base::FilePath& path,
base::Value::Dict options = {});
ElectronBrowserContext* browser_context() const { return browser_context_; }
// gin::Wrappable

View file

@ -106,9 +106,10 @@ ElectronBrowserContext::browser_context_map() {
return *browser_context_map;
}
ElectronBrowserContext::ElectronBrowserContext(const std::string& partition,
bool in_memory,
base::Value::Dict options)
ElectronBrowserContext::ElectronBrowserContext(
const PartitionOrPath partition_location,
bool in_memory,
base::Value::Dict options)
: in_memory_pref_store_(new ValueMapPrefStore),
storage_policy_(base::MakeRefCounted<SpecialStoragePolicy>()),
protocol_registry_(base::WrapUnique(new ProtocolRegistry)),
@ -124,11 +125,21 @@ ElectronBrowserContext::ElectronBrowserContext(const std::string& partition,
base::StringToInt(command_line->GetSwitchValueASCII(switches::kDiskCacheSize),
&max_cache_size_);
base::PathService::Get(DIR_SESSION_DATA, &path_);
if (!in_memory && !partition.empty())
path_ = path_.Append(FILE_PATH_LITERAL("Partitions"))
.Append(base::FilePath::FromUTF8Unsafe(
MakePartitionName(partition)));
if (auto* path_value = std::get_if<std::reference_wrapper<const std::string>>(
&partition_location)) {
base::PathService::Get(DIR_SESSION_DATA, &path_);
const std::string& partition_loc = path_value->get();
if (!in_memory && !partition_loc.empty()) {
path_ = path_.Append(FILE_PATH_LITERAL("Partitions"))
.Append(base::FilePath::FromUTF8Unsafe(
MakePartitionName(partition_loc)));
}
} else if (auto* filepath_partition =
std::get_if<std::reference_wrapper<const base::FilePath>>(
&partition_location)) {
const base::FilePath& partition_path = filepath_partition->get();
path_ = std::move(partition_path);
}
BrowserContextDependencyManager::GetInstance()->MarkBrowserContextLive(this);
@ -674,8 +685,25 @@ ElectronBrowserContext* ElectronBrowserContext::From(
return browser_context;
}
auto* new_context = new ElectronBrowserContext(std::cref(partition),
in_memory, std::move(options));
browser_context_map()[key] =
std::unique_ptr<ElectronBrowserContext>(new_context);
return new_context;
}
ElectronBrowserContext* ElectronBrowserContext::FromPath(
const base::FilePath& path,
base::Value::Dict options) {
PartitionKey key(path);
ElectronBrowserContext* browser_context = browser_context_map()[key].get();
if (browser_context) {
return browser_context;
}
auto* new_context =
new ElectronBrowserContext(partition, in_memory, std::move(options));
new ElectronBrowserContext(std::cref(path), false, std::move(options));
browser_context_map()[key] =
std::unique_ptr<ElectronBrowserContext>(new_context);
return new_context;

View file

@ -65,6 +65,9 @@ using DisplayMediaResponseCallbackJs =
using DisplayMediaRequestHandler =
base::RepeatingCallback<void(const content::MediaStreamRequest&,
DisplayMediaResponseCallbackJs)>;
using PartitionOrPath =
std::variant<std::reference_wrapper<const std::string>,
std::reference_wrapper<const base::FilePath>>;
class ElectronBrowserContext : public content::BrowserContext {
public:
@ -74,22 +77,43 @@ class ElectronBrowserContext : public content::BrowserContext {
// partition_id => browser_context
struct PartitionKey {
std::string partition;
enum class KeyType { Partition, FilePath };
std::string location;
bool in_memory;
KeyType partition_type;
PartitionKey(const std::string& partition, bool in_memory)
: partition(partition), in_memory(in_memory) {}
: location(partition),
in_memory(in_memory),
partition_type(KeyType::Partition) {}
explicit PartitionKey(const base::FilePath& file_path)
: location(file_path.AsUTF8Unsafe()),
in_memory(false),
partition_type(KeyType::FilePath) {}
bool operator<(const PartitionKey& other) const {
if (partition == other.partition)
return in_memory < other.in_memory;
return partition < other.partition;
if (partition_type == KeyType::Partition) {
if (location == other.location)
return in_memory < other.in_memory;
return location < other.location;
} else {
if (location == other.location)
return false;
return location < other.location;
}
}
bool operator==(const PartitionKey& other) const {
return (partition == other.partition) && (in_memory == other.in_memory);
if (partition_type == KeyType::Partition) {
return (location == other.location) && (in_memory < other.in_memory);
} else {
if (location == other.location)
return true;
return false;
}
}
};
using BrowserContextMap =
std::map<PartitionKey, std::unique_ptr<ElectronBrowserContext>>;
@ -100,6 +124,12 @@ class ElectronBrowserContext : public content::BrowserContext {
bool in_memory,
base::Value::Dict options = {});
// Get or create the BrowserContext using the |path|.
// The |options| will be passed to constructor when there is no
// existing BrowserContext.
static ElectronBrowserContext* FromPath(const base::FilePath& path,
base::Value::Dict options = {});
static BrowserContextMap& browser_context_map();
void SetUserAgent(const std::string& user_agent);
@ -190,10 +220,12 @@ class ElectronBrowserContext : public content::BrowserContext {
blink::PermissionType permissionType);
private:
ElectronBrowserContext(const std::string& partition,
ElectronBrowserContext(const PartitionOrPath partition_location,
bool in_memory,
base::Value::Dict options);
ElectronBrowserContext(base::FilePath partition, base::Value::Dict options);
static void DisplayMediaDeviceChosen(
const content::MediaStreamRequest& request,
content::MediaResponseCallback callback,