http 6.0.0-java → 6.0.1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/http.gemspec +2 -2
- data/lib/http/version.rb +1 -1
- metadata +4 -79
- data/CHANGELOG.md +0 -267
- data/CONTRIBUTING.md +0 -26
- data/SECURITY.md +0 -17
- data/UPGRADING.md +0 -491
- data/sig/deps.rbs +0 -122
- data/test/http/base64_test.rb +0 -28
- data/test/http/client_test.rb +0 -739
- data/test/http/connection_test.rb +0 -1533
- data/test/http/content_type_test.rb +0 -190
- data/test/http/errors_test.rb +0 -28
- data/test/http/feature_test.rb +0 -49
- data/test/http/features/auto_deflate_test.rb +0 -317
- data/test/http/features/auto_inflate_test.rb +0 -213
- data/test/http/features/caching_test.rb +0 -942
- data/test/http/features/digest_auth_test.rb +0 -996
- data/test/http/features/instrumentation_test.rb +0 -246
- data/test/http/features/logging_test.rb +0 -654
- data/test/http/features/normalize_uri_test.rb +0 -41
- data/test/http/features/raise_error_test.rb +0 -77
- data/test/http/form_data/composite_io_test.rb +0 -215
- data/test/http/form_data/file_test.rb +0 -255
- data/test/http/form_data/fixtures/the-http-gem.info +0 -1
- data/test/http/form_data/multipart_test.rb +0 -303
- data/test/http/form_data/part_test.rb +0 -90
- data/test/http/form_data/urlencoded_test.rb +0 -164
- data/test/http/form_data_test.rb +0 -232
- data/test/http/headers/normalizer_test.rb +0 -93
- data/test/http/headers_test.rb +0 -888
- data/test/http/mime_type/json_test.rb +0 -39
- data/test/http/mime_type_test.rb +0 -150
- data/test/http/options/base_uri_test.rb +0 -148
- data/test/http/options/body_test.rb +0 -21
- data/test/http/options/features_test.rb +0 -38
- data/test/http/options/form_test.rb +0 -21
- data/test/http/options/headers_test.rb +0 -32
- data/test/http/options/json_test.rb +0 -21
- data/test/http/options/merge_test.rb +0 -78
- data/test/http/options/new_test.rb +0 -37
- data/test/http/options/proxy_test.rb +0 -32
- data/test/http/options_test.rb +0 -575
- data/test/http/redirector_test.rb +0 -639
- data/test/http/request/body_test.rb +0 -318
- data/test/http/request/builder_test.rb +0 -623
- data/test/http/request/writer_test.rb +0 -391
- data/test/http/request_test.rb +0 -1733
- data/test/http/response/body_test.rb +0 -292
- data/test/http/response/parser_test.rb +0 -105
- data/test/http/response/status_test.rb +0 -322
- data/test/http/response_test.rb +0 -502
- data/test/http/retriable/delay_calculator_test.rb +0 -194
- data/test/http/retriable/errors_test.rb +0 -71
- data/test/http/retriable/performer_test.rb +0 -551
- data/test/http/session_test.rb +0 -424
- data/test/http/timeout/global_test.rb +0 -239
- data/test/http/timeout/null_test.rb +0 -218
- data/test/http/timeout/per_operation_test.rb +0 -220
- data/test/http/uri/normalizer_test.rb +0 -89
- data/test/http/uri_test.rb +0 -1140
- data/test/http/version_test.rb +0 -15
- data/test/http_test.rb +0 -818
- data/test/regression_tests.rb +0 -27
- data/test/support/capture_warning.rb +0 -10
- data/test/support/dummy_server/encoding_routes.rb +0 -47
- data/test/support/dummy_server/routes.rb +0 -201
- data/test/support/dummy_server/servlet.rb +0 -81
- data/test/support/dummy_server.rb +0 -200
- data/test/support/fakeio.rb +0 -21
- data/test/support/http_handling_shared/connection_reuse_tests.rb +0 -97
- data/test/support/http_handling_shared/timeout_tests.rb +0 -134
- data/test/support/http_handling_shared.rb +0 -11
- data/test/support/proxy_server.rb +0 -207
- data/test/support/servers/runner.rb +0 -67
- data/test/support/simplecov.rb +0 -28
- data/test/support/ssl_helper.rb +0 -108
- data/test/test_helper.rb +0 -38
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module TimeoutTests
|
|
4
|
-
# Including class must provide:
|
|
5
|
-
# - server: a DummyServer instance
|
|
6
|
-
# - build_client(**options): builds an HTTP::Client with given options
|
|
7
|
-
|
|
8
|
-
def test_timeout_without_timeouts_works
|
|
9
|
-
client = build_client(timeout_class: HTTP::Timeout::Null, timeout_options: {})
|
|
10
|
-
|
|
11
|
-
assert_equal "<!doctype html>", client.get(server.endpoint).body.to_s
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def test_timeout_per_operation_works
|
|
15
|
-
client = build_client(
|
|
16
|
-
timeout_class: HTTP::Timeout::PerOperation,
|
|
17
|
-
timeout_options: {
|
|
18
|
-
connect_timeout: 0.5,
|
|
19
|
-
read_timeout: 0.1,
|
|
20
|
-
write_timeout: 0.5
|
|
21
|
-
}
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
assert_equal "<!doctype html>", client.get(server.endpoint).body.to_s
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def test_timeout_per_operation_connection_of_half_second_does_not_time_out
|
|
28
|
-
client = build_client(
|
|
29
|
-
timeout_class: HTTP::Timeout::PerOperation,
|
|
30
|
-
timeout_options: {
|
|
31
|
-
connect_timeout: 0.5,
|
|
32
|
-
read_timeout: 0.1,
|
|
33
|
-
write_timeout: 0.5
|
|
34
|
-
}
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
client.get(server.endpoint).body.to_s
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def test_timeout_per_operation_read_of_zero_times_out
|
|
41
|
-
client = build_client(
|
|
42
|
-
timeout_class: HTTP::Timeout::PerOperation,
|
|
43
|
-
timeout_options: {
|
|
44
|
-
connect_timeout: 0.5,
|
|
45
|
-
read_timeout: 0,
|
|
46
|
-
write_timeout: 0.5
|
|
47
|
-
}
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
err = assert_raises(HTTP::TimeoutError) do
|
|
51
|
-
client.get("#{server.endpoint}/sleep").body.to_s
|
|
52
|
-
end
|
|
53
|
-
assert_match(/Read/i, err.message)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def test_timeout_per_operation_read_of_tenth_does_not_time_out
|
|
57
|
-
client = build_client(
|
|
58
|
-
timeout_class: HTTP::Timeout::PerOperation,
|
|
59
|
-
timeout_options: {
|
|
60
|
-
connect_timeout: 0.5,
|
|
61
|
-
read_timeout: 0.1,
|
|
62
|
-
write_timeout: 0.5
|
|
63
|
-
}
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
client.get("#{server.endpoint}/sleep").body.to_s
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def test_timeout_global_errors_if_connecting_takes_too_long
|
|
70
|
-
client = build_client(
|
|
71
|
-
timeout_class: HTTP::Timeout::Global,
|
|
72
|
-
timeout_options: { global_timeout: 0.01 }
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
TCPSocket.stub(:open, ->(*) { sleep 0.025 }) do
|
|
76
|
-
err = assert_raises(HTTP::ConnectTimeoutError) { client.get(server.endpoint).body.to_s }
|
|
77
|
-
assert_match(/execution/, err.message)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def test_timeout_global_errors_if_reading_takes_too_long
|
|
82
|
-
client = build_client(
|
|
83
|
-
timeout_class: HTTP::Timeout::Global,
|
|
84
|
-
timeout_options: { global_timeout: 0.01 }
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
err = assert_raises(HTTP::TimeoutError) do
|
|
88
|
-
client.get("#{server.endpoint}/sleep").body.to_s
|
|
89
|
-
end
|
|
90
|
-
assert_match(/Timed out|execution expired/, err.message)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def test_timeout_global_resets_state_when_reusing_connections
|
|
94
|
-
client = build_client(
|
|
95
|
-
timeout_class: HTTP::Timeout::Global,
|
|
96
|
-
timeout_options: { global_timeout: 0.5 },
|
|
97
|
-
persistent: server.endpoint
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
client.get("#{server.endpoint}/sleep").body.to_s
|
|
101
|
-
client.get("#{server.endpoint}/sleep").body.to_s
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def test_timeout_combined_global_and_per_operation_works
|
|
105
|
-
client = build_client(
|
|
106
|
-
timeout_class: HTTP::Timeout::Global,
|
|
107
|
-
timeout_options: {
|
|
108
|
-
global_timeout: 0.5,
|
|
109
|
-
connect_timeout: 0.25,
|
|
110
|
-
read_timeout: 0.25,
|
|
111
|
-
write_timeout: 0.25
|
|
112
|
-
}
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
assert_equal "<!doctype html>", client.get(server.endpoint).body.to_s
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def test_timeout_combined_per_op_read_of_zero_times_out
|
|
119
|
-
client = build_client(
|
|
120
|
-
timeout_class: HTTP::Timeout::Global,
|
|
121
|
-
timeout_options: {
|
|
122
|
-
global_timeout: 0.5,
|
|
123
|
-
connect_timeout: 0.25,
|
|
124
|
-
read_timeout: 0,
|
|
125
|
-
write_timeout: 0.25
|
|
126
|
-
}
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
err = assert_raises(HTTP::TimeoutError) do
|
|
130
|
-
client.get("#{server.endpoint}/sleep").body.to_s
|
|
131
|
-
end
|
|
132
|
-
assert_match(/Read timed out/, err.message)
|
|
133
|
-
end
|
|
134
|
-
end
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "support/http_handling_shared/timeout_tests"
|
|
4
|
-
require "support/http_handling_shared/connection_reuse_tests"
|
|
5
|
-
|
|
6
|
-
module HTTPHandlingTests
|
|
7
|
-
def self.included(base)
|
|
8
|
-
base.include TimeoutTests
|
|
9
|
-
base.include ConnectionReuseTests
|
|
10
|
-
end
|
|
11
|
-
end
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "socket"
|
|
4
|
-
require "uri"
|
|
5
|
-
|
|
6
|
-
require "support/servers/runner"
|
|
7
|
-
|
|
8
|
-
class ProxyServer
|
|
9
|
-
Target = Struct.new(:host, :port, :path, :query)
|
|
10
|
-
|
|
11
|
-
def initialize
|
|
12
|
-
@tcp_server = TCPServer.new("127.0.0.1", 0)
|
|
13
|
-
@port = @tcp_server.addr[1]
|
|
14
|
-
@ready = Queue.new
|
|
15
|
-
@shutdown_read, @shutdown_write = IO.pipe
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def addr
|
|
19
|
-
"127.0.0.1"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
attr_reader :port
|
|
23
|
-
|
|
24
|
-
def wait_ready
|
|
25
|
-
@ready.pop
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def start
|
|
29
|
-
@ready << true
|
|
30
|
-
|
|
31
|
-
loop do
|
|
32
|
-
readable, = IO.select([@tcp_server, @shutdown_read])
|
|
33
|
-
break unless readable
|
|
34
|
-
break if readable.include?(@shutdown_read)
|
|
35
|
-
|
|
36
|
-
client = @tcp_server.accept
|
|
37
|
-
Thread.new(client) do |c|
|
|
38
|
-
Thread.current.report_on_exception = false
|
|
39
|
-
handle_request(c)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
rescue IOError, Errno::EBADF
|
|
43
|
-
# Server socket closed during shutdown
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def shutdown
|
|
47
|
-
@shutdown_write.close
|
|
48
|
-
@tcp_server.close rescue nil
|
|
49
|
-
@shutdown_read.close rescue nil
|
|
50
|
-
rescue
|
|
51
|
-
nil
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
private
|
|
55
|
-
|
|
56
|
-
def handle_request(client)
|
|
57
|
-
method, target, version, headers, body = read_proxy_request(client)
|
|
58
|
-
return unless method && target
|
|
59
|
-
|
|
60
|
-
if (response = authenticate(headers))
|
|
61
|
-
client.write(response)
|
|
62
|
-
return
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
if method == "CONNECT"
|
|
66
|
-
tunnel_connection(client, target)
|
|
67
|
-
else
|
|
68
|
-
forward_and_respond(client, method, target, body, version)
|
|
69
|
-
end
|
|
70
|
-
rescue IOError, Errno::ECONNRESET, Errno::EPIPE, Errno::EBADF, URI::InvalidURIError
|
|
71
|
-
# Connection closed
|
|
72
|
-
ensure
|
|
73
|
-
client.close rescue nil
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def read_proxy_request(client)
|
|
77
|
-
line = client.gets
|
|
78
|
-
return unless line
|
|
79
|
-
|
|
80
|
-
method, target, version = line.strip.split(" ", 3)
|
|
81
|
-
headers = read_headers(client)
|
|
82
|
-
body = headers["Content-Length"] ? client.read(headers["Content-Length"].to_i) : nil
|
|
83
|
-
|
|
84
|
-
[method, parse_target(method, target), version, headers, body]
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def parse_target(method, target)
|
|
88
|
-
return parse_connect_target(target) if method == "CONNECT"
|
|
89
|
-
|
|
90
|
-
uri = URI.parse(target)
|
|
91
|
-
Target.new(host: uri.host, port: uri.port, path: uri.path, query: uri.query)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def parse_connect_target(target)
|
|
95
|
-
host, port = target.split(":", 2)
|
|
96
|
-
return unless host && port
|
|
97
|
-
|
|
98
|
-
Target.new(host: host, port: Integer(port))
|
|
99
|
-
rescue ArgumentError
|
|
100
|
-
nil
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def read_headers(client)
|
|
104
|
-
headers = {}
|
|
105
|
-
while (header_line = client.gets)
|
|
106
|
-
break if header_line == "\r\n"
|
|
107
|
-
|
|
108
|
-
key, value = header_line.split(": ", 2)
|
|
109
|
-
headers[key] = value.strip
|
|
110
|
-
end
|
|
111
|
-
headers
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def authenticate(_headers)
|
|
115
|
-
nil
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def forward_and_respond(client, method, target, body, version)
|
|
119
|
-
target_socket = send_to_target(method, target, body, version)
|
|
120
|
-
relay_response(client, target_socket)
|
|
121
|
-
ensure
|
|
122
|
-
target_socket&.close rescue nil
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def send_to_target(method, target, body, version)
|
|
126
|
-
socket = TCPSocket.new(target.host, target.port)
|
|
127
|
-
path = target.path.to_s.empty? ? "/" : target.path
|
|
128
|
-
path = "#{path}?#{target.query}" if target.query
|
|
129
|
-
|
|
130
|
-
socket.write("#{method} #{path} #{version}\r\n")
|
|
131
|
-
socket.write("Host: #{target.host}:#{target.port}\r\n")
|
|
132
|
-
socket.write("Content-Length: #{body.bytesize}\r\n") if body
|
|
133
|
-
socket.write("\r\n")
|
|
134
|
-
socket.write(body) if body
|
|
135
|
-
socket
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def relay_response(client, target)
|
|
139
|
-
response_line = target.gets
|
|
140
|
-
return unless response_line
|
|
141
|
-
|
|
142
|
-
headers, content_length = read_response_headers(target)
|
|
143
|
-
body = content_length&.positive? ? target.read(content_length) : ""
|
|
144
|
-
|
|
145
|
-
client.write("#{response_line}X-PROXIED: true\r\n#{headers}\r\n#{body}")
|
|
146
|
-
rescue IOError, Errno::ECONNRESET
|
|
147
|
-
# Target connection error
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def tunnel_connection(client, target)
|
|
151
|
-
target_socket = TCPSocket.new(target.host, target.port)
|
|
152
|
-
|
|
153
|
-
client.write("HTTP/1.1 200 Connection established\r\n\r\n")
|
|
154
|
-
relay_tunnel(client, target_socket)
|
|
155
|
-
ensure
|
|
156
|
-
target_socket&.close rescue nil
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def relay_tunnel(client, target)
|
|
160
|
-
threads = [
|
|
161
|
-
Thread.new { copy_stream(client, target) },
|
|
162
|
-
Thread.new { copy_stream(target, client) }
|
|
163
|
-
]
|
|
164
|
-
threads.each { |t| t.join(5) }
|
|
165
|
-
ensure
|
|
166
|
-
threads&.each { |t| t.kill if t.alive? }
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def copy_stream(source, destination)
|
|
170
|
-
loop do
|
|
171
|
-
destination.write(source.readpartial(1024))
|
|
172
|
-
end
|
|
173
|
-
rescue IOError, Errno::ECONNRESET, Errno::EPIPE
|
|
174
|
-
nil
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def read_response_headers(target)
|
|
178
|
-
headers = +""
|
|
179
|
-
content_length = nil
|
|
180
|
-
while (hl = target.gets)
|
|
181
|
-
break if hl == "\r\n"
|
|
182
|
-
|
|
183
|
-
content_length = ::Regexp.last_match(1).to_i if hl =~ /^Content-Length:\s*(\d+)/i
|
|
184
|
-
headers << hl
|
|
185
|
-
end
|
|
186
|
-
[headers, content_length]
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
class AuthProxyServer < ProxyServer
|
|
191
|
-
private
|
|
192
|
-
|
|
193
|
-
def authenticate(headers)
|
|
194
|
-
auth = headers["Proxy-Authorization"]
|
|
195
|
-
|
|
196
|
-
if auth
|
|
197
|
-
encoded = auth.sub(/^Basic\s+/, "")
|
|
198
|
-
user, pass = encoded.unpack1("m0").split(":", 2)
|
|
199
|
-
return if user == "username" && pass == "password"
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
"HTTP/1.1 407 Proxy Authentication Required\r\n" \
|
|
203
|
-
"Proxy-Authenticate: Basic realm=\"proxy\"\r\n" \
|
|
204
|
-
"Content-Length: 0\r\n" \
|
|
205
|
-
"\r\n"
|
|
206
|
-
end
|
|
207
|
-
end
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module ServerRunner
|
|
4
|
-
@all_servers = []
|
|
5
|
-
|
|
6
|
-
def self.all_servers
|
|
7
|
-
@all_servers
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def run_server(name)
|
|
11
|
-
defining_class = self
|
|
12
|
-
|
|
13
|
-
define_method(name) do
|
|
14
|
-
cache = defining_class.instance_variable_get(:@_server_cache) ||
|
|
15
|
-
defining_class.instance_variable_set(:@_server_cache, {})
|
|
16
|
-
|
|
17
|
-
cache[name] ||= begin
|
|
18
|
-
server = yield
|
|
19
|
-
Thread.new { server.start }
|
|
20
|
-
server.wait_ready
|
|
21
|
-
ServerRunner.all_servers << server
|
|
22
|
-
server
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
_run_servers << name
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def _run_servers
|
|
30
|
-
@_run_servers ||= []
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
module ServerLifecycle
|
|
35
|
-
def setup
|
|
36
|
-
super
|
|
37
|
-
_all_run_servers.each do |s|
|
|
38
|
-
server = send(s)
|
|
39
|
-
server.reset if server.respond_to?(:reset)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
private
|
|
44
|
-
|
|
45
|
-
def _all_run_servers
|
|
46
|
-
klass = self.class
|
|
47
|
-
servers = []
|
|
48
|
-
|
|
49
|
-
while klass.respond_to?(:_run_servers)
|
|
50
|
-
servers.concat(klass._run_servers)
|
|
51
|
-
klass = klass.superclass
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
servers.uniq
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
Minitest::Test.extend(ServerRunner)
|
|
59
|
-
Minitest::Test.include(ServerLifecycle)
|
|
60
|
-
|
|
61
|
-
Minitest.after_run do
|
|
62
|
-
ServerRunner.all_servers.each do |server|
|
|
63
|
-
server.shutdown
|
|
64
|
-
rescue
|
|
65
|
-
nil
|
|
66
|
-
end
|
|
67
|
-
end
|
data/test/support/simplecov.rb
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
return if ENV["MUTANT"] || ENV["NOCOV"]
|
|
4
|
-
|
|
5
|
-
require "simplecov"
|
|
6
|
-
|
|
7
|
-
if ENV["CI"]
|
|
8
|
-
require "simplecov-lcov"
|
|
9
|
-
|
|
10
|
-
SimpleCov::Formatter::LcovFormatter.config do |config|
|
|
11
|
-
config.report_with_single_file = true
|
|
12
|
-
config.lcov_file_name = "lcov.info"
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
SimpleCov.start do
|
|
19
|
-
add_filter "/test/"
|
|
20
|
-
add_filter "/minitest-memory/"
|
|
21
|
-
|
|
22
|
-
if RUBY_ENGINE == "ruby"
|
|
23
|
-
enable_coverage :branch
|
|
24
|
-
minimum_coverage line: 100, branch: 100
|
|
25
|
-
else
|
|
26
|
-
minimum_coverage line: 99
|
|
27
|
-
end
|
|
28
|
-
end
|
data/test/support/ssl_helper.rb
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "openssl"
|
|
4
|
-
require "pathname"
|
|
5
|
-
|
|
6
|
-
module SSLHelper
|
|
7
|
-
CERTS_PATH = Pathname.new File.expand_path("../../tmp/certs", __dir__)
|
|
8
|
-
|
|
9
|
-
class << self
|
|
10
|
-
def server_context
|
|
11
|
-
context = OpenSSL::SSL::SSLContext.new
|
|
12
|
-
|
|
13
|
-
context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
14
|
-
context.key = server_cert_key
|
|
15
|
-
context.cert = server_cert_cert
|
|
16
|
-
context.ca_file = ca_file
|
|
17
|
-
|
|
18
|
-
context
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def client_context
|
|
22
|
-
# Ensure server cert is generated (triggers CA generation too)
|
|
23
|
-
server_cert_cert
|
|
24
|
-
context = OpenSSL::SSL::SSLContext.new
|
|
25
|
-
|
|
26
|
-
context.options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
|
|
27
|
-
context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
28
|
-
context.verify_hostname = true if context.respond_to?(:verify_hostname=)
|
|
29
|
-
context.ca_file = ca_file
|
|
30
|
-
|
|
31
|
-
context
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def client_params
|
|
35
|
-
server_cert_cert
|
|
36
|
-
{
|
|
37
|
-
ca_file: ca_file
|
|
38
|
-
}
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
def ca_key
|
|
44
|
-
@ca_key ||= OpenSSL::PKey::RSA.new(2048)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def ca_cert
|
|
48
|
-
@ca_cert ||= begin
|
|
49
|
-
cert = OpenSSL::X509::Certificate.new
|
|
50
|
-
cert.version = 2
|
|
51
|
-
cert.serial = 1
|
|
52
|
-
cert.subject = OpenSSL::X509::Name.parse("/CN=honestachmed.com")
|
|
53
|
-
cert.issuer = cert.subject
|
|
54
|
-
cert.public_key = ca_key.public_key
|
|
55
|
-
cert.not_before = Time.now - 60
|
|
56
|
-
cert.not_after = Time.now + (365 * 24 * 60 * 60)
|
|
57
|
-
|
|
58
|
-
ef = OpenSSL::X509::ExtensionFactory.new
|
|
59
|
-
ef.subject_certificate = cert
|
|
60
|
-
ef.issuer_certificate = cert
|
|
61
|
-
|
|
62
|
-
cert.add_extension(ef.create_extension("basicConstraints", "CA:TRUE", true))
|
|
63
|
-
cert.add_extension(ef.create_extension("keyUsage", "keyCertSign,cRLSign", true))
|
|
64
|
-
|
|
65
|
-
cert.sign(ca_key, OpenSSL::Digest.new("SHA256"))
|
|
66
|
-
cert
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def ca_file
|
|
71
|
-
return @ca_file if defined?(@ca_file)
|
|
72
|
-
|
|
73
|
-
CERTS_PATH.mkpath
|
|
74
|
-
cert_file = CERTS_PATH.join("ca.crt")
|
|
75
|
-
cert_file.open("w") { |io| io << ca_cert.to_pem }
|
|
76
|
-
@ca_file = cert_file.to_s
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def server_cert_key
|
|
80
|
-
@server_cert_key ||= OpenSSL::PKey::RSA.new(2048)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def server_cert_cert
|
|
84
|
-
@server_cert_cert ||= begin
|
|
85
|
-
cert = OpenSSL::X509::Certificate.new
|
|
86
|
-
cert.version = 2
|
|
87
|
-
cert.serial = 2
|
|
88
|
-
cert.subject = OpenSSL::X509::Name.parse("/CN=127.0.0.1")
|
|
89
|
-
cert.issuer = ca_cert.subject
|
|
90
|
-
cert.public_key = server_cert_key.public_key
|
|
91
|
-
cert.not_before = Time.now - 60
|
|
92
|
-
cert.not_after = Time.now + (365 * 24 * 60 * 60)
|
|
93
|
-
|
|
94
|
-
ef = OpenSSL::X509::ExtensionFactory.new
|
|
95
|
-
ef.subject_certificate = cert
|
|
96
|
-
ef.issuer_certificate = ca_cert
|
|
97
|
-
|
|
98
|
-
cert.add_extension(ef.create_extension("basicConstraints", "CA:FALSE"))
|
|
99
|
-
cert.add_extension(ef.create_extension("keyUsage", "digitalSignature,keyEncipherment", true))
|
|
100
|
-
cert.add_extension(ef.create_extension("extendedKeyUsage", "serverAuth"))
|
|
101
|
-
cert.add_extension(ef.create_extension("subjectAltName", "IP:127.0.0.1"))
|
|
102
|
-
|
|
103
|
-
cert.sign(ca_key, OpenSSL::Digest.new("SHA256"))
|
|
104
|
-
cert
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
data/test/test_helper.rb
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "support/simplecov"
|
|
4
|
-
|
|
5
|
-
require "minitest/autorun"
|
|
6
|
-
require "minitest/mock"
|
|
7
|
-
require "minitest/memory" if RUBY_ENGINE == "ruby"
|
|
8
|
-
require "minitest/strict"
|
|
9
|
-
|
|
10
|
-
require "http"
|
|
11
|
-
|
|
12
|
-
# No-op for mutant cover declarations when mutant is not loaded
|
|
13
|
-
Minitest::Test.extend(Module.new { def cover(*); end }) unless Minitest::Test.respond_to?(:cover)
|
|
14
|
-
|
|
15
|
-
require "support/capture_warning"
|
|
16
|
-
require "support/fakeio"
|
|
17
|
-
|
|
18
|
-
# Helper for creating fake objects with predefined method responses
|
|
19
|
-
module FakeHelper
|
|
20
|
-
def fake(**methods)
|
|
21
|
-
obj = Object.new
|
|
22
|
-
methods.each do |name, value|
|
|
23
|
-
if value.is_a?(Proc)
|
|
24
|
-
obj.define_singleton_method(name) { |*args, **kwargs, &blk| value.call(*args, **kwargs, &blk) }
|
|
25
|
-
else
|
|
26
|
-
obj.define_singleton_method(name) { |*| value }
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
obj
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
module Minitest
|
|
34
|
-
class Test
|
|
35
|
-
include FakeHelper
|
|
36
|
-
include Minitest::Memory if RUBY_ENGINE == "ruby"
|
|
37
|
-
end
|
|
38
|
-
end
|