elasticsearch-transport 7.5.0 → 7.17.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +26 -13
- data/README.md +159 -64
- data/Rakefile +25 -13
- data/elasticsearch-transport.gemspec +57 -63
- data/lib/elasticsearch/transport/client.rb +183 -58
- data/lib/elasticsearch/transport/meta_header.rb +135 -0
- data/lib/elasticsearch/transport/redacted.rb +16 -3
- data/lib/elasticsearch/transport/transport/base.rb +69 -30
- data/lib/elasticsearch/transport/transport/connections/collection.rb +18 -8
- data/lib/elasticsearch/transport/transport/connections/connection.rb +25 -9
- data/lib/elasticsearch/transport/transport/connections/selector.rb +16 -3
- data/lib/elasticsearch/transport/transport/errors.rb +17 -3
- data/lib/elasticsearch/transport/transport/http/curb.rb +60 -35
- data/lib/elasticsearch/transport/transport/http/faraday.rb +32 -9
- data/lib/elasticsearch/transport/transport/http/manticore.rb +51 -31
- data/lib/elasticsearch/transport/transport/loggable.rb +16 -3
- data/lib/elasticsearch/transport/transport/response.rb +16 -4
- data/lib/elasticsearch/transport/transport/serializer/multi_json.rb +16 -3
- data/lib/elasticsearch/transport/transport/sniffer.rb +35 -15
- data/lib/elasticsearch/transport/version.rb +17 -4
- data/lib/elasticsearch/transport.rb +35 -33
- data/lib/elasticsearch-transport.rb +16 -3
- data/spec/elasticsearch/connections/collection_spec.rb +28 -3
- data/spec/elasticsearch/connections/selector_spec.rb +16 -3
- data/spec/elasticsearch/transport/base_spec.rb +104 -43
- data/spec/elasticsearch/transport/client_spec.rb +727 -163
- 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 +301 -0
- data/spec/elasticsearch/transport/sniffer_spec.rb +16 -16
- data/spec/spec_helper.rb +28 -6
- data/test/integration/jruby_test.rb +43 -0
- data/test/integration/transport_test.rb +46 -29
- data/test/profile/client_benchmark_test.rb +16 -3
- data/test/test_helper.rb +22 -25
- data/test/unit/connection_test.rb +23 -5
- data/test/unit/response_test.rb +18 -5
- data/test/unit/serializer_test.rb +16 -3
- data/test/unit/transport_base_test.rb +33 -11
- data/test/unit/transport_curb_test.rb +16 -4
- data/test/unit/transport_faraday_test.rb +18 -5
- data/test/unit/transport_manticore_test.rb +258 -158
- metadata +80 -71
@@ -1,11 +1,23 @@
|
|
1
|
-
# Licensed to Elasticsearch B.V under one or more
|
2
|
-
#
|
3
|
-
#
|
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.
|
4
17
|
|
5
18
|
module Elasticsearch
|
6
19
|
module Transport
|
7
20
|
module Transport
|
8
|
-
|
9
21
|
# @abstract Module with common functionality for transport implementations.
|
10
22
|
#
|
11
23
|
module Base
|
@@ -34,13 +46,14 @@ module Elasticsearch
|
|
34
46
|
#
|
35
47
|
# @see Client#initialize
|
36
48
|
#
|
37
|
-
def initialize(arguments={}, &block)
|
49
|
+
def initialize(arguments = {}, &block)
|
38
50
|
@state_mutex = Mutex.new
|
39
51
|
|
40
52
|
@hosts = arguments[:hosts] || []
|
41
53
|
@options = arguments[:options] || {}
|
42
54
|
@options[:http] ||= {}
|
43
55
|
@options[:retry_on_status] ||= []
|
56
|
+
@options[:delay_on_retry] ||= 0
|
44
57
|
|
45
58
|
@block = block
|
46
59
|
@compression = !!@options[:compression]
|
@@ -210,7 +223,7 @@ module Elasticsearch
|
|
210
223
|
# @api private
|
211
224
|
#
|
212
225
|
def __convert_to_json(o=nil, options={})
|
213
|
-
o
|
226
|
+
o.is_a?(String) ? o : serializer.dump(o, options)
|
214
227
|
end
|
215
228
|
|
216
229
|
# Returns a full URL based on information from host
|
@@ -221,9 +234,9 @@ module Elasticsearch
|
|
221
234
|
def __full_url(host)
|
222
235
|
url = "#{host[:protocol]}://"
|
223
236
|
url += "#{CGI.escape(host[:user])}:#{CGI.escape(host[:password])}@" if host[:user]
|
224
|
-
url +=
|
237
|
+
url += host[:host]
|
225
238
|
url += ":#{host[:port]}" if host[:port]
|
226
|
-
url +=
|
239
|
+
url += host[:path] if host[:path]
|
227
240
|
url
|
228
241
|
end
|
229
242
|
|
@@ -245,11 +258,13 @@ module Elasticsearch
|
|
245
258
|
# @raise [ServerError] If request failed on server
|
246
259
|
# @raise [Error] If no connection is available
|
247
260
|
#
|
248
|
-
def perform_request(method, path, params={}, body=nil, headers=nil, opts={}, &block)
|
249
|
-
raise NoMethodError,
|
261
|
+
def perform_request(method, path, params = {}, body = nil, headers = nil, opts = {}, &block)
|
262
|
+
raise NoMethodError, 'Implement this method in your transport class' unless block_given?
|
263
|
+
|
250
264
|
start = Time.now
|
251
265
|
tries = 0
|
252
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])
|
253
268
|
|
254
269
|
max_retries = if opts.key?(:retry_on_failure)
|
255
270
|
opts[:retry_on_failure] === true ? DEFAULT_MAX_RETRIES : opts[:retry_on_failure]
|
@@ -258,21 +273,19 @@ module Elasticsearch
|
|
258
273
|
end
|
259
274
|
|
260
275
|
params = params.clone
|
261
|
-
|
262
276
|
ignore = Array(params.delete(:ignore)).compact.map { |s| s.to_i }
|
263
277
|
|
264
278
|
begin
|
279
|
+
sleep(delay_on_retry / 1000.0) if tries > 0
|
265
280
|
tries += 1
|
266
|
-
connection = get_connection or raise Error.new(
|
281
|
+
connection = get_connection or raise Error.new('Cannot get new connection from pool.')
|
267
282
|
|
268
283
|
if connection.connection.respond_to?(:params) && connection.connection.params.respond_to?(:to_hash)
|
269
284
|
params = connection.connection.params.merge(params.to_hash)
|
270
285
|
end
|
271
286
|
|
272
|
-
url
|
273
|
-
|
274
|
-
response = block.call(connection, url)
|
275
|
-
|
287
|
+
url = connection.full_url(path, params)
|
288
|
+
response = block.call(connection, url)
|
276
289
|
connection.healthy! if connection.failures > 0
|
277
290
|
|
278
291
|
# Raise an exception so we can catch it for `retry_on_status`
|
@@ -295,7 +308,6 @@ module Elasticsearch
|
|
295
308
|
log_error "[#{e.class}] #{e.message} #{connection.host.inspect}"
|
296
309
|
|
297
310
|
connection.dead!
|
298
|
-
|
299
311
|
if reload_on_failure and tries < connections.all.size
|
300
312
|
log_warn "[#{e.class}] Reloading connections (attempt #{tries} of #{connections.all.size})"
|
301
313
|
reload_connections! and retry
|
@@ -322,14 +334,10 @@ module Elasticsearch
|
|
322
334
|
duration = Time.now - start
|
323
335
|
|
324
336
|
if response.status.to_i >= 300
|
325
|
-
__log_response
|
326
|
-
__trace
|
327
|
-
|
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
|
328
339
|
# Log the failure only when `ignore` doesn't match the response status
|
329
|
-
unless ignore.include?(response.status.to_i)
|
330
|
-
log_fatal "[#{response.status}] #{response.body}"
|
331
|
-
end
|
332
|
-
|
340
|
+
log_fatal "[#{response.status}] #{response.body}" unless ignore.include?(response.status.to_i)
|
333
341
|
__raise_transport_error response unless ignore.include?(response.status.to_i)
|
334
342
|
end
|
335
343
|
|
@@ -340,8 +348,8 @@ module Elasticsearch
|
|
340
348
|
__log_response method, path, params, body, url, response, json, took, duration
|
341
349
|
end
|
342
350
|
|
343
|
-
__trace
|
344
|
-
|
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')
|
345
353
|
Response.new response.status, json || response.body, response.headers
|
346
354
|
ensure
|
347
355
|
@last_request_at = Time.now
|
@@ -360,17 +368,38 @@ module Elasticsearch
|
|
360
368
|
|
361
369
|
USER_AGENT_STR = 'User-Agent'.freeze
|
362
370
|
USER_AGENT_REGEX = /user\-?\_?agent/
|
371
|
+
ACCEPT_ENCODING = 'Accept-Encoding'.freeze
|
372
|
+
CONTENT_ENCODING = 'Content-Encoding'.freeze
|
363
373
|
CONTENT_TYPE_STR = 'Content-Type'.freeze
|
364
374
|
CONTENT_TYPE_REGEX = /content\-?\_?type/
|
365
375
|
DEFAULT_CONTENT_TYPE = 'application/json'.freeze
|
366
376
|
GZIP = 'gzip'.freeze
|
367
|
-
ACCEPT_ENCODING = 'Accept-Encoding'.freeze
|
368
377
|
GZIP_FIRST_TWO_BYTES = '1f8b'.freeze
|
369
378
|
HEX_STRING_DIRECTIVE = 'H*'.freeze
|
370
379
|
RUBY_ENCODING = '1.9'.respond_to?(:force_encoding)
|
371
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
|
+
|
372
402
|
def decompress_response(body)
|
373
|
-
return body unless use_compression?
|
374
403
|
return body unless gzipped?(body)
|
375
404
|
|
376
405
|
io = StringIO.new(body)
|
@@ -383,6 +412,8 @@ module Elasticsearch
|
|
383
412
|
end
|
384
413
|
|
385
414
|
def gzipped?(body)
|
415
|
+
return unless body && !body.empty?
|
416
|
+
|
386
417
|
body[0..1].unpack(HEX_STRING_DIRECTIVE)[0] == GZIP_FIRST_TWO_BYTES
|
387
418
|
end
|
388
419
|
|
@@ -399,7 +430,7 @@ module Elasticsearch
|
|
399
430
|
end
|
400
431
|
|
401
432
|
def find_value(hash, regex)
|
402
|
-
key_value = hash.find { |k,
|
433
|
+
key_value = hash.find { |k, _| k.to_s.downcase =~ regex }
|
403
434
|
if key_value
|
404
435
|
hash.delete(key_value[0])
|
405
436
|
key_value[1]
|
@@ -415,7 +446,15 @@ module Elasticsearch
|
|
415
446
|
"elasticsearch-ruby/#{VERSION} (#{meta.join('; ')})"
|
416
447
|
end
|
417
448
|
end
|
449
|
+
|
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
|
456
|
+
end
|
418
457
|
end
|
419
458
|
end
|
420
459
|
end
|
421
|
-
end
|
460
|
+
end
|
@@ -1,6 +1,19 @@
|
|
1
|
-
# Licensed to Elasticsearch B.V under one or more
|
2
|
-
#
|
3
|
-
#
|
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.
|
4
17
|
|
5
18
|
module Elasticsearch
|
6
19
|
module Transport
|
@@ -65,16 +78,13 @@ module Elasticsearch
|
|
65
78
|
|
66
79
|
# Returns a connection.
|
67
80
|
#
|
68
|
-
# If there are no alive connections,
|
81
|
+
# If there are no alive connections, returns a connection with least failures.
|
69
82
|
# Delegates to selector's `#select` method to get the connection.
|
70
83
|
#
|
71
84
|
# @return [Connection]
|
72
85
|
#
|
73
86
|
def get_connection(options={})
|
74
|
-
|
75
|
-
dead_connection.alive!
|
76
|
-
end
|
77
|
-
selector.select(options)
|
87
|
+
selector.select(options) || @connections.min_by(&:failures)
|
78
88
|
end
|
79
89
|
|
80
90
|
def each(&block)
|
@@ -1,12 +1,24 @@
|
|
1
|
-
# Licensed to Elasticsearch B.V under one or more
|
2
|
-
#
|
3
|
-
#
|
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.
|
4
17
|
|
5
18
|
module Elasticsearch
|
6
19
|
module Transport
|
7
20
|
module Transport
|
8
21
|
module Connections
|
9
|
-
|
10
22
|
# Wraps the connection information and logic.
|
11
23
|
#
|
12
24
|
# The Connection instance wraps the host information (hostname, port, attributes, etc),
|
@@ -21,6 +33,7 @@ module Elasticsearch
|
|
21
33
|
DEFAULT_RESURRECT_TIMEOUT = 60
|
22
34
|
|
23
35
|
attr_reader :host, :connection, :options, :failures, :dead_since
|
36
|
+
attr_accessor :verified
|
24
37
|
|
25
38
|
# @option arguments [Hash] :host Host information (example: `{host: 'localhost', port: 9200}`)
|
26
39
|
# @option arguments [Object] :connection The transport-specific physical connection or "session"
|
@@ -30,6 +43,7 @@ module Elasticsearch
|
|
30
43
|
@host = arguments[:host].is_a?(Hash) ? Redacted.new(arguments[:host]) : arguments[:host]
|
31
44
|
@connection = arguments[:connection]
|
32
45
|
@options = arguments[:options] || {}
|
46
|
+
@verified = false
|
33
47
|
@state_mutex = Mutex.new
|
34
48
|
|
35
49
|
@options[:resurrect_timeout] ||= DEFAULT_RESURRECT_TIMEOUT
|
@@ -41,12 +55,14 @@ module Elasticsearch
|
|
41
55
|
#
|
42
56
|
# @return [String]
|
43
57
|
#
|
44
|
-
def full_url(path, params={})
|
58
|
+
def full_url(path, params = {})
|
45
59
|
url = "#{host[:protocol]}://"
|
46
60
|
url += "#{CGI.escape(host[:user])}:#{CGI.escape(host[:password])}@" if host[:user]
|
47
61
|
url += "#{host[:host]}:#{host[:port]}"
|
48
62
|
url += "#{host[:path]}" if host[:path]
|
49
|
-
|
63
|
+
full_path = full_path(path, params)
|
64
|
+
url += '/' unless full_path.match?(/^\//)
|
65
|
+
url += full_path
|
50
66
|
end
|
51
67
|
|
52
68
|
# Returns the complete endpoint path with serialized parameters.
|
@@ -122,14 +138,15 @@ module Elasticsearch
|
|
122
138
|
}
|
123
139
|
end
|
124
140
|
|
125
|
-
# Equality operator based on connection protocol, host and
|
141
|
+
# Equality operator based on connection protocol, host, port and attributes
|
126
142
|
#
|
127
143
|
# @return [Boolean]
|
128
144
|
#
|
129
145
|
def ==(other)
|
130
146
|
self.host[:protocol] == other.host[:protocol] && \
|
131
147
|
self.host[:host] == other.host[:host] && \
|
132
|
-
self.host[:port].to_i == other.host[:port].to_i
|
148
|
+
self.host[:port].to_i == other.host[:port].to_i && \
|
149
|
+
self.host[:attributes] == other.host[:attributes]
|
133
150
|
end
|
134
151
|
|
135
152
|
# @return [String]
|
@@ -138,7 +155,6 @@ module Elasticsearch
|
|
138
155
|
"<#{self.class.name} host: #{host} (#{dead? ? 'dead since ' + dead_since.to_s : 'alive'})>"
|
139
156
|
end
|
140
157
|
end
|
141
|
-
|
142
158
|
end
|
143
159
|
end
|
144
160
|
end
|
@@ -1,6 +1,19 @@
|
|
1
|
-
# Licensed to Elasticsearch B.V under one or more
|
2
|
-
#
|
3
|
-
#
|
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.
|
4
17
|
|
5
18
|
module Elasticsearch
|
6
19
|
module Transport
|
@@ -1,6 +1,19 @@
|
|
1
|
-
# Licensed to Elasticsearch B.V under one or more
|
2
|
-
#
|
3
|
-
#
|
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.
|
4
17
|
|
5
18
|
module Elasticsearch
|
6
19
|
module Transport
|
@@ -51,6 +64,7 @@ module Elasticsearch
|
|
51
64
|
418 => 'ImATeapot',
|
52
65
|
421 => 'TooManyConnectionsFromThisIP',
|
53
66
|
426 => 'UpgradeRequired',
|
67
|
+
429 => 'TooManyRequests',
|
54
68
|
450 => 'BlockedByWindowsParentalControls',
|
55
69
|
494 => 'RequestHeaderTooLarge',
|
56
70
|
497 => 'HTTPToHTTPS',
|
@@ -1,56 +1,82 @@
|
|
1
|
-
# Licensed to Elasticsearch B.V under one or more
|
2
|
-
#
|
3
|
-
#
|
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.
|
4
17
|
|
5
18
|
module Elasticsearch
|
6
19
|
module Transport
|
7
20
|
module Transport
|
8
21
|
module HTTP
|
9
|
-
|
10
22
|
# Alternative HTTP transport implementation, using the [_Curb_](https://rubygems.org/gems/curb) client.
|
11
23
|
#
|
12
24
|
# @see Transport::Base
|
13
25
|
#
|
14
26
|
class Curb
|
15
27
|
include Base
|
16
|
-
|
17
28
|
# Performs the request by invoking {Transport::Base#perform_request} with a block.
|
18
29
|
#
|
19
30
|
# @return [Response]
|
20
31
|
# @see Transport::Base#perform_request
|
21
32
|
#
|
22
33
|
def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
|
23
|
-
super do |connection,
|
34
|
+
super do |connection, _url|
|
24
35
|
connection.connection.url = connection.full_url(path, params)
|
36
|
+
body = body ? __convert_to_json(body) : nil
|
37
|
+
body, headers = compress_request(body, headers)
|
25
38
|
|
26
39
|
case method
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
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
|
40
52
|
end
|
41
|
-
|
42
|
-
|
53
|
+
end
|
54
|
+
else
|
55
|
+
raise ArgumentError, "Unsupported HTTP method: #{method}"
|
43
56
|
end
|
44
57
|
|
45
58
|
connection.connection.http(method.to_sym)
|
46
59
|
|
47
|
-
|
48
|
-
|
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?
|
49
71
|
|
50
|
-
|
51
|
-
|
52
|
-
|
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'
|
53
78
|
end
|
79
|
+
headers_hash
|
54
80
|
end
|
55
81
|
|
56
82
|
# Builds and returns a connection
|
@@ -59,9 +85,8 @@ module Elasticsearch
|
|
59
85
|
#
|
60
86
|
def __build_connection(host, options={}, block=nil)
|
61
87
|
client = ::Curl::Easy.new
|
62
|
-
|
63
88
|
apply_headers(client, options)
|
64
|
-
client.url
|
89
|
+
client.url = __full_url(host)
|
65
90
|
|
66
91
|
if host[:user]
|
67
92
|
client.http_auth_types = host[:auth_type] || :basic
|
@@ -93,13 +118,13 @@ module Elasticsearch
|
|
93
118
|
|
94
119
|
def user_agent_header(client)
|
95
120
|
@user_agent ||= begin
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
103
128
|
end
|
104
129
|
end
|
105
130
|
end
|
@@ -1,12 +1,24 @@
|
|
1
|
-
# Licensed to Elasticsearch B.V under one or more
|
2
|
-
#
|
3
|
-
#
|
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.
|
4
17
|
|
5
18
|
module Elasticsearch
|
6
19
|
module Transport
|
7
20
|
module Transport
|
8
21
|
module HTTP
|
9
|
-
|
10
22
|
# The default transport implementation, using the [_Faraday_](https://rubygems.org/gems/faraday)
|
11
23
|
# library for abstracting the HTTP client.
|
12
24
|
#
|
@@ -20,13 +32,24 @@ module Elasticsearch
|
|
20
32
|
# @return [Response]
|
21
33
|
# @see Transport::Base#perform_request
|
22
34
|
#
|
23
|
-
def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
|
35
|
+
def perform_request(method, path, params = {}, body = nil, headers = nil, opts = {})
|
24
36
|
super do |connection, url|
|
25
|
-
headers =
|
37
|
+
headers = if connection.connection.headers
|
38
|
+
if !headers.nil?
|
39
|
+
connection.connection.headers.merge(headers)
|
40
|
+
else
|
41
|
+
connection.connection.headers
|
42
|
+
end
|
43
|
+
else
|
44
|
+
headers
|
45
|
+
end
|
46
|
+
|
47
|
+
body = body ? __convert_to_json(body) : nil
|
48
|
+
body, headers = compress_request(body, headers)
|
26
49
|
|
27
50
|
response = connection.connection.run_request(method.downcase.to_sym,
|
28
51
|
url,
|
29
|
-
|
52
|
+
body,
|
30
53
|
headers)
|
31
54
|
|
32
55
|
Response.new response.status, decompress_response(response.body), response.headers
|
@@ -40,7 +63,7 @@ module Elasticsearch
|
|
40
63
|
def __build_connection(host, options={}, block=nil)
|
41
64
|
client = ::Faraday.new(__full_url(host), options, &block)
|
42
65
|
apply_headers(client, options)
|
43
|
-
Connections::Connection.new
|
66
|
+
Connections::Connection.new(host: host, connection: client)
|
44
67
|
end
|
45
68
|
|
46
69
|
# Returns an array of implementation specific connection errors.
|
@@ -48,7 +71,7 @@ module Elasticsearch
|
|
48
71
|
# @return [Array]
|
49
72
|
#
|
50
73
|
def host_unreachable_exceptions
|
51
|
-
[::Faraday::
|
74
|
+
[::Faraday::ConnectionFailed, ::Faraday::TimeoutError]
|
52
75
|
end
|
53
76
|
|
54
77
|
private
|