elasticsearch-transport 7.13.3 → 7.17.7
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|