mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-10-13 13:58:57 +00:00
parent
18be558740
commit
3298ba21ce
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 \\[(.*)\\]");
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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}.
|
||||
@ -77,7 +77,7 @@ public class ElasticsearchRestTemplateConfiguration extends AbstractElasticsearc
|
||||
defaultHeaders.add("Accept", "application/vnd.elasticsearch+json;compatible-with=7");
|
||||
defaultHeaders.add("Content-Type", "application/vnd.elasticsearch+json;compatible-with=7");
|
||||
|
||||
//noinspection resource
|
||||
// noinspection resource
|
||||
return RestClients.create(configurationBuilder //
|
||||
.withDefaultHeaders(defaultHeaders) //
|
||||
.withConnectTimeout(Duration.ofSeconds(20)) //
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user