elasticsearch-transport 7.15.0 → 7.16.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 013ab25456f1d6d612e5aae61b72c761998ec6483141399482b7457ed6cfe697
4
- data.tar.gz: d5d88475a41abb557a8ec9557a2306bb3098941bf2b031c62f24c0ace9a94859
3
+ metadata.gz: 86cb8f5de5ca5fc4270376d791ea8bd03252e5bbed8494d232da2eea8512434a
4
+ data.tar.gz: 27a6b7bfeea33bfa6e56ddd4a01109a1864a48685b54558707fe9af15ae73948
5
5
  SHA512:
6
- metadata.gz: 0db31f9306cecfcbddf99a4ebeb953c48ab4f949a5607fb58307601a7f90f0e859ee2d9016b68eea9d0cd13e080d56219a24b166dc7b2d68b3492cd6e24e0cb7
7
- data.tar.gz: 06bfbb100a2205868ab071aea96c9827a8fbcdd55530b64eb639b8f27e0244b5d908ed93f33f914e14d3afd38bac84abba43dfb68c9990bb34760a32d9ca4af8
6
+ metadata.gz: d2c129c4eeeb76a83d3fea12764ec135ad768920cd20c7c447a768708ab324db32482bdf616197e0674fe72a62ec74422b35774117a2d22cd0de8cc1520df20d
7
+ data.tar.gz: 586f14ab09c77a7a257667131d692dfd056e06ea66ccd3f53194985113043dec32e0fab5cf7fb3ed3d1a84036df02127df051c589ca137c6412ea8456a238a68
@@ -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($/)
@@ -92,6 +92,8 @@ module Elasticsearch
92
92
  #
93
93
  # @option arguments [Boolean,Number] :retry_on_failure Retry X times when request fails before raising and
94
94
  # exception (false by default)
95
+ # @option arguments [Number] :delay_on_retry Delay in milliseconds between each retry (0 by default)
96
+ #
95
97
  # @option arguments Array<Number> :retry_on_status Retry when specific status codes are returned
96
98
  #
97
99
  # @option arguments [Boolean] :reload_on_failure Reload connections after failure (false by default)
@@ -126,6 +128,7 @@ module Elasticsearch
126
128
  # if you're using X-Opaque-Id
127
129
  # @option enable_meta_header [Boolean] :enable_meta_header Enable sending the meta data header to Cloud.
128
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
129
132
  #
130
133
  # @yield [faraday] Access and configure the `Faraday::Connection` instance directly with a block
131
134
  #
@@ -136,6 +139,7 @@ module Elasticsearch
136
139
  @arguments[:tracer] ||= @arguments[:trace] ? DEFAULT_TRACER.call() : nil
137
140
  @arguments[:reload_connections] ||= false
138
141
  @arguments[:retry_on_failure] ||= false
142
+ @arguments[:delay_on_retry] ||= 0
139
143
  @arguments[:reload_on_failure] ||= false
140
144
  @arguments[:randomize_hosts] ||= false
141
145
  @arguments[:transport_options] ||= {}
@@ -156,6 +160,7 @@ module Elasticsearch
156
160
 
157
161
  @send_get_body_as = @arguments[:send_get_body_as] || 'GET'
158
162
  @opaque_id_prefix = @arguments[:opaque_id_prefix] || nil
163
+ @ca_fingerprint = @arguments.delete(:ca_fingerprint)
159
164
 
160
165
  if @arguments[:request_timeout]
161
166
  @arguments[:transport_options][:request] = { timeout: @arguments[:request_timeout] }
@@ -188,6 +193,7 @@ module Elasticsearch
188
193
  opaque_id = @opaque_id_prefix ? "#{@opaque_id_prefix}#{opaque_id}" : opaque_id
189
194
  headers.merge!('X-Opaque-Id' => opaque_id)
190
195
  end
196
+ validate_ca_fingerprints if @ca_fingerprint
191
197
  transport.perform_request(method, path, params, body, headers)
192
198
  end
193
199
 
@@ -211,6 +217,31 @@ module Elasticsearch
211
217
  )
212
218
  end
213
219
 
220
+ def validate_ca_fingerprints
221
+ transport.connections.connections.each do |connection|
222
+ unless connection.host[:scheme] == 'https'
223
+ raise Elasticsearch::Transport::Transport::Error, 'CA fingerprinting can\'t be configured over http'
224
+ end
225
+
226
+ next if connection.verified
227
+
228
+ ctx = OpenSSL::SSL::SSLContext.new
229
+ socket = TCPSocket.new(connection.host[:host], connection.host[:port])
230
+ ssl = OpenSSL::SSL::SSLSocket.new(socket, ctx)
231
+ ssl.connect
232
+ cert_store = ssl.peer_cert_chain
233
+ matching_certs = cert_store.select do |cert|
234
+ OpenSSL::Digest::SHA256.hexdigest(cert.to_der).upcase == @ca_fingerprint.upcase.gsub(':', '')
235
+ end
236
+ if matching_certs.empty?
237
+ raise Elasticsearch::Transport::Transport::Error,
238
+ 'Server certificate CA fingerprint does not match the value configured in ca_fingerprint'
239
+ end
240
+
241
+ connection.verified = true
242
+ end
243
+ end
244
+
214
245
  def add_header(header)
215
246
  headers = @arguments[:transport_options]&.[](:headers) || {}
216
247
  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 = o.is_a?(String) ? o : serializer.dump(o, options)
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]
@@ -275,6 +277,7 @@ module Elasticsearch
275
277
  ignore = Array(params.delete(:ignore)).compact.map { |s| s.to_i }
276
278
 
277
279
  begin
280
+ sleep(delay_on_retry / 1000.0) if tries > 0
278
281
  tries += 1
279
282
  connection = get_connection or raise Error.new('Cannot get new connection from pool.')
280
283
 
@@ -306,7 +309,6 @@ module Elasticsearch
306
309
  log_error "[#{e.class}] #{e.message} #{connection.host.inspect}"
307
310
 
308
311
  connection.dead!
309
-
310
312
  if reload_on_failure and tries < connections.all.size
311
313
  log_warn "[#{e.class}] Reloading connections (attempt #{tries} of #{connections.all.size})"
312
314
  reload_connections! and retry
@@ -348,7 +350,7 @@ module Elasticsearch
348
350
  end
349
351
 
350
352
  __trace(method, path, params, connection_headers(connection), body, url, response, nil, 'N/A', duration) if tracer
351
- warnings(response.headers['warning']) if response.headers&.[]('warning')
353
+ log_warn(response.headers['warning']) if response.headers&.[]('warning')
352
354
  Response.new response.status, json || response.body, response.headers
353
355
  ensure
354
356
  @last_request_at = Time.now
@@ -367,17 +369,38 @@ module Elasticsearch
367
369
 
368
370
  USER_AGENT_STR = 'User-Agent'.freeze
369
371
  USER_AGENT_REGEX = /user\-?\_?agent/
372
+ ACCEPT_ENCODING = 'Accept-Encoding'.freeze
373
+ CONTENT_ENCODING = 'Content-Encoding'.freeze
370
374
  CONTENT_TYPE_STR = 'Content-Type'.freeze
371
375
  CONTENT_TYPE_REGEX = /content\-?\_?type/
372
376
  DEFAULT_CONTENT_TYPE = 'application/json'.freeze
373
377
  GZIP = 'gzip'.freeze
374
- ACCEPT_ENCODING = 'Accept-Encoding'.freeze
375
378
  GZIP_FIRST_TWO_BYTES = '1f8b'.freeze
376
379
  HEX_STRING_DIRECTIVE = 'H*'.freeze
377
380
  RUBY_ENCODING = '1.9'.respond_to?(:force_encoding)
378
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
+
379
403
  def decompress_response(body)
380
- return body unless use_compression?
381
404
  return body unless gzipped?(body)
382
405
 
383
406
  io = StringIO.new(body)
@@ -390,6 +413,8 @@ module Elasticsearch
390
413
  end
391
414
 
392
415
  def gzipped?(body)
416
+ return unless body && !body.empty?
417
+
393
418
  body[0..1].unpack(HEX_STRING_DIRECTIVE)[0] == GZIP_FIRST_TWO_BYTES
394
419
  end
395
420
 
@@ -423,10 +448,6 @@ module Elasticsearch
423
448
  end
424
449
  end
425
450
 
426
- def warnings(warning)
427
- warn("warning: #{warning}")
428
- end
429
-
430
451
  def connection_headers(connection)
431
452
  if defined?(Elasticsearch::Transport::Transport::HTTP::Manticore) && self.class == Elasticsearch::Transport::Transport::HTTP::Manticore
432
453
  @request_options[:headers]
@@ -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,29 +19,31 @@ 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, url|
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
40
  when 'HEAD'
41
41
  connection.connection.set :nobody, true
42
42
  when 'GET', 'POST', 'PUT', 'DELETE'
43
43
  connection.connection.set :nobody, false
44
- connection.connection.put_data = __convert_to_json(body) if body
44
+
45
+ connection.connection.put_data = body if body
46
+
45
47
  if headers
46
48
  if connection.connection.headers
47
49
  connection.connection.headers.merge!(headers)
@@ -44,12 +44,13 @@ module Elasticsearch
44
44
  headers
45
45
  end
46
46
 
47
- response = connection.connection.run_request(
48
- method.downcase.to_sym,
49
- url,
50
- (body ? __convert_to_json(body) : nil),
51
- headers
52
- )
47
+ body = body ? __convert_to_json(body) : nil
48
+ body, headers = compress_request(body, headers)
49
+
50
+ response = connection.connection.run_request(method.downcase.to_sym,
51
+ url,
52
+ body,
53
+ headers)
53
54
 
54
55
  Response.new response.status, decompress_response(response.body), response.headers
55
56
  end
@@ -62,7 +63,7 @@ module Elasticsearch
62
63
  def __build_connection(host, options={}, block=nil)
63
64
  client = ::Faraday.new(__full_url(host), options, &block)
64
65
  apply_headers(client, options)
65
- Connections::Connection.new :host => host, :connection => client
66
+ Connections::Connection.new(host: host, connection: client)
66
67
  end
67
68
 
68
69
  # Returns an array of implementation specific connection errors.
@@ -83,7 +83,10 @@ module Elasticsearch
83
83
  #
84
84
  def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
85
85
  super do |connection, url|
86
- params[:body] = __convert_to_json(body) if body
86
+ body = body ? __convert_to_json(body) : nil
87
+ body, headers = compress_request(body, @request_options[:headers])
88
+
89
+ params[:body] = body if body
87
90
  params[:headers] = headers if headers
88
91
  params = params.merge @request_options
89
92
  case method
@@ -17,6 +17,6 @@
17
17
 
18
18
  module Elasticsearch
19
19
  module Transport
20
- VERSION = '7.15.0'.freeze
20
+ VERSION = '7.16.0'.freeze
21
21
  end
22
22
  end
@@ -18,6 +18,7 @@
18
18
  require 'uri'
19
19
  require 'time'
20
20
  require 'timeout'
21
+ require 'zlib'
21
22
  require 'multi_json'
22
23
  require 'faraday'
23
24
 
@@ -1466,28 +1466,19 @@ describe Elasticsearch::Transport::Client do
1466
1466
  end
1467
1467
 
1468
1468
  context 'when Elasticsearch response includes a warning header' do
1469
+ let(:logger) { double('logger', warn: '', warn?: '', info?: '', info: '', debug?: '', debug: '') }
1469
1470
  let(:client) do
1470
- Elasticsearch::Transport::Client.new(hosts: hosts)
1471
+ Elasticsearch::Transport::Client.new(hosts: hosts, logger: logger)
1471
1472
  end
1472
1473
 
1473
1474
  let(:warning) { 'Elasticsearch warning: "deprecation warning"' }
1474
1475
 
1475
1476
  it 'prints a warning' do
1476
- allow_any_instance_of(Elasticsearch::Transport::Transport::Response).to receive(:headers) do
1477
- { 'warning' => warning }
1478
- end
1479
-
1480
- begin
1481
- stderr = $stderr
1482
- fake_stderr = StringIO.new
1483
- $stderr = fake_stderr
1484
-
1485
- client.perform_request('GET', '/')
1486
- fake_stderr.rewind
1487
- expect(fake_stderr.string).to eq("warning: #{warning}\n")
1488
- ensure
1489
- $stderr = stderr
1477
+ expect_any_instance_of(Faraday::Connection).to receive(:run_request) do
1478
+ Elasticsearch::Transport::Transport::Response.new(200, {}, { 'warning' => warning })
1490
1479
  end
1480
+ client.perform_request('GET', '/')
1481
+ expect(logger).to have_received(:warn).with(warning)
1491
1482
  end
1492
1483
  end
1493
1484
 
@@ -1668,6 +1659,29 @@ describe Elasticsearch::Transport::Client do
1668
1659
  end
1669
1660
  end
1670
1661
 
1662
+ context 'when retry_on_failure is true and delay_on_retry is specified' do
1663
+ context 'when a node is unreachable' do
1664
+ let(:hosts) do
1665
+ [ELASTICSEARCH_HOSTS.first, "foobar1", "foobar2"]
1666
+ end
1667
+
1668
+ let(:options) do
1669
+ { retry_on_failure: true, delay_on_retry: 3000 }
1670
+ end
1671
+
1672
+ let(:responses) do
1673
+ 5.times.collect do
1674
+ client.perform_request('GET', '_nodes/_local')
1675
+ end
1676
+ end
1677
+
1678
+ it 'retries on failure' do
1679
+ allow_any_instance_of(Object).to receive(:sleep).with(3000 / 1000)
1680
+ expect(responses.all? { true }).to be(true)
1681
+ end
1682
+ end
1683
+ end
1684
+
1671
1685
  context 'when reload_on_failure is true' do
1672
1686
 
1673
1687
  let(:hosts) do
@@ -1727,7 +1741,7 @@ describe Elasticsearch::Transport::Client do
1727
1741
  end
1728
1742
 
1729
1743
  it 'sets the Accept-Encoding header' do
1730
- expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1744
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding']).to eq 'gzip'
1731
1745
  end
1732
1746
 
1733
1747
  it 'preserves the other headers' do
@@ -1746,7 +1760,7 @@ describe Elasticsearch::Transport::Client do
1746
1760
  end
1747
1761
 
1748
1762
  it 'sets the Accept-Encoding header' do
1749
- expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1763
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding']).to eq 'gzip'
1750
1764
  end
1751
1765
 
1752
1766
  it 'preserves the other headers' do
@@ -1765,7 +1779,7 @@ describe Elasticsearch::Transport::Client do
1765
1779
  end
1766
1780
 
1767
1781
  it 'sets the Accept-Encoding header' do
1768
- expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1782
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding']).to eq 'gzip'
1769
1783
  end
1770
1784
 
1771
1785
  it 'preserves the other headers' do
@@ -1784,7 +1798,7 @@ describe Elasticsearch::Transport::Client do
1784
1798
  end
1785
1799
 
1786
1800
  it 'sets the Accept-Encoding header' do
1787
- expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1801
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding']).to eq 'gzip'
1788
1802
  end
1789
1803
 
1790
1804
  it 'preserves the other headers' do
@@ -1803,7 +1817,7 @@ describe Elasticsearch::Transport::Client do
1803
1817
  end
1804
1818
 
1805
1819
  it 'sets the Accept-Encoding header' do
1806
- expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1820
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding']).to eq 'gzip'
1807
1821
  end
1808
1822
 
1809
1823
  it 'preserves the other headers' do
@@ -1827,7 +1841,7 @@ describe Elasticsearch::Transport::Client do
1827
1841
  end
1828
1842
 
1829
1843
  it 'sets the Accept-Encoding header' do
1830
- expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1844
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding']).to eq 'gzip'
1831
1845
  end
1832
1846
 
1833
1847
  it 'preserves the other headers' do
@@ -1895,7 +1909,6 @@ describe Elasticsearch::Transport::Client do
1895
1909
  end
1896
1910
 
1897
1911
  context 'when request headers are specified' do
1898
-
1899
1912
  let(:response) do
1900
1913
  client.perform_request('GET', '/', {}, nil, { 'Content-Type' => 'application/yaml' })
1901
1914
  end
@@ -1906,9 +1919,7 @@ describe Elasticsearch::Transport::Client do
1906
1919
  end
1907
1920
 
1908
1921
  describe 'selector' do
1909
-
1910
1922
  context 'when the round-robin selector is used' do
1911
-
1912
1923
  let(:nodes) do
1913
1924
  3.times.collect do
1914
1925
  client.perform_request('GET', '_nodes/_local').body['nodes'].to_a[0][1]['name']
@@ -1989,4 +2000,76 @@ describe Elasticsearch::Transport::Client do
1989
2000
  end
1990
2001
  end
1991
2002
  end
2003
+
2004
+ context 'CA Fingerprinting' do
2005
+ context 'when setting a ca_fingerprint' do
2006
+ after do
2007
+ File.delete('./certificate.crt')
2008
+ File.delete('./certificate.key')
2009
+ end
2010
+
2011
+ let(:certificate) do
2012
+ system(
2013
+ 'openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj "/C=BE/O=Test/CN=Test"' \
2014
+ ' -keyout certificate.key -out certificate.crt',
2015
+ err: File::NULL
2016
+ )
2017
+ OpenSSL::X509::Certificate.new File.read('./certificate.crt')
2018
+ end
2019
+
2020
+ let(:client) do
2021
+ Elasticsearch::Transport::Client.new(
2022
+ host: 'https://elastic:changeme@localhost:9200',
2023
+ ca_fingerprint: OpenSSL::Digest::SHA256.hexdigest(certificate.to_der)
2024
+ )
2025
+ end
2026
+
2027
+ it 'validates CA fingerprints on perform request' do
2028
+ expect(client.transport.connections.connections.map(&:verified).uniq).to eq [false]
2029
+ allow(client.transport).to receive(:perform_request) { 'Hello' }
2030
+
2031
+ server = double('server').as_null_object
2032
+ allow(TCPSocket).to receive(:new) { server }
2033
+ socket = double('socket')
2034
+ allow(OpenSSL::SSL::SSLSocket).to receive(:new) { socket }
2035
+ allow(socket).to receive(:connect) { nil }
2036
+ allow(socket).to receive(:peer_cert_chain) { [certificate] }
2037
+
2038
+ response = client.perform_request('GET', '/')
2039
+ expect(client.transport.connections.connections.map(&:verified).uniq).to eq [true]
2040
+ expect(response).to eq 'Hello'
2041
+ end
2042
+ end
2043
+
2044
+ context 'when using an http host' do
2045
+ let(:client) do
2046
+ Elasticsearch::Transport::Client.new(
2047
+ host: 'http://elastic:changeme@localhost:9200',
2048
+ ca_fingerprint: 'test'
2049
+ )
2050
+ end
2051
+
2052
+ it 'raises an error' do
2053
+ expect do
2054
+ client.perform_request('GET', '/')
2055
+ end.to raise_exception(Elasticsearch::Transport::Transport::Error)
2056
+ end
2057
+ end
2058
+
2059
+ context 'when not setting a ca_fingerprint' do
2060
+ let(:client) do
2061
+ Elasticsearch::Transport::Client.new(
2062
+ host: 'http://elastic:changeme@localhost:9200'
2063
+ )
2064
+ end
2065
+
2066
+ it 'has unvalidated connections' do
2067
+ allow(client).to receive(:validate_ca_fingerprints) { nil }
2068
+ allow(client.transport).to receive(:perform_request) { nil }
2069
+
2070
+ client.perform_request('GET', '/')
2071
+ expect(client).to_not have_received(:validate_ca_fingerprints)
2072
+ end
2073
+ end
2074
+ end
1992
2075
  end
@@ -0,0 +1,126 @@
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
+ unless defined?(JRUBY_VERSION)
19
+ require_relative '../../../spec_helper'
20
+
21
+ describe Elasticsearch::Transport::Transport::HTTP::Curb do
22
+ let(:client) do
23
+ Elasticsearch::Transport::Client.new(transport_class: described_class)
24
+ end
25
+
26
+ describe '#perform_request' do
27
+ subject(:perform_request) { client.perform_request(*args) }
28
+ let(:args) do
29
+ ['POST', '/', {}, body, headers]
30
+ end
31
+ let(:body) { '{"foo":"bar"}' }
32
+ let(:headers) { { 'Content-Type' => 'application/x-ndjson' } }
33
+
34
+ before do
35
+ allow_any_instance_of(Curl::Easy).to receive(:http).and_return(true)
36
+ end
37
+
38
+ it 'convert body to json' do
39
+ expect(client.transport).to receive(:__convert_to_json).with(body)
40
+ perform_request
41
+ end
42
+
43
+ it 'call compress_request' do
44
+ expect(client.transport).to receive(:compress_request).with(body, headers)
45
+ perform_request
46
+ end
47
+
48
+ it 'return response' do
49
+ expect(perform_request).to be_kind_of(Elasticsearch::Transport::Transport::Response)
50
+ end
51
+
52
+ it 'put body' do
53
+ expect(client.transport.connections.first.connection).to receive('put_data=').with(body)
54
+ perform_request
55
+ end
56
+
57
+ context 'when body nil' do
58
+ let(:body) { nil }
59
+
60
+ it 'convert body to json' do
61
+ expect(client.transport).not_to receive(:__convert_to_json)
62
+ perform_request
63
+ end
64
+
65
+ it 'call compress_request' do
66
+ expect(client.transport).to receive(:compress_request).with(body, headers)
67
+ perform_request
68
+ end
69
+
70
+ it 'put body' do
71
+ expect(client.transport.connections.first.connection).not_to receive('put_data=')
72
+ perform_request
73
+ end
74
+ end
75
+
76
+ context 'when body is hash' do
77
+ let(:body) { { foo: 'bar' } }
78
+ let(:body_string) { '{"foo":"bar"}' }
79
+
80
+ it 'convert body to json' do
81
+ expect(client.transport).to receive(:__convert_to_json).with(body)
82
+ perform_request
83
+ end
84
+
85
+ it 'call compress_request' do
86
+ expect(client.transport).to receive(:compress_request).with(body_string, headers)
87
+ perform_request
88
+ end
89
+
90
+ it 'put body' do
91
+ expect(client.transport.connections.first.connection).to receive('put_data=').with(body_string)
92
+ perform_request
93
+ end
94
+ end
95
+
96
+ context 'when compression enabled' do
97
+ let(:client) do
98
+ Elasticsearch::Transport::Client.new(transport_class: described_class, compression: true)
99
+ end
100
+ let(:body_string) { '{"foo":"bar"}' }
101
+ let(:compressed_body) do
102
+ gzip = Zlib::GzipWriter.new(StringIO.new)
103
+ gzip << body_string
104
+ gzip.close.string
105
+ end
106
+
107
+ before { allow(client.transport).to receive(:decompress_response).and_return('') }
108
+
109
+ it 'put compressed body' do
110
+ expect(client.transport.connections.first.connection).to receive('put_data=').with(compressed_body)
111
+ perform_request
112
+ end
113
+
114
+ it 'set Content-Encoding header' do
115
+ perform_request
116
+ expect(client.transport.connections.first.connection.headers).to include('Content-Encoding')
117
+ end
118
+
119
+ it 'set Content-Encoding to gzip' do
120
+ perform_request
121
+ expect(client.transport.connections.first.connection.headers['Content-Encoding']).to eql('gzip')
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,141 @@
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
+ require_relative '../../../spec_helper'
19
+
20
+ describe Elasticsearch::Transport::Transport::HTTP::Faraday do
21
+ let(:client) do
22
+ Elasticsearch::Transport::Client.new(transport_class: described_class)
23
+ end
24
+
25
+ describe '#perform_request' do
26
+ subject(:perform_request) { client.perform_request(*args) }
27
+ let(:args) do
28
+ ['POST', '/', {}, body, headers]
29
+ end
30
+ let(:body) { '{"foo":"bar"}' }
31
+ let(:headers) { { 'Content-Type' => 'application/x-ndjson' } }
32
+ let(:response) { instance_double('Faraday::Response', status: 200, body: '', headers: headers) }
33
+ let(:expected_headers) do
34
+ client.transport.connections.first.connection.headers.merge(headers)
35
+ end
36
+
37
+ before do
38
+ allow_any_instance_of(Faraday::Connection).to receive(:run_request).and_return(response)
39
+ end
40
+
41
+ it 'convert body to json' do
42
+ expect(client.transport).to receive(:__convert_to_json).with(body)
43
+ perform_request
44
+ end
45
+
46
+ it 'call compress_request' do
47
+ expect(client.transport).to receive(:compress_request).with(body, expected_headers)
48
+ perform_request
49
+ end
50
+
51
+ it 'return response' do
52
+ expect(perform_request).to be_kind_of(Elasticsearch::Transport::Transport::Response)
53
+ end
54
+
55
+ it 'run body with preper params' do
56
+ expect(
57
+ client.transport.connections.first.connection
58
+ ).to receive(:run_request).with(:post, 'http://localhost:9200/', body, expected_headers).and_return(response)
59
+ perform_request
60
+ end
61
+
62
+ context 'when body nil' do
63
+ let(:body) { nil }
64
+ let(:request_params) { [:post, 'http://localhost:9200/', body, expected_headers] }
65
+
66
+ it 'convert body to json' do
67
+ expect(client.transport).not_to receive(:__convert_to_json)
68
+ perform_request
69
+ end
70
+
71
+ it 'call compress_request' do
72
+ expect(client.transport).to receive(:compress_request).with(body, expected_headers)
73
+ perform_request
74
+ end
75
+
76
+ it 'run body with preper params' do
77
+ expect(
78
+ client.transport.connections.first.connection
79
+ ).to receive(:run_request).with(*request_params).and_return(response)
80
+ perform_request
81
+ end
82
+ end
83
+
84
+ context 'when body is hash' do
85
+ let(:body) { { foo: 'bar' } }
86
+ let(:body_string) { '{"foo":"bar"}' }
87
+ let(:request_params) { [:post, 'http://localhost:9200/', body_string, expected_headers] }
88
+
89
+ it 'convert body to json' do
90
+ expect(client.transport).to receive(:__convert_to_json).with(body)
91
+ perform_request
92
+ end
93
+
94
+ it 'call compress_request' do
95
+ expect(client.transport).to receive(:compress_request).with(body_string, expected_headers)
96
+ perform_request
97
+ end
98
+
99
+ it 'run body with preper params' do
100
+ expect(
101
+ client.transport.connections.first.connection
102
+ ).to receive(:run_request).with(*request_params).and_return(response)
103
+ perform_request
104
+ end
105
+ end
106
+
107
+ context 'when compression enabled' do
108
+ let(:client) do
109
+ Elasticsearch::Transport::Client.new(transport_class: described_class, compression: true)
110
+ end
111
+ let(:body_string) { '{"foo":"bar"}' }
112
+ let(:expected_headers) { super().merge({ "Content-Encoding" => "gzip", "Accept-Encoding" => "gzip"}) }
113
+ let(:request_params) { [:post, 'http://localhost:9200/', compressed_body, expected_headers] }
114
+ let(:compressed_body) do
115
+ gzip = Zlib::GzipWriter.new(StringIO.new)
116
+ gzip << body_string
117
+ gzip.close.string
118
+ end
119
+
120
+ it 'run body with preper params' do
121
+ expect(
122
+ client.transport.connections.first.connection
123
+ ).to receive(:run_request).with(*request_params).and_return(response)
124
+ perform_request
125
+ end
126
+
127
+ context 'when client makes second request with nil boby' do
128
+ before { perform_request }
129
+
130
+ it 'remove Content-Encoding header' do
131
+ expected_headers.delete("Content-Encoding")
132
+ expect(
133
+ client.transport.connections.first.connection
134
+ ).to receive(:run_request).with(:post, 'http://localhost:9200/', nil, expected_headers)
135
+ .and_return(response)
136
+ client.perform_request('POST', '/', {}, nil, headers)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,143 @@
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
+ if defined?(JRUBY_VERSION)
19
+ require_relative '../../../spec_helper'
20
+
21
+ describe Elasticsearch::Transport::Transport::HTTP::Manticore do
22
+ let(:client) do
23
+ Elasticsearch::Transport::Client.new(transport_class: described_class)
24
+ end
25
+
26
+ describe '#perform_request' do
27
+ subject(:perform_request) { client.perform_request(*args) }
28
+ let(:args) do
29
+ ['POST', '/', {}, body, headers]
30
+ end
31
+ let(:body) { '{"foo":"bar"}' }
32
+ let(:headers) { { 'Content-Type' => 'application/json' } }
33
+ let(:response) { instance_double('Manticore::Response', code: 200, read_body: '', headers: headers) }
34
+ let(:expected_headers) do
35
+ client.transport.instance_variable_get('@request_options')[:headers].merge(headers)
36
+ end
37
+
38
+ before do
39
+ allow_any_instance_of(Manticore::Client).to receive(:post).and_return(response)
40
+ end
41
+
42
+ it 'convert body to json' do
43
+ expect(client.transport).to receive(:__convert_to_json).with(body)
44
+ perform_request
45
+ end
46
+
47
+ it 'call compress_request' do
48
+ expect(client.transport).to receive(:compress_request).with(body, expected_headers)
49
+ perform_request
50
+ end
51
+
52
+ it 'return response' do
53
+ expect(perform_request).to be_kind_of(Elasticsearch::Transport::Transport::Response)
54
+ end
55
+
56
+ it 'run body with preper params' do
57
+ expect(
58
+ client.transport.connections.first.connection
59
+ ).to receive(:post).with('http://localhost:9200/', { body: body, headers: expected_headers }).and_return(response)
60
+ perform_request
61
+ end
62
+
63
+ context 'when body nil' do
64
+ let(:body) { nil }
65
+ let(:request_params) { ['http://localhost:9200/', { body: body, headers: expected_headers }] }
66
+
67
+ it 'convert body to json' do
68
+ expect(client.transport).not_to receive(:__convert_to_json)
69
+ perform_request
70
+ end
71
+
72
+ it 'call compress_request' do
73
+ expect(client.transport).to receive(:compress_request).with(body, expected_headers)
74
+ perform_request
75
+ end
76
+
77
+ it 'run body with preper params' do
78
+ expect(
79
+ client.transport.connections.first.connection
80
+ ).to receive(:post).with('http://localhost:9200/', { headers: expected_headers }).and_return(response)
81
+ perform_request
82
+ end
83
+ end
84
+
85
+ context 'when body is hash' do
86
+ let(:body) { { foo: 'bar' } }
87
+ let(:body_string) { '{"foo":"bar"}' }
88
+ let(:request_params) { ['http://localhost:9200/', { body: body_string, headers: expected_headers }] }
89
+
90
+ it 'convert body to json' do
91
+ expect(client.transport).to receive(:__convert_to_json).with(body)
92
+ perform_request
93
+ end
94
+
95
+ it 'call compress_request' do
96
+ expect(client.transport).to receive(:compress_request).with(body_string, expected_headers)
97
+ perform_request
98
+ end
99
+
100
+ it 'run body with preper params' do
101
+ expect(
102
+ client.transport.connections.first.connection
103
+ ).to receive(:post).with(*request_params).and_return(response)
104
+ perform_request
105
+ end
106
+ end
107
+
108
+ context 'when compression enabled' do
109
+ let(:client) do
110
+ Elasticsearch::Transport::Client.new(transport_class: described_class, compression: true)
111
+ end
112
+ let(:body_string) { '{"foo":"bar"}' }
113
+ let(:expected_headers) { super().merge({ "Content-Encoding" => "gzip", "Accept-Encoding" => "gzip"}) }
114
+ let(:request_params) { ['http://localhost:9200/', { body: compressed_body, headers: expected_headers }] }
115
+ let(:compressed_body) do
116
+ gzip = Zlib::GzipWriter.new(StringIO.new)
117
+ gzip << body_string
118
+ gzip.close.string
119
+ end
120
+
121
+ it 'run body with preper params' do
122
+ expect(
123
+ client.transport.connections.first.connection
124
+ ).to receive(:post).with(*request_params).and_return(response)
125
+ perform_request
126
+ end
127
+
128
+ context 'when client makes second request with nil boby' do
129
+ before { perform_request }
130
+
131
+ it 'remove Content-Encoding header' do
132
+ expected_headers.delete("Content-Encoding")
133
+ expect(
134
+ client.transport.connections.first.connection
135
+ ).to receive(:post).with('http://localhost:9200/', { headers: expected_headers })
136
+ .and_return(response)
137
+ client.perform_request('POST', '/', {}, nil, headers)
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elasticsearch-transport
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.15.0
4
+ version: 7.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karel Minarik
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-22 00:00:00.000000000 Z
11
+ date: 2021-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
@@ -392,6 +392,9 @@ files:
392
392
  - spec/elasticsearch/connections/selector_spec.rb
393
393
  - spec/elasticsearch/transport/base_spec.rb
394
394
  - spec/elasticsearch/transport/client_spec.rb
395
+ - spec/elasticsearch/transport/http/curb_spec.rb
396
+ - spec/elasticsearch/transport/http/faraday_spec.rb
397
+ - spec/elasticsearch/transport/http/manticore_spec.rb
395
398
  - spec/elasticsearch/transport/meta_header_spec.rb
396
399
  - spec/elasticsearch/transport/sniffer_spec.rb
397
400
  - spec/spec_helper.rb
@@ -406,13 +409,13 @@ files:
406
409
  - test/unit/transport_curb_test.rb
407
410
  - test/unit/transport_faraday_test.rb
408
411
  - test/unit/transport_manticore_test.rb
409
- homepage: https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/7.x/index.html
412
+ homepage: https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/7.16/index.html
410
413
  licenses:
411
414
  - Apache-2.0
412
415
  metadata:
413
- homepage_uri: https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/7.x/index.html
414
- changelog_uri: https://github.com/elastic/elasticsearch-ruby/blob/7.x/CHANGELOG.md
415
- source_code_uri: https://github.com/elastic/elasticsearch-ruby/tree/7.x/elasticsearch-transport
416
+ homepage_uri: https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/7.16/index.html
417
+ changelog_uri: https://github.com/elastic/elasticsearch-ruby/blob/7.16/CHANGELOG.md
418
+ source_code_uri: https://github.com/elastic/elasticsearch-ruby/tree/7.16/elasticsearch-transport
416
419
  bug_tracker_uri: https://github.com/elastic/elasticsearch-ruby/issues
417
420
  post_install_message:
418
421
  rdoc_options:
@@ -439,6 +442,9 @@ test_files:
439
442
  - spec/elasticsearch/connections/selector_spec.rb
440
443
  - spec/elasticsearch/transport/base_spec.rb
441
444
  - spec/elasticsearch/transport/client_spec.rb
445
+ - spec/elasticsearch/transport/http/curb_spec.rb
446
+ - spec/elasticsearch/transport/http/faraday_spec.rb
447
+ - spec/elasticsearch/transport/http/manticore_spec.rb
442
448
  - spec/elasticsearch/transport/meta_header_spec.rb
443
449
  - spec/elasticsearch/transport/sniffer_spec.rb
444
450
  - spec/spec_helper.rb