Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rb/lib/selenium/webdriver/remote/http/default.rb
1990 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
require 'ipaddr'
20
21
module Selenium
22
module WebDriver
23
module Remote
24
module Http
25
# @api private
26
class Default < Common
27
attr_writer :proxy
28
29
attr_accessor :open_timeout, :read_timeout
30
31
# Initializes object.
32
# Warning: Setting {#open_timeout} to non-nil values will cause a separate thread to spawn.
33
# Debuggers that freeze the process will not be able to evaluate any operations if that happens.
34
# @param [Numeric] open_timeout - Open timeout to apply to HTTP client.
35
# @param [Numeric] read_timeout - Read timeout (seconds) to apply to HTTP client.
36
def initialize(open_timeout: nil, read_timeout: nil)
37
@open_timeout = open_timeout
38
@read_timeout = read_timeout
39
super()
40
end
41
42
def close
43
@http&.finish
44
end
45
46
private
47
48
def http
49
@http ||= begin
50
http = new_http_client
51
if server_url.scheme == 'https'
52
http.use_ssl = true
53
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
54
end
55
56
http.open_timeout = open_timeout if open_timeout
57
http.read_timeout = read_timeout if read_timeout
58
59
start(http)
60
http
61
end
62
end
63
64
def start(http)
65
http.start
66
end
67
68
MAX_RETRIES = 3
69
70
def request(verb, url, headers, payload, redirects = 0)
71
retries = 0
72
73
begin
74
request = new_request_for(verb, url, headers, payload)
75
response = response_for(request)
76
rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EADDRINUSE, Errno::EADDRNOTAVAIL
77
# a retry is sometimes needed:
78
# on Windows XP where we may quickly run out of ephemeral ports
79
# when the port becomes temporarily unavailable
80
#
81
# A more robust solution is bumping the MaxUserPort setting
82
# as described here:
83
#
84
# http://msdn.microsoft.com/en-us/library/aa560610%28v=bts.20%29.aspx
85
raise if retries >= MAX_RETRIES
86
87
retries += 1
88
sleep 2
89
retry
90
rescue Errno::ECONNREFUSED => e
91
raise e.class, "using proxy: #{proxy.http}" if use_proxy?
92
93
raise
94
end
95
96
if response.is_a? Net::HTTPRedirection
97
WebDriver.logger.debug("Redirect to #{response['Location']}; times: #{redirects}")
98
raise Error::WebDriverError, 'too many redirects' if redirects >= MAX_REDIRECTS
99
100
request(:get, URI.parse(response['Location']), DEFAULT_HEADERS.dup, nil, redirects + 1)
101
else
102
WebDriver.logger.debug(" <<< #{response.instance_variable_get(:@header).inspect}", id: :header)
103
create_response response.code, response.body, response.content_type
104
end
105
end
106
107
def new_request_for(verb, url, headers, payload)
108
req = Net::HTTP.const_get(verb.to_s.capitalize).new(url.path, headers)
109
110
req.basic_auth server_url.user, server_url.password if server_url.userinfo
111
112
req.body = payload if payload
113
114
req
115
end
116
117
def response_for(request)
118
http.request request
119
end
120
121
def new_http_client
122
if use_proxy?
123
url = @proxy.http
124
unless proxy.respond_to?(:http) && url
125
raise Error::WebDriverError,
126
"expected HTTP proxy, got #{@proxy.inspect}"
127
end
128
129
proxy = URI.parse(url)
130
131
Net::HTTP.new(server_url.host, server_url.port, proxy.host, proxy.port, proxy.user, proxy.password)
132
else
133
Net::HTTP.new server_url.host, server_url.port
134
end
135
end
136
137
def proxy
138
@proxy ||= begin
139
proxy = ENV.fetch('http_proxy', nil) || ENV.fetch('HTTP_PROXY', nil)
140
no_proxy = ENV.fetch('no_proxy', nil) || ENV.fetch('NO_PROXY', nil)
141
142
if proxy
143
proxy = "http://#{proxy}" unless proxy.start_with?('http://')
144
Proxy.new(http: proxy, no_proxy: no_proxy)
145
end
146
end
147
end
148
149
def use_proxy?
150
return false if proxy.nil?
151
152
if proxy.no_proxy
153
ignored = proxy.no_proxy.split(',').any? do |host|
154
host == '*' ||
155
host == server_url.host || (
156
begin
157
IPAddr.new(host).include?(server_url.host)
158
rescue ArgumentError
159
false
160
end
161
)
162
end
163
164
!ignored
165
else
166
true
167
end
168
end
169
end # Default
170
end # Http
171
end # Remote
172
end # WebDriver
173
end # Selenium
174
175