mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
1 Commits
test-linux
...
fix/electr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4e9cbfe2d |
@@ -451,6 +451,7 @@ filenames = {
|
||||
"shell/browser/net/network_context_service.h",
|
||||
"shell/browser/net/network_context_service_factory.cc",
|
||||
"shell/browser/net/network_context_service_factory.h",
|
||||
"shell/browser/net/network_service_restart_observer.h",
|
||||
"shell/browser/net/node_stream_loader.cc",
|
||||
"shell/browser/net/node_stream_loader.h",
|
||||
"shell/browser/net/proxying_url_loader_factory.cc",
|
||||
|
||||
@@ -30,8 +30,9 @@
|
||||
#include "components/proxy_config/proxy_config_dictionary.h"
|
||||
#include "components/proxy_config/proxy_config_pref_names.h"
|
||||
#include "components/proxy_config/proxy_prefs.h"
|
||||
#include "content/browser/gpu/compositor_util.h" // nogncheck
|
||||
#include "content/browser/gpu/gpu_data_manager_impl.h" // nogncheck
|
||||
#include "content/browser/gpu/compositor_util.h" // nogncheck
|
||||
#include "content/browser/gpu/gpu_data_manager_impl.h" // nogncheck
|
||||
#include "content/browser/network_service_instance_impl.h" // nogncheck
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
#include "content/public/browser/browser_child_process_host.h"
|
||||
#include "content/public/browser/child_process_data.h"
|
||||
@@ -627,6 +628,19 @@ void App::OnPreMainMessageLoopRun() {
|
||||
process_singleton_->StartWatching();
|
||||
watch_singleton_socket_on_ready_ = false;
|
||||
}
|
||||
|
||||
// Register handler for Network Service process gone events (crash/restart).
|
||||
// This is used for testing Network Service restart recovery.
|
||||
// Must be called on the UI thread after browser initialization is complete.
|
||||
network_service_gone_subscription_ =
|
||||
content::RegisterNetworkServiceProcessGoneHandler(base::BindRepeating(
|
||||
[](App* app, bool crashed) {
|
||||
if (crashed) {
|
||||
// Emit event when Network Service crashes (for testing).
|
||||
app->Emit("-network-service-crashed");
|
||||
}
|
||||
},
|
||||
base::Unretained(this)));
|
||||
}
|
||||
|
||||
void App::OnPreCreateThreads() {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback_list.h"
|
||||
#include "base/containers/flat_map.h"
|
||||
#include "base/task/cancelable_task_tracker.h"
|
||||
#include "chrome/browser/process_singleton.h"
|
||||
@@ -293,6 +294,9 @@ class App final : public gin::Wrappable<App>,
|
||||
bool disable_domain_blocking_for_3DAPIs_ = false;
|
||||
bool watch_singleton_socket_on_ready_ = false;
|
||||
|
||||
// Subscription to Network Service process gone notifications.
|
||||
base::CallbackListSubscription network_service_gone_subscription_;
|
||||
|
||||
std::unique_ptr<content::ScopedAccessibilityMode> scoped_accessibility_mode_;
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
#include "base/process/kill.h"
|
||||
#include "base/process/launch.h"
|
||||
#include "base/process/process.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/child_process_host.h"
|
||||
#include "content/public/browser/service_process_host.h"
|
||||
#include "content/public/common/result_codes.h"
|
||||
@@ -223,6 +226,7 @@ UtilityProcessWrapper::UtilityProcessWrapper(
|
||||
loader_params->url_loader_network_observer =
|
||||
url_loader_network_observer_->Bind();
|
||||
}
|
||||
|
||||
network::mojom::NetworkContext* network_context =
|
||||
g_browser_process->system_network_context_manager()->GetContext();
|
||||
network_context->CreateURLLoaderFactory(
|
||||
@@ -238,6 +242,14 @@ UtilityProcessWrapper::UtilityProcessWrapper(
|
||||
|
||||
node_service_remote_->Initialize(std::move(params),
|
||||
receiver_.BindNewPipeAndPassRemote());
|
||||
|
||||
// Subscribe to Network Service restart notifications.
|
||||
if (auto* manager = g_browser_process->system_network_context_manager()) {
|
||||
network_service_restart_subscription_ =
|
||||
manager->AddNetworkServiceRestartCallback(base::BindRepeating(
|
||||
&UtilityProcessWrapper::OnNetworkServiceRestarted,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
}
|
||||
|
||||
UtilityProcessWrapper::~UtilityProcessWrapper() {
|
||||
@@ -429,6 +441,48 @@ void UtilityProcessWrapper::OnV8FatalError(const std::string& location,
|
||||
EmitWithoutEvent("error", "FatalError", location, report);
|
||||
}
|
||||
|
||||
void UtilityProcessWrapper::OnNetworkServiceRestarted() {
|
||||
if (!node_service_remote_.is_connected())
|
||||
return;
|
||||
|
||||
content::GetUIThreadTaskRunner({})->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&UtilityProcessWrapper::CreateAndSendURLLoaderFactory,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void UtilityProcessWrapper::CreateAndSendURLLoaderFactory() {
|
||||
if (!node_service_remote_.is_connected())
|
||||
return;
|
||||
|
||||
auto* manager = g_browser_process->system_network_context_manager();
|
||||
if (!manager)
|
||||
return;
|
||||
|
||||
network::mojom::NetworkContext* network_context = manager->GetContext();
|
||||
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory;
|
||||
auto loader_params = network::mojom::URLLoaderFactoryParams::New();
|
||||
// Use kBrowserProcessId to match the initial factory creation (where pid_
|
||||
// was 0 before the process launched). This is required because non-browser
|
||||
// process IDs require a request_initiator_origin_lock to be set.
|
||||
loader_params->process_id = network::OriginatingProcess::browser();
|
||||
loader_params->is_orb_enabled = false;
|
||||
loader_params->is_trusted = true;
|
||||
|
||||
network_context->CreateURLLoaderFactory(
|
||||
url_loader_factory.InitWithNewPipeAndPassReceiver(),
|
||||
std::move(loader_params));
|
||||
|
||||
// Create host resolver from the same network context
|
||||
mojo::PendingRemote<network::mojom::HostResolver> host_resolver;
|
||||
network_context->CreateHostResolver(
|
||||
{}, host_resolver.InitWithNewPipeAndPassReceiver());
|
||||
|
||||
node_service_remote_->UpdateURLLoaderFactory(std::move(url_loader_factory),
|
||||
std::move(host_resolver));
|
||||
}
|
||||
|
||||
// static
|
||||
raw_ptr<UtilityProcessWrapper> UtilityProcessWrapper::FromProcessId(
|
||||
base::ProcessId pid) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/callback_list.h"
|
||||
#include "base/containers/id_map.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
@@ -99,6 +100,13 @@ class UtilityProcessWrapper final
|
||||
void OnServiceProcessDisconnected(uint32_t exit_code,
|
||||
const std::string& description);
|
||||
|
||||
// Called when the Network Service restarts.
|
||||
void OnNetworkServiceRestarted();
|
||||
|
||||
// Creates and sends a new URLLoaderFactory to the utility process.
|
||||
// Called after Network Service restart to update the factory.
|
||||
void CreateAndSendURLLoaderFactory();
|
||||
|
||||
base::ProcessId pid_ = base::kNullProcessId;
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// Non-owning handles, these will be closed when the
|
||||
@@ -117,6 +125,7 @@ class UtilityProcessWrapper final
|
||||
mojo::Remote<node::mojom::NodeService> node_service_remote_;
|
||||
std::optional<electron::URLLoaderNetworkObserver>
|
||||
url_loader_network_observer_;
|
||||
base::CallbackListSubscription network_service_restart_subscription_;
|
||||
base::WeakPtrFactory<UtilityProcessWrapper> weak_factory_{this};
|
||||
};
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include "shell/browser/file_system_access/file_system_access_permission_context_factory.h"
|
||||
#include "shell/browser/media/media_device_id_salt.h"
|
||||
#include "shell/browser/net/resolve_proxy_helper.h"
|
||||
#include "shell/browser/net/system_network_context_manager.h"
|
||||
#include "shell/browser/protocol_registry.h"
|
||||
#include "shell/browser/serial/serial_chooser_context.h"
|
||||
#include "shell/browser/special_storage_policy.h"
|
||||
@@ -407,10 +408,20 @@ ElectronBrowserContext::ElectronBrowserContext(
|
||||
extension_system->FinishInitialization();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Subscribe to Network Service restart notifications to reset the cached
|
||||
// URLLoaderFactory.
|
||||
if (auto* manager = SystemNetworkContextManager::GetInstance()) {
|
||||
network_service_restart_subscription_ =
|
||||
manager->AddNetworkServiceRestartCallback(base::BindRepeating(
|
||||
&ElectronBrowserContext::OnNetworkServiceRestarted,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
}
|
||||
|
||||
ElectronBrowserContext::~ElectronBrowserContext() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
NotifyWillBeDestroyed();
|
||||
|
||||
// Notify any keyed services of browser context destruction.
|
||||
@@ -568,6 +579,12 @@ content::PreconnectManager* ElectronBrowserContext::GetPreconnectManager() {
|
||||
return preconnect_manager_.get();
|
||||
}
|
||||
|
||||
void ElectronBrowserContext::OnNetworkServiceRestarted() {
|
||||
// Clear the cached URLLoaderFactory so the next request creates a new one
|
||||
// from the new NetworkContext.
|
||||
url_loader_factory_.reset();
|
||||
}
|
||||
|
||||
scoped_refptr<network::SharedURLLoaderFactory>
|
||||
ElectronBrowserContext::GetURLLoaderFactory() {
|
||||
if (url_loader_factory_)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback_list.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/media_stream_request.h"
|
||||
@@ -184,6 +185,9 @@ class ElectronBrowserContext : public content::BrowserContext {
|
||||
// Initialize pref registry.
|
||||
void InitPrefs();
|
||||
|
||||
// Called when the Network Service restarts.
|
||||
void OnNetworkServiceRestarted();
|
||||
|
||||
scoped_refptr<ValueMapPrefStore> in_memory_pref_store_;
|
||||
std::unique_ptr<CookieChangeNotifier> cookie_change_notifier_;
|
||||
std::unique_ptr<PrefService> prefs_;
|
||||
@@ -207,6 +211,9 @@ class ElectronBrowserContext : public content::BrowserContext {
|
||||
// Shared URLLoaderFactory.
|
||||
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
|
||||
|
||||
// Subscription to Network Service restart notifications.
|
||||
base::CallbackListSubscription network_service_restart_subscription_;
|
||||
|
||||
network::mojom::SSLConfigPtr ssl_config_;
|
||||
mojo::Remote<network::mojom::SSLConfigClient> ssl_config_client_;
|
||||
|
||||
|
||||
18
shell/browser/net/network_service_restart_observer.h
Normal file
18
shell/browser/net/network_service_restart_observer.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2026 Microsoft GmbH.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_NET_NETWORK_SERVICE_RESTART_OBSERVER_H_
|
||||
#define ELECTRON_SHELL_BROWSER_NET_NETWORK_SERVICE_RESTART_OBSERVER_H_
|
||||
|
||||
#include "base/observer_list_types.h"
|
||||
|
||||
// Observer interface for Network Service restart notifications.
|
||||
class NetworkServiceRestartObserver : public base::CheckedObserver {
|
||||
public:
|
||||
// Called after the Network Service has been recreated following a crash.
|
||||
// Observers should use this to refresh any cached URLLoaderFactory instances.
|
||||
virtual void OnNetworkServiceRestarted() = 0;
|
||||
};
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_NET_NETWORK_SERVICE_RESTART_OBSERVER_H_
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
||||
#include "services/network/public/mojom/network_context.mojom.h"
|
||||
#include "services/network/public/mojom/url_response_head.mojom.h"
|
||||
#include "shell/browser/api/electron_api_app.h"
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/browser/electron_browser_client.h"
|
||||
#include "shell/common/application_info.h"
|
||||
@@ -287,6 +288,18 @@ void SystemNetworkContextManager::OnNetworkServiceCreated(
|
||||
network_service->SetEncryptionKey(OSCrypt::GetRawEncryptionKey());
|
||||
#endif
|
||||
}
|
||||
|
||||
restart_callbacks_.Notify();
|
||||
|
||||
// Test-only event to signal Network Service has been recreated.
|
||||
if (auto* app = electron::api::App::Get())
|
||||
app->Emit("-network-service-created");
|
||||
}
|
||||
|
||||
base::CallbackListSubscription
|
||||
SystemNetworkContextManager::AddNetworkServiceRestartCallback(
|
||||
base::RepeatingClosure callback) {
|
||||
return restart_callbacks_.Add(std::move(callback));
|
||||
}
|
||||
|
||||
network::mojom::NetworkContextParamsPtr
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef ELECTRON_SHELL_BROWSER_NET_SYSTEM_NETWORK_CONTEXT_MANAGER_H_
|
||||
#define ELECTRON_SHELL_BROWSER_NET_SYSTEM_NETWORK_CONTEXT_MANAGER_H_
|
||||
|
||||
#include "base/callback_list.h"
|
||||
#include "chrome/browser/net/proxy_config_monitor.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
#include "net/base/features.h"
|
||||
@@ -83,6 +84,11 @@ class SystemNetworkContextManager {
|
||||
// SystemNetworkContext, if the network service is enabled.
|
||||
void OnNetworkServiceCreated(network::mojom::NetworkService* network_service);
|
||||
|
||||
// Subscribe to Network Service restart notifications. Returns a subscription
|
||||
// that will automatically unsubscribe when destroyed.
|
||||
base::CallbackListSubscription AddNetworkServiceRestartCallback(
|
||||
base::RepeatingClosure callback);
|
||||
|
||||
private:
|
||||
class URLLoaderFactoryForSystem;
|
||||
|
||||
@@ -102,6 +108,9 @@ class SystemNetworkContextManager {
|
||||
// consumers don't all need to create their own factory.
|
||||
scoped_refptr<URLLoaderFactoryForSystem> shared_url_loader_factory_;
|
||||
mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_;
|
||||
|
||||
// Callbacks notified when Network Service restarts.
|
||||
base::RepeatingClosureList restart_callbacks_;
|
||||
};
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_NET_SYSTEM_NETWORK_CONTEXT_MANAGER_H_
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
#include <utility>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/process/process.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "electron/fuses.h"
|
||||
#include "electron/mas.h"
|
||||
#include "net/base/network_change_notifier.h"
|
||||
#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
|
||||
#include "services/network/public/mojom/host_resolver.mojom.h"
|
||||
#include "services/network/public/mojom/network_context.mojom.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
@@ -56,22 +56,26 @@ void V8FatalErrorCallback(const char* location, const char* message) {
|
||||
*zero = 0;
|
||||
}
|
||||
|
||||
URLLoaderBundle::URLLoaderBundle() = default;
|
||||
// URLLoaderBundle implementation
|
||||
URLLoaderBundle::URLLoaderBundle() {
|
||||
// Add an extra reference to prevent the singleton from ever being deleted
|
||||
AddRef();
|
||||
}
|
||||
|
||||
URLLoaderBundle::~URLLoaderBundle() = default;
|
||||
|
||||
URLLoaderBundle* URLLoaderBundle::GetInstance() {
|
||||
static base::NoDestructor<URLLoaderBundle> instance;
|
||||
return instance.get();
|
||||
static URLLoaderBundle* instance = new URLLoaderBundle();
|
||||
return instance;
|
||||
}
|
||||
|
||||
void URLLoaderBundle::SetURLLoaderFactory(
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_factory,
|
||||
mojo::Remote<network::mojom::HostResolver> host_resolver,
|
||||
bool use_network_observer_from_url_loader_factory) {
|
||||
factory_ = network::SharedURLLoaderFactory::Create(
|
||||
std::make_unique<network::WrapperPendingSharedURLLoaderFactory>(
|
||||
std::move(pending_factory)));
|
||||
// Reset the old remote before binding the new one
|
||||
factory_remote_.reset();
|
||||
factory_remote_.Bind(std::move(pending_factory));
|
||||
host_resolver_ = std::move(host_resolver);
|
||||
should_use_network_observer_from_url_loader_factory_ =
|
||||
use_network_observer_from_url_loader_factory;
|
||||
@@ -79,7 +83,35 @@ void URLLoaderBundle::SetURLLoaderFactory(
|
||||
|
||||
scoped_refptr<network::SharedURLLoaderFactory>
|
||||
URLLoaderBundle::GetSharedURLLoaderFactory() {
|
||||
return factory_;
|
||||
// Return ourselves since we implement SharedURLLoaderFactory
|
||||
return scoped_refptr<network::SharedURLLoaderFactory>(this);
|
||||
}
|
||||
|
||||
void URLLoaderBundle::CreateLoaderAndStart(
|
||||
mojo::PendingReceiver<network::mojom::URLLoader> loader,
|
||||
int32_t request_id,
|
||||
uint32_t options,
|
||||
const network::ResourceRequest& request,
|
||||
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
|
||||
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
|
||||
if (factory_remote_.is_bound() && factory_remote_.is_connected()) {
|
||||
factory_remote_->CreateLoaderAndStart(std::move(loader), request_id,
|
||||
options, request, std::move(client),
|
||||
traffic_annotation);
|
||||
}
|
||||
}
|
||||
|
||||
void URLLoaderBundle::Clone(
|
||||
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) {
|
||||
if (factory_remote_.is_bound() && factory_remote_.is_connected()) {
|
||||
factory_remote_->Clone(std::move(receiver));
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<network::PendingSharedURLLoaderFactory>
|
||||
URLLoaderBundle::Clone() {
|
||||
// Return nullptr - callers should use GetSharedURLLoaderFactory() instead
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
network::mojom::HostResolver* URLLoaderBundle::GetHostResolver() {
|
||||
@@ -208,4 +240,13 @@ void NodeService::Initialize(
|
||||
node_bindings_->StartPolling();
|
||||
}
|
||||
|
||||
void NodeService::UpdateURLLoaderFactory(
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory,
|
||||
mojo::PendingRemote<network::mojom::HostResolver> host_resolver) {
|
||||
URLLoaderBundle::GetInstance()->SetURLLoaderFactory(
|
||||
std::move(url_loader_factory), mojo::Remote(std::move(host_resolver)),
|
||||
URLLoaderBundle::GetInstance()
|
||||
->ShouldUseNetworkObserverfromURLLoaderFactory());
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "net/base/network_change_notifier.h"
|
||||
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
||||
#include "services/network/public/mojom/host_resolver.mojom.h"
|
||||
#include "services/network/public/mojom/url_loader_factory.mojom-forward.h"
|
||||
#include "services/network/public/mojom/url_loader_factory.mojom.h"
|
||||
#include "shell/services/node/public/mojom/node_service.mojom.h"
|
||||
|
||||
namespace node {
|
||||
@@ -29,25 +29,40 @@ class ElectronBindings;
|
||||
class JavascriptEnvironment;
|
||||
class NodeBindings;
|
||||
|
||||
class URLLoaderBundle {
|
||||
class URLLoaderBundle : public network::SharedURLLoaderFactory {
|
||||
public:
|
||||
URLLoaderBundle();
|
||||
~URLLoaderBundle();
|
||||
|
||||
URLLoaderBundle(const URLLoaderBundle&) = delete;
|
||||
URLLoaderBundle& operator=(const URLLoaderBundle&) = delete;
|
||||
|
||||
static URLLoaderBundle* GetInstance();
|
||||
|
||||
void SetURLLoaderFactory(
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory> factory,
|
||||
mojo::Remote<network::mojom::HostResolver> host_resolver,
|
||||
bool use_network_observer_from_url_loader_factory);
|
||||
|
||||
scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory();
|
||||
network::mojom::HostResolver* GetHostResolver();
|
||||
bool ShouldUseNetworkObserverfromURLLoaderFactory() const;
|
||||
|
||||
void CreateLoaderAndStart(
|
||||
mojo::PendingReceiver<network::mojom::URLLoader> loader,
|
||||
int32_t request_id,
|
||||
uint32_t options,
|
||||
const network::ResourceRequest& request,
|
||||
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
|
||||
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
|
||||
override;
|
||||
void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
|
||||
override;
|
||||
std::unique_ptr<network::PendingSharedURLLoaderFactory> Clone() override;
|
||||
|
||||
private:
|
||||
scoped_refptr<network::SharedURLLoaderFactory> factory_;
|
||||
~URLLoaderBundle() override;
|
||||
|
||||
mojo::Remote<network::mojom::URLLoaderFactory> factory_remote_;
|
||||
mojo::Remote<network::mojom::HostResolver> host_resolver_;
|
||||
bool should_use_network_observer_from_url_loader_factory_ = false;
|
||||
};
|
||||
@@ -65,6 +80,9 @@ class NodeService : public node::mojom::NodeService {
|
||||
void Initialize(node::mojom::NodeServiceParamsPtr params,
|
||||
mojo::PendingRemote<node::mojom::NodeServiceClient>
|
||||
client_pending_remote) override;
|
||||
void UpdateURLLoaderFactory(
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory,
|
||||
mojo::PendingRemote<network::mojom::HostResolver> host_resolver) override;
|
||||
|
||||
private:
|
||||
// This needs to be initialized first so that it can be destroyed last
|
||||
|
||||
@@ -28,4 +28,9 @@ interface NodeServiceClient {
|
||||
interface NodeService {
|
||||
Initialize(NodeServiceParams params,
|
||||
pending_remote<NodeServiceClient> client_remote);
|
||||
|
||||
// Update the URLLoaderFactory and HostResolver after Network Service restart.
|
||||
UpdateURLLoaderFactory(
|
||||
pending_remote<network.mojom.URLLoaderFactory> url_loader_factory,
|
||||
pending_remote<network.mojom.HostResolver> host_resolver);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { net, session, ClientRequest, ClientRequestConstructorOptions, utilityProcess } from 'electron/main';
|
||||
import { app, net, session, ClientRequest, ClientRequestConstructorOptions, utilityProcess } from 'electron/main';
|
||||
|
||||
import { expect } from 'chai';
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as path from 'node:path';
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
|
||||
import { collectStreamBody, collectStreamBodyBuffer, getResponse, kOneKiloByte, kOneMegaByte, randomBuffer, randomString, respondNTimes, respondOnce } from './lib/net-helpers';
|
||||
import { listen, defer } from './lib/spec-helpers';
|
||||
import { ifit, listen, defer } from './lib/spec-helpers';
|
||||
|
||||
const utilityFixturePath = path.resolve(__dirname, 'fixtures', 'api', 'utility-process', 'api-net-spec.js');
|
||||
const fixturesPath = path.resolve(__dirname, 'fixtures');
|
||||
@@ -1688,4 +1688,80 @@ describe('net module', () => {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Network Service crash recovery', () => {
|
||||
ifit(process.platform !== 'linux')('should recover net.fetch after Network Service crash (main process)', async () => {
|
||||
const serverUrl = await respondOnce.toSingleURL((request, response) => {
|
||||
response.end('first');
|
||||
});
|
||||
const firstResponse = await net.fetch(serverUrl);
|
||||
expect(firstResponse.ok).to.be.true();
|
||||
expect(await firstResponse.text()).to.equal('first');
|
||||
|
||||
const metrics = app.getAppMetrics();
|
||||
const networkServiceProcess = metrics.find(
|
||||
m => m.type === 'Utility' && m.serviceName === 'network.mojom.NetworkService'
|
||||
);
|
||||
expect(networkServiceProcess).to.not.be.undefined();
|
||||
|
||||
const crashPromise = once(app, '-network-service-crashed');
|
||||
const restartPromise = once(app, '-network-service-created');
|
||||
|
||||
process.kill(networkServiceProcess!.pid, 'SIGKILL');
|
||||
|
||||
await crashPromise;
|
||||
await restartPromise;
|
||||
|
||||
const secondServerUrl = await respondOnce.toSingleURL((request, response) => {
|
||||
response.end('second');
|
||||
});
|
||||
const secondResponse = await net.fetch(secondServerUrl);
|
||||
expect(secondResponse.ok).to.be.true();
|
||||
expect(await secondResponse.text()).to.equal('second');
|
||||
});
|
||||
|
||||
ifit(process.platform !== 'linux')('should recover net.fetch after Network Service crash (utility process)', async () => {
|
||||
const child = utilityProcess.fork(path.join(fixturesPath, 'api', 'utility-process', 'network-restart-test.js'));
|
||||
await once(child, 'spawn');
|
||||
await once(child, 'message');
|
||||
|
||||
const firstServerUrl = await respondOnce.toSingleURL((request, response) => {
|
||||
response.end('utility-first');
|
||||
});
|
||||
child.postMessage({ type: 'fetch', url: firstServerUrl });
|
||||
const [firstResult] = await once(child, 'message');
|
||||
expect(firstResult.ok).to.be.true();
|
||||
expect(firstResult.body).to.equal('utility-first');
|
||||
|
||||
// Find the Network Service process
|
||||
const metrics = app.getAppMetrics();
|
||||
const networkServiceProcess = metrics.find(
|
||||
m => m.type === 'Utility' && m.serviceName === 'network.mojom.NetworkService'
|
||||
);
|
||||
expect(networkServiceProcess).to.not.be.undefined();
|
||||
|
||||
const crashPromise = once(app, '-network-service-crashed');
|
||||
const restartPromise = once(app, '-network-service-created');
|
||||
|
||||
process.kill(networkServiceProcess!.pid, 'SIGKILL');
|
||||
|
||||
await crashPromise;
|
||||
await restartPromise;
|
||||
|
||||
// Needed for UpdateURLLoaderFactory IPC to propagate to the utility process
|
||||
// and for any in-flight requests to settle
|
||||
await setTimeout(500);
|
||||
|
||||
const secondServerUrl = await respondOnce.toSingleURL((request, response) => {
|
||||
response.end('utility-second');
|
||||
});
|
||||
child.postMessage({ type: 'fetch', url: secondServerUrl });
|
||||
const [secondResult] = await once(child, 'message');
|
||||
expect(secondResult.ok).to.be.true();
|
||||
expect(secondResult.body).to.equal('utility-second');
|
||||
|
||||
child.kill();
|
||||
await once(child, 'exit');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
24
spec/fixtures/api/utility-process/network-restart-test.js
vendored
Normal file
24
spec/fixtures/api/utility-process/network-restart-test.js
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
const { net } = require('electron');
|
||||
|
||||
process.parentPort.on('message', async (e) => {
|
||||
const { type, url } = e.data;
|
||||
|
||||
if (type === 'fetch') {
|
||||
try {
|
||||
const response = await net.fetch(url);
|
||||
const body = await response.text();
|
||||
process.parentPort.postMessage({
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
body
|
||||
});
|
||||
} catch (error) {
|
||||
process.parentPort.postMessage({
|
||||
ok: false,
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
process.parentPort.postMessage({ type: 'ready' });
|
||||
Reference in New Issue
Block a user