elasticsearch-transport 7.13.3 → 7.17.11

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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -9
  3. data/Gemfile-faraday1.gemfile +47 -0
  4. data/README.md +3 -8
  5. data/Rakefile +47 -10
  6. data/elasticsearch-transport.gemspec +17 -18
  7. data/lib/elasticsearch/transport/client.rb +34 -3
  8. data/lib/elasticsearch/transport/transport/base.rb +41 -22
  9. data/lib/elasticsearch/transport/transport/connections/connection.rb +2 -1
  10. data/lib/elasticsearch/transport/transport/errors.rb +1 -0
  11. data/lib/elasticsearch/transport/transport/http/curb.rb +44 -32
  12. data/lib/elasticsearch/transport/transport/http/faraday.rb +5 -3
  13. data/lib/elasticsearch/transport/transport/http/manticore.rb +41 -29
  14. data/lib/elasticsearch/transport/transport/response.rb +1 -1
  15. data/lib/elasticsearch/transport/version.rb +1 -1
  16. data/lib/elasticsearch/transport.rb +19 -30
  17. data/spec/elasticsearch/transport/base_spec.rb +50 -9
  18. data/spec/elasticsearch/transport/client_spec.rb +138 -64
  19. data/spec/elasticsearch/transport/http/curb_spec.rb +126 -0
  20. data/spec/elasticsearch/transport/http/faraday_spec.rb +141 -0
  21. data/spec/elasticsearch/transport/http/manticore_spec.rb +161 -0
  22. data/spec/elasticsearch/transport/meta_header_spec.rb +66 -30
  23. data/spec/spec_helper.rb +13 -5
  24. data/test/integration/jruby_test.rb +43 -0
  25. data/test/integration/transport_test.rb +89 -52
  26. data/test/test_helper.rb +10 -22
  27. data/test/unit/adapters_test.rb +88 -0
  28. data/test/unit/response_test.rb +1 -1
  29. data/test/unit/transport_base_test.rb +16 -7
  30. data/test/unit/transport_curb_test.rb +0 -1
  31. data/test/unit/transport_manticore_test.rb +242 -155
  32. metadata +68 -79
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a045f07e51e54095cdd4d050a786070b35eadc7356b5167c99da881738cf5607
4
- data.tar.gz: 854f2d899cdbbb184ce945a6b6dfa0a1f7f463bcf3d818c4e7f66a28ca81a504
3
+ metadata.gz: 59b2557cbc0cae9a06df0884cf46555a7ea77340ef225cb16a7a1609dc9406dc
4
+ data.tar.gz: 073e138b197584481816f64643555d01a8da358bfc361664deb684c146c1ca87
5
5
  SHA512:
6
- metadata.gz: 89c3b0674a119afb4aa397bacf6282bd301862ca4a5aa107b0789c93493644f678414587dd695e3210fdbe8afaed6bf9db8a10ee1a3597767211afb2fb4d4da4
7
- data.tar.gz: 6706d0c3441f9eed32b7e930e2cd808774bb8de1083109a6681a1433929dc407f324e97bdbaf1bf3dce9c452fc527abc3cbd7ccd071cfbff46977a93af31ba5d
6
+ metadata.gz: 62b023fbdde3ee2b0c493fcddadf1264cdfdfedc254bd7a4981b512ea3bb40b776cf43e66decc2842a43673de3006ddde470d5a7e06a30357ab126676bfa6222
7
+ data.tar.gz: 142543397abf64b400f1ba6873fc8672b78a94e5ffdf7451c99e0eab5fe337f251087aeb68e607fa7ae1af5411745e880020678cf6d73f473a6eecf3564f14d7
data/Gemfile CHANGED
@@ -20,23 +20,23 @@ 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('../../elasticsearch-api/elasticsearch-api.gemspec', __FILE__)
24
- gem 'elasticsearch-api', path: File.expand_path('../../elasticsearch-api', __FILE__), require: false
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('../../elasticsearch-extensions/elasticsearch-extensions.gemspec', __FILE__)
28
- gem 'elasticsearch-extensions', path: File.expand_path('../../elasticsearch-extensions', __FILE__), require: false
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
32
+ gem 'faraday-httpclient'
33
+ gem 'faraday-net_http_persistent'
34
+ gem 'faraday-patron' unless defined? JRUBY_VERSION
35
+ gem 'faraday-typhoeus'
36
36
  gem 'rspec'
37
37
  if defined?(JRUBY_VERSION)
38
38
  gem 'pry-nav'
39
39
  else
40
- gem 'pry-byebug'
40
+ gem 'pry-byebug', '~> 3.9'
41
41
  end
42
42
  end
@@ -0,0 +1,47 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ source 'https://rubygems.org'
19
+
20
+ # Usage:
21
+ #
22
+ # $ BUNDLE_GEMFILE=./Gemfile-faraday1.gemfile bundle install
23
+ # $ BUNDLE_GEMFILE=./Gemfile-faraday1.gemfile bundle exec rake test:faraday1:unit
24
+
25
+ gem 'faraday', '~> 1'
26
+ gemspec path: './'
27
+
28
+ if File.exist? File.expand_path('../elasticsearch-api/elasticsearch-api.gemspec', __dir__)
29
+ gem 'elasticsearch-api', path: File.expand_path('../elasticsearch-api', __dir__), require: false
30
+ end
31
+
32
+ if File.exist? File.expand_path('../elasticsearch/elasticsearch.gemspec', __dir__)
33
+ gem 'elasticsearch', path: File.expand_path('../elasticsearch', __dir__), require: false
34
+ end
35
+
36
+ group :development, :test do
37
+ gem 'httpclient'
38
+ gem 'net-http-persistent'
39
+ gem 'patron' unless defined? JRUBY_VERSION
40
+ gem 'typhoeus'
41
+ gem 'rspec'
42
+ if defined?(JRUBY_VERSION)
43
+ gem 'pry-nav'
44
+ else
45
+ gem 'pry-byebug'
46
+ end
47
+ end
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, for example sign the requests for the [AWS Elasticsearch service](https://aws.amazon.com/elasticsearch-service/). See [the AWS documentation](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-request-signing.html#es-request-signing-ruby) for an example.
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 -- again, see instructions
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
- Unit tests have to use Ruby 1.8 compatible syntax, integration tests
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
@@ -25,40 +25,77 @@ task :test => 'test:unit'
25
25
 
26
26
  require 'rake/testtask'
27
27
  require 'rspec/core/rake_task'
28
+ FARADAY1_GEMFILE = 'Gemfile-faraday1.gemfile'.freeze
29
+ GEMFILES = ['Gemfile', FARADAY1_GEMFILE].freeze
28
30
 
29
- namespace :test do
31
+ task :install do
32
+ GEMFILES.each do |gemfile|
33
+ gemfile = File.expand_path("../#{gemfile}", __FILE__)
34
+ sh "bundle install --gemfile #{gemfile}"
35
+ end
36
+ end
30
37
 
31
- desc "Wait for Elasticsearch to be in a green state"
38
+ namespace :test do
39
+ desc 'Wait for Elasticsearch to be in a green state'
32
40
  task :wait_for_green do
33
41
  sh '../scripts/wait-cluster.sh'
34
42
  end
35
43
 
36
- task :spec => :wait_for_green
37
44
  RSpec::Core::RakeTask.new(:spec)
38
45
 
39
46
  Rake::TestTask.new(:unit) do |test|
40
47
  test.libs << 'lib' << 'test'
41
- test.test_files = FileList["test/unit/**/*_test.rb"]
48
+ test.test_files = FileList['test/unit/**/*_test.rb']
42
49
  test.verbose = false
43
50
  test.warning = false
44
51
  end
45
52
 
46
53
  Rake::TestTask.new(:integration) do |test|
47
54
  test.libs << 'lib' << 'test'
48
- test.test_files = FileList["test/integration/**/*_test.rb"]
49
- test.deps = [ 'test:wait_for_green', 'test:spec' ]
55
+ test.test_files = FileList['test/integration/**/*_test.rb']
56
+ test.deps = ['test:wait_for_green', 'test:spec']
50
57
  test.verbose = false
51
58
  test.warning = false
52
59
  end
53
60
 
54
- Rake::TestTask.new(:all) do |test|
55
- test.libs << 'lib' << 'test'
56
- test.test_files = FileList["test/unit/**/*_test.rb", "test/integration/**/*_test.rb"]
61
+ desc 'Run all tests'
62
+ task :all do
63
+ Rake::Task['test:unit'].invoke
64
+ Rake::Task['test:spec'].invoke
65
+ Rake::Task['test:integration'].invoke
57
66
  end
58
67
 
59
68
  Rake::TestTask.new(:profile) do |test|
60
69
  test.libs << 'lib' << 'test'
61
- test.test_files = FileList["test/profile/**/*_test.rb"]
70
+ test.test_files = FileList['test/profile/**/*_test.rb']
71
+ end
72
+
73
+ namespace :faraday1 do
74
+ desc 'Faraday 1: Run RSpec with dependency on Faraday 1'
75
+ task :spec do
76
+ sh "BUNDLE_GEMFILE=#{FARADAY1_GEMFILE} bundle exec rspec"
77
+ end
78
+
79
+ desc 'Faraday 1: Run unit tests with dependency on Faraday 1'
80
+ task :unit do
81
+ Dir.glob('./test/unit/**/**.rb').each do |test|
82
+ sh "BUNDLE_GEMFILE=#{FARADAY1_GEMFILE} ruby -Ilib:test #{test}"
83
+ end
84
+ end
85
+
86
+ desc 'Faraday 1: Run integration tests with dependency on Faraday 1'
87
+ task :integration do
88
+ Dir.glob('./test/integration/**/**.rb').each do |test|
89
+ sh "BUNDLE_GEMFILE=#{FARADAY1_GEMFILE} ruby -Ilib:test #{test}"
90
+ end
91
+ end
92
+
93
+ desc 'Faraday 1: Run all tests'
94
+ task :all do
95
+ Rake::Task['test:faraday1:unit'].invoke
96
+ Rake::Task['test:faraday1:spec'].invoke
97
+ Rake::Task['test:faraday1:integration'].invoke
98
+ end
62
99
  end
63
100
 
64
101
  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.x/index.html'
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.x/index.html',
33
- 'changelog_uri' => 'https://github.com/elastic/elasticsearch-ruby/blob/7.x/CHANGELOG.md',
34
- 'source_code_uri' => 'https://github.com/elastic/elasticsearch-ruby/tree/7.x/elasticsearch-transport',
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($/)
@@ -44,32 +44,31 @@ Gem::Specification.new do |s|
44
44
 
45
45
  s.required_ruby_version = '>= 2.4'
46
46
 
47
+ s.add_dependency 'base64'
47
48
  s.add_dependency 'multi_json'
48
- s.add_dependency 'faraday', '~> 1'
49
+ s.add_dependency 'faraday', '>= 1', '< 3'
49
50
 
51
+ # Faraday Adapters
52
+ s.add_development_dependency 'manticore' if defined? JRUBY_VERSION
53
+ s.add_development_dependency 'curb' unless defined? JRUBY_VERSION
54
+ s.add_development_dependency 'ansi'
55
+ s.add_development_dependency 'bundler'
50
56
  s.add_development_dependency 'cane'
51
- s.add_development_dependency 'curb' unless defined? JRUBY_VERSION
57
+ s.add_development_dependency 'elasticsearch', ['>= 7', '< 8.0.0']
52
58
  s.add_development_dependency 'elasticsearch-extensions'
59
+ s.add_development_dependency 'hashie'
53
60
  s.add_development_dependency 'minitest'
54
61
  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
- s.add_development_dependency 'hashie'
62
- s.add_development_dependency 'httpclient'
63
- s.add_development_dependency 'manticore', '~> 0.6' if defined? JRUBY_VERSION
64
62
  s.add_development_dependency 'mocha'
65
- 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
- s.add_development_dependency 'typhoeus', '~> 1.4'
71
71
  s.add_development_dependency 'yard'
72
- s.add_development_dependency 'bundler'
73
72
 
74
73
  s.description = <<-DESC.gsub(/^ /, '')
75
74
  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 = Transport::HTTP::Faraday
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 = o.is_a?(String) ? o : serializer.dump(o, options)
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 method, path, params, body, url, response, nil, 'N/A', duration
340
- __trace method, path, params, connection.connection.headers, body, url, response, nil, 'N/A', duration if tracer
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 method, path, params, connection.connection.headers, body, url, response, nil, 'N/A', duration if tracer
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,v| k.to_s.downcase =~ regex }
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 warnings(warning)
436
- warn("warning: #{warning}")
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
@@ -64,6 +64,7 @@ module Elasticsearch
64
64
  418 => 'ImATeapot',
65
65
  421 => 'TooManyConnectionsFromThisIP',
66
66
  426 => 'UpgradeRequired',
67
+ 429 => 'TooManyRequests',
67
68
  450 => 'BlockedByWindowsParentalControls',
68
69
  494 => 'RequestHeaderTooLarge',
69
70
  497 => 'HTTPToHTTPS',