elasticsearch-transport 7.13.3 → 7.17.7
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/Gemfile +4 -8
- data/README.md +3 -8
- data/Rakefile +9 -10
- data/elasticsearch-transport.gemspec +15 -15
- data/lib/elasticsearch/transport/client.rb +34 -3
- data/lib/elasticsearch/transport/transport/base.rb +41 -22
- data/lib/elasticsearch/transport/transport/connections/connection.rb +2 -1
- data/lib/elasticsearch/transport/transport/errors.rb +1 -0
- data/lib/elasticsearch/transport/transport/http/curb.rb +44 -32
- data/lib/elasticsearch/transport/transport/http/faraday.rb +5 -3
- data/lib/elasticsearch/transport/transport/http/manticore.rb +35 -28
- data/lib/elasticsearch/transport/version.rb +1 -1
- data/lib/elasticsearch/transport.rb +19 -30
- data/spec/elasticsearch/transport/base_spec.rb +46 -7
- data/spec/elasticsearch/transport/client_spec.rb +129 -61
- data/spec/elasticsearch/transport/http/curb_spec.rb +126 -0
- data/spec/elasticsearch/transport/http/faraday_spec.rb +141 -0
- data/spec/elasticsearch/transport/http/manticore_spec.rb +143 -0
- data/spec/elasticsearch/transport/meta_header_spec.rb +64 -28
- data/spec/spec_helper.rb +9 -5
- data/test/integration/jruby_test.rb +43 -0
- data/test/integration/transport_test.rb +18 -27
- data/test/test_helper.rb +6 -22
- data/test/unit/response_test.rb +1 -1
- data/test/unit/transport_base_test.rb +16 -7
- data/test/unit/transport_curb_test.rb +0 -1
- data/test/unit/transport_manticore_test.rb +242 -155
- metadata +63 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 515176cfbf829f3153d85e4975eebed91424aaa14256d332f0dc3f87030ce671
|
4
|
+
data.tar.gz: c8bdcb22a2f81446f55d4d3025f05863020629eb0ff139e80832a3dc8f43eb8b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 850fc6102767844a698044cbc3cef9e63f01895ef5735e9c9e831db4e62dac9f448c71cc6eac591f5ce3e225b35106a083366ead9e3267d24f8723f81a792f8c
|
7
|
+
data.tar.gz: 18ba115ba8d1b55866806c75845c8a39dd920c9bd227b64e586ecdedc7274530c28dcc3f62bfb70f61510091f2acc3aa67511323e0b6b70c5afdbf5df035f175
|
data/Gemfile
CHANGED
@@ -20,16 +20,12 @@ source 'https://rubygems.org'
|
|
20
20
|
# Specify your gem's dependencies in elasticsearch-transport.gemspec
|
21
21
|
gemspec
|
22
22
|
|
23
|
-
if File.exist? File.expand_path('
|
24
|
-
gem 'elasticsearch-api', path: File.expand_path('
|
23
|
+
if File.exist? File.expand_path('../elasticsearch-api/elasticsearch-api.gemspec', __dir__)
|
24
|
+
gem 'elasticsearch-api', path: File.expand_path('../elasticsearch-api', __dir__), require: false
|
25
25
|
end
|
26
26
|
|
27
|
-
if File.exist? File.expand_path('
|
28
|
-
gem 'elasticsearch
|
29
|
-
end
|
30
|
-
|
31
|
-
if File.exist? File.expand_path('../../elasticsearch/elasticsearch.gemspec', __FILE__)
|
32
|
-
gem 'elasticsearch', path: File.expand_path('../../elasticsearch', __FILE__), require: false
|
27
|
+
if File.exist? File.expand_path('../elasticsearch/elasticsearch.gemspec', __dir__)
|
28
|
+
gem 'elasticsearch', path: File.expand_path('../elasticsearch', __dir__), require: false
|
33
29
|
end
|
34
30
|
|
35
31
|
group :development, :test do
|
data/README.md
CHANGED
@@ -424,10 +424,7 @@ To configure the _Faraday_ instance directly, use a block:
|
|
424
424
|
f.adapter :patron
|
425
425
|
end
|
426
426
|
|
427
|
-
You can use any standard Faraday middleware and plugins in the configuration block
|
428
|
-
|
429
|
-
You can also initialize the transport class yourself, and pass it to the client constructor
|
430
|
-
as the `transport` argument:
|
427
|
+
You can use any standard Faraday middleware and plugins in the configuration block. You can also initialize the transport class yourself, and pass it to the client constructor as the `transport` argument:
|
431
428
|
|
432
429
|
```ruby
|
433
430
|
require 'patron'
|
@@ -561,16 +558,14 @@ Github's pull requests and issues are used to communicate, send bug reports and
|
|
561
558
|
To work on the code, clone and bootstrap the main repository first --
|
562
559
|
please see instructions in the main [README](../README.md#development).
|
563
560
|
|
564
|
-
To run tests, launch a testing cluster
|
565
|
-
in the main [README](../README.md#development) -- and use the Rake tasks:
|
561
|
+
To run tests, launch a testing cluster and use the Rake tasks:
|
566
562
|
|
567
563
|
```
|
568
564
|
time rake test:unit
|
569
565
|
time rake test:integration
|
570
566
|
```
|
571
567
|
|
572
|
-
|
573
|
-
can use Ruby 2.x syntax and features.
|
568
|
+
Use `COVERAGE=true` before running a test task to check coverage with Simplecov.
|
574
569
|
|
575
570
|
## License
|
576
571
|
|
data/Rakefile
CHANGED
@@ -27,38 +27,37 @@ require 'rake/testtask'
|
|
27
27
|
require 'rspec/core/rake_task'
|
28
28
|
|
29
29
|
namespace :test do
|
30
|
-
|
31
|
-
desc "Wait for Elasticsearch to be in a green state"
|
30
|
+
desc 'Wait for Elasticsearch to be in a green state'
|
32
31
|
task :wait_for_green do
|
33
32
|
sh '../scripts/wait-cluster.sh'
|
34
33
|
end
|
35
34
|
|
36
|
-
task :spec => :wait_for_green
|
37
35
|
RSpec::Core::RakeTask.new(:spec)
|
38
36
|
|
39
37
|
Rake::TestTask.new(:unit) do |test|
|
40
38
|
test.libs << 'lib' << 'test'
|
41
|
-
test.test_files = FileList[
|
39
|
+
test.test_files = FileList['test/unit/**/*_test.rb']
|
42
40
|
test.verbose = false
|
43
41
|
test.warning = false
|
44
42
|
end
|
45
43
|
|
46
44
|
Rake::TestTask.new(:integration) do |test|
|
47
45
|
test.libs << 'lib' << 'test'
|
48
|
-
test.test_files = FileList[
|
49
|
-
test.deps = [
|
46
|
+
test.test_files = FileList['test/integration/**/*_test.rb']
|
47
|
+
test.deps = ['test:wait_for_green', 'test:spec']
|
50
48
|
test.verbose = false
|
51
49
|
test.warning = false
|
52
50
|
end
|
53
51
|
|
54
|
-
|
55
|
-
|
56
|
-
|
52
|
+
desc 'Run all tests'
|
53
|
+
task :all do
|
54
|
+
Rake::Task['test:unit'].invoke
|
55
|
+
Rake::Task['test:integration'].invoke
|
57
56
|
end
|
58
57
|
|
59
58
|
Rake::TestTask.new(:profile) do |test|
|
60
59
|
test.libs << 'lib' << 'test'
|
61
|
-
test.test_files = FileList[
|
60
|
+
test.test_files = FileList['test/profile/**/*_test.rb']
|
62
61
|
end
|
63
62
|
|
64
63
|
namespace :cluster do
|
@@ -26,12 +26,12 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.authors = ['Karel Minarik']
|
27
27
|
s.email = ['karel.minarik@elasticsearch.org']
|
28
28
|
s.summary = 'Ruby client for Elasticsearch.'
|
29
|
-
s.homepage = 'https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/7.
|
29
|
+
s.homepage = 'https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/7.16/index.html'
|
30
30
|
s.license = 'Apache-2.0'
|
31
31
|
s.metadata = {
|
32
|
-
'homepage_uri' => 'https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/7.
|
33
|
-
'changelog_uri' => 'https://github.com/elastic/elasticsearch-ruby/blob/7.
|
34
|
-
'source_code_uri' => 'https://github.com/elastic/elasticsearch-ruby/tree/7.
|
32
|
+
'homepage_uri' => 'https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/7.16/index.html',
|
33
|
+
'changelog_uri' => 'https://github.com/elastic/elasticsearch-ruby/blob/7.16/CHANGELOG.md',
|
34
|
+
'source_code_uri' => 'https://github.com/elastic/elasticsearch-ruby/tree/7.16/elasticsearch-transport',
|
35
35
|
'bug_tracker_uri' => 'https://github.com/elastic/elasticsearch-ruby/issues'
|
36
36
|
}
|
37
37
|
s.files = `git ls-files`.split($/)
|
@@ -47,29 +47,29 @@ Gem::Specification.new do |s|
|
|
47
47
|
s.add_dependency 'multi_json'
|
48
48
|
s.add_dependency 'faraday', '~> 1'
|
49
49
|
|
50
|
+
s.add_development_dependency 'ansi'
|
51
|
+
s.add_development_dependency 'bundler'
|
50
52
|
s.add_development_dependency 'cane'
|
51
|
-
s.add_development_dependency 'curb'
|
53
|
+
s.add_development_dependency 'curb' unless defined? JRUBY_VERSION
|
54
|
+
s.add_development_dependency 'elasticsearch', ['>= 7', '< 8.0.0']
|
52
55
|
s.add_development_dependency 'elasticsearch-extensions'
|
53
|
-
s.add_development_dependency 'minitest'
|
54
|
-
s.add_development_dependency 'minitest-reporters'
|
55
|
-
s.add_development_dependency 'rake', '~> 13'
|
56
|
-
s.add_development_dependency 'require-prof' unless defined?(JRUBY_VERSION) || defined?(Rubinius)
|
57
|
-
s.add_development_dependency 'ruby-prof' unless defined?(JRUBY_VERSION) || defined?(Rubinius)
|
58
|
-
s.add_development_dependency 'simplecov', '~> 0.17', '< 0.18'
|
59
|
-
s.add_development_dependency 'simplecov-rcov'
|
60
|
-
s.add_development_dependency 'ansi'
|
61
56
|
s.add_development_dependency 'hashie'
|
62
57
|
s.add_development_dependency 'httpclient'
|
63
|
-
s.add_development_dependency 'manticore'
|
58
|
+
s.add_development_dependency 'manticore' if defined? JRUBY_VERSION
|
59
|
+
s.add_development_dependency 'minitest'
|
60
|
+
s.add_development_dependency 'minitest-reporters'
|
64
61
|
s.add_development_dependency 'mocha'
|
65
62
|
s.add_development_dependency 'net-http-persistent'
|
66
63
|
s.add_development_dependency 'patron' unless defined? JRUBY_VERSION
|
67
64
|
s.add_development_dependency 'pry'
|
65
|
+
s.add_development_dependency 'rake', '~> 13'
|
66
|
+
s.add_development_dependency 'require-prof' unless defined?(JRUBY_VERSION) || defined?(Rubinius)
|
67
|
+
s.add_development_dependency 'ruby-prof' unless defined?(JRUBY_VERSION) || defined?(Rubinius)
|
68
68
|
s.add_development_dependency 'shoulda-context'
|
69
|
+
s.add_development_dependency 'simplecov'
|
69
70
|
s.add_development_dependency 'test-unit', '~> 2'
|
70
71
|
s.add_development_dependency 'typhoeus', '~> 1.4'
|
71
72
|
s.add_development_dependency 'yard'
|
72
|
-
s.add_development_dependency 'bundler'
|
73
73
|
|
74
74
|
s.description = <<-DESC.gsub(/^ /, '')
|
75
75
|
Ruby client for Elasticsearch. See the `elasticsearch` gem for full integration.
|
@@ -20,14 +20,13 @@ require 'elasticsearch/transport/meta_header'
|
|
20
20
|
|
21
21
|
module Elasticsearch
|
22
22
|
module Transport
|
23
|
-
|
24
23
|
# Handles communication with an Elasticsearch cluster.
|
25
24
|
#
|
26
25
|
# See {file:README.md README} for usage and code examples.
|
27
26
|
#
|
28
27
|
class Client
|
29
28
|
include MetaHeader
|
30
|
-
DEFAULT_TRANSPORT_CLASS
|
29
|
+
DEFAULT_TRANSPORT_CLASS = Transport::HTTP::Faraday
|
31
30
|
|
32
31
|
DEFAULT_LOGGER = lambda do
|
33
32
|
require 'logger'
|
@@ -93,6 +92,8 @@ module Elasticsearch
|
|
93
92
|
#
|
94
93
|
# @option arguments [Boolean,Number] :retry_on_failure Retry X times when request fails before raising and
|
95
94
|
# exception (false by default)
|
95
|
+
# @option arguments [Number] :delay_on_retry Delay in milliseconds between each retry (0 by default)
|
96
|
+
#
|
96
97
|
# @option arguments Array<Number> :retry_on_status Retry when specific status codes are returned
|
97
98
|
#
|
98
99
|
# @option arguments [Boolean] :reload_on_failure Reload connections after failure (false by default)
|
@@ -127,6 +128,7 @@ module Elasticsearch
|
|
127
128
|
# if you're using X-Opaque-Id
|
128
129
|
# @option enable_meta_header [Boolean] :enable_meta_header Enable sending the meta data header to Cloud.
|
129
130
|
# (Default: true)
|
131
|
+
# @option ca_fingerprint [String] :ca_fingerprint provide this value to only trust certificates that are signed by a specific CA certificate
|
130
132
|
#
|
131
133
|
# @yield [faraday] Access and configure the `Faraday::Connection` instance directly with a block
|
132
134
|
#
|
@@ -137,6 +139,7 @@ module Elasticsearch
|
|
137
139
|
@arguments[:tracer] ||= @arguments[:trace] ? DEFAULT_TRACER.call() : nil
|
138
140
|
@arguments[:reload_connections] ||= false
|
139
141
|
@arguments[:retry_on_failure] ||= false
|
142
|
+
@arguments[:delay_on_retry] ||= 0
|
140
143
|
@arguments[:reload_on_failure] ||= false
|
141
144
|
@arguments[:randomize_hosts] ||= false
|
142
145
|
@arguments[:transport_options] ||= {}
|
@@ -157,6 +160,7 @@ module Elasticsearch
|
|
157
160
|
|
158
161
|
@send_get_body_as = @arguments[:send_get_body_as] || 'GET'
|
159
162
|
@opaque_id_prefix = @arguments[:opaque_id_prefix] || nil
|
163
|
+
@ca_fingerprint = @arguments.delete(:ca_fingerprint)
|
160
164
|
|
161
165
|
if @arguments[:request_timeout]
|
162
166
|
@arguments[:transport_options][:request] = { timeout: @arguments[:request_timeout] }
|
@@ -189,6 +193,7 @@ module Elasticsearch
|
|
189
193
|
opaque_id = @opaque_id_prefix ? "#{@opaque_id_prefix}#{opaque_id}" : opaque_id
|
190
194
|
headers.merge!('X-Opaque-Id' => opaque_id)
|
191
195
|
end
|
196
|
+
validate_ca_fingerprints if @ca_fingerprint
|
192
197
|
transport.perform_request(method, path, params, body, headers)
|
193
198
|
end
|
194
199
|
|
@@ -203,15 +208,41 @@ module Elasticsearch
|
|
203
208
|
|
204
209
|
def set_compatibility_header
|
205
210
|
return unless ['1', 'true'].include?(ENV['ELASTIC_CLIENT_APIVERSIONING'])
|
211
|
+
return if instance_variable_get('@options').dig(:transport_options, :headers, 'Accept')
|
206
212
|
|
207
213
|
add_header(
|
208
214
|
{
|
209
|
-
'Accept' => 'application/vnd.elasticsearch+json;compatible-with=7',
|
215
|
+
'Accept' => 'application/vnd.elasticsearch+json; compatible-with=7',
|
210
216
|
'Content-Type' => 'application/vnd.elasticsearch+json; compatible-with=7'
|
211
217
|
}
|
212
218
|
)
|
213
219
|
end
|
214
220
|
|
221
|
+
def validate_ca_fingerprints
|
222
|
+
transport.connections.connections.each do |connection|
|
223
|
+
unless connection.host[:scheme] == 'https'
|
224
|
+
raise Elasticsearch::Transport::Transport::Error, 'CA fingerprinting can\'t be configured over http'
|
225
|
+
end
|
226
|
+
|
227
|
+
next if connection.verified
|
228
|
+
|
229
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
230
|
+
socket = TCPSocket.new(connection.host[:host], connection.host[:port])
|
231
|
+
ssl = OpenSSL::SSL::SSLSocket.new(socket, ctx)
|
232
|
+
ssl.connect
|
233
|
+
cert_store = ssl.peer_cert_chain
|
234
|
+
matching_certs = cert_store.select do |cert|
|
235
|
+
OpenSSL::Digest::SHA256.hexdigest(cert.to_der).upcase == @ca_fingerprint.upcase.gsub(':', '')
|
236
|
+
end
|
237
|
+
if matching_certs.empty?
|
238
|
+
raise Elasticsearch::Transport::Transport::Error,
|
239
|
+
'Server certificate CA fingerprint does not match the value configured in ca_fingerprint'
|
240
|
+
end
|
241
|
+
|
242
|
+
connection.verified = true
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
215
246
|
def add_header(header)
|
216
247
|
headers = @arguments[:transport_options]&.[](:headers) || {}
|
217
248
|
headers.merge!(header)
|
@@ -18,7 +18,6 @@
|
|
18
18
|
module Elasticsearch
|
19
19
|
module Transport
|
20
20
|
module Transport
|
21
|
-
|
22
21
|
# @abstract Module with common functionality for transport implementations.
|
23
22
|
#
|
24
23
|
module Base
|
@@ -54,6 +53,7 @@ module Elasticsearch
|
|
54
53
|
@options = arguments[:options] || {}
|
55
54
|
@options[:http] ||= {}
|
56
55
|
@options[:retry_on_status] ||= []
|
56
|
+
@options[:delay_on_retry] ||= 0
|
57
57
|
|
58
58
|
@block = block
|
59
59
|
@compression = !!@options[:compression]
|
@@ -223,7 +223,7 @@ module Elasticsearch
|
|
223
223
|
# @api private
|
224
224
|
#
|
225
225
|
def __convert_to_json(o=nil, options={})
|
226
|
-
o
|
226
|
+
o.is_a?(String) ? o : serializer.dump(o, options)
|
227
227
|
end
|
228
228
|
|
229
229
|
# Returns a full URL based on information from host
|
@@ -264,6 +264,7 @@ module Elasticsearch
|
|
264
264
|
start = Time.now
|
265
265
|
tries = 0
|
266
266
|
reload_on_failure = opts.fetch(:reload_on_failure, @options[:reload_on_failure])
|
267
|
+
delay_on_retry = opts.fetch(:delay_on_retry, @options[:delay_on_retry])
|
267
268
|
|
268
269
|
max_retries = if opts.key?(:retry_on_failure)
|
269
270
|
opts[:retry_on_failure] === true ? DEFAULT_MAX_RETRIES : opts[:retry_on_failure]
|
@@ -272,10 +273,10 @@ module Elasticsearch
|
|
272
273
|
end
|
273
274
|
|
274
275
|
params = params.clone
|
275
|
-
|
276
276
|
ignore = Array(params.delete(:ignore)).compact.map { |s| s.to_i }
|
277
277
|
|
278
278
|
begin
|
279
|
+
sleep(delay_on_retry / 1000.0) if tries > 0
|
279
280
|
tries += 1
|
280
281
|
connection = get_connection or raise Error.new('Cannot get new connection from pool.')
|
281
282
|
|
@@ -284,9 +285,7 @@ module Elasticsearch
|
|
284
285
|
end
|
285
286
|
|
286
287
|
url = connection.full_url(path, params)
|
287
|
-
|
288
288
|
response = block.call(connection, url)
|
289
|
-
|
290
289
|
connection.healthy! if connection.failures > 0
|
291
290
|
|
292
291
|
# Raise an exception so we can catch it for `retry_on_status`
|
@@ -309,7 +308,6 @@ module Elasticsearch
|
|
309
308
|
log_error "[#{e.class}] #{e.message} #{connection.host.inspect}"
|
310
309
|
|
311
310
|
connection.dead!
|
312
|
-
|
313
311
|
if reload_on_failure and tries < connections.all.size
|
314
312
|
log_warn "[#{e.class}] Reloading connections (attempt #{tries} of #{connections.all.size})"
|
315
313
|
reload_connections! and retry
|
@@ -336,14 +334,10 @@ module Elasticsearch
|
|
336
334
|
duration = Time.now - start
|
337
335
|
|
338
336
|
if response.status.to_i >= 300
|
339
|
-
__log_response
|
340
|
-
__trace
|
341
|
-
|
337
|
+
__log_response(method, path, params, body, url, response, nil, 'N/A', duration)
|
338
|
+
__trace(method, path, params, connection_headers(connection), body, url, response, nil, 'N/A', duration) if tracer
|
342
339
|
# Log the failure only when `ignore` doesn't match the response status
|
343
|
-
unless ignore.include?(response.status.to_i)
|
344
|
-
log_fatal "[#{response.status}] #{response.body}"
|
345
|
-
end
|
346
|
-
|
340
|
+
log_fatal "[#{response.status}] #{response.body}" unless ignore.include?(response.status.to_i)
|
347
341
|
__raise_transport_error response unless ignore.include?(response.status.to_i)
|
348
342
|
end
|
349
343
|
|
@@ -354,10 +348,8 @@ module Elasticsearch
|
|
354
348
|
__log_response method, path, params, body, url, response, json, took, duration
|
355
349
|
end
|
356
350
|
|
357
|
-
__trace
|
358
|
-
|
359
|
-
warnings(response.headers['warning']) if response.headers&.[]('warning')
|
360
|
-
|
351
|
+
__trace(method, path, params, connection_headers(connection), body, url, response, nil, 'N/A', duration) if tracer
|
352
|
+
log_warn(response.headers['warning']) if response.headers&.[]('warning')
|
361
353
|
Response.new response.status, json || response.body, response.headers
|
362
354
|
ensure
|
363
355
|
@last_request_at = Time.now
|
@@ -376,17 +368,38 @@ module Elasticsearch
|
|
376
368
|
|
377
369
|
USER_AGENT_STR = 'User-Agent'.freeze
|
378
370
|
USER_AGENT_REGEX = /user\-?\_?agent/
|
371
|
+
ACCEPT_ENCODING = 'Accept-Encoding'.freeze
|
372
|
+
CONTENT_ENCODING = 'Content-Encoding'.freeze
|
379
373
|
CONTENT_TYPE_STR = 'Content-Type'.freeze
|
380
374
|
CONTENT_TYPE_REGEX = /content\-?\_?type/
|
381
375
|
DEFAULT_CONTENT_TYPE = 'application/json'.freeze
|
382
376
|
GZIP = 'gzip'.freeze
|
383
|
-
ACCEPT_ENCODING = 'Accept-Encoding'.freeze
|
384
377
|
GZIP_FIRST_TWO_BYTES = '1f8b'.freeze
|
385
378
|
HEX_STRING_DIRECTIVE = 'H*'.freeze
|
386
379
|
RUBY_ENCODING = '1.9'.respond_to?(:force_encoding)
|
387
380
|
|
381
|
+
def compress_request(body, headers)
|
382
|
+
if body
|
383
|
+
headers ||= {}
|
384
|
+
|
385
|
+
if gzipped?(body)
|
386
|
+
headers[CONTENT_ENCODING] = GZIP
|
387
|
+
elsif use_compression?
|
388
|
+
headers[CONTENT_ENCODING] = GZIP
|
389
|
+
gzip = Zlib::GzipWriter.new(StringIO.new)
|
390
|
+
gzip << body
|
391
|
+
body = gzip.close.string
|
392
|
+
else
|
393
|
+
headers.delete(CONTENT_ENCODING)
|
394
|
+
end
|
395
|
+
elsif headers
|
396
|
+
headers.delete(CONTENT_ENCODING)
|
397
|
+
end
|
398
|
+
|
399
|
+
[body, headers]
|
400
|
+
end
|
401
|
+
|
388
402
|
def decompress_response(body)
|
389
|
-
return body unless use_compression?
|
390
403
|
return body unless gzipped?(body)
|
391
404
|
|
392
405
|
io = StringIO.new(body)
|
@@ -399,6 +412,8 @@ module Elasticsearch
|
|
399
412
|
end
|
400
413
|
|
401
414
|
def gzipped?(body)
|
415
|
+
return unless body && !body.empty?
|
416
|
+
|
402
417
|
body[0..1].unpack(HEX_STRING_DIRECTIVE)[0] == GZIP_FIRST_TWO_BYTES
|
403
418
|
end
|
404
419
|
|
@@ -415,7 +430,7 @@ module Elasticsearch
|
|
415
430
|
end
|
416
431
|
|
417
432
|
def find_value(hash, regex)
|
418
|
-
key_value = hash.find { |k,
|
433
|
+
key_value = hash.find { |k, _| k.to_s.downcase =~ regex }
|
419
434
|
if key_value
|
420
435
|
hash.delete(key_value[0])
|
421
436
|
key_value[1]
|
@@ -432,8 +447,12 @@ module Elasticsearch
|
|
432
447
|
end
|
433
448
|
end
|
434
449
|
|
435
|
-
def
|
436
|
-
|
450
|
+
def connection_headers(connection)
|
451
|
+
if defined?(Elasticsearch::Transport::Transport::HTTP::Manticore) && self.class == Elasticsearch::Transport::Transport::HTTP::Manticore
|
452
|
+
@request_options[:headers]
|
453
|
+
else
|
454
|
+
connection.connection.headers
|
455
|
+
end
|
437
456
|
end
|
438
457
|
end
|
439
458
|
end
|
@@ -33,6 +33,7 @@ module Elasticsearch
|
|
33
33
|
DEFAULT_RESURRECT_TIMEOUT = 60
|
34
34
|
|
35
35
|
attr_reader :host, :connection, :options, :failures, :dead_since
|
36
|
+
attr_accessor :verified
|
36
37
|
|
37
38
|
# @option arguments [Hash] :host Host information (example: `{host: 'localhost', port: 9200}`)
|
38
39
|
# @option arguments [Object] :connection The transport-specific physical connection or "session"
|
@@ -42,6 +43,7 @@ module Elasticsearch
|
|
42
43
|
@host = arguments[:host].is_a?(Hash) ? Redacted.new(arguments[:host]) : arguments[:host]
|
43
44
|
@connection = arguments[:connection]
|
44
45
|
@options = arguments[:options] || {}
|
46
|
+
@verified = false
|
45
47
|
@state_mutex = Mutex.new
|
46
48
|
|
47
49
|
@options[:resurrect_timeout] ||= DEFAULT_RESURRECT_TIMEOUT
|
@@ -153,7 +155,6 @@ module Elasticsearch
|
|
153
155
|
"<#{self.class.name} host: #{host} (#{dead? ? 'dead since ' + dead_since.to_s : 'alive'})>"
|
154
156
|
end
|
155
157
|
end
|
156
|
-
|
157
158
|
end
|
158
159
|
end
|
159
160
|
end
|
@@ -19,51 +19,64 @@ module Elasticsearch
|
|
19
19
|
module Transport
|
20
20
|
module Transport
|
21
21
|
module HTTP
|
22
|
-
|
23
22
|
# Alternative HTTP transport implementation, using the [_Curb_](https://rubygems.org/gems/curb) client.
|
24
23
|
#
|
25
24
|
# @see Transport::Base
|
26
25
|
#
|
27
26
|
class Curb
|
28
27
|
include Base
|
29
|
-
|
30
28
|
# Performs the request by invoking {Transport::Base#perform_request} with a block.
|
31
29
|
#
|
32
30
|
# @return [Response]
|
33
31
|
# @see Transport::Base#perform_request
|
34
32
|
#
|
35
33
|
def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
|
36
|
-
super do |connection,
|
34
|
+
super do |connection, _url|
|
37
35
|
connection.connection.url = connection.full_url(path, params)
|
36
|
+
body = body ? __convert_to_json(body) : nil
|
37
|
+
body, headers = compress_request(body, headers)
|
38
38
|
|
39
39
|
case method
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
40
|
+
when 'HEAD'
|
41
|
+
connection.connection.set :nobody, true
|
42
|
+
when 'GET', 'POST', 'PUT', 'DELETE'
|
43
|
+
connection.connection.set :nobody, false
|
44
|
+
|
45
|
+
connection.connection.put_data = body if body
|
46
|
+
|
47
|
+
if headers
|
48
|
+
if connection.connection.headers
|
49
|
+
connection.connection.headers.merge!(headers)
|
50
|
+
else
|
51
|
+
connection.connection.headers = headers
|
53
52
|
end
|
54
|
-
|
55
|
-
|
53
|
+
end
|
54
|
+
else
|
55
|
+
raise ArgumentError, "Unsupported HTTP method: #{method}"
|
56
56
|
end
|
57
57
|
|
58
58
|
connection.connection.http(method.to_sym)
|
59
59
|
|
60
|
-
|
61
|
-
|
60
|
+
Response.new(
|
61
|
+
connection.connection.response_code,
|
62
|
+
decompress_response(connection.connection.body_str),
|
63
|
+
headers(connection)
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def headers(connection)
|
69
|
+
headers_string = connection.connection.header_str
|
70
|
+
return nil if headers_string.nil?
|
62
71
|
|
63
|
-
|
64
|
-
|
65
|
-
|
72
|
+
response_headers = headers_string&.split(/\\r\\n|\r\n/).reject(&:empty?)
|
73
|
+
response_headers.shift # Removes HTTP status string
|
74
|
+
processed_header = response_headers.flat_map { |s| s.scan(/^(\S+): (.+)/) }
|
75
|
+
headers_hash = Hash[processed_header].transform_keys(&:downcase)
|
76
|
+
if headers_hash['content-type']&.match?(/application\/json/)
|
77
|
+
headers_hash['content-type'] = 'application/json'
|
66
78
|
end
|
79
|
+
headers_hash
|
67
80
|
end
|
68
81
|
|
69
82
|
# Builds and returns a connection
|
@@ -72,9 +85,8 @@ module Elasticsearch
|
|
72
85
|
#
|
73
86
|
def __build_connection(host, options={}, block=nil)
|
74
87
|
client = ::Curl::Easy.new
|
75
|
-
|
76
88
|
apply_headers(client, options)
|
77
|
-
client.url
|
89
|
+
client.url = __full_url(host)
|
78
90
|
|
79
91
|
if host[:user]
|
80
92
|
client.http_auth_types = host[:auth_type] || :basic
|
@@ -106,13 +118,13 @@ module Elasticsearch
|
|
106
118
|
|
107
119
|
def user_agent_header(client)
|
108
120
|
@user_agent ||= begin
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
121
|
+
meta = ["RUBY_VERSION: #{RUBY_VERSION}"]
|
122
|
+
if RbConfig::CONFIG && RbConfig::CONFIG['host_os']
|
123
|
+
meta << "#{RbConfig::CONFIG['host_os'].split('_').first[/[a-z]+/i].downcase} #{RbConfig::CONFIG['target_cpu']}"
|
124
|
+
end
|
125
|
+
meta << "Curb #{Curl::CURB_VERSION}"
|
126
|
+
"elasticsearch-ruby/#{VERSION} (#{meta.join('; ')})"
|
127
|
+
end
|
116
128
|
end
|
117
129
|
end
|
118
130
|
end
|
@@ -19,7 +19,6 @@ module Elasticsearch
|
|
19
19
|
module Transport
|
20
20
|
module Transport
|
21
21
|
module HTTP
|
22
|
-
|
23
22
|
# The default transport implementation, using the [_Faraday_](https://rubygems.org/gems/faraday)
|
24
23
|
# library for abstracting the HTTP client.
|
25
24
|
#
|
@@ -45,9 +44,12 @@ module Elasticsearch
|
|
45
44
|
headers
|
46
45
|
end
|
47
46
|
|
47
|
+
body = body ? __convert_to_json(body) : nil
|
48
|
+
body, headers = compress_request(body, headers)
|
49
|
+
|
48
50
|
response = connection.connection.run_request(method.downcase.to_sym,
|
49
51
|
url,
|
50
|
-
|
52
|
+
body,
|
51
53
|
headers)
|
52
54
|
|
53
55
|
Response.new response.status, decompress_response(response.body), response.headers
|
@@ -61,7 +63,7 @@ module Elasticsearch
|
|
61
63
|
def __build_connection(host, options={}, block=nil)
|
62
64
|
client = ::Faraday.new(__full_url(host), options, &block)
|
63
65
|
apply_headers(client, options)
|
64
|
-
Connections::Connection.new
|
66
|
+
Connections::Connection.new(host: host, connection: client)
|
65
67
|
end
|
66
68
|
|
67
69
|
# Returns an array of implementation specific connection errors.
|