diff --git a/elasticsearch-transport/lib/elasticsearch/transport/client.rb b/elasticsearch-transport/lib/elasticsearch/transport/client.rb index 40b5481d13..12885aab65 100644 --- a/elasticsearch-transport/lib/elasticsearch/transport/client.rb +++ b/elasticsearch-transport/lib/elasticsearch/transport/client.rb @@ -16,6 +16,7 @@ # under the License. require 'base64' +require 'elasticsearch/transport/meta_header' module Elasticsearch module Transport @@ -25,6 +26,7 @@ module Transport # class Client DEFAULT_TRANSPORT_CLASS = Transport::HTTP::Faraday + include MetaHeader DEFAULT_LOGGER = lambda do require 'logger' @@ -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 @@ -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? diff --git a/elasticsearch-transport/lib/elasticsearch/transport/meta_header.rb b/elasticsearch-transport/lib/elasticsearch/transport/meta_header.rb new file mode 100644 index 0000000000..8bf0b3606d --- /dev/null +++ b/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 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 + # + 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 diff --git a/elasticsearch-transport/spec/elasticsearch/transport/meta_header_spec.rb b/elasticsearch-transport/spec/elasticsearch/transport/meta_header_spec.rb index 8b3dd336bc..d423d7837f 100644 --- a/elasticsearch-transport/spec/elasticsearch/transport/meta_header_spec.rb +++ b/elasticsearch-transport/spec/elasticsearch/transport/meta_header_spec.rb @@ -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 @@ -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) @@ -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) @@ -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) @@ -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' @@ -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