From 30efe098df28de9b39f9da3b5dc5b4aa2be4bec1 Mon Sep 17 00:00:00 2001 From: Ibrahim Awwal Date: Wed, 3 Jul 2024 18:06:35 -0700 Subject: [PATCH 1/5] Create a Contexts entry for the default browser context This has access to the browser's persisted state (e.g. cookies, sessions, history, etc). --- lib/ferrum/contexts.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/ferrum/contexts.rb b/lib/ferrum/contexts.rb index 1a0f1ddf..d6e28ea4 100644 --- a/lib/ferrum/contexts.rb +++ b/lib/ferrum/contexts.rb @@ -11,6 +11,7 @@ class Contexts def initialize(client) @contexts = Concurrent::Map.new @client = client + @default_context = create_default_context subscribe auto_attach discover @@ -20,6 +21,20 @@ def default_context @default_context ||= create end + def create_default_context + default_context_id = compute_default_context_id + # Targets created in this context will not be created with a browserContextId + @contexts[default_context_id] = ::Ferrum::Context.new(@client, self, nil) + end + + # Compute the default context ID by looking for contexts not returned by Target.getBrowserContexts + def compute_default_context_id + created_contexts = Set.new(@client.command("Target.getBrowserContexts")["browserContextIds"]) + targets = @client.command("Target.getTargets")["targetInfos"] + all_contexts = Set.new(targets.map { |target| target["browserContextId"] }) + (all_contexts - created_contexts).first + end + def each(&block) return enum_for(__method__) unless block_given? From 556ccadedaad0252f4b128caf3bff4fefb53bba1 Mon Sep 17 00:00:00 2001 From: Ibrahim Awwal Date: Wed, 3 Jul 2024 18:10:54 -0700 Subject: [PATCH 2/5] Allow targets to be created in the default context --- lib/ferrum/context.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ferrum/context.rb b/lib/ferrum/context.rb index af71f8d2..9e99805b 100644 --- a/lib/ferrum/context.rb +++ b/lib/ferrum/context.rb @@ -46,7 +46,8 @@ def create_page(**options) end def create_target - @client.command("Target.createTarget", browserContextId: @id, url: "about:blank") + target_params = {browserContextId: @id, url: "about:blank"}.compact + @client.command("Target.createTarget", **target_params) target = @pendings.take(@client.timeout) raise NoSuchTargetError unless target.is_a?(Target) From f24136d2aff12ae3f2919e8f7cbe395ef309319a Mon Sep 17 00:00:00 2001 From: Ibrahim Awwal Date: Wed, 3 Jul 2024 18:24:08 -0700 Subject: [PATCH 3/5] Add option to allow using the browser's default context This would grant access to persistent state such as cookies that are associated with the default browser profile. --- lib/ferrum/browser.rb | 3 +++ lib/ferrum/browser/options.rb | 3 ++- lib/ferrum/contexts.rb | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/ferrum/browser.rb b/lib/ferrum/browser.rb index 9626ad1d..ccf7b801 100644 --- a/lib/ferrum/browser.rb +++ b/lib/ferrum/browser.rb @@ -125,6 +125,9 @@ class Browser # @option options [Hash] :env # Environment variables you'd like to pass through to the process. # + # @option options [Boolean] :use_default_context + # When true, allows using the default browser context that has access to the browser's persistent state. + # def initialize(options = nil) @options = Options.new(options) @client = @process = @contexts = nil diff --git a/lib/ferrum/browser/options.rb b/lib/ferrum/browser/options.rb index 987f9442..962cbe8c 100644 --- a/lib/ferrum/browser/options.rb +++ b/lib/ferrum/browser/options.rb @@ -15,7 +15,7 @@ class Options :js_errors, :base_url, :slowmo, :pending_connection_errors, :url, :ws_url, :env, :process_timeout, :browser_name, :browser_path, :save_path, :proxy, :port, :host, :headless, :browser_options, - :ignore_default_browser_options, :xvfb, :flatten + :ignore_default_browser_options, :xvfb, :flatten, :use_default_context attr_accessor :timeout, :default_user_agent def initialize(options = nil) @@ -45,6 +45,7 @@ def initialize(options = nil) @base_url = parse_base_url(@options[:base_url]) if @options[:base_url] @url = @options[:url].to_s if @options[:url] @ws_url = @options[:ws_url].to_s if @options[:ws_url] + @use_default_context = @options.fetch(:use_default_context, false) @options = @options.merge(window_size: @window_size).freeze @browser_options = @options.fetch(:browser_options, {}).freeze diff --git a/lib/ferrum/contexts.rb b/lib/ferrum/contexts.rb index d6e28ea4..a493ac4d 100644 --- a/lib/ferrum/contexts.rb +++ b/lib/ferrum/contexts.rb @@ -11,7 +11,7 @@ class Contexts def initialize(client) @contexts = Concurrent::Map.new @client = client - @default_context = create_default_context + @default_context = create_default_context if @client.options.use_default_context subscribe auto_attach discover From e821a086cf7f17f88ac0cdde02f48781b78fa652 Mon Sep 17 00:00:00 2001 From: Ibrahim Awwal Date: Wed, 3 Jul 2024 18:58:43 -0700 Subject: [PATCH 4/5] Don't need namespace here This was probably leftover from my local monkeypatch. --- lib/ferrum/contexts.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ferrum/contexts.rb b/lib/ferrum/contexts.rb index a493ac4d..1c4be73a 100644 --- a/lib/ferrum/contexts.rb +++ b/lib/ferrum/contexts.rb @@ -24,7 +24,7 @@ def default_context def create_default_context default_context_id = compute_default_context_id # Targets created in this context will not be created with a browserContextId - @contexts[default_context_id] = ::Ferrum::Context.new(@client, self, nil) + @contexts[default_context_id] = Context.new(@client, self, nil) end # Compute the default context ID by looking for contexts not returned by Target.getBrowserContexts From 9bfd0fb533b219e6cf4ee1b700a3a4a7443e4b01 Mon Sep 17 00:00:00 2001 From: Ibrahim Awwal Date: Mon, 19 Aug 2024 13:47:36 -0700 Subject: [PATCH 5/5] Fix lint --- lib/ferrum/context.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ferrum/context.rb b/lib/ferrum/context.rb index 9e99805b..fd8115d6 100644 --- a/lib/ferrum/context.rb +++ b/lib/ferrum/context.rb @@ -46,7 +46,7 @@ def create_page(**options) end def create_target - target_params = {browserContextId: @id, url: "about:blank"}.compact + target_params = { browserContextId: @id, url: "about:blank" }.compact @client.command("Target.createTarget", **target_params) target = @pendings.take(@client.timeout) raise NoSuchTargetError unless target.is_a?(Target)