Use custom HttpHeaders.

Original Pull Request #2278
Closes #2277
This commit is contained in:
Peter-Josef Meisch 2022-08-24 13:10:27 +02:00 committed by GitHub
parent 18be558740
commit 3298ba21ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 352 additions and 64 deletions

View File

@ -26,7 +26,7 @@ import java.util.function.Supplier;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.springframework.http.HttpHeaders;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.web.reactive.function.client.WebClient;

View File

@ -22,7 +22,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
@ -31,7 +30,7 @@ import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
import org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithRequiredEndpoint;
import org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder;
import org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder;
import org.springframework.http.HttpHeaders;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.client.WebClient;
@ -50,7 +49,7 @@ class ClientConfigurationBuilder
implements ClientConfigurationBuilderWithRequiredEndpoint, MaybeSecureClientConfigurationBuilder {
private final List<InetSocketAddress> hosts = new ArrayList<>();
private HttpHeaders headers = HttpHeaders.EMPTY;
private HttpHeaders headers = new HttpHeaders();
private boolean useSsl;
private @Nullable SSLContext sslContext;
private @Nullable HostnameVerifier hostnameVerifier;
@ -60,10 +59,10 @@ class ClientConfigurationBuilder
private @Nullable String password;
private @Nullable String pathPrefix;
private @Nullable String proxy;
private Function<WebClient, WebClient> webClientConfigurer = Function.identity();
private Supplier<HttpHeaders> headersSupplier = () -> HttpHeaders.EMPTY;
@Deprecated private HttpClientConfigCallback httpClientConfigurer = httpClientBuilder -> httpClientBuilder;
private List<ClientConfiguration.ClientConfigurationCallback<?>> clientConfigurers = new ArrayList<>();
private final Function<WebClient, WebClient> webClientConfigurer = Function.identity();
private Supplier<HttpHeaders> headersSupplier = HttpHeaders::new;
@Deprecated private final HttpClientConfigCallback httpClientConfigurer = httpClientBuilder -> httpClientBuilder;
private final List<ClientConfiguration.ClientConfigurationCallback<?>> clientConfigurers = new ArrayList<>();
/*
* (non-Javadoc)
@ -74,7 +73,7 @@ class ClientConfigurationBuilder
Assert.notEmpty(hostAndPorts, "At least one host is required");
this.hosts.addAll(Arrays.stream(hostAndPorts).map(ClientConfigurationBuilder::parse).collect(Collectors.toList()));
this.hosts.addAll(Arrays.stream(hostAndPorts).map(ClientConfigurationBuilder::parse).toList());
return this;
}
@ -227,9 +226,6 @@ class ClientConfigurationBuilder
public ClientConfiguration build() {
if (username != null && password != null) {
if (HttpHeaders.EMPTY.equals(headers)) {
headers = new HttpHeaders();
}
headers.setBasicAuth(username, password);
}

View File

@ -19,8 +19,6 @@ import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
@ -127,10 +125,10 @@ public abstract class ClientLogger {
* @param logId the correlation id, see {@link #newLogId()}.
* @param statusCode the HTTP status code.
*/
public static void logRawResponse(String logId, @Nullable HttpStatusCode statusCode) {
public static void logRawResponse(String logId, @Nullable Integer statusCode) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Received raw response: %s", logId, statusCode));
WIRE_LOGGER.trace(String.format("[%s] Received raw response: %d", logId, statusCode));
}
}
@ -141,10 +139,10 @@ public abstract class ClientLogger {
* @param statusCode the HTTP status code.
* @param headers a String containing the headers
*/
public static void logRawResponse(String logId, @Nullable HttpStatus statusCode, String headers) {
public static void logRawResponse(String logId, @Nullable Integer statusCode, String headers) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Received response: %s%n%s", logId, statusCode, headers));
WIRE_LOGGER.trace(String.format("[%s] Received response: %d%n%s", logId, statusCode, headers));
}
}
@ -155,10 +153,10 @@ public abstract class ClientLogger {
* @param statusCode the HTTP status code.
* @param body body content.
*/
public static void logResponse(String logId, HttpStatusCode statusCode, String body) {
public static void logResponse(String logId, Integer statusCode, String body) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Received response: %s%nResponse body: %s", logId, statusCode, body));
WIRE_LOGGER.trace(String.format("[%s] Received response: %d%nResponse body: %s", logId, statusCode, body));
}
}
@ -171,10 +169,10 @@ public abstract class ClientLogger {
* @param body body content.
* @since 4.4
*/
public static void logResponse(String logId, @Nullable HttpStatus statusCode, String headers, String body) {
public static void logResponse(String logId, @Nullable Integer statusCode, String headers, String body) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Received response: %s%nHeaders: %s%nResponse body: %s", logId, statusCode,
WIRE_LOGGER.trace(String.format("[%s] Received response: %d%nHeaders: %s%nResponse body: %s", logId, statusCode,
headers, body));
}
}

View File

@ -26,7 +26,7 @@ import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
import org.springframework.http.HttpHeaders;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.web.reactive.function.client.WebClient;
@ -62,7 +62,7 @@ class DefaultClientConfiguration implements ClientConfiguration {
List<ClientConfigurationCallback<?>> clientConfigurers, Supplier<HttpHeaders> headersSupplier) {
this.hosts = List.copyOf(hosts);
this.headers = new HttpHeaders(headers);
this.headers = headers;
this.useSsl = useSsl;
this.sslContext = sslContext;
this.soTimeout = soTimeout;
@ -127,7 +127,6 @@ class DefaultClientConfiguration implements ClientConfiguration {
return webClientConfigurer;
}
@SuppressWarnings("unchecked")
@Override
public <T> List<ClientConfigurationCallback<?>> getClientConfigurers() {
return clientConfigurers;

View File

@ -52,8 +52,7 @@ import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.ClientLogger;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -336,7 +335,7 @@ public final class ElasticsearchClients {
// no way of logging the body, in this callback, it is not read yset, later there is no callback possibility in
// RestClient or RestClientTransport
ClientLogger.logRawResponse(logId, HttpStatus.resolve(response.getStatusLine().getStatusCode()), headers);
ClientLogger.logRawResponse(logId, response.getStatusLine().getStatusCode(), headers);
}
}
@ -357,7 +356,7 @@ public final class ElasticsearchClients {
public void process(HttpRequest request, HttpContext context) {
HttpHeaders httpHeaders = headersSupplier.get();
if (httpHeaders != null && httpHeaders != HttpHeaders.EMPTY) {
if (httpHeaders != null && !httpHeaders.isEmpty()) {
Arrays.stream(toHeaderArray(httpHeaders)).forEach(request::addHeader);
}
}

View File

@ -31,7 +31,6 @@ import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.http.HttpStatus;
/**
* Simple {@link PersistenceExceptionTranslator} for Elasticsearch. Convert the given runtime exception to an
@ -76,8 +75,7 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
ErrorResponse response = elasticsearchException.response();
if (response.status() == HttpStatus.NOT_FOUND.value()
&& "index_not_found_exception".equals(response.error().type())) {
if (response.status() == 404 && "index_not_found_exception".equals(response.error().type())) {
// noinspection RegExpRedundantEscape
Pattern pattern = Pattern.compile(".*no such index \\[(.*)\\]");

View File

@ -139,7 +139,7 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
private final HostProvider<?> hostProvider;
private final RequestCreator requestCreator;
private Supplier<HttpHeaders> headersSupplier = () -> HttpHeaders.EMPTY;
private Supplier<org.springframework.data.elasticsearch.support.HttpHeaders> headersSupplier = org.springframework.data.elasticsearch.support.HttpHeaders::new;
/**
* Create a new {@link DefaultReactiveElasticsearchClient} using the given {@link HostProvider} to obtain server
@ -181,8 +181,10 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
Assert.notNull(headers, "HttpHeaders must not be null");
Assert.notEmpty(hosts, "Elasticsearch Cluster needs to consist of at least one host");
var httpHeaders = new org.springframework.data.elasticsearch.support.HttpHeaders();
httpHeaders.addAll(headers);
ClientConfiguration clientConfiguration = ClientConfiguration.builder().connectedTo(hosts)
.withDefaultHeaders(headers).build();
.withDefaultHeaders(httpHeaders).build();
return create(clientConfiguration);
}
@ -226,7 +228,7 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
return client;
}
public void setHeadersSupplier(Supplier<HttpHeaders> headersSupplier) {
public void setHeadersSupplier(Supplier<org.springframework.data.elasticsearch.support.HttpHeaders> headersSupplier) {
Assert.notNull(headersSupplier, "headersSupplier must not be null");
@ -716,25 +718,25 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
if (RawActionResponse.class.equals(responseType)) {
ClientLogger.logRawResponse(logId, response.statusCode());
ClientLogger.logRawResponse(logId, response.statusCode().value());
return Mono.just(responseType.cast(RawActionResponse.create(response)));
}
if (response.statusCode().is5xxServerError()) {
ClientLogger.logRawResponse(logId, response.statusCode());
ClientLogger.logRawResponse(logId, response.statusCode().value());
return handleServerError(request, response);
}
if (response.statusCode().is4xxClientError()) {
ClientLogger.logRawResponse(logId, response.statusCode());
ClientLogger.logRawResponse(logId, response.statusCode().value());
return handleClientError(logId, response, responseType);
}
return response.body(BodyExtractors.toMono(byte[].class)) //
.map(it -> new String(it, StandardCharsets.UTF_8)) //
.doOnNext(it -> ClientLogger.logResponse(logId, response.statusCode(), it)) //
.doOnNext(it -> ClientLogger.logResponse(logId, response.statusCode().value(), it)) //
.flatMap(content -> doDecode(response, responseType, content));
}
@ -811,7 +813,7 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
return response.body(BodyExtractors.toMono(byte[].class)) //
.map(bytes -> new String(bytes, StandardCharsets.UTF_8)) //
.flatMap(content -> contentOrError(content, mediaType, status)) //
.doOnNext(content -> ClientLogger.logResponse(logId, response.statusCode(), content)) //
.doOnNext(content -> ClientLogger.logResponse(logId, response.statusCode().value(), content)) //
.flatMap(content -> doDecode(response, responseType, content));
}

View File

@ -24,7 +24,7 @@ import java.util.function.Supplier;
import org.springframework.data.elasticsearch.client.ElasticsearchHost;
import org.springframework.data.elasticsearch.client.NoReachableHostException;
import org.springframework.http.HttpHeaders;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.client.WebClient;

View File

@ -46,8 +46,7 @@ import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.RestHighLevelClientBuilder;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.ClientLogger;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.util.Assert;
/**
@ -219,7 +218,7 @@ public final class RestClients {
@Override
public void process(HttpResponse response, HttpContext context) {
String logId = (String) context.getAttribute(RestClients.LOG_ID_ATTRIBUTE);
ClientLogger.logRawResponse(logId, HttpStatus.resolve(response.getStatusLine().getStatusCode()));
ClientLogger.logRawResponse(logId, response.getStatusLine().getStatusCode());
}
}
@ -240,7 +239,7 @@ public final class RestClients {
public void process(HttpRequest request, HttpContext context) {
HttpHeaders httpHeaders = headersSupplier.get();
if (httpHeaders != null && httpHeaders != HttpHeaders.EMPTY) {
if (httpHeaders != null && !httpHeaders.isEmpty()) {
Arrays.stream(toHeaderArray(httpHeaders)).forEach(request::addHeader);
}
}

View File

@ -243,11 +243,12 @@ public interface WebClientProvider {
};
provider = provider //
.withDefaultHeaders(clientConfiguration.getDefaultHeaders()) //
.withDefaultHeaders(HttpHeaders.readOnlyHttpHeaders(clientConfiguration.getDefaultHeaders())) //
.withWebClientConfigurer(webClientConfigurer) //
.withRequestConfigurer(requestHeadersSpec -> requestHeadersSpec //
.headers(httpHeaders -> {
HttpHeaders suppliedHeaders = clientConfiguration.getHeadersSupplier().get();
HttpHeaders suppliedHeaders = HttpHeaders
.readOnlyHttpHeaders(clientConfiguration.getHeadersSupplier().get());
if (suppliedHeaders != null && suppliedHeaders != HttpHeaders.EMPTY) {
httpHeaders.addAll(suppliedHeaders);

View File

@ -0,0 +1,215 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed 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
*
* https://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.
*/
package org.springframework.data.elasticsearch.support;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.MultiValueMapAdapter;
/**
* A simple class implementing HTTP headers as a MultiValueMap. This own implementation is necessary to remove the
* dependency to the class with the same name from org.springframework:spring-web. Under the hood is uses a
* {@link LinkedCaseInsensitiveMap}.
*
* @author Peter-Josef Meisch
* @since 5.0
*/
public class HttpHeaders implements MultiValueMap<String, String> {
public static final String AUTHORIZATION = "Authorization";
private final MultiValueMap<String, String> delegate;
public HttpHeaders() {
this.delegate = new MultiValueMapAdapter<>(new LinkedCaseInsensitiveMap<>(Locale.ENGLISH));
}
// region MultiValueMap
@Override
@Nullable
public String getFirst(String key) {
return delegate.getFirst(key);
}
@Override
public void add(String key, @Nullable String value) {
delegate.add(key, value);
}
@Override
public void addAll(String key, List<? extends String> values) {
delegate.addAll(key, values);
}
@Override
public void addAll(MultiValueMap<String, String> values) {
delegate.addAll(values);
}
@Override
public void set(String key, @Nullable String value) {
delegate.set(key, value);
}
@Override
public void setAll(Map<String, String> values) {
delegate.setAll(values);
}
@Override
public Map<String, String> toSingleValueMap() {
return delegate.toSingleValueMap();
}
// endregion
// region Map
@Override
public int size() {
return delegate.size();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return delegate.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return delegate.containsValue(value);
}
@Override
@Nullable
public List<String> get(Object key) {
return delegate.get(key);
}
@Nullable
@Override
public List<String> put(String key, List<String> value) {
return delegate.put(key, value);
}
@Override
public List<String> remove(Object key) {
return delegate.remove(key);
}
@Override
public void putAll(Map<? extends String, ? extends List<String>> m) {
Assert.notNull(m, "m must not be null");
delegate.putAll(m);
}
@Override
public void clear() {
delegate.clear();
}
@Override
public Set<String> keySet() {
return delegate.keySet();
}
@Override
public Collection<List<String>> values() {
return delegate.values();
}
@Override
public Set<Entry<String, List<String>>> entrySet() {
return delegate.entrySet();
}
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
@Override
public boolean equals(Object o) {
return delegate.equals(o);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
// endregion
public void setBasicAuth(String username, String password) {
Assert.notNull(username, "username must not be null");
Assert.notNull(password, "password must not be null");
set(AUTHORIZATION, "Basic " + encodeBasicAuth(username, password));
}
/**
* Encode a username and password to be used in basic authorization. Code copied from the spring-web HttpHeaders
* class.
*
* @param username the username, must not contain a colon
* @param password the password
* @return the encoded value
*/
public static String encodeBasicAuth(String username, String password) {
return encodeBasicAuth(username, password, null);
}
/**
* Encode a username and password to be used in basic authorization. Code copied from the spring-web HttpHeaders
* class.
*
* @param username the username, must not contain a colon
* @param password the password
* @param charset charset for the encoding, if {@literal null} StandardCharsets.ISO_8859_1 is used
* @return the encoded value
*/
public static String encodeBasicAuth(String username, String password, @Nullable Charset charset) {
Assert.notNull(username, "Username must not be null");
Assert.doesNotContain(username, ":", "Username must not contain a colon");
Assert.notNull(password, "Password must not be null");
if (charset == null) {
charset = StandardCharsets.ISO_8859_1;
}
CharsetEncoder encoder = charset.newEncoder();
if (encoder.canEncode(username) && encoder.canEncode(password)) {
String credentialsString = username + ':' + password;
byte[] encodedBytes = Base64.getEncoder().encode(credentialsString.getBytes(charset));
return new String(encodedBytes, charset);
} else {
throw new IllegalArgumentException(
"Username or password contains characters that cannot be encoded to " + charset.displayName());
}
}
}

View File

@ -17,10 +17,10 @@ package org.springframework.data.elasticsearch.client;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.elasticsearch.support.HttpHeaders.*;
import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
@ -32,7 +32,7 @@ import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.data.elasticsearch.client.erhlc.ReactiveRestClients;
import org.springframework.data.elasticsearch.client.erhlc.RestClients;
import org.springframework.http.HttpHeaders;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.web.reactive.function.client.WebClient;
/**
@ -45,6 +45,8 @@ import org.springframework.web.reactive.function.client.WebClient;
*/
public class ClientConfigurationUnitTests {
private static final String AUTHORIZATION = "Authorization";
@Test // DATAES-488
public void shouldCreateSimpleConfiguration() {
@ -106,8 +108,8 @@ public class ClientConfigurationUnitTests {
.withBasicAuth(username, password) //
.build();
assertThat(clientConfiguration.getDefaultHeaders().get(HttpHeaders.AUTHORIZATION))
.containsOnly(buildBasicAuth(username, password));
assertThat(clientConfiguration.getDefaultHeaders().get(AUTHORIZATION))
.containsOnly("Basic " + encodeBasicAuth(username, password));
}
@Test // DATAES-607
@ -127,9 +129,9 @@ public class ClientConfigurationUnitTests {
HttpHeaders httpHeaders = clientConfiguration.getDefaultHeaders();
assertThat(httpHeaders.get(HttpHeaders.AUTHORIZATION)).containsOnly(buildBasicAuth(username, password));
assertThat(httpHeaders.get(AUTHORIZATION)).containsOnly("Basic " + encodeBasicAuth(username, password));
assertThat(httpHeaders.getFirst("foo")).isEqualTo("bar");
assertThat(defaultHeaders.get(HttpHeaders.AUTHORIZATION)).isNull();
assertThat(defaultHeaders.get(AUTHORIZATION)).isNull();
}
@Test // DATAES-673
@ -219,14 +221,8 @@ public class ClientConfigurationUnitTests {
ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer = clientConfiguration.getClientConfigurers()
.get(0);
// noinspection unchecked
((ClientConfiguration.ClientConfigurationCallback<Object>) clientConfigurer).configure(new Object());
assertThat(callCounter.get()).isEqualTo(1);
}
private static String buildBasicAuth(String username, String password) {
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);
return Objects.requireNonNull(headers.getFirst(HttpHeaders.AUTHORIZATION));
}
}

View File

@ -46,7 +46,7 @@ import org.springframework.data.elasticsearch.client.elc.ElasticsearchClients;
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
import org.springframework.data.elasticsearch.client.erhlc.ReactiveRestClients;
import org.springframework.data.elasticsearch.client.erhlc.RestClients;
import org.springframework.http.HttpHeaders;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;

View File

@ -54,7 +54,7 @@ import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.http.HttpHeaders;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
/**

View File

@ -31,7 +31,7 @@ import org.springframework.data.elasticsearch.client.erhlc.RestClients;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.http.HttpHeaders;
import org.springframework.data.elasticsearch.support.HttpHeaders;
/**
* Configuration for Spring Data Elasticsearch using {@link ElasticsearchRestTemplate}.

View File

@ -0,0 +1,85 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed 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
*
* https://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.
*/
package org.springframework.data.elasticsearch.support;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.elasticsearch.support.HttpHeaders.*;
import java.util.List;
import java.util.Locale;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
* @author Peter-Josef Meisch
* @since 5.0
*/
class HttpHeadersTest {
public static final String X_TEST_HEADER = "X-Test-Header";
@Test // #2277
@DisplayName("should find with case insensitive key")
void shouldFindWithCaseInsensitiveKey() {
var httpHeaders = new HttpHeaders();
httpHeaders.set(X_TEST_HEADER, "foo");
assertThat(httpHeaders.get(X_TEST_HEADER.toLowerCase(Locale.ENGLISH))).containsExactly("foo");
}
@Test // #2277
@DisplayName("should overwrite values with set")
void shouldOverwriteValuesWithSet() {
var httpHeaders = new HttpHeaders();
httpHeaders.add(X_TEST_HEADER, "foo");
httpHeaders.set(X_TEST_HEADER, "bar");
assertThat(httpHeaders.get(X_TEST_HEADER)).containsExactly("bar");
}
@Test // #2277
@DisplayName("should set authentication header")
void shouldSetAuthenticationHeader() {
var encodedAuth = encodeBasicAuth("foo", "bar");
var httpHeaders = new HttpHeaders();
httpHeaders.setBasicAuth("foo", "bar");
assertThat(httpHeaders.getFirst(AUTHORIZATION)).isEqualTo("Basic " + encodedAuth);
}
@Test // #2277
@DisplayName("should initialize from Spring HttpHeaders")
void shouldInitializeFromSpringHttpHeaders() {
// we can use the Spring class in this test as we have spring-webflux as optional dependency and so have spring-web
// as well
org.springframework.http.HttpHeaders springHttpHeaders = new org.springframework.http.HttpHeaders();
springHttpHeaders.addAll(X_TEST_HEADER, List.of("foo", "bar"));
var headerName = "x-from-spring";
springHttpHeaders.add(headerName, "true");
var httpHeaders = new HttpHeaders();
httpHeaders.addAll(springHttpHeaders);
assertThat(httpHeaders.get(X_TEST_HEADER)).containsExactly("foo", "bar");
assertThat(httpHeaders.get(headerName)).containsExactly("true");
}
}