Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rb/lib/selenium/webdriver/remote/http/common.rb
4014 views
1
# frozen_string_literal: true
2
3
# Licensed to the Software Freedom Conservancy (SFC) under one
4
# or more contributor license agreements. See the NOTICE file
5
# distributed with this work for additional information
6
# regarding copyright ownership. The SFC licenses this file
7
# to you under the Apache License, Version 2.0 (the
8
# "License"); you may not use this file except in compliance
9
# with the License. You may obtain a copy of the License at
10
#
11
# http://www.apache.org/licenses/LICENSE-2.0
12
#
13
# Unless required by applicable law or agreed to in writing,
14
# software distributed under the License is distributed on an
15
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
# KIND, either express or implied. See the License for the
17
# specific language governing permissions and limitations
18
# under the License.
19
20
module Selenium
21
module WebDriver
22
module Remote
23
module Http
24
class Common
25
MAX_REDIRECTS = 20 # same as chromium/gecko
26
CONTENT_TYPE = 'application/json'
27
DEFAULT_HEADERS = {
28
'Accept' => CONTENT_TYPE,
29
'Content-Type' => "#{CONTENT_TYPE}; charset=UTF-8"
30
}.freeze
31
BINARY_ENCODINGS = [Encoding::BINARY, Encoding::ASCII_8BIT].freeze
32
33
class << self
34
attr_accessor :extra_headers
35
attr_writer :user_agent
36
37
def user_agent
38
@user_agent ||= "selenium/#{WebDriver::VERSION} (ruby #{Platform.os})"
39
end
40
end
41
42
attr_writer :server_url
43
44
def quit_errors
45
[IOError]
46
end
47
48
def close
49
# hook for subclasses - will be called on Driver#quit
50
end
51
52
# steep:ignore:start
53
def call(verb, url, command_hash)
54
url = server_url.merge(url) unless url.is_a?(URI)
55
headers = common_headers.dup
56
headers['Cache-Control'] = 'no-cache' if verb == :get
57
58
if command_hash
59
command_hash = ensure_utf8_encoding(command_hash)
60
payload = JSON.generate(command_hash)
61
headers['Content-Length'] = payload.bytesize.to_s if %i[post put].include?(verb)
62
63
WebDriver.logger.debug(" >>> #{url} | #{payload}", id: :command)
64
WebDriver.logger.debug(" > #{headers.inspect}", id: :header)
65
elsif verb == :post
66
payload = '{}'
67
headers['Content-Length'] = '2'
68
end
69
70
request verb, url, headers, payload
71
end
72
# steep:ignore:end
73
74
private
75
76
def common_headers
77
@common_headers ||= begin
78
headers = DEFAULT_HEADERS.dup
79
headers['User-Agent'] = Common.user_agent
80
headers = headers.merge(Common.extra_headers || {})
81
82
headers
83
end
84
end
85
86
def server_url
87
return @server_url if @server_url
88
89
raise Error::WebDriverError, 'server_url not set'
90
end
91
92
def request(*)
93
raise NotImplementedError, 'subclass responsibility'
94
end
95
96
def ensure_utf8_encoding(obj)
97
case obj
98
when String
99
encode_string_to_utf8(obj)
100
when Array
101
obj.map { |item| ensure_utf8_encoding(item) }
102
when Hash
103
obj.each_with_object({}) do |(key, value), result|
104
result[ensure_utf8_encoding(key)] = ensure_utf8_encoding(value)
105
end
106
else
107
obj
108
end
109
end
110
111
def encode_string_to_utf8(str)
112
return str if str.encoding == Encoding::UTF_8 && str.valid_encoding?
113
114
if BINARY_ENCODINGS.include?(str.encoding)
115
result = str.dup.force_encoding(Encoding::UTF_8)
116
return result if result.valid_encoding?
117
end
118
119
str.encode(Encoding::UTF_8)
120
rescue EncodingError => e
121
raise Error::WebDriverError,
122
"Unable to encode string to UTF-8: #{e.message}. " \
123
"String encoding: #{str.encoding}, content: #{str.inspect}"
124
end
125
126
def create_response(code, body, content_type)
127
code = code.to_i
128
body = body.to_s.strip
129
content_type = content_type.to_s
130
WebDriver.logger.debug("<- #{body}", id: :command)
131
132
if content_type.include? CONTENT_TYPE
133
raise Error::WebDriverError, "empty body: #{content_type.inspect} (#{code})\n#{body}" if body.empty?
134
135
Response.new(code, JSON.parse(body))
136
elsif code == 204
137
Response.new(code)
138
else
139
msg = if body.empty?
140
"unexpected response, code=#{code}, content-type=#{content_type.inspect}"
141
else
142
"unexpected response, code=#{code}, content-type=#{content_type.inspect}\n#{body}"
143
end
144
145
raise Error::WebDriverError, msg
146
end
147
end
148
end # Common
149
end # Http
150
end # Remote
151
end # WebDriver
152
end # Selenium
153
154