From b62c8060041b6e588468958b088e81fb230fb1ed Mon Sep 17 00:00:00 2001 From: titusfortner Date: Sun, 19 Oct 2025 20:18:22 -0500 Subject: [PATCH 1/3] [rb] allow setting socket timeout and interval from http client --- rb/lib/selenium/webdriver/bidi.rb | 4 ++-- .../webdriver/common/websocket_connection.rb | 14 +++++++++----- rb/lib/selenium/webdriver/remote/bidi_bridge.rb | 2 +- rb/lib/selenium/webdriver/remote/http/default.rb | 7 ++++--- .../webdriver/common/websocket_connection.rbs | 4 ++++ .../selenium/webdriver/remote/http/default.rbs | 4 ++++ .../webdriver/spec_support/test_environment.rb | 10 +++++++--- .../webdriver/remote/http/default_spec.rb | 16 ++++++++++------ 8 files changed, 41 insertions(+), 20 deletions(-) diff --git a/rb/lib/selenium/webdriver/bidi.rb b/rb/lib/selenium/webdriver/bidi.rb index 80fc5b92fbe22..891f6b6fe9003 100644 --- a/rb/lib/selenium/webdriver/bidi.rb +++ b/rb/lib/selenium/webdriver/bidi.rb @@ -31,8 +31,8 @@ class BiDi autoload :InterceptedAuth, 'selenium/webdriver/bidi/network/intercepted_auth' autoload :InterceptedItem, 'selenium/webdriver/bidi/network/intercepted_item' - def initialize(url:) - @ws = WebSocketConnection.new(url: url) + def initialize(url:, http:) + @ws = WebSocketConnection.new(url: url, http: http) end def close diff --git a/rb/lib/selenium/webdriver/common/websocket_connection.rb b/rb/lib/selenium/webdriver/common/websocket_connection.rb index 26f02ebc9bf1c..1213038b64875 100644 --- a/rb/lib/selenium/webdriver/common/websocket_connection.rb +++ b/rb/lib/selenium/webdriver/common/websocket_connection.rb @@ -21,19 +21,23 @@ module Selenium module WebDriver + # + # WebSocketConnection manages lifecycle of sockets for Devtools and BiDi implementations. + # @api private + # + class WebSocketConnection CONNECTION_ERRORS = [ Errno::ECONNRESET, # connection is aborted (browser process was killed) Errno::EPIPE # broken pipe (browser process was killed) ].freeze - RESPONSE_WAIT_TIMEOUT = 30 - RESPONSE_WAIT_INTERVAL = 0.1 - MAX_LOG_MESSAGE_SIZE = 9999 - def initialize(url:) + def initialize(url:, http: nil) @callback_threads = ThreadGroup.new + @socket_timeout = http&.socket_timeout || 30 + @socket_interval = http&.socket_interval || 0.1 @session_id = nil @url = url @@ -147,7 +151,7 @@ def callback_thread(params) end def wait - @wait ||= Wait.new(timeout: RESPONSE_WAIT_TIMEOUT, interval: RESPONSE_WAIT_INTERVAL) + @wait ||= Wait.new(timeout: @socket_timeout, interval: @socket_interval) end def socket diff --git a/rb/lib/selenium/webdriver/remote/bidi_bridge.rb b/rb/lib/selenium/webdriver/remote/bidi_bridge.rb index c95ddec538f85..a809ea2ebc4ae 100644 --- a/rb/lib/selenium/webdriver/remote/bidi_bridge.rb +++ b/rb/lib/selenium/webdriver/remote/bidi_bridge.rb @@ -26,7 +26,7 @@ class BiDiBridge < Bridge def create_session(capabilities) super socket_url = @capabilities[:web_socket_url] - @bidi = Selenium::WebDriver::BiDi.new(url: socket_url) + @bidi = Selenium::WebDriver::BiDi.new(url: socket_url, http: @http) end def get(url) diff --git a/rb/lib/selenium/webdriver/remote/http/default.rb b/rb/lib/selenium/webdriver/remote/http/default.rb index 2677eefc2de15..af19a9bd9e773 100644 --- a/rb/lib/selenium/webdriver/remote/http/default.rb +++ b/rb/lib/selenium/webdriver/remote/http/default.rb @@ -22,20 +22,21 @@ module Selenium module WebDriver module Remote module Http - # @api private class Default < Common attr_writer :proxy - attr_accessor :open_timeout, :read_timeout + attr_accessor :open_timeout, :read_timeout, :socket_timeout, :socket_interval # Initializes object. # Warning: Setting {#open_timeout} to non-nil values will cause a separate thread to spawn. # Debuggers that freeze the process will not be able to evaluate any operations if that happens. # @param [Numeric] open_timeout - Open timeout to apply to HTTP client. # @param [Numeric] read_timeout - Read timeout (seconds) to apply to HTTP client. - def initialize(open_timeout: nil, read_timeout: nil) + def initialize(open_timeout: nil, read_timeout: nil, socket_timeout: 30, socket_interval: 0.1) @open_timeout = open_timeout @read_timeout = read_timeout + @socket_timeout = socket_timeout + @socket_interval = socket_interval super() end diff --git a/rb/sig/lib/selenium/webdriver/common/websocket_connection.rbs b/rb/sig/lib/selenium/webdriver/common/websocket_connection.rbs index 98ac289f081ed..f2041ca79b7eb 100644 --- a/rb/sig/lib/selenium/webdriver/common/websocket_connection.rbs +++ b/rb/sig/lib/selenium/webdriver/common/websocket_connection.rbs @@ -7,6 +7,10 @@ module Selenium @session_id: untyped + @socket_interval: float + + @socket_timeout: int + @url: untyped @socket_thread: untyped diff --git a/rb/sig/lib/selenium/webdriver/remote/http/default.rbs b/rb/sig/lib/selenium/webdriver/remote/http/default.rbs index 7fb7a41c9ac7a..bf726c9696fa6 100644 --- a/rb/sig/lib/selenium/webdriver/remote/http/default.rbs +++ b/rb/sig/lib/selenium/webdriver/remote/http/default.rbs @@ -18,6 +18,10 @@ module Selenium attr_accessor read_timeout: untyped + attr_accessor socket_timeout: int + + attr_accessor socket_interval: float + def initialize: (?open_timeout: untyped?, ?read_timeout: untyped?) -> void def close: () -> untyped diff --git a/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb b/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb index 44b25580477b2..b39a9bc54fffa 100644 --- a/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb +++ b/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb @@ -31,6 +31,7 @@ def initialize WebDriver.logger.ignore(:logger_info) SeleniumManager.bin_path = root.join('bazel-bin/rb/bin').to_s if File.exist?(root.join('bazel-bin/rb/bin')) + ENV['WEBDRIVER_BIDI'] = 'true' @driver = ENV.fetch('WD_SPEC_DRIVER', 'chrome').tr('-', '_').to_sym @driver_instance = nil @remote_server = nil @@ -168,14 +169,17 @@ def root @root ||= Pathname.new('../../../../../../../').realpath(__FILE__) end - def create_driver!(listener: nil, **, &block) + def create_driver!(listener: nil, **opts, &block) check_for_previous_error + socket_timeout = opts.delete(:socket_timeout) + http_client = WebDriver::Remote::Http::Default.new(socket_timeout: socket_timeout) if socket_timeout + method = :"#{driver}_driver" instance = if private_methods.include?(method) - send(method, listener: listener, options: build_options(**)) + send(method, listener: listener, http_client: http_client, options: build_options(**opts)) else - WebDriver::Driver.for(driver, listener: listener, options: build_options(**)) + WebDriver::Driver.for(driver, listener: listener, options: build_options(**opts)) end @create_driver_error_count -= 1 unless @create_driver_error_count.zero? if block diff --git a/rb/spec/unit/selenium/webdriver/remote/http/default_spec.rb b/rb/spec/unit/selenium/webdriver/remote/http/default_spec.rb index 21eff54011c37..976ac85ff0b63 100644 --- a/rb/spec/unit/selenium/webdriver/remote/http/default_spec.rb +++ b/rb/spec/unit/selenium/webdriver/remote/http/default_spec.rb @@ -36,17 +36,21 @@ module Http expect(http.open_timeout).to eq 60 expect(http.read_timeout).to eq 60 + expect(http.socket_timeout).to eq 30 + expect(http.socket_interval).to eq 0.1 end describe '#initialize' do - let(:client) { described_class.new(read_timeout: 22, open_timeout: 23) } - - it 'accepts read timeout options' do + it 'constructs values' do + client = described_class.new(read_timeout: 22, + open_timeout: 23, + socket_timeout: 4, + socket_interval: 0.5) expect(client.open_timeout).to eq 23 - end - - it 'accepts open timeout options' do expect(client.read_timeout).to eq 22 + expect(client.socket_timeout).to eq 4 + expect(client.socket_interval).to eq 0.5 + end end From f61988f5aea151f3175974439e494fe77737a1d8 Mon Sep 17 00:00:00 2001 From: titusfortner Date: Mon, 20 Oct 2025 17:51:28 -0500 Subject: [PATCH 2/3] fix failures --- rb/lib/selenium/webdriver/remote/http/default.rb | 6 +++--- rb/sig/lib/selenium/webdriver/remote/http/common.rbs | 2 +- rb/sig/lib/selenium/webdriver/remote/http/default.rbs | 4 ++-- .../selenium/webdriver/spec_support/test_environment.rb | 9 +++------ .../unit/selenium/webdriver/remote/http/default_spec.rb | 3 --- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/rb/lib/selenium/webdriver/remote/http/default.rb b/rb/lib/selenium/webdriver/remote/http/default.rb index af19a9bd9e773..d38459d1e539c 100644 --- a/rb/lib/selenium/webdriver/remote/http/default.rb +++ b/rb/lib/selenium/webdriver/remote/http/default.rb @@ -32,11 +32,11 @@ class Default < Common # Debuggers that freeze the process will not be able to evaluate any operations if that happens. # @param [Numeric] open_timeout - Open timeout to apply to HTTP client. # @param [Numeric] read_timeout - Read timeout (seconds) to apply to HTTP client. - def initialize(open_timeout: nil, read_timeout: nil, socket_timeout: 30, socket_interval: 0.1) + def initialize(open_timeout: nil, read_timeout: nil, socket_timeout: nil, socket_interval: nil) @open_timeout = open_timeout @read_timeout = read_timeout - @socket_timeout = socket_timeout - @socket_interval = socket_interval + @socket_timeout = socket_timeout || 30 + @socket_interval = socket_interval || 0.1 super() end diff --git a/rb/sig/lib/selenium/webdriver/remote/http/common.rbs b/rb/sig/lib/selenium/webdriver/remote/http/common.rbs index dfafbbf8456bf..e2186feeb0f4f 100644 --- a/rb/sig/lib/selenium/webdriver/remote/http/common.rbs +++ b/rb/sig/lib/selenium/webdriver/remote/http/common.rbs @@ -17,7 +17,7 @@ module Selenium def self.user_agent: -> String - attr_writer server_url: String + attr_writer server_url: URI::Generic def quit_errors: () -> Array[untyped] diff --git a/rb/sig/lib/selenium/webdriver/remote/http/default.rbs b/rb/sig/lib/selenium/webdriver/remote/http/default.rbs index bf726c9696fa6..4f8b8bfbf0976 100644 --- a/rb/sig/lib/selenium/webdriver/remote/http/default.rbs +++ b/rb/sig/lib/selenium/webdriver/remote/http/default.rbs @@ -20,9 +20,9 @@ module Selenium attr_accessor socket_timeout: int - attr_accessor socket_interval: float + attr_accessor socket_interval: Numeric - def initialize: (?open_timeout: untyped?, ?read_timeout: untyped?) -> void + def initialize: (?open_timeout: untyped?, ?read_timeout: untyped?, ?socket_timeout: int?, ?socket_interval: Numeric?) -> void def close: () -> untyped diff --git a/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb b/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb index b39a9bc54fffa..e823cc4df55d2 100644 --- a/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb +++ b/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb @@ -169,17 +169,14 @@ def root @root ||= Pathname.new('../../../../../../../').realpath(__FILE__) end - def create_driver!(listener: nil, **opts, &block) + def create_driver!(listener: nil, **, &block) check_for_previous_error - socket_timeout = opts.delete(:socket_timeout) - http_client = WebDriver::Remote::Http::Default.new(socket_timeout: socket_timeout) if socket_timeout - method = :"#{driver}_driver" instance = if private_methods.include?(method) - send(method, listener: listener, http_client: http_client, options: build_options(**opts)) + send(method, listener: listener, options: build_options(**)) else - WebDriver::Driver.for(driver, listener: listener, options: build_options(**opts)) + WebDriver::Driver.for(driver, listener: listener, options: build_options(**)) end @create_driver_error_count -= 1 unless @create_driver_error_count.zero? if block diff --git a/rb/spec/unit/selenium/webdriver/remote/http/default_spec.rb b/rb/spec/unit/selenium/webdriver/remote/http/default_spec.rb index 976ac85ff0b63..3309ce89d8267 100644 --- a/rb/spec/unit/selenium/webdriver/remote/http/default_spec.rb +++ b/rb/spec/unit/selenium/webdriver/remote/http/default_spec.rb @@ -36,8 +36,6 @@ module Http expect(http.open_timeout).to eq 60 expect(http.read_timeout).to eq 60 - expect(http.socket_timeout).to eq 30 - expect(http.socket_interval).to eq 0.1 end describe '#initialize' do @@ -50,7 +48,6 @@ module Http expect(client.read_timeout).to eq 22 expect(client.socket_timeout).to eq 4 expect(client.socket_interval).to eq 0.5 - end end From e1a06da55800cd0c82548e7a2094e24f95170280 Mon Sep 17 00:00:00 2001 From: titusfortner Date: Mon, 20 Oct 2025 19:38:44 -0500 Subject: [PATCH 3/3] checked in by accident --- .../selenium/webdriver/spec_support/test_environment.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb b/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb index e823cc4df55d2..44b25580477b2 100644 --- a/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb +++ b/rb/spec/integration/selenium/webdriver/spec_support/test_environment.rb @@ -31,7 +31,6 @@ def initialize WebDriver.logger.ignore(:logger_info) SeleniumManager.bin_path = root.join('bazel-bin/rb/bin').to_s if File.exist?(root.join('bazel-bin/rb/bin')) - ENV['WEBDRIVER_BIDI'] = 'true' @driver = ENV.fetch('WD_SPEC_DRIVER', 'chrome').tr('-', '_').to_sym @driver_instance = nil @remote_server = nil