http 5.3.1 → 6.0.0

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.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +241 -41
  3. data/LICENSE.txt +1 -1
  4. data/README.md +110 -13
  5. data/UPGRADING.md +491 -0
  6. data/http.gemspec +32 -29
  7. data/lib/http/base64.rb +11 -1
  8. data/lib/http/chainable/helpers.rb +62 -0
  9. data/lib/http/chainable/verbs.rb +136 -0
  10. data/lib/http/chainable.rb +232 -136
  11. data/lib/http/client.rb +158 -127
  12. data/lib/http/connection/internals.rb +141 -0
  13. data/lib/http/connection.rb +126 -97
  14. data/lib/http/content_type.rb +61 -6
  15. data/lib/http/errors.rb +25 -1
  16. data/lib/http/feature.rb +65 -5
  17. data/lib/http/features/auto_deflate.rb +124 -17
  18. data/lib/http/features/auto_inflate.rb +38 -15
  19. data/lib/http/features/caching/entry.rb +178 -0
  20. data/lib/http/features/caching/in_memory_store.rb +63 -0
  21. data/lib/http/features/caching.rb +216 -0
  22. data/lib/http/features/digest_auth.rb +234 -0
  23. data/lib/http/features/instrumentation.rb +97 -17
  24. data/lib/http/features/logging.rb +183 -5
  25. data/lib/http/features/normalize_uri.rb +17 -0
  26. data/lib/http/features/raise_error.rb +18 -3
  27. data/lib/http/form_data/composite_io.rb +106 -0
  28. data/lib/http/form_data/file.rb +95 -0
  29. data/lib/http/form_data/multipart/param.rb +62 -0
  30. data/lib/http/form_data/multipart.rb +106 -0
  31. data/lib/http/form_data/part.rb +52 -0
  32. data/lib/http/form_data/readable.rb +58 -0
  33. data/lib/http/form_data/urlencoded.rb +175 -0
  34. data/lib/http/form_data/version.rb +8 -0
  35. data/lib/http/form_data.rb +102 -0
  36. data/lib/http/headers/known.rb +3 -0
  37. data/lib/http/headers/normalizer.rb +17 -36
  38. data/lib/http/headers.rb +172 -65
  39. data/lib/http/mime_type/adapter.rb +24 -9
  40. data/lib/http/mime_type/json.rb +19 -4
  41. data/lib/http/mime_type.rb +21 -3
  42. data/lib/http/options/definitions.rb +189 -0
  43. data/lib/http/options.rb +172 -125
  44. data/lib/http/redirector.rb +80 -75
  45. data/lib/http/request/body.rb +87 -6
  46. data/lib/http/request/builder.rb +184 -0
  47. data/lib/http/request/proxy.rb +83 -0
  48. data/lib/http/request/writer.rb +76 -16
  49. data/lib/http/request.rb +214 -98
  50. data/lib/http/response/body.rb +103 -18
  51. data/lib/http/response/inflater.rb +35 -7
  52. data/lib/http/response/parser.rb +98 -4
  53. data/lib/http/response/status/reasons.rb +2 -4
  54. data/lib/http/response/status.rb +141 -31
  55. data/lib/http/response.rb +219 -61
  56. data/lib/http/retriable/delay_calculator.rb +38 -11
  57. data/lib/http/retriable/errors.rb +21 -0
  58. data/lib/http/retriable/performer.rb +82 -38
  59. data/lib/http/session.rb +280 -0
  60. data/lib/http/timeout/global.rb +147 -34
  61. data/lib/http/timeout/null.rb +155 -9
  62. data/lib/http/timeout/per_operation.rb +139 -18
  63. data/lib/http/uri/normalizer.rb +82 -0
  64. data/lib/http/uri/parsing.rb +182 -0
  65. data/lib/http/uri.rb +289 -124
  66. data/lib/http/version.rb +2 -1
  67. data/lib/http.rb +11 -2
  68. data/sig/deps.rbs +122 -0
  69. data/sig/http.rbs +1619 -0
  70. data/test/http/base64_test.rb +28 -0
  71. data/test/http/client_test.rb +739 -0
  72. data/test/http/connection_test.rb +1533 -0
  73. data/test/http/content_type_test.rb +190 -0
  74. data/test/http/errors_test.rb +28 -0
  75. data/test/http/feature_test.rb +49 -0
  76. data/test/http/features/auto_deflate_test.rb +317 -0
  77. data/test/http/features/auto_inflate_test.rb +213 -0
  78. data/test/http/features/caching_test.rb +942 -0
  79. data/test/http/features/digest_auth_test.rb +996 -0
  80. data/test/http/features/instrumentation_test.rb +246 -0
  81. data/test/http/features/logging_test.rb +654 -0
  82. data/test/http/features/normalize_uri_test.rb +41 -0
  83. data/test/http/features/raise_error_test.rb +77 -0
  84. data/test/http/form_data/composite_io_test.rb +215 -0
  85. data/test/http/form_data/file_test.rb +255 -0
  86. data/test/http/form_data/fixtures/the-http-gem.info +1 -0
  87. data/test/http/form_data/multipart_test.rb +303 -0
  88. data/test/http/form_data/part_test.rb +90 -0
  89. data/test/http/form_data/urlencoded_test.rb +164 -0
  90. data/test/http/form_data_test.rb +232 -0
  91. data/test/http/headers/normalizer_test.rb +93 -0
  92. data/test/http/headers_test.rb +888 -0
  93. data/test/http/mime_type/json_test.rb +39 -0
  94. data/test/http/mime_type_test.rb +150 -0
  95. data/test/http/options/base_uri_test.rb +148 -0
  96. data/test/http/options/body_test.rb +21 -0
  97. data/test/http/options/features_test.rb +38 -0
  98. data/test/http/options/form_test.rb +21 -0
  99. data/test/http/options/headers_test.rb +32 -0
  100. data/test/http/options/json_test.rb +21 -0
  101. data/test/http/options/merge_test.rb +78 -0
  102. data/test/http/options/new_test.rb +37 -0
  103. data/test/http/options/proxy_test.rb +32 -0
  104. data/test/http/options_test.rb +575 -0
  105. data/test/http/redirector_test.rb +639 -0
  106. data/test/http/request/body_test.rb +318 -0
  107. data/test/http/request/builder_test.rb +623 -0
  108. data/test/http/request/writer_test.rb +391 -0
  109. data/test/http/request_test.rb +1733 -0
  110. data/test/http/response/body_test.rb +292 -0
  111. data/test/http/response/parser_test.rb +105 -0
  112. data/test/http/response/status_test.rb +322 -0
  113. data/test/http/response_test.rb +502 -0
  114. data/test/http/retriable/delay_calculator_test.rb +194 -0
  115. data/test/http/retriable/errors_test.rb +71 -0
  116. data/test/http/retriable/performer_test.rb +551 -0
  117. data/test/http/session_test.rb +424 -0
  118. data/test/http/timeout/global_test.rb +239 -0
  119. data/test/http/timeout/null_test.rb +218 -0
  120. data/test/http/timeout/per_operation_test.rb +220 -0
  121. data/test/http/uri/normalizer_test.rb +89 -0
  122. data/test/http/uri_test.rb +1140 -0
  123. data/test/http/version_test.rb +15 -0
  124. data/test/http_test.rb +818 -0
  125. data/test/regression_tests.rb +27 -0
  126. data/test/support/dummy_server/encoding_routes.rb +47 -0
  127. data/test/support/dummy_server/routes.rb +201 -0
  128. data/test/support/dummy_server/servlet.rb +81 -0
  129. data/test/support/dummy_server.rb +200 -0
  130. data/{spec → test}/support/fakeio.rb +2 -2
  131. data/test/support/http_handling_shared/connection_reuse_tests.rb +97 -0
  132. data/test/support/http_handling_shared/timeout_tests.rb +134 -0
  133. data/test/support/http_handling_shared.rb +11 -0
  134. data/test/support/proxy_server.rb +207 -0
  135. data/test/support/servers/runner.rb +67 -0
  136. data/{spec → test}/support/simplecov.rb +11 -2
  137. data/test/support/ssl_helper.rb +108 -0
  138. data/test/test_helper.rb +38 -0
  139. metadata +108 -168
  140. data/.github/workflows/ci.yml +0 -67
  141. data/.gitignore +0 -15
  142. data/.rspec +0 -1
  143. data/.rubocop/layout.yml +0 -8
  144. data/.rubocop/metrics.yml +0 -4
  145. data/.rubocop/rspec.yml +0 -9
  146. data/.rubocop/style.yml +0 -32
  147. data/.rubocop.yml +0 -11
  148. data/.rubocop_todo.yml +0 -219
  149. data/.yardopts +0 -2
  150. data/CHANGES_OLD.md +0 -1002
  151. data/Gemfile +0 -51
  152. data/Guardfile +0 -18
  153. data/Rakefile +0 -64
  154. data/lib/http/headers/mixin.rb +0 -34
  155. data/lib/http/retriable/client.rb +0 -37
  156. data/logo.png +0 -0
  157. data/spec/lib/http/client_spec.rb +0 -556
  158. data/spec/lib/http/connection_spec.rb +0 -88
  159. data/spec/lib/http/content_type_spec.rb +0 -47
  160. data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
  161. data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
  162. data/spec/lib/http/features/instrumentation_spec.rb +0 -81
  163. data/spec/lib/http/features/logging_spec.rb +0 -65
  164. data/spec/lib/http/features/raise_error_spec.rb +0 -62
  165. data/spec/lib/http/headers/mixin_spec.rb +0 -36
  166. data/spec/lib/http/headers/normalizer_spec.rb +0 -52
  167. data/spec/lib/http/headers_spec.rb +0 -527
  168. data/spec/lib/http/options/body_spec.rb +0 -15
  169. data/spec/lib/http/options/features_spec.rb +0 -33
  170. data/spec/lib/http/options/form_spec.rb +0 -15
  171. data/spec/lib/http/options/headers_spec.rb +0 -24
  172. data/spec/lib/http/options/json_spec.rb +0 -15
  173. data/spec/lib/http/options/merge_spec.rb +0 -68
  174. data/spec/lib/http/options/new_spec.rb +0 -30
  175. data/spec/lib/http/options/proxy_spec.rb +0 -20
  176. data/spec/lib/http/options_spec.rb +0 -13
  177. data/spec/lib/http/redirector_spec.rb +0 -530
  178. data/spec/lib/http/request/body_spec.rb +0 -211
  179. data/spec/lib/http/request/writer_spec.rb +0 -121
  180. data/spec/lib/http/request_spec.rb +0 -234
  181. data/spec/lib/http/response/body_spec.rb +0 -85
  182. data/spec/lib/http/response/parser_spec.rb +0 -74
  183. data/spec/lib/http/response/status_spec.rb +0 -253
  184. data/spec/lib/http/response_spec.rb +0 -262
  185. data/spec/lib/http/retriable/delay_calculator_spec.rb +0 -69
  186. data/spec/lib/http/retriable/performer_spec.rb +0 -302
  187. data/spec/lib/http/uri/normalizer_spec.rb +0 -95
  188. data/spec/lib/http/uri_spec.rb +0 -71
  189. data/spec/lib/http_spec.rb +0 -535
  190. data/spec/regression_specs.rb +0 -24
  191. data/spec/spec_helper.rb +0 -89
  192. data/spec/support/black_hole.rb +0 -13
  193. data/spec/support/dummy_server/servlet.rb +0 -203
  194. data/spec/support/dummy_server.rb +0 -44
  195. data/spec/support/fuubar.rb +0 -21
  196. data/spec/support/http_handling_shared.rb +0 -190
  197. data/spec/support/proxy_server.rb +0 -39
  198. data/spec/support/servers/config.rb +0 -11
  199. data/spec/support/servers/runner.rb +0 -19
  200. data/spec/support/ssl_helper.rb +0 -104
  201. /data/{spec → test}/support/capture_warning.rb +0 -0
@@ -1,203 +0,0 @@
1
- # encoding: UTF-8
2
- # frozen_string_literal: true
3
-
4
- require "cgi"
5
-
6
- class DummyServer < WEBrick::HTTPServer
7
- class Servlet < WEBrick::HTTPServlet::AbstractServlet # rubocop:disable Metrics/ClassLength
8
- def self.sockets
9
- @sockets ||= []
10
- end
11
-
12
- def not_found(req, res)
13
- res.status = 404
14
- res.body = "#{req.unparsed_uri} not found"
15
- end
16
-
17
- def self.handlers
18
- @handlers ||= {}
19
- end
20
-
21
- def initialize(server, memo)
22
- super(server)
23
- @memo = memo
24
- end
25
-
26
- %w[get post head].each do |method|
27
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
28
- def self.#{method}(path, &block)
29
- handlers["#{method}:\#{path}"] = block
30
- end
31
-
32
- def do_#{method.upcase}(req, res)
33
- handler = self.class.handlers["#{method}:\#{req.path}"]
34
- return instance_exec(req, res, &handler) if handler
35
- not_found(req, res)
36
- end
37
- RUBY
38
- end
39
-
40
- get "/" do |req, res|
41
- res.status = 200
42
-
43
- case req["Accept"]
44
- when "application/json"
45
- res["Content-Type"] = "application/json"
46
- res.body = '{"json": true}'
47
- else
48
- res["Content-Type"] = "text/html"
49
- res.body = "<!doctype html>"
50
- end
51
- end
52
-
53
- get "/sleep" do |_, res|
54
- sleep 2
55
-
56
- res.status = 200
57
- res.body = "hello"
58
- end
59
-
60
- post "/sleep" do |_, res|
61
- sleep 2
62
-
63
- res.status = 200
64
- res.body = "hello"
65
- end
66
-
67
- ["", "/1", "/2"].each do |path|
68
- get "/socket#{path}" do |req, res|
69
- self.class.sockets << req.instance_variable_get(:@socket)
70
- res.status = 200
71
- res.body = req.instance_variable_get(:@socket).object_id.to_s
72
- end
73
- end
74
-
75
- get "/params" do |req, res|
76
- next not_found(req, res) unless "foo=bar" == req.query_string
77
-
78
- res.status = 200
79
- res.body = "Params!"
80
- end
81
-
82
- get "/multiple-params" do |req, res|
83
- params = CGI.parse req.query_string
84
-
85
- next not_found(req, res) unless {"foo" => ["bar"], "baz" => ["quux"]} == params
86
-
87
- res.status = 200
88
- res.body = "More Params!"
89
- end
90
-
91
- get "/proxy" do |_req, res|
92
- res.status = 200
93
- res.body = "Proxy!"
94
- end
95
-
96
- get "/not-found" do |_req, res|
97
- res.status = 404
98
- res.body = "not found"
99
- end
100
-
101
- get "/redirect-301" do |_req, res|
102
- res.status = 301
103
- res["Location"] = "http://#{@server.config[:BindAddress]}:#{@server.config[:Port]}/"
104
- end
105
-
106
- get "/redirect-302" do |_req, res|
107
- res.status = 302
108
- res["Location"] = "http://#{@server.config[:BindAddress]}:#{@server.config[:Port]}/"
109
- end
110
-
111
- post "/form" do |req, res|
112
- if "testing-form" == req.query["example"]
113
- res.status = 200
114
- res.body = "passed :)"
115
- else
116
- res.status = 400
117
- res.body = "invalid! >:E"
118
- end
119
- end
120
-
121
- post "/body" do |req, res|
122
- if "testing-body" == req.body
123
- res.status = 200
124
- res.body = "passed :)"
125
- else
126
- res.status = 400
127
- res.body = "invalid! >:E"
128
- end
129
- end
130
-
131
- head "/" do |_req, res|
132
- res.status = 200
133
- res["Content-Type"] = "text/html"
134
- end
135
-
136
- get "/bytes" do |_req, res|
137
- bytes = [80, 75, 3, 4, 20, 0, 0, 0, 8, 0, 123, 104, 169, 70, 99, 243, 243]
138
- res["Content-Type"] = "application/octet-stream"
139
- res.body = bytes.pack("c*")
140
- end
141
-
142
- get "/iso-8859-1" do |_req, res|
143
- res["Content-Type"] = "text/plain; charset=ISO-8859-1"
144
- res.body = "testæ".encode(Encoding::ISO8859_1)
145
- end
146
-
147
- get "/cookies" do |req, res|
148
- res["Set-Cookie"] = "foo=bar"
149
- res.body = req.cookies.map { |c| [c.name, c.value].join ": " }.join("\n")
150
- end
151
-
152
- post "/echo-body" do |req, res|
153
- res.status = 200
154
- res.body = req.body
155
- end
156
-
157
- get "/héllö-wörld".b do |_req, res|
158
- res.status = 200
159
- res.body = "hello world"
160
- end
161
-
162
- post "/encoded-body" do |req, res|
163
- res.status = 200
164
-
165
- res.body = case req["Accept-Encoding"]
166
- when "gzip"
167
- res["Content-Encoding"] = "gzip"
168
- StringIO.open do |out|
169
- Zlib::GzipWriter.wrap(out) do |gz|
170
- gz.write "#{req.body}-gzipped"
171
- gz.finish
172
- out.tap(&:rewind).read
173
- end
174
- end
175
- when "deflate"
176
- res["Content-Encoding"] = "deflate"
177
- Zlib::Deflate.deflate("#{req.body}-deflated")
178
- else
179
- "#{req.body}-raw"
180
- end
181
- end
182
-
183
- post "/no-content-204" do |req, res|
184
- res.status = 204
185
- res.body = ""
186
-
187
- case req["Accept-Encoding"]
188
- when "gzip"
189
- res["Content-Encoding"] = "gzip"
190
- when "deflate"
191
- res["Content-Encoding"] = "deflate"
192
- end
193
- end
194
-
195
- get "/retry-2" do |_req, res|
196
- @memo[:attempts] ||= 0
197
- @memo[:attempts] += 1
198
-
199
- res.body = "retried #{@memo[:attempts]}x"
200
- res.status = @memo[:attempts] == 2 ? 200 : 500
201
- end
202
- end
203
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "webrick"
4
- require "webrick/ssl"
5
-
6
- require "support/black_hole"
7
- require "support/dummy_server/servlet"
8
- require "support/servers/config"
9
- require "support/servers/runner"
10
- require "support/ssl_helper"
11
-
12
- class DummyServer < WEBrick::HTTPServer
13
- include ServerConfig
14
-
15
- CONFIG = {
16
- :BindAddress => "127.0.0.1",
17
- :Port => 0,
18
- :AccessLog => BlackHole,
19
- :Logger => BlackHole
20
- }.freeze
21
-
22
- SSL_CONFIG = CONFIG.merge(
23
- :SSLEnable => true,
24
- :SSLStartImmediately => true
25
- ).freeze
26
-
27
- def initialize(options = {})
28
- super(options[:ssl] ? SSL_CONFIG : CONFIG)
29
- @memo = {}
30
- mount("/", Servlet, @memo)
31
- end
32
-
33
- def endpoint
34
- "#{scheme}://#{addr}:#{port}"
35
- end
36
-
37
- def scheme
38
- config[:SSLEnable] ? "https" : "http"
39
- end
40
-
41
- def ssl_context
42
- @ssl_context ||= SSLHelper.server_context
43
- end
44
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fuubar"
4
-
5
- RSpec.configure do |config|
6
- # Use Fuubar instafail-alike formatter, unless a formatter has already been
7
- # configured (e.g. via a command-line flag).
8
- config.default_formatter = "Fuubar"
9
-
10
- # Disable auto-refresh of the fuubar progress bar to avoid surprises during
11
- # debugiing. And simply because there's next to absolutely no point in having
12
- # this turned on.
13
- #
14
- # > By default fuubar will automatically refresh the bar (and therefore
15
- # > the ETA) every second. Unfortunately this doesn't play well with things
16
- # > like debuggers. When you're debugging, having a bar show up every second
17
- # > is undesireable.
18
- #
19
- # See: https://github.com/thekompanee/fuubar#disabling-auto-refresh
20
- config.fuubar_auto_refresh = false
21
- end
@@ -1,190 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.shared_context "HTTP handling" do
4
- context "without timeouts" do
5
- let(:options) { {:timeout_class => HTTP::Timeout::Null, :timeout_options => {}} }
6
-
7
- it "works" do
8
- expect(client.get(server.endpoint).body.to_s).to eq("<!doctype html>")
9
- end
10
- end
11
-
12
- context "with a per operation timeout" do
13
- let(:response) { client.get(server.endpoint).body.to_s }
14
-
15
- let(:options) do
16
- {
17
- :timeout_class => HTTP::Timeout::PerOperation,
18
- :timeout_options => {
19
- :connect_timeout => conn_timeout,
20
- :read_timeout => read_timeout,
21
- :write_timeout => write_timeout
22
- }
23
- }
24
- end
25
- let(:conn_timeout) { 1 }
26
- let(:read_timeout) { 1 }
27
- let(:write_timeout) { 1 }
28
-
29
- it "works" do
30
- expect(response).to eq("<!doctype html>")
31
- end
32
-
33
- context "connection" do
34
- context "of 1" do
35
- let(:conn_timeout) { 1 }
36
-
37
- it "does not time out" do
38
- expect { response }.to_not raise_error
39
- end
40
- end
41
- end
42
-
43
- context "read" do
44
- context "of 0" do
45
- let(:read_timeout) { 0 }
46
-
47
- it "times out", :flaky do
48
- expect { response }.to raise_error(HTTP::TimeoutError, /Read/i)
49
- end
50
- end
51
-
52
- context "of 2.5" do
53
- let(:read_timeout) { 2.5 }
54
-
55
- it "does not time out", :flaky do
56
- expect { client.get("#{server.endpoint}/sleep").body.to_s }.to_not raise_error
57
- end
58
- end
59
- end
60
- end
61
-
62
- context "with a global timeout" do
63
- let(:options) do
64
- {
65
- :timeout_class => HTTP::Timeout::Global,
66
- :timeout_options => {
67
- :global_timeout => global_timeout
68
- }
69
- }
70
- end
71
- let(:global_timeout) { 1 }
72
-
73
- let(:response) { client.get(server.endpoint).body.to_s }
74
-
75
- it "errors if connecting takes too long" do
76
- expect(TCPSocket).to receive(:open) do
77
- sleep 1.25
78
- end
79
-
80
- expect { response }.to raise_error(HTTP::ConnectTimeoutError, /execution/)
81
- end
82
-
83
- it "errors if reading takes too long" do
84
- expect { client.get("#{server.endpoint}/sleep").body.to_s }.
85
- to raise_error(HTTP::TimeoutError, /Timed out/)
86
- end
87
-
88
- context "it resets state when reusing connections" do
89
- let(:extra_options) { {:persistent => server.endpoint} }
90
-
91
- let(:global_timeout) { 2.5 }
92
-
93
- it "does not timeout", :flaky do
94
- client.get("#{server.endpoint}/sleep").body.to_s
95
- client.get("#{server.endpoint}/sleep").body.to_s
96
- end
97
- end
98
- end
99
-
100
- describe "connection reuse" do
101
- let(:sockets_used) do
102
- [
103
- client.get("#{server.endpoint}/socket/1").body.to_s,
104
- client.get("#{server.endpoint}/socket/2").body.to_s
105
- ]
106
- end
107
-
108
- context "when enabled" do
109
- let(:options) { {:persistent => server.endpoint} }
110
-
111
- context "without a host" do
112
- it "infers host from persistent config" do
113
- expect(client.get("/").body.to_s).to eq("<!doctype html>")
114
- end
115
- end
116
-
117
- it "re-uses the socket" do
118
- expect(sockets_used).to_not include("")
119
- expect(sockets_used.uniq.length).to eq(1)
120
- end
121
-
122
- context "on a mixed state" do
123
- it "re-opens the connection", :flaky do
124
- first_socket_id = client.get("#{server.endpoint}/socket/1").body.to_s
125
-
126
- client.instance_variable_set(:@state, :dirty)
127
-
128
- second_socket_id = client.get("#{server.endpoint}/socket/2").body.to_s
129
-
130
- expect(first_socket_id).to_not eq(second_socket_id)
131
- end
132
- end
133
-
134
- context "when trying to read a stale body" do
135
- it "errors" do
136
- client.get("#{server.endpoint}/not-found")
137
- expect { client.get(server.endpoint) }.to raise_error(HTTP::StateError, /Tried to send a request/)
138
- end
139
- end
140
-
141
- context "when reading a cached body" do
142
- it "succeeds" do
143
- first_res = client.get(server.endpoint)
144
- first_res.body.to_s
145
-
146
- second_res = client.get(server.endpoint)
147
-
148
- expect(first_res.body.to_s).to eq("<!doctype html>")
149
- expect(second_res.body.to_s).to eq("<!doctype html>")
150
- end
151
- end
152
-
153
- context "with a socket issue" do
154
- it "transparently reopens", :flaky do
155
- first_socket_id = client.get("#{server.endpoint}/socket").body.to_s
156
- expect(first_socket_id).to_not eq("")
157
- # Kill off the sockets we used
158
- # rubocop:disable Style/RescueModifier
159
- DummyServer::Servlet.sockets.each do |socket|
160
- socket.close rescue nil
161
- end
162
- DummyServer::Servlet.sockets.clear
163
- # rubocop:enable Style/RescueModifier
164
-
165
- # Should error because we tried to use a bad socket
166
- expect { client.get("#{server.endpoint}/socket").body.to_s }.to raise_error HTTP::ConnectionError
167
-
168
- # Should succeed since we create a new socket
169
- second_socket_id = client.get("#{server.endpoint}/socket").body.to_s
170
- expect(second_socket_id).to_not eq(first_socket_id)
171
- end
172
- end
173
-
174
- context "with a change in host" do
175
- it "errors" do
176
- expect { client.get("https://invalid.com/socket") }.to raise_error(/Persistence is enabled/i)
177
- end
178
- end
179
- end
180
-
181
- context "when disabled" do
182
- let(:options) { {} }
183
-
184
- it "opens new sockets", :flaky do
185
- expect(sockets_used).to_not include("")
186
- expect(sockets_used.uniq.length).to eq(2)
187
- end
188
- end
189
- end
190
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "webrick/httpproxy"
4
-
5
- require "support/black_hole"
6
- require "support/servers/config"
7
- require "support/servers/runner"
8
-
9
- class ProxyServer < WEBrick::HTTPProxyServer
10
- include ServerConfig
11
-
12
- CONFIG = {
13
- :BindAddress => "127.0.0.1",
14
- :Port => 0,
15
- :AccessLog => BlackHole,
16
- :Logger => BlackHole,
17
- :RequestCallback => proc { |_, res| res["X-PROXIED"] = true }
18
- }.freeze
19
-
20
- def initialize
21
- super CONFIG
22
- end
23
- end
24
-
25
- class AuthProxyServer < WEBrick::HTTPProxyServer
26
- include ServerConfig
27
-
28
- AUTHENTICATOR = proc do |req, res|
29
- WEBrick::HTTPAuth.proxy_basic_auth(req, res, "proxy") do |user, pass|
30
- user == "username" && pass == "password"
31
- end
32
- end
33
-
34
- CONFIG = ProxyServer::CONFIG.merge :ProxyAuthProc => AUTHENTICATOR
35
-
36
- def initialize
37
- super CONFIG
38
- end
39
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ServerConfig
4
- def addr
5
- config[:BindAddress]
6
- end
7
-
8
- def port
9
- config[:Port]
10
- end
11
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ServerRunner
4
- def run_server(name)
5
- let! name do
6
- server = yield
7
-
8
- Thread.new { server.start }
9
-
10
- server
11
- end
12
-
13
- after do
14
- send(name).shutdown
15
- end
16
- end
17
- end
18
-
19
- RSpec.configure { |c| c.extend ServerRunner }
@@ -1,104 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pathname"
4
-
5
- require "certificate_authority"
6
-
7
- module SSLHelper
8
- CERTS_PATH = Pathname.new File.expand_path("../../tmp/certs", __dir__)
9
-
10
- class RootCertificate < ::CertificateAuthority::Certificate
11
- EXTENSIONS = {"keyUsage" => {"usage" => %w[critical keyCertSign]}}.freeze
12
-
13
- def initialize
14
- super()
15
-
16
- subject.common_name = "honestachmed.com"
17
- serial_number.number = 1
18
- key_material.generate_key
19
-
20
- self.signing_entity = true
21
-
22
- sign!("extensions" => EXTENSIONS)
23
- end
24
-
25
- def file
26
- return @file if defined? @file
27
-
28
- CERTS_PATH.mkpath
29
-
30
- cert_file = CERTS_PATH.join("ca.crt")
31
- cert_file.open("w") { |io| io << to_pem }
32
-
33
- @file = cert_file.to_s
34
- end
35
- end
36
-
37
- class ChildCertificate < ::CertificateAuthority::Certificate
38
- def initialize(parent)
39
- super()
40
-
41
- subject.common_name = "127.0.0.1"
42
- serial_number.number = 1
43
-
44
- key_material.generate_key
45
-
46
- self.parent = parent
47
-
48
- sign!
49
- end
50
-
51
- def cert
52
- OpenSSL::X509::Certificate.new to_pem
53
- end
54
-
55
- def key
56
- OpenSSL::PKey::RSA.new key_material.private_key.to_pem
57
- end
58
- end
59
-
60
- class << self
61
- def server_context
62
- context = OpenSSL::SSL::SSLContext.new
63
-
64
- context.verify_mode = OpenSSL::SSL::VERIFY_PEER
65
- context.key = server_cert.key
66
- context.cert = server_cert.cert
67
- context.ca_file = ca.file
68
-
69
- context
70
- end
71
-
72
- def client_context
73
- context = OpenSSL::SSL::SSLContext.new
74
-
75
- context.options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
76
- context.verify_mode = OpenSSL::SSL::VERIFY_PEER
77
- context.key = client_cert.key
78
- context.cert = client_cert.cert
79
- context.ca_file = ca.file
80
-
81
- context
82
- end
83
-
84
- def client_params
85
- {
86
- :key => client_cert.key,
87
- :cert => client_cert.cert,
88
- :ca_file => ca.file
89
- }
90
- end
91
-
92
- %w[server client].each do |side|
93
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
94
- def #{side}_cert
95
- @#{side}_cert ||= ChildCertificate.new ca
96
- end
97
- RUBY
98
- end
99
-
100
- def ca
101
- @ca ||= RootCertificate.new
102
- end
103
- end
104
- end
File without changes