diff --git a/elasticsearch/Gemfile b/elasticsearch/Gemfile index 21c38fe23..9fd65ae5b 100644 --- a/elasticsearch/Gemfile +++ b/elasticsearch/Gemfile @@ -31,3 +31,6 @@ if ENV['TRANSPORT_VERSION'] == 'main' end gem 'opentelemetry-sdk', require: false if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0') +if defined?(JRUBY_VERSION) + gem 'manticore', platform: :jruby +end diff --git a/elasticsearch/lib/elasticsearch.rb b/elasticsearch/lib/elasticsearch.rb index 3bf2e7930..e27c79cd4 100644 --- a/elasticsearch/lib/elasticsearch.rb +++ b/elasticsearch/lib/elasticsearch.rb @@ -189,10 +189,10 @@ def set_user_agent!(arguments) def set_content_type!(arguments) headers = {} user_headers = arguments&.[](:transport_options)&.[](:headers) - unless user_headers&.keys&.detect { |h| h =~ /content-?_?type/ } + unless user_headers&.keys&.detect { |h| h =~ /content-?_?type/i } headers['content-type'] = 'application/vnd.elasticsearch+json; compatible-with=9' end - unless user_headers&.keys&.detect { |h| h =~ /accept/ } + unless user_headers&.keys&.detect { |h| h =~ /accept/i } headers['accept'] = 'application/vnd.elasticsearch+json; compatible-with=9' end set_header(headers, arguments) unless headers.empty? diff --git a/elasticsearch/spec/unit/headers_jruby_spec.rb b/elasticsearch/spec/unit/headers_jruby_spec.rb new file mode 100644 index 000000000..0255acf02 --- /dev/null +++ b/elasticsearch/spec/unit/headers_jruby_spec.rb @@ -0,0 +1,111 @@ +# 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. +return unless defined?(JRUBY_VERSION) + +require 'spec_helper' +require 'ostruct' + +describe Elasticsearch::Client do + context 'Using Manticore with JRuby' do + let(:client) do + require 'elastic/transport/transport/http/manticore' + described_class.new( + transport_class: Elastic::Transport::Transport::HTTP::Manticore, + transport_options: { headers: instance_headers } + ).tap do |client| + client.instance_variable_set('@verified', true) + end + end + + let(:client_headers) do + client.transport.connections.connections.first.connection.instance_variable_get('@options')[:headers] + end + + context 'when Content-Type header is used' do + let(:instance_headers) do + { 'Content-Type' => 'application/text' } + end + + it 'does not duplicate the content-type header' do + expect(client_headers['accept']).to eq 'application/vnd.elasticsearch+json; compatible-with=9' + expect(client_headers['content-type']).to be nil + expect(client_headers.fetch('Content-Type')).to eq 'application/text' + + expect_any_instance_of(Manticore::Client) + .to receive(:get).with( + 'http://localhost:9200/_search', + { headers: client_headers } + ) { OpenStruct.new(body: '') } + client.search + end + + context 'when content-type header is used' do + let(:instance_headers) do + { 'content-type' => 'application/text' } + end + + it 'does not duplicate the Content-Type header' do + expect(client_headers['accept']).to eq 'application/vnd.elasticsearch+json; compatible-with=9' + expect(client_headers['content-type']).to be nil + expect(client_headers.fetch('Content-Type')).to eq 'application/text' + + expect_any_instance_of(Manticore::Client) + .to receive(:get).with( + 'http://localhost:9200/_search', + { headers: client_headers } + ) { OpenStruct.new(body: '') } + client.search + end + end + + context 'when Content-Type is set in request' do + let(:instance_headers) do + { 'Content-Type' => 'instance_headers' } + end + let(:request_headers) { { 'Content-Type' => 'request headers' } } + + it 'does not duplicate content-type headers' do + expect_any_instance_of(Manticore::Client) + .to receive(:get).with( + 'http://localhost:9200/_search', + { headers: client_headers.merge(request_headers) } + ) { OpenStruct.new(body: '') } + client.search(headers: request_headers) + puts client_headers.merge(request_headers) + end + end + + context 'when content-type is set in request' do + let(:instance_headers) do + { 'Content-Type' => 'instance_headers' } + end + let(:request_headers) { { 'content-type' => 'request headers' } } + + it 'does not duplicate content-type headers' do + expect_any_instance_of(Manticore::Client) + .to receive(:get).with( + 'http://localhost:9200/_search', + { headers: client_headers.merge(request_headers) } + ) { OpenStruct.new(body: '') } + client.search(headers: request_headers) + puts client_headers.merge(request_headers) + + end + end + end + end +end diff --git a/elasticsearch/spec/unit/headers_spec.rb b/elasticsearch/spec/unit/headers_spec.rb index 3751c7448..a6155032d 100644 --- a/elasticsearch/spec/unit/headers_spec.rb +++ b/elasticsearch/spec/unit/headers_spec.rb @@ -73,20 +73,18 @@ expect_any_instance_of(Faraday::Connection) .to receive(:run_request) - .with(:get, 'http://localhost:9200/_search', nil, connection_headers) { OpenStruct.new(body: '') } + .with(:get, 'http://localhost:9200/_search', nil, connection_headers) { OpenStruct.new(body: '') } client.search end end context 'when content-type header is changed' do let!(:client) do - described_class.new( - host: 'http://localhost:9200', - transport_options: { headers: instance_headers } - ).tap do |client| + described_class.new(transport_options: { headers: instance_headers }).tap do |client| client.instance_variable_set('@verified', true) end end + let(:instance_headers) do { content_type: 'application/json' } end @@ -98,7 +96,30 @@ expect_any_instance_of(Faraday::Connection) .to receive(:run_request) - .with(:get, 'http://localhost:9200/_search', nil, connection_headers) { OpenStruct.new(body: '') } + .with(:get, 'http://localhost:9200/_search', nil, connection_headers) { OpenStruct.new(body: '') } + client.search + end + end + + context 'when Content-Type header is used' do + let(:client) do + described_class.new(transport_options: { headers: instance_headers }).tap do |client| + client.instance_variable_set('@verified', true) + end + end + + let(:instance_headers) do + { 'Content-Type' => 'application/text' } + end + + it 'performs the request with the header' do + connection_headers = client.transport.connections.connections.first.connection.headers + expect(connection_headers['Accept']).to eq 'application/vnd.elasticsearch+json; compatible-with=9' + expect(connection_headers['Content-Type']).to eq 'application/text' + + expect_any_instance_of(Faraday::Connection) + .to receive(:run_request) + .with(:get, 'http://localhost:9200/_search', nil, connection_headers) { OpenStruct.new(body: '') } client.search end end @@ -117,7 +138,7 @@ expect_any_instance_of(Faraday::Connection) .to receive(:run_request) - .with(:get, 'http://localhost:9200/_search', nil, expected_headers) { OpenStruct.new(body: '') } + .with(:get, 'http://localhost:9200/_search', nil, expected_headers) { OpenStruct.new(body: '') } client.search end end