File: //usr/lib/ruby/vendor_ruby/selenium/webdriver/remote/bridge.rb
# frozen_string_literal: true
# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
module Selenium
module WebDriver
module Remote
class Bridge
include Atoms
include BridgeHelper
PORT = 4444
COMMANDS = {
new_session: [:post, 'session']
}.freeze
attr_accessor :context, :http, :file_detector
attr_reader :capabilities, :dialect
#
# Implements protocol handshake which:
#
# 1. Creates session with driver.
# 2. Sniffs response.
# 3. Based on the response, understands which dialect we should use.
#
# @return [OSS:Bridge, W3C::Bridge]
#
def self.handshake(**opts)
desired_capabilities = opts.delete(:desired_capabilities) { Capabilities.new }
if desired_capabilities.is_a?(Symbol)
unless Capabilities.respond_to?(desired_capabilities)
raise Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
end
desired_capabilities = Capabilities.__send__(desired_capabilities)
end
bridge = new(opts)
capabilities = bridge.create_session(desired_capabilities, opts.delete(:options))
case bridge.dialect
when :oss
Remote::OSS::Bridge.new(capabilities, bridge.session_id, **opts)
when :w3c
Remote::W3C::Bridge.new(capabilities, bridge.session_id, **opts)
else
raise WebDriverError, 'cannot understand dialect'
end
end
#
# Initializes the bridge with the given server URL
# @param [Hash] opts options for the driver
# @option opts [String] :url url for the remote server
# @option opts [Object] :http_client an HTTP client instance that implements the same protocol as Http::Default
# @option opts [Capabilities] :desired_capabilities an instance of Remote::Capabilities describing the capabilities you want
# @api private
#
def initialize(opts = {})
opts = opts.dup
http_client = opts.delete(:http_client) { Http::Default.new }
url = opts.delete(:url) { "http://#{Platform.localhost}:#{PORT}/wd/hub" }
opts.delete(:options)
unless opts.empty?
raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
end
uri = url.is_a?(URI) ? url : URI.parse(url)
uri.path += '/' unless uri.path =~ %r{\/$}
http_client.server_url = uri
@http = http_client
@file_detector = nil
end
#
# Creates session handling both OSS and W3C dialects.
#
def create_session(desired_capabilities, options = nil)
response = execute(:new_session, {}, merged_capabilities(desired_capabilities, options))
@session_id = response['sessionId']
oss_status = response['status']
value = response['value']
if value.is_a?(Hash)
@session_id = value['sessionId'] if value.key?('sessionId')
if value.key?('capabilities')
value = value['capabilities']
elsif value.key?('value')
value = value['value']
end
end
raise Error::WebDriverError, 'no sessionId in returned payload' unless @session_id
if oss_status
WebDriver.logger.info 'Detected OSS dialect.'
@dialect = :oss
Capabilities.json_create(value)
else
WebDriver.logger.info 'Detected W3C dialect.'
@dialect = :w3c
W3C::Capabilities.json_create(value)
end
end
#
# Returns the current session ID.
#
def session_id
@session_id || raise(Error::WebDriverError, 'no current session exists')
end
def browser
@browser ||= begin
name = @capabilities.browser_name
name ? name.tr(' ', '_').to_sym : 'unknown'
end
end
private
#
# executes a command on the remote server.
#
# @return [WebDriver::Remote::Response]
#
def execute(command, opts = {}, command_hash = nil)
verb, path = commands(command) || raise(ArgumentError, "unknown command: #{command.inspect}")
path = path.dup
path[':session_id'] = session_id if path.include?(':session_id')
begin
opts.each { |key, value| path[key.inspect] = escaper.escape(value.to_s) }
rescue IndexError
raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
end
WebDriver.logger.info("-> #{verb.to_s.upcase} #{path}")
http.call(verb, path, command_hash)
end
def escaper
@escaper ||= defined?(URI::Parser) ? URI::DEFAULT_PARSER : URI
end
def commands(command)
raise NotImplementedError unless command == :new_session
COMMANDS[command]
end
def merged_capabilities(oss_capabilities, options = nil)
w3c_capabilities = W3C::Capabilities.from_oss(oss_capabilities)
w3c_capabilities.merge!(options.as_json) if options
{
desiredCapabilities: oss_capabilities,
capabilities: {
firstMatch: [w3c_capabilities]
}
}
end
end # Bridge
end # Remote
end # WebDriver
end # Selenium