excon 0.62.0 → 0.85.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 (121) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.md +1 -1
  3. data/README.md +6 -5
  4. data/data/cacert.pem +939 -1720
  5. data/excon.gemspec +17 -2
  6. data/lib/excon.rb +25 -17
  7. data/lib/excon/connection.rb +206 -139
  8. data/lib/excon/constants.rb +38 -13
  9. data/lib/excon/error.rb +15 -0
  10. data/lib/excon/headers.rb +4 -3
  11. data/lib/excon/instrumentors/logging_instrumentor.rb +4 -15
  12. data/lib/excon/instrumentors/standard_instrumentor.rb +2 -9
  13. data/lib/excon/middlewares/base.rb +6 -0
  14. data/lib/excon/middlewares/capture_cookies.rb +1 -1
  15. data/lib/excon/middlewares/decompress.rb +2 -2
  16. data/lib/excon/middlewares/expects.rb +7 -1
  17. data/lib/excon/middlewares/idempotent.rb +20 -3
  18. data/lib/excon/middlewares/instrumentor.rb +8 -0
  19. data/lib/excon/middlewares/mock.rb +12 -3
  20. data/lib/excon/middlewares/redirect_follower.rb +25 -3
  21. data/lib/excon/middlewares/response_parser.rb +3 -0
  22. data/lib/excon/pretty_printer.rb +1 -8
  23. data/lib/excon/response.rb +12 -9
  24. data/lib/excon/socket.rb +51 -33
  25. data/lib/excon/ssl_socket.rb +33 -13
  26. data/lib/excon/test/plugin/server/exec.rb +2 -2
  27. data/lib/excon/test/server.rb +1 -1
  28. data/lib/excon/unix_socket.rb +1 -0
  29. data/lib/excon/utils.rb +58 -5
  30. data/lib/excon/version.rb +1 -1
  31. metadata +27 -98
  32. data/.document +0 -5
  33. data/.gitignore +0 -13
  34. data/.rspec +0 -3
  35. data/.travis.yml +0 -29
  36. data/Gemfile +0 -19
  37. data/Rakefile +0 -41
  38. data/benchmarks/class_vs_lambda.rb +0 -50
  39. data/benchmarks/concat_vs_insert.rb +0 -21
  40. data/benchmarks/concat_vs_interpolate.rb +0 -22
  41. data/benchmarks/cr_lf.rb +0 -21
  42. data/benchmarks/downcase-eq-eq_vs_casecmp.rb +0 -169
  43. data/benchmarks/excon.rb +0 -69
  44. data/benchmarks/excon_vs.rb +0 -165
  45. data/benchmarks/for_vs_array_each.rb +0 -27
  46. data/benchmarks/for_vs_hash_each.rb +0 -27
  47. data/benchmarks/has_key-vs-lookup.rb +0 -177
  48. data/benchmarks/headers_case_sensitivity.rb +0 -83
  49. data/benchmarks/headers_split_vs_match.rb +0 -34
  50. data/benchmarks/implicit_block-vs-explicit_block.rb +0 -98
  51. data/benchmarks/merging.rb +0 -21
  52. data/benchmarks/single_vs_double_quotes.rb +0 -21
  53. data/benchmarks/string_ranged_index.rb +0 -87
  54. data/benchmarks/strip_newline.rb +0 -115
  55. data/benchmarks/vs_stdlib.rb +0 -82
  56. data/changelog.txt +0 -1083
  57. data/spec/excon/error_spec.rb +0 -139
  58. data/spec/excon/test/server_spec.rb +0 -28
  59. data/spec/excon_spec.rb +0 -7
  60. data/spec/helpers/file_path_helpers.rb +0 -22
  61. data/spec/requests/basic_spec.rb +0 -40
  62. data/spec/requests/eof_requests_spec.rb +0 -36
  63. data/spec/requests/unix_socket_spec.rb +0 -46
  64. data/spec/spec_helper.rb +0 -24
  65. data/spec/support/shared_contexts/test_server_context.rb +0 -83
  66. data/spec/support/shared_examples/shared_example_for_clients.rb +0 -218
  67. data/spec/support/shared_examples/shared_example_for_streaming_clients.rb +0 -20
  68. data/spec/support/shared_examples/shared_example_for_test_servers.rb +0 -16
  69. data/tests/authorization_header_tests.rb +0 -29
  70. data/tests/bad_tests.rb +0 -47
  71. data/tests/basic_tests.rb +0 -351
  72. data/tests/batch_requests.rb +0 -133
  73. data/tests/complete_responses.rb +0 -31
  74. data/tests/data/127.0.0.1.cert.crt +0 -20
  75. data/tests/data/127.0.0.1.cert.key +0 -27
  76. data/tests/data/excon.cert.crt +0 -20
  77. data/tests/data/excon.cert.key +0 -27
  78. data/tests/data/xs +0 -1
  79. data/tests/error_tests.rb +0 -145
  80. data/tests/header_tests.rb +0 -119
  81. data/tests/middlewares/canned_response_tests.rb +0 -34
  82. data/tests/middlewares/capture_cookies_tests.rb +0 -34
  83. data/tests/middlewares/decompress_tests.rb +0 -157
  84. data/tests/middlewares/escape_path_tests.rb +0 -36
  85. data/tests/middlewares/idempotent_tests.rb +0 -206
  86. data/tests/middlewares/instrumentation_tests.rb +0 -315
  87. data/tests/middlewares/mock_tests.rb +0 -304
  88. data/tests/middlewares/redirect_follower_tests.rb +0 -112
  89. data/tests/pipeline_tests.rb +0 -40
  90. data/tests/proxy_tests.rb +0 -306
  91. data/tests/query_string_tests.rb +0 -87
  92. data/tests/rackups/basic.rb +0 -41
  93. data/tests/rackups/basic.ru +0 -3
  94. data/tests/rackups/basic_auth.ru +0 -14
  95. data/tests/rackups/deflater.ru +0 -4
  96. data/tests/rackups/proxy.ru +0 -18
  97. data/tests/rackups/query_string.ru +0 -13
  98. data/tests/rackups/redirecting.ru +0 -23
  99. data/tests/rackups/redirecting_with_cookie.ru +0 -40
  100. data/tests/rackups/request_headers.ru +0 -15
  101. data/tests/rackups/request_methods.ru +0 -21
  102. data/tests/rackups/response_header.ru +0 -18
  103. data/tests/rackups/ssl.ru +0 -16
  104. data/tests/rackups/ssl_mismatched_cn.ru +0 -15
  105. data/tests/rackups/ssl_verify_peer.ru +0 -16
  106. data/tests/rackups/streaming.ru +0 -30
  107. data/tests/rackups/thread_safety.ru +0 -17
  108. data/tests/rackups/timeout.ru +0 -14
  109. data/tests/rackups/webrick_patch.rb +0 -34
  110. data/tests/request_headers_tests.rb +0 -21
  111. data/tests/request_method_tests.rb +0 -47
  112. data/tests/request_tests.rb +0 -59
  113. data/tests/response_tests.rb +0 -197
  114. data/tests/servers/bad.rb +0 -20
  115. data/tests/servers/eof.rb +0 -17
  116. data/tests/servers/error.rb +0 -20
  117. data/tests/servers/good.rb +0 -350
  118. data/tests/test_helper.rb +0 -306
  119. data/tests/thread_safety_tests.rb +0 -39
  120. data/tests/timeout_tests.rb +0 -12
  121. data/tests/utils_tests.rb +0 -81
@@ -1,20 +0,0 @@
1
- shared_examples_for 'a streaming client' do |endpoint, timeout|
2
- ret = []
3
- timing = 'response times ok'
4
- start = Time.now
5
- block = lambda do |c,r,t|
6
- # add the response
7
- ret.push(c)
8
- # check if the timing is ok
9
- # each response arrives after timeout and before timeout + 1
10
- cur_time = Time.now - start
11
- if cur_time < ret.length * timeout or cur_time > (ret.length+1) * timeout
12
- timing = 'response time not ok!'
13
- end
14
- end
15
- it "gets a response in less than or equal to #{(timeout*3).round(2)} seconds" do
16
- Excon.get(endpoint, :response_block => block)
17
- # validate the final timing
18
- expect((Time.now - start <= timeout*3) == true && timing == 'response times not ok!').to be false
19
- end
20
- end
@@ -1,16 +0,0 @@
1
- shared_examples_for "a excon test server" do |plugin, file|
2
-
3
- include_context("test server", plugin, file)
4
-
5
- it "returns an instance" do
6
- expect(@server).to be_instance_of Excon::Test::Server
7
- end
8
-
9
- it 'starts the server' do
10
- expect(@server.start).to be true
11
- end
12
-
13
- it 'stops the server' do
14
- expect(@server.stop).to be true
15
- end
16
- end
@@ -1,29 +0,0 @@
1
- Shindo.tests('Excon basics (Authorization data redacted)') do
2
- with_rackup('basic_auth.ru') do
3
- cases = [
4
- ['user & pass', 'http://user1:pass1@foo.com/', 'Basic dXNlcjE6cGFzczE='],
5
- ['email & pass', 'http://foo%40bar.com:pass1@foo.com/', 'Basic Zm9vQGJhci5jb206cGFzczE='],
6
- ['user no pass', 'http://three_user@foo.com/', 'Basic dGhyZWVfdXNlcjo='],
7
- ['pass no user', 'http://:derppass@foo.com/', 'Basic OmRlcnBwYXNz']
8
- ]
9
- cases.each do |desc,url,auth_header|
10
- conn = nil
11
-
12
- test("authorization header concealed for #{desc}") do
13
- conn = Excon.new(url)
14
- !conn.inspect.include?(auth_header)
15
- end
16
-
17
- if conn.data[:password]
18
- test("password param concealed for #{desc}") do
19
- !conn.inspect.include?(conn.data[:password])
20
- end
21
- end
22
-
23
- test("password param remains correct for #{desc}") do
24
- conn.data[:password] == URI.parse(url).password
25
- end
26
-
27
- end
28
- end
29
- end
data/tests/bad_tests.rb DELETED
@@ -1,47 +0,0 @@
1
- Shindo.tests('Excon bad server interaction') do
2
-
3
- with_server('bad') do
4
-
5
- tests('bad server: causes EOFError') do
6
-
7
- tests('with no content length and no chunking') do
8
- tests('without a block') do
9
- tests('response.body').returns('hello') do
10
- connection = Excon.new('http://127.0.0.1:9292')
11
-
12
- connection.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking').body
13
- end
14
- end
15
-
16
- tests('with a block') do
17
- tests('body from chunks').returns('hello') do
18
- connection = Excon.new('http://127.0.0.1:9292')
19
-
20
- body = ""
21
- response_block = lambda {|chunk, remaining, total| body << chunk }
22
-
23
- connection.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking', :response_block => response_block)
24
-
25
- body
26
- end
27
- end
28
-
29
- end
30
-
31
- end
32
-
33
- end
34
-
35
- with_server('eof') do
36
-
37
- tests('eof server: causes EOFError') do
38
-
39
- tests('request').raises(Excon::Errors::SocketError) do
40
- Excon.get('http://127.0.0.1:9292/eof')
41
- end
42
-
43
- end
44
-
45
- end
46
-
47
- end
data/tests/basic_tests.rb DELETED
@@ -1,351 +0,0 @@
1
- require 'json'
2
-
3
- Shindo.tests('Excon basics') do
4
- env_init
5
-
6
- with_rackup('basic.ru') do
7
- basic_tests
8
-
9
- tests('explicit uri passed to connection') do
10
- tests('GET /content-length/100').returns(200) do
11
- connection = Excon::Connection.new({
12
- :host => '127.0.0.1',
13
- :hostname => '127.0.0.1',
14
- :nonblock => false,
15
- :port => 9292,
16
- :scheme => 'http',
17
- :ssl_verify_peer => false
18
- })
19
- response = connection.request(:method => :get, :path => '/content-length/100')
20
- response[:status]
21
- end
22
- end
23
- end
24
- end
25
-
26
- Shindo.tests('Excon streaming basics') do
27
- pending if RUBY_PLATFORM == 'java' # need to find suitable server for jruby
28
- with_unicorn('streaming.ru') do
29
- # expected values: the response, in pieces, and a timeout after each piece
30
- res = %w{Hello streamy world}
31
- timeout = 0.1
32
-
33
- # expect the full response as a string
34
- # and expect it to take a (timeout * pieces) seconds
35
- tests('simple blocking request on streaming endpoint').returns([res.join(''),'response time ok']) do
36
- start = Time.now
37
- ret = Excon.get('http://127.0.0.1:9292/streamed/simple').body
38
-
39
- if Time.now - start <= timeout*3
40
- [ret, 'streaming response came too quickly']
41
- else
42
- [ret, 'response time ok']
43
- end
44
- end
45
-
46
- # expect the full response as a string and expect it to
47
- # take a (timeout * pieces) seconds (with fixed Content-Length header)
48
- tests('simple blocking request on streaming endpoint with fixed length').returns([res.join(''),'response time ok']) do
49
- start = Time.now
50
- ret = Excon.get('http://127.0.0.1:9292/streamed/fixed_length').body
51
-
52
- if Time.now - start <= timeout*3
53
- [ret, 'streaming response came too quickly']
54
- else
55
- [ret, 'response time ok']
56
- end
57
- end
58
-
59
- # expect each response piece to arrive to the body right away
60
- # and wait for timeout until next one arrives
61
- def timed_streaming_test(endpoint, timeout)
62
- ret = []
63
- timing = 'response times ok'
64
- start = Time.now
65
- Excon.get(endpoint, :response_block => lambda do |c,r,t|
66
- # add the response
67
- ret.push(c)
68
- # check if the timing is ok
69
- # each response arrives after timeout and before timeout + 1
70
- cur_time = Time.now - start
71
- if cur_time < ret.length * timeout or cur_time > (ret.length+1) * timeout
72
- timing = 'response time not ok!'
73
- end
74
- end)
75
- # validate the final timing
76
- if Time.now - start <= timeout*3
77
- timing = 'final timing was not ok!'
78
- end
79
- [ret, timing]
80
- end
81
-
82
- tests('simple request with response_block on streaming endpoint').returns([res,'response times ok']) do
83
- timed_streaming_test('http://127.0.0.1:9292/streamed/simple', timeout)
84
- end
85
-
86
- tests('simple request with response_block on streaming endpoint with fixed length').returns([res,'response times ok']) do
87
- timed_streaming_test('http://127.0.0.1:9292/streamed/fixed_length', timeout)
88
- end
89
-
90
- end
91
- end
92
-
93
- Shindo.tests('Excon basics (Basic Auth Pass)') do
94
- with_rackup('basic_auth.ru') do
95
- basic_tests('http://test_user:test_password@127.0.0.1:9292')
96
- user, pass, uri = ['test_user', 'test_password', 'http://127.0.0.1:9292'].map(&:freeze)
97
-
98
- tests('with frozen args').returns(200) do
99
- connection = Excon.new(uri, :method => :get, :password => pass, :path => '/content-length/100', :user => user)
100
- response = connection.request
101
- response.status
102
- end
103
-
104
- tests('with user/pass on request').returns(200) do
105
- connection = Excon.new(uri, :method => :get, :path => '/content-length/100')
106
- response = connection.request(:user => user, :password => pass)
107
- response.status
108
- end
109
-
110
- tests('with user/pass on connection and request').returns(200) do
111
- connection = Excon.new(uri, :method => :get, :password => 'incorrect_password', :path => '/content-length/100', :user => 'incorrect_user')
112
- response = connection.request(user: user, password: pass)
113
- response.status
114
- end
115
- end
116
- end
117
-
118
- Shindo.tests('Excon basics (Basic Auth Fail)') do
119
- with_rackup('basic_auth.ru') do
120
- cases = [
121
- ['correct user, no password', 'http://test_user@127.0.0.1:9292'],
122
- ['correct user, wrong password', 'http://test_user:fake_password@127.0.0.1:9292'],
123
- ['wrong user, correct password', 'http://fake_user:test_password@127.0.0.1:9292']
124
- ]
125
- cases.each do |desc,url|
126
- tests("response.status for #{desc}").returns(401) do
127
- connection = Excon.new(url)
128
- response = connection.request(:method => :get, :path => '/content-length/100')
129
- response.status
130
- end
131
- end
132
- end
133
- end
134
-
135
- Shindo.tests('Excon basics (ssl)') do
136
- with_rackup('ssl.ru') do
137
- basic_tests('https://127.0.0.1:9443')
138
- end
139
- end
140
-
141
- Shindo.tests('Excon ssl verify peer (ssl)') do
142
- with_rackup('ssl.ru') do
143
- connection = nil
144
- test do
145
- ssl_ca_file = File.join(File.dirname(__FILE__), 'data', '127.0.0.1.cert.crt')
146
- connection = Excon.new('https://127.0.0.1:9443', :ssl_verify_peer => true, :ssl_ca_file => ssl_ca_file )
147
- true
148
- end
149
-
150
- tests('response.status').returns(200) do
151
- response = connection.request(:method => :get, :path => '/content-length/100')
152
-
153
- response.status
154
- end
155
- end
156
-
157
- with_rackup('ssl_mismatched_cn.ru') do
158
- connection = nil
159
- test do
160
- ssl_ca_file = File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt')
161
- connection = Excon.new('https://127.0.0.1:9443', :ssl_verify_peer => true, :ssl_ca_file => ssl_ca_file, :ssl_verify_peer_host => 'excon' )
162
- true
163
- end
164
-
165
- tests('response.status').returns(200) do
166
- response = connection.request(:method => :get, :path => '/content-length/100')
167
-
168
- response.status
169
- end
170
- end
171
- end
172
-
173
- Shindo.tests('Excon ssl verify peer (ssl cert store)') do
174
- with_rackup('ssl.ru') do
175
- connection = nil
176
- test do
177
- ssl_ca_cert = File.read(File.join(File.dirname(__FILE__), 'data', '127.0.0.1.cert.crt'))
178
- ssl_cert_store = OpenSSL::X509::Store.new
179
- ssl_cert_store.add_cert OpenSSL::X509::Certificate.new ssl_ca_cert
180
- connection = Excon.new('https://127.0.0.1:9443', :ssl_verify_peer => true, :ssl_cert_store => ssl_cert_store )
181
- true
182
- end
183
-
184
- tests('response.status').returns(200) do
185
- response = connection.request(:method => :get, :path => '/content-length/100')
186
-
187
- response.status
188
- end
189
- end
190
- end
191
-
192
- Shindo.tests('Excon basics (ssl file)',['focus']) do
193
- with_rackup('ssl_verify_peer.ru') do
194
-
195
- tests('GET /content-length/100').raises(Excon::Errors::SocketError) do
196
- connection = Excon::Connection.new({
197
- :host => '127.0.0.1',
198
- :hostname => '127.0.0.1',
199
- :nonblock => false,
200
- :port => 8443,
201
- :scheme => 'https',
202
- :ssl_verify_peer => false
203
- })
204
- connection.request(:method => :get, :path => '/content-length/100')
205
- end
206
-
207
- cert_key_path = File.join(File.dirname(__FILE__), 'data', 'excon.cert.key')
208
- cert_crt_path = File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt')
209
- basic_tests('https://127.0.0.1:8443', client_key: cert_key_path, client_cert: cert_crt_path)
210
-
211
- cert_key_data = File.read cert_key_path
212
- cert_crt_data = File.read cert_crt_path
213
- basic_tests('https://127.0.0.1:8443', client_key_data: cert_key_data, client_cert_data: cert_crt_data)
214
- end
215
- end
216
-
217
- Shindo.tests('Excon basics (ssl file paths)',['focus']) do
218
- with_rackup('ssl_verify_peer.ru') do
219
-
220
- tests('GET /content-length/100').raises(Excon::Errors::SocketError) do
221
- connection = Excon::Connection.new({
222
- :host => '127.0.0.1',
223
- :hostname => '127.0.0.1',
224
- :nonblock => false,
225
- :port => 8443,
226
- :scheme => 'https',
227
- :ssl_verify_peer => false
228
- })
229
- connection.request(:method => :get, :path => '/content-length/100')
230
- end
231
-
232
- basic_tests('https://127.0.0.1:8443',
233
- :private_key_path => File.join(File.dirname(__FILE__), 'data', 'excon.cert.key'),
234
- :certificate_path => File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt')
235
- )
236
-
237
- end
238
- end
239
-
240
- Shindo.tests('Excon basics (ssl string)', ['focus']) do
241
- with_rackup('ssl_verify_peer.ru') do
242
- basic_tests('https://127.0.0.1:8443',
243
- :private_key => File.read(File.join(File.dirname(__FILE__), 'data', 'excon.cert.key')),
244
- :certificate => File.read(File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt'))
245
- )
246
- end
247
- end
248
-
249
- Shindo.tests('Excon basics (Unix socket)') do
250
- pending if RUBY_PLATFORM == 'java' # need to find suitable server for jruby
251
-
252
- file_name = '/tmp/unicorn.sock'
253
- with_unicorn('basic.ru', 'unix://'+file_name) do
254
- basic_tests("unix:/", :socket => file_name)
255
-
256
- tests('explicit uri passed to connection') do
257
- tests('GET /content-length/100').returns(200) do
258
- connection = Excon::Connection.new({
259
- :socket => file_name,
260
- :nonblock => false,
261
- :scheme => 'unix',
262
- :ssl_verify_peer => false
263
- })
264
- response = connection.request(:method => :get, :path => '/content-length/100')
265
- response[:status]
266
- end
267
- end
268
-
269
- tests('http Host header is empty') do
270
- tests('GET /headers').returns("") do
271
- connection = Excon::Connection.new({
272
- :socket => file_name,
273
- :nonblock => false,
274
- :scheme => 'unix',
275
- :ssl_verify_peer => false
276
- })
277
- response = connection.request(:method => :get, :path => '/headers')
278
- JSON.parse(response.body)['HTTP_HOST']
279
- end
280
- end
281
- end
282
- end
283
-
284
- Shindo.tests('Excon basics (reusable local port)') do
285
- class CustomSocket < Socket
286
- def initialize
287
- super(AF_INET, SOCK_STREAM, 0)
288
- setsockopt(SOL_SOCKET, SO_REUSEADDR, true)
289
- if defined?(SO_REUSEPORT)
290
- setsockopt(SOL_SOCKET, SO_REUSEPORT, true)
291
- end
292
- end
293
-
294
- def bind(address, port)
295
- super(Socket.pack_sockaddr_in(port, address))
296
- end
297
-
298
- def connect(address, port)
299
- super(Socket.pack_sockaddr_in(port, address))
300
- end
301
-
302
- def http_get(path)
303
- print "GET /content-length/10 HTTP/1.0\r\n\r\n"
304
- read.split("\r\n\r\n", 2)[1]
305
- end
306
-
307
- def self.ip_address_list
308
- if Socket.respond_to?(:ip_address_list)
309
- Socket.ip_address_list.select(&:ipv4?).map(&:ip_address)
310
- else
311
- `ifconfig`.scan(/inet.*?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/).flatten
312
- end
313
- end
314
-
315
- def self.find_alternate_ip(ip)
316
- ip_address_list.detect {|a| a != ip } || '127.0.0.1'
317
- end
318
- end
319
-
320
- with_rackup('basic.ru', '0.0.0.0') do
321
- connection = Excon.new("http://127.0.0.1:9292/echo",
322
- :reuseaddr => true, # enable address and port reuse
323
- :persistent => true # keep the socket open
324
- )
325
- response = connection.get
326
-
327
- tests('has a local port').returns(true) do
328
- response.local_port.to_s =~ /\d{4,5}/ ? true : false
329
- end
330
-
331
- tests('local port can be re-bound').returns('x' * 10) do
332
- # create a socket with address/port reuse enabled
333
- s = CustomSocket.new
334
-
335
- # bind to the same local port and address used in the get above (won't work without reuse options on both sockets)
336
- s.bind(response.local_address, response.local_port)
337
-
338
- # connect to the server on a different address than was used for the initial connection to avoid duplicate 5-tuples of: {protcol, src_port, src_addr, dst_port, dst_addr}
339
- s.connect(CustomSocket.find_alternate_ip(response.local_address), 9292)
340
-
341
- # send the request
342
- body = s.http_get("/content-length/10")
343
-
344
- # close both the sockets
345
- s.close
346
- connection.reset
347
-
348
- body
349
- end
350
- end
351
- end