Skip to content

Commit

Permalink
Refactors Meta Header
Browse files Browse the repository at this point in the history
- Extracts meta header related code into a module
- Adds more tests for specific situations when http libraries haven't been loaded by the time the meta header methods are called

Related to #1224
  • Loading branch information
picandocodigo committed Mar 25, 2021
1 parent fe4facb commit eb3b1f5
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 76 deletions.
78 changes: 4 additions & 74 deletions elasticsearch-transport/lib/elasticsearch/transport/client.rb
Expand Up @@ -16,6 +16,7 @@
# under the License.

require 'base64'
require 'elasticsearch/transport/meta_header'

module Elasticsearch
module Transport
Expand All @@ -25,6 +26,7 @@ module Transport
#
class Client
DEFAULT_TRANSPORT_CLASS = Transport::HTTP::Faraday
include MetaHeader

DEFAULT_LOGGER = lambda do
require 'logger'
Expand Down Expand Up @@ -163,13 +165,13 @@ def initialize(arguments = {}, &block)
@transport_class = @arguments[:transport_class] || DEFAULT_TRANSPORT_CLASS
@transport = if @transport_class == Transport::HTTP::Faraday
@arguments[:adapter] ||= __auto_detect_adapter
set_meta_header
set_meta_header # from include MetaHeader
@transport_class.new(hosts: @seeds, options: @arguments) do |faraday|
faraday.adapter(@arguments[:adapter])
block&.call faraday
end
else
set_meta_header
set_meta_header # from include MetaHeader
@transport_class.new(hosts: @seeds, options: @arguments)
end
end
Expand Down Expand Up @@ -204,78 +206,6 @@ def add_header(header)
)
end

def set_meta_header
return if @arguments[:enable_meta_header] == false

service, version = meta_header_service_version

meta_headers = {
service.to_sym => version,
rb: RUBY_VERSION,
t: Elasticsearch::Transport::VERSION
}
meta_headers.merge!(meta_header_engine) if meta_header_engine
meta_headers.merge!(meta_header_adapter) if meta_header_adapter

add_header({ 'x-elastic-client-meta' => meta_headers.map { |k, v| "#{k}=#{v}" }.join(',') })
end

def meta_header_service_version
if defined?(Elastic::META_HEADER_SERVICE_VERSION)
Elastic::META_HEADER_SERVICE_VERSION
elsif defined?(Elasticsearch::VERSION)
[:es, client_meta_version(Elasticsearch::VERSION)]
else
[:es, client_meta_version(Elasticsearch::Transport::VERSION)]
end
end

def client_meta_version(version)
regexp = /^([0-9]+\.[0-9]+\.[0-9]+)(\.?[a-z0-9.-]+)?$/
match = version.match(regexp)
return "#{match[1]}p" if (match[2])

version
end

def meta_header_engine
case RUBY_ENGINE
when 'ruby'
{}
when 'jruby'
{ jv: ENV_JAVA['java.version'], jr: JRUBY_VERSION }
when 'rbx'
{ rbx: RUBY_VERSION }
else
{ RUBY_ENGINE.to_sym => RUBY_VERSION }
end
end

def meta_header_adapter
if @transport_class == Transport::HTTP::Faraday
{fd: Faraday::VERSION}.merge(
case @arguments[:adapter]
when :patron
{pt: Patron::VERSION}
when :net_http
{nh: defined?(Net::HTTP::VERSION) ? Net::HTTP::VERSION : Net::HTTP::HTTPVersion}
when :typhoeus
{ty: Typhoeus::VERSION}
when :httpclient
{hc: HTTPClient::VERSION}
when :net_http_persistent
{np: Net::HTTP::Persistent::VERSION}
else
{}
end
)
elsif defined?(Transport::HTTP::Curb) && @transport_class == Transport::HTTP::Curb
{cl: Curl::CURB_VERSION}
elsif defined?(Transport::HTTP::Manticore) && @transport_class == Transport::HTTP::Manticore
{mc: Manticore::VERSION}
end
end

def extract_cloud_creds(arguments)
return unless arguments[:cloud_id] && !arguments[:cloud_id].empty?

Expand Down
120 changes: 120 additions & 0 deletions elasticsearch-transport/lib/elasticsearch/transport/meta_header.rb
@@ -0,0 +1,120 @@
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

require 'base64'

module Elasticsearch
module Transport

# Methods for the Elastic meta header used by Cloud.
# X-Elastic-Client-Meta HTTP header which is used by Elastic Cloud and can be disabled when
# instantiating the Client with the :enable_meta_header parameter set to `false`.
#
module MetaHeader
def set_meta_header
return if @arguments[:enable_meta_header] == false

service, version = meta_header_service_version

meta_headers = {
service.to_sym => version,
rb: RUBY_VERSION,
t: Elasticsearch::Transport::VERSION
}
meta_headers.merge!(meta_header_engine) if meta_header_engine
meta_headers.merge!(meta_header_adapter) if meta_header_adapter

add_header({ 'x-elastic-client-meta' => meta_headers.map { |k, v| "#{k}=#{v}" }.join(',') })
end

def meta_header_service_version
if defined?(Elastic::META_HEADER_SERVICE_VERSION)
Elastic::META_HEADER_SERVICE_VERSION
elsif defined?(Elasticsearch::VERSION)
[:es, client_meta_version(Elasticsearch::VERSION)]
else
[:es, client_meta_version(Elasticsearch::Transport::VERSION)]
end
end

# We return the current version if it's a release, but if it's a pre/alpha/beta release we
# return <VERSION_NUMBER>p
#
def client_meta_version(version)
regexp = /^([0-9]+\.[0-9]+\.[0-9]+)(\.?[a-z0-9.-]+)?$/
match = version.match(regexp)
return "#{match[1]}p" if (match[2])

version
end

def meta_header_engine
case RUBY_ENGINE
when 'ruby'
{}
when 'jruby'
{ jv: ENV_JAVA['java.version'], jr: JRUBY_VERSION }
when 'rbx'
{ rbx: RUBY_VERSION }
else
{ RUBY_ENGINE.to_sym => RUBY_VERSION }
end
end

# This function tries to define the version for the Faraday adapter. If it hasn't been loaded
# by the time we're calling this method, it's going to report the adapter (if we know it) but
# return 0 as the version. It won't report anything when using a custom adapter we don't
# identify.
#
# Returns a Hash<adapter_alias, version>
#
def meta_header_adapter
if @transport_class == Transport::HTTP::Faraday
version = '0'
adapter_version = case @arguments[:adapter]
when :patron
version = Patron::VERSION if defined?(::Patron::VERSION)
{pt: version}
when :net_http
version = if defined?(Net::HTTP::VERSION)
Net::HTTP::VERSION
elsif defined?(Net::HTTP::HTTPVersion)
Net::HTTP::HTTPVersion
end
{nh: version}
when :typhoeus
version = Typhoeus::VERSION if defined?(::Typhoeus::VERSION)
{ty: version}
when :httpclient
version = HTTPClient::VERSION if defined?(HTTPClient::VERSION)
{hc: version}
when :net_http_persistent
version = Net::HTTP::Persistent::VERSION if defined?(Net::HTTP::Persistent::VERSION)
{np: version}
else
{}
end
{fd: Faraday::VERSION}.merge(adapter_version)
elsif defined?(Transport::HTTP::Curb) && @transport_class == Transport::HTTP::Curb
{cl: Curl::CURB_VERSION}
elsif defined?(Transport::HTTP::Manticore) && @transport_class == Transport::HTTP::Manticore
{mc: Manticore::VERSION}
end
end
end
end
end
Expand Up @@ -32,7 +32,7 @@
end
end

context 'client_meta_version_' do
context 'client_meta_version' do
let(:version) { ['7.1.0-alpha', '7.11.0.pre.1', '8.0.0-beta', '8.0.0.beta.2']}

it 'converts the version to X.X.Xp' do
Expand Down Expand Up @@ -108,6 +108,14 @@ def meta_version
context 'using net/http/persistent' do
let(:adapter) { :net_http_persistent }

it 'sets adapter in the meta header version to 0 when not loaded' do
fork {
expect(headers['x-elastic-client-meta']).to match(regexp)
meta = "#{meta_header},np=0"
expect(headers).to include('x-elastic-client-meta' => meta)
}
end unless jruby?

it 'sets adapter in the meta header' do
require 'net/http/persistent'
expect(headers['x-elastic-client-meta']).to match(regexp)
Expand All @@ -119,6 +127,14 @@ def meta_version
context 'using httpclient' do
let(:adapter) { :httpclient }

it 'sets adapter in the meta header version to 0 when not loaded' do
fork {
expect(headers['x-elastic-client-meta']).to match(regexp)
meta = "#{meta_header},hc=0"
expect(headers).to include('x-elastic-client-meta' => meta)
}
end unless jruby?

it 'sets adapter in the meta header' do
require 'httpclient'
expect(headers['x-elastic-client-meta']).to match(regexp)
Expand All @@ -130,6 +146,14 @@ def meta_version
context 'using typhoeus' do
let(:adapter) { :typhoeus }

it 'sets adapter in the meta header version to 0 when not loaded' do
fork {
expect(headers['x-elastic-client-meta']).to match(regexp)
meta = "#{meta_header},ty=0"
expect(headers).to include('x-elastic-client-meta' => meta)
}
end unless jruby?

it 'sets adapter in the meta header' do
require 'typhoeus'
expect(headers['x-elastic-client-meta']).to match(regexp)
Expand All @@ -138,9 +162,19 @@ def meta_version
end
end

unless defined?(JRUBY_VERSION)
unless jruby?
let(:adapter) { :patron }

context 'using patron without requiring it' do
it 'sets adapter in the meta header version to 0 when not loaded' do
fork {
expect(headers['x-elastic-client-meta']).to match(regexp)
meta = "#{meta_header},pt=0"
expect(headers).to include('x-elastic-client-meta' => meta)
}
end
end

context 'using patron' do
it 'sets adapter in the meta header' do
require 'patron'
Expand All @@ -154,6 +188,12 @@ def meta_version
context 'using other' do
let(:adapter) { :some_other_adapter }

it 'sets adapter in the meta header without requiring' do
Faraday::Adapter.register_middleware some_other_adapter: Faraday::Adapter::NetHttpPersistent
expect(headers['x-elastic-client-meta']).to match(regexp)
expect(headers).to include('x-elastic-client-meta' => meta_header)
end

it 'sets adapter in the meta header' do
require 'net/http/persistent'
Faraday::Adapter.register_middleware some_other_adapter: Faraday::Adapter::NetHttpPersistent
Expand Down

0 comments on commit eb3b1f5

Please sign in to comment.