Skip to content

Commit 206d34e

Browse files
committed
[CLIENT] Meta header: Adds adapter detection
1 parent a9b6233 commit 206d34e

File tree

4 files changed

+165
-27
lines changed

4 files changed

+165
-27
lines changed

elasticsearch-transport/Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ if File.exist? File.expand_path('../../elasticsearch/elasticsearch.gemspec', __F
3232
gem 'elasticsearch', path: File.expand_path('../../elasticsearch', __FILE__), require: false
3333
end
3434

35-
group :development do
35+
group :development, :test do
3636
gem 'rspec'
3737
if defined?(JRUBY_VERSION)
3838
gem 'pry-nav'

elasticsearch-transport/lib/elasticsearch/transport/client.rb

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,10 @@ def initialize(arguments={}, &block)
139139
@arguments[:randomize_hosts] ||= false
140140
@arguments[:transport_options] ||= {}
141141
@arguments[:http] ||= {}
142-
@arguments[:enable_meta_header] ||= true
142+
@arguments[:enable_meta_header] = arguments.fetch(:enable_meta_header) { true }
143143
@options[:http] ||= {}
144144

145145
set_api_key if (@api_key = @arguments[:api_key])
146-
set_meta_header unless @arguments[:enable_meta_header] == false
147146

148147
@seeds = extract_cloud_creds(@arguments)
149148
@seeds ||= __extract_hosts(@arguments[:hosts] ||
@@ -163,15 +162,18 @@ def initialize(arguments={}, &block)
163162
if @arguments[:transport]
164163
@transport = @arguments[:transport]
165164
else
166-
transport_class = @arguments[:transport_class] || DEFAULT_TRANSPORT_CLASS
167-
if transport_class == Transport::HTTP::Faraday
168-
@transport = transport_class.new(hosts: @seeds, options: @arguments) do |faraday|
169-
faraday.adapter(@arguments[:adapter] || __auto_detect_adapter)
170-
block&.call faraday
171-
end
172-
else
173-
@transport = transport_class.new(hosts: @seeds, options: @arguments)
174-
end
165+
@transport_class = @arguments[:transport_class] || DEFAULT_TRANSPORT_CLASS
166+
@transport = if @transport_class == Transport::HTTP::Faraday
167+
@arguments[:adapter] ||= __auto_detect_adapter
168+
set_meta_header
169+
@transport_class.new(hosts: @seeds, options: @arguments) do |faraday|
170+
faraday.adapter(@arguments[:adapter])
171+
block&.call faraday
172+
end
173+
else
174+
set_meta_header
175+
@transport_class.new(hosts: @seeds, options: @arguments)
176+
end
175177
end
176178
end
177179

@@ -205,12 +207,16 @@ def add_header(header)
205207
end
206208

207209
def set_meta_header
210+
return if @arguments[:enable_meta_header] == false
211+
208212
meta_headers = {
209-
es: Elasticsearch::VERSION,
213+
es: Elasticsearch::VERSION, # TODO - es|ent
210214
rb: RUBY_VERSION,
211215
t: Elasticsearch::Transport::VERSION
212216
}
213217
meta_headers.merge!(meta_header_engine) if meta_header_engine
218+
meta_headers.merge!(meta_header_adapter) if meta_header_adapter
219+
214220
add_header({ 'x-elastic-client-meta' => meta_headers.map { |k, v| "#{k}=#{v}" }.join(',') })
215221
end
216222

@@ -227,6 +233,29 @@ def meta_header_engine
227233
end
228234
end
229235

236+
def meta_header_adapter
237+
if @transport_class == Transport::HTTP::Faraday
238+
{fd: Faraday::VERSION}.merge(
239+
case @arguments[:adapter]
240+
when :patron
241+
{pt: Patron::VERSION}
242+
when :net_http
243+
{nh: defined?(Net::HTTP::VERSION) ? Net::HTTP::VERSION : Net::HTTP::HTTPVersion}
244+
when :typhoeus
245+
{ty: Typhoeus::VERSION}
246+
when :httpclient
247+
{hc: HTTPClient::VERSION}
248+
when :net_http_persistent
249+
{np: Net::HTTP::Persistent::VERSION}
250+
end
251+
)
252+
elsif defined?(Transport::HTTP::Curb) && @transport_class == Transport::HTTP::Curb
253+
{cl: Curl::CURB_VERSION}
254+
elsif defined?(Transport::HTTP::Manticore) && @transport_class == Transport::HTTP::Manticore
255+
{mc: Manticore::VERSION}
256+
end
257+
end
258+
230259
def extract_cloud_creds(arguments)
231260
return unless arguments[:cloud_id] && !arguments[:cloud_id].empty?
232261

elasticsearch-transport/spec/elasticsearch/transport/client_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@
246246
end
247247

248248
let(:client) do
249-
described_class.new(adapter: :patron)
249+
described_class.new(adapter: :patron, enable_meta_header: false)
250250
end
251251

252252
it 'uses Faraday with the adapter' do
@@ -260,7 +260,7 @@
260260
end
261261

262262
let(:client) do
263-
described_class.new(adapter: :typhoeus)
263+
described_class.new(adapter: :typhoeus, enable_meta_header: false)
264264
end
265265

266266
it 'uses Faraday with the adapter' do
@@ -274,7 +274,7 @@
274274
end
275275

276276
let(:client) do
277-
described_class.new('adapter' => :patron)
277+
described_class.new(adapter: :patron, enable_meta_header: false)
278278
end
279279

280280
it 'uses Faraday with the adapter' do
@@ -1684,7 +1684,7 @@
16841684
context 'when using the HTTPClient adapter' do
16851685

16861686
let(:client) do
1687-
described_class.new(hosts: ELASTICSEARCH_HOSTS, compression: true, adapter: :httpclient)
1687+
described_class.new(hosts: ELASTICSEARCH_HOSTS, compression: true, adapter: :httpclient, enable_meta_header: false)
16881688
end
16891689

16901690
it 'compresses the request and decompresses the response' do

elasticsearch-transport/spec/elasticsearch/transport/meta_header_spec.rb

Lines changed: 119 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,25 @@
1919

2020
describe Elasticsearch::Transport::Client do
2121
context 'meta-header' do
22-
let(:client) do
23-
described_class.new.tap do |klient|
24-
allow(klient).to receive(:__build_connections)
25-
end
26-
end
2722
let(:subject) { client.transport.connections.first.connection.headers }
2823
let(:regexp) { /^[a-z]{1,}=[a-z0-9.\-]{1,}(?:,[a-z]{1,}=[a-z0-9.\-]+)*$/ }
24+
let(:adapter) { :net_http }
25+
let(:adapter_code) { "nh=#{defined?(Net::HTTP::VERSION) ? Net::HTTP::VERSION : Net::HTTP::HTTPVersion}" }
2926
let(:meta_header) do
3027
if RUBY_ENGINE == 'jruby'
31-
"es=#{Elasticsearch::VERSION},rb=#{RUBY_VERSION},t=#{Elasticsearch::Transport::VERSION},jr=#{JRUBY_VERSION}"
28+
"es=#{Elasticsearch::VERSION},rb=#{RUBY_VERSION},t=#{Elasticsearch::Transport::VERSION},jr=#{JRUBY_VERSION},fd=#{Faraday::VERSION},#{adapter_code}"
3229
else
33-
"es=#{Elasticsearch::VERSION},rb=#{RUBY_VERSION},t=#{Elasticsearch::Transport::VERSION}"
30+
"es=#{Elasticsearch::VERSION},rb=#{RUBY_VERSION},t=#{Elasticsearch::Transport::VERSION},fd=#{Faraday::VERSION},#{adapter_code}"
3431
end
3532
end
3633

3734
context 'single use of meta header' do
35+
let(:client) do
36+
described_class.new(adapter: adapter).tap do |klient|
37+
allow(klient).to receive(:__build_connections)
38+
end
39+
end
40+
3841
it 'x-elastic-client-header value matches regexp' do
3942
expect(subject['x-elastic-client-meta']).to match(regexp)
4043
expect(subject).to include('x-elastic-client-meta' => meta_header)
@@ -44,29 +47,135 @@
4447
context 'when using user-agent headers' do
4548
let(:client) do
4649
transport_options = { headers: { user_agent: 'My Ruby App' } }
47-
described_class.new(transport_options: transport_options).tap do |klient|
50+
described_class.new(transport_options: transport_options, adapter: adapter).tap do |klient|
4851
allow(klient).to receive(:__build_connections)
4952
end
5053
end
5154

5255
it 'is friendly to previously set headers' do
5356
expect(subject).to include(user_agent: 'My Ruby App')
57+
expect(subject['x-elastic-client-meta']).to match(regexp)
5458
expect(subject).to include('x-elastic-client-meta' => meta_header)
5559
end
5660
end
5761

5862
context 'when using API Key' do
5963
let(:client) do
60-
described_class.new(api_key: 'an_api_key')
64+
described_class.new(api_key: 'an_api_key', adapter: adapter)
6165
end
6266

6367
let(:authorization_header) do
6468
client.transport.connections.first.connection.headers['Authorization']
6569
end
6670

67-
it 'Adds the ApiKey header to the connection' do
71+
it 'adds the ApiKey header to the connection' do
6872
expect(authorization_header).to eq('ApiKey an_api_key')
6973
expect(subject['x-elastic-client-meta']).to match(regexp)
74+
expect(subject).to include('x-elastic-client-meta' => meta_header)
75+
end
76+
end
77+
78+
context 'adapters' do
79+
let(:meta_header) do
80+
if RUBY_ENGINE == 'jruby'
81+
"es=#{Elasticsearch::VERSION},rb=#{RUBY_VERSION},t=#{Elasticsearch::Transport::VERSION},jr=#{JRUBY_VERSION},fd=#{Faraday::VERSION}"
82+
else
83+
"es=#{Elasticsearch::VERSION},rb=#{RUBY_VERSION},t=#{Elasticsearch::Transport::VERSION},fd=#{Faraday::VERSION}"
84+
end
85+
end
86+
let(:client) { described_class.new(adapter: adapter) }
87+
let(:headers) { client.transport.connections.first.connection.headers }
88+
89+
context 'using net/http/persistent' do
90+
let(:adapter) { :net_http_persistent }
91+
92+
it 'sets adapter in the meta header' do
93+
require 'net/http/persistent'
94+
expect(headers['x-elastic-client-meta']).to match(regexp)
95+
meta = "#{meta_header},np=#{Net::HTTP::Persistent::VERSION}"
96+
expect(headers).to include('x-elastic-client-meta' => meta)
97+
end
98+
end
99+
100+
context 'using httpclient' do
101+
let(:adapter) { :httpclient }
102+
103+
it 'sets adapter in the meta header' do
104+
require 'httpclient'
105+
expect(headers['x-elastic-client-meta']).to match(regexp)
106+
meta = "#{meta_header},hc=#{HTTPClient::VERSION}"
107+
expect(headers).to include('x-elastic-client-meta' => meta)
108+
end
109+
end
110+
111+
context 'using typhoeus' do
112+
let(:adapter) { :typhoeus }
113+
114+
it 'sets adapter in the meta header' do
115+
require 'typhoeus'
116+
expect(headers['x-elastic-client-meta']).to match(regexp)
117+
meta = "#{meta_header},ty=#{Typhoeus::VERSION}"
118+
expect(headers).to include('x-elastic-client-meta' => meta)
119+
end
120+
end
121+
122+
unless defined?(JRUBY_VERSION)
123+
let(:adapter) { :patron }
124+
125+
context 'using patron' do
126+
it 'sets adapter in the meta header' do
127+
require 'patron'
128+
expect(headers['x-elastic-client-meta']).to match(regexp)
129+
meta = "#{meta_header},pt=#{Patron::VERSION}"
130+
expect(headers).to include('x-elastic-client-meta' => meta)
131+
end
132+
end
133+
end
134+
end
135+
136+
if defined?(JRUBY_VERSION)
137+
context 'when using manticore' do
138+
let(:client) do
139+
Elasticsearch::Client.new(transport_class: Elasticsearch::Transport::Transport::HTTP::Manticore)
140+
end
141+
let(:subject) { client.transport.connections.first.connection.instance_variable_get("@options")[:headers]}
142+
143+
it 'sets manticore in the metaheader' do
144+
expect(subject['x-elastic-client-meta']).to match(regexp)
145+
expect(subject['x-elastic-client-meta']).to match(/mc=[0-9.]+/)
146+
end
147+
end
148+
else
149+
context 'when using curb' do
150+
let(:client) do
151+
Elasticsearch::Client.new(transport_class: Elasticsearch::Transport::Transport::HTTP::Curb)
152+
end
153+
154+
it 'sets curb in the metaheader' do
155+
expect(subject['x-elastic-client-meta']).to match(regexp)
156+
expect(subject['x-elastic-client-meta']).to match(/cl=[0-9.]+/)
157+
end
158+
end
159+
end
160+
161+
context 'when using custom transport implementation' do
162+
class MyTransport
163+
include Elasticsearch::Transport::Transport::Base
164+
def initialize(args); end
165+
end
166+
let(:client) { Elasticsearch::Client.new(transport_class: MyTransport) }
167+
let(:subject){ client.instance_variable_get("@arguments")[:transport_options][:headers] }
168+
let(:meta_header) do
169+
if RUBY_ENGINE == 'jruby'
170+
"es=#{Elasticsearch::VERSION},rb=#{RUBY_VERSION},t=#{Elasticsearch::Transport::VERSION},jr=#{JRUBY_VERSION}"
171+
else
172+
"es=#{Elasticsearch::VERSION},rb=#{RUBY_VERSION},t=#{Elasticsearch::Transport::VERSION}"
173+
end
174+
end
175+
176+
it 'doesnae set any info about the implementation in the metaheader' do
177+
expect(subject['x-elastic-client-meta']).to match(regexp)
178+
expect(subject).to include('x-elastic-client-meta' => meta_header)
70179
end
71180
end
72181
end

0 commit comments

Comments
 (0)