elasticsearch-transport 7.13.3 → 7.17.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.
- 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 +40 -20
- 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 +7 -4
- 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 +224 -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: 4fc7f318edc5730a123909637ce8cf74f32c4ddb2c9571e6744b4ad864e5c5d8
|
4
|
+
data.tar.gz: 11549daa6e4586a272f01e64ae56c01a510a57687fc0a06ecec58b35906f21d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5ea6b69fcb79dc9502b057195ef71bd6f60aca21170cae677e92510f01091199391ac38ce081af54fb269fa1600aeee81b586565317eac3065ff308c177f703
|
7
|
+
data.tar.gz: 9274659714937b8505a1a2252da28658900458982b3abe338838dbe8328e5408481351edb10623378a3e6f48cf8ca48a55a14f9739cc7e6e5650627b4a03a587
|
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)
|
@@ -54,6 +54,7 @@ module Elasticsearch
|
|
54
54
|
@options = arguments[:options] || {}
|
55
55
|
@options[:http] ||= {}
|
56
56
|
@options[:retry_on_status] ||= []
|
57
|
+
@options[:delay_on_retry] ||= 0
|
57
58
|
|
58
59
|
@block = block
|
59
60
|
@compression = !!@options[:compression]
|
@@ -223,7 +224,7 @@ module Elasticsearch
|
|
223
224
|
# @api private
|
224
225
|
#
|
225
226
|
def __convert_to_json(o=nil, options={})
|
226
|
-
o
|
227
|
+
o.is_a?(String) ? o : serializer.dump(o, options)
|
227
228
|
end
|
228
229
|
|
229
230
|
# Returns a full URL based on information from host
|
@@ -264,6 +265,7 @@ module Elasticsearch
|
|
264
265
|
start = Time.now
|
265
266
|
tries = 0
|
266
267
|
reload_on_failure = opts.fetch(:reload_on_failure, @options[:reload_on_failure])
|
268
|
+
delay_on_retry = opts.fetch(:delay_on_retry, @options[:delay_on_retry])
|
267
269
|
|
268
270
|
max_retries = if opts.key?(:retry_on_failure)
|
269
271
|
opts[:retry_on_failure] === true ? DEFAULT_MAX_RETRIES : opts[:retry_on_failure]
|
@@ -272,10 +274,10 @@ module Elasticsearch
|
|
272
274
|
end
|
273
275
|
|
274
276
|
params = params.clone
|
275
|
-
|
276
277
|
ignore = Array(params.delete(:ignore)).compact.map { |s| s.to_i }
|
277
278
|
|
278
279
|
begin
|
280
|
+
sleep(delay_on_retry / 1000.0) if tries > 0
|
279
281
|
tries += 1
|
280
282
|
connection = get_connection or raise Error.new('Cannot get new connection from pool.')
|
281
283
|
|
@@ -284,9 +286,7 @@ module Elasticsearch
|
|
284
286
|
end
|
285
287
|
|
286
288
|
url = connection.full_url(path, params)
|
287
|
-
|
288
289
|
response = block.call(connection, url)
|
289
|
-
|
290
290
|
connection.healthy! if connection.failures > 0
|
291
291
|
|
292
292
|
# Raise an exception so we can catch it for `retry_on_status`
|
@@ -309,7 +309,6 @@ module Elasticsearch
|
|
309
309
|
log_error "[#{e.class}] #{e.message} #{connection.host.inspect}"
|
310
310
|
|
311
311
|
connection.dead!
|
312
|
-
|
313
312
|
if reload_on_failure and tries < connections.all.size
|
314
313
|
log_warn "[#{e.class}] Reloading connections (attempt #{tries} of #{connections.all.size})"
|
315
314
|
reload_connections! and retry
|
@@ -336,14 +335,10 @@ module Elasticsearch
|
|
336
335
|
duration = Time.now - start
|
337
336
|
|
338
337
|
if response.status.to_i >= 300
|
339
|
-
__log_response
|
340
|
-
__trace
|
341
|
-
|
338
|
+
__log_response(method, path, params, body, url, response, nil, 'N/A', duration)
|
339
|
+
__trace(method, path, params, connection_headers(connection), body, url, response, nil, 'N/A', duration) if tracer
|
342
340
|
# 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
|
-
|
341
|
+
log_fatal "[#{response.status}] #{response.body}" unless ignore.include?(response.status.to_i)
|
347
342
|
__raise_transport_error response unless ignore.include?(response.status.to_i)
|
348
343
|
end
|
349
344
|
|
@@ -354,10 +349,8 @@ module Elasticsearch
|
|
354
349
|
__log_response method, path, params, body, url, response, json, took, duration
|
355
350
|
end
|
356
351
|
|
357
|
-
__trace
|
358
|
-
|
359
|
-
warnings(response.headers['warning']) if response.headers&.[]('warning')
|
360
|
-
|
352
|
+
__trace(method, path, params, connection_headers(connection), body, url, response, nil, 'N/A', duration) if tracer
|
353
|
+
log_warn(response.headers['warning']) if response.headers&.[]('warning')
|
361
354
|
Response.new response.status, json || response.body, response.headers
|
362
355
|
ensure
|
363
356
|
@last_request_at = Time.now
|
@@ -376,17 +369,38 @@ module Elasticsearch
|
|
376
369
|
|
377
370
|
USER_AGENT_STR = 'User-Agent'.freeze
|
378
371
|
USER_AGENT_REGEX = /user\-?\_?agent/
|
372
|
+
ACCEPT_ENCODING = 'Accept-Encoding'.freeze
|
373
|
+
CONTENT_ENCODING = 'Content-Encoding'.freeze
|
379
374
|
CONTENT_TYPE_STR = 'Content-Type'.freeze
|
380
375
|
CONTENT_TYPE_REGEX = /content\-?\_?type/
|
381
376
|
DEFAULT_CONTENT_TYPE = 'application/json'.freeze
|
382
377
|
GZIP = 'gzip'.freeze
|
383
|
-
ACCEPT_ENCODING = 'Accept-Encoding'.freeze
|
384
378
|
GZIP_FIRST_TWO_BYTES = '1f8b'.freeze
|
385
379
|
HEX_STRING_DIRECTIVE = 'H*'.freeze
|
386
380
|
RUBY_ENCODING = '1.9'.respond_to?(:force_encoding)
|
387
381
|
|
382
|
+
def compress_request(body, headers)
|
383
|
+
if body
|
384
|
+
headers ||= {}
|
385
|
+
|
386
|
+
if gzipped?(body)
|
387
|
+
headers[CONTENT_ENCODING] = GZIP
|
388
|
+
elsif use_compression?
|
389
|
+
headers[CONTENT_ENCODING] = GZIP
|
390
|
+
gzip = Zlib::GzipWriter.new(StringIO.new)
|
391
|
+
gzip << body
|
392
|
+
body = gzip.close.string
|
393
|
+
else
|
394
|
+
headers.delete(CONTENT_ENCODING)
|
395
|
+
end
|
396
|
+
elsif headers
|
397
|
+
headers.delete(CONTENT_ENCODING)
|
398
|
+
end
|
399
|
+
|
400
|
+
[body, headers]
|
401
|
+
end
|
402
|
+
|
388
403
|
def decompress_response(body)
|
389
|
-
return body unless use_compression?
|
390
404
|
return body unless gzipped?(body)
|
391
405
|
|
392
406
|
io = StringIO.new(body)
|
@@ -399,6 +413,8 @@ module Elasticsearch
|
|
399
413
|
end
|
400
414
|
|
401
415
|
def gzipped?(body)
|
416
|
+
return unless body && !body.empty?
|
417
|
+
|
402
418
|
body[0..1].unpack(HEX_STRING_DIRECTIVE)[0] == GZIP_FIRST_TWO_BYTES
|
403
419
|
end
|
404
420
|
|
@@ -432,8 +448,12 @@ module Elasticsearch
|
|
432
448
|
end
|
433
449
|
end
|
434
450
|
|
435
|
-
def
|
436
|
-
|
451
|
+
def connection_headers(connection)
|
452
|
+
if defined?(Elasticsearch::Transport::Transport::HTTP::Manticore) && self.class == Elasticsearch::Transport::Transport::HTTP::Manticore
|
453
|
+
@request_options[:headers]
|
454
|
+
else
|
455
|
+
connection.connection.headers
|
456
|
+
end
|
437
457
|
end
|
438
458
|
end
|
439
459
|
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.
|
@@ -63,6 +63,7 @@ module Elasticsearch
|
|
63
63
|
include Base
|
64
64
|
|
65
65
|
def initialize(arguments={}, &block)
|
66
|
+
@request_options = { headers: (arguments.dig(:transport_options, :headers) || {}) }
|
66
67
|
@manticore = build_client(arguments[:options] || {})
|
67
68
|
super(arguments, &block)
|
68
69
|
end
|
@@ -82,7 +83,10 @@ module Elasticsearch
|
|
82
83
|
#
|
83
84
|
def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
|
84
85
|
super do |connection, url|
|
85
|
-
|
86
|
+
body = body ? __convert_to_json(body) : nil
|
87
|
+
body, headers = compress_request(body, @request_options[:headers])
|
88
|
+
|
89
|
+
params[:body] = body if body
|
86
90
|
params[:headers] = headers if headers
|
87
91
|
params = params.merge @request_options
|
88
92
|
case method
|
@@ -109,7 +113,6 @@ module Elasticsearch
|
|
109
113
|
# @return [Connections::Collection]
|
110
114
|
#
|
111
115
|
def __build_connections
|
112
|
-
@request_options = {}
|
113
116
|
apply_headers(@request_options, options[:transport_options])
|
114
117
|
apply_headers(@request_options, options)
|
115
118
|
|
@@ -155,11 +158,11 @@ module Elasticsearch
|
|
155
158
|
private
|
156
159
|
|
157
160
|
def apply_headers(request_options, options)
|
158
|
-
headers =
|
161
|
+
headers = options&.[](:headers) || {}
|
159
162
|
headers[CONTENT_TYPE_STR] = find_value(headers, CONTENT_TYPE_REGEX) || DEFAULT_CONTENT_TYPE
|
160
163
|
headers[USER_AGENT_STR] = find_value(headers, USER_AGENT_REGEX) || user_agent_header
|
161
164
|
headers[ACCEPT_ENCODING] = GZIP if use_compression?
|
162
|
-
request_options.merge!(headers
|
165
|
+
request_options[:headers].merge!(headers)
|
163
166
|
end
|
164
167
|
|
165
168
|
def user_agent_header
|