diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml
index 77e27b8768..46bd9ca80d 100644
--- a/checkstyle-suppressions.xml
+++ b/checkstyle-suppressions.xml
@@ -7,4 +7,5 @@
+
diff --git a/checkstyle.xml b/checkstyle.xml
index a33fc48319..36d2b15bd8 100644
--- a/checkstyle.xml
+++ b/checkstyle.xml
@@ -136,5 +136,22 @@ For more information on CheckStyle configurations below, see: http://checkstyle.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml
index 4aad288f21..23fc831554 100644
--- a/dspace-api/pom.xml
+++ b/dspace-api/pom.xml
@@ -774,6 +774,7 @@
1.19.0
test
+
com.opencsv
@@ -873,7 +874,7 @@
jclouds-core
${jclouds.version}
-
+
com.google.code.gson
gson
@@ -942,5 +943,10 @@
+
+ com.squareup.okhttp3
+ mockwebserver
+ test
+
diff --git a/dspace-api/src/main/java/org/dspace/app/client/DSpaceHttpClientFactory.java b/dspace-api/src/main/java/org/dspace/app/client/DSpaceHttpClientFactory.java
new file mode 100644
index 0000000000..59c8172f72
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/client/DSpaceHttpClientFactory.java
@@ -0,0 +1,152 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.client;
+
+import static org.apache.commons.collections4.ListUtils.emptyIfNull;
+
+import java.util.List;
+
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.dspace.services.ConfigurationService;
+import org.dspace.utils.DSpace;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Factory of {@link HttpClient} with common configurations.
+ *
+ * @author Luca Giamminonni (luca.giamminonni at 4science.it)
+ *
+ */
+public class DSpaceHttpClientFactory {
+
+ @Autowired
+ private ConfigurationService configurationService;
+
+ @Autowired
+ private DSpaceProxyRoutePlanner proxyRoutePlanner;
+
+ @Autowired(required = false)
+ private List requestInterceptors;
+
+ @Autowired(required = false)
+ private List responseInterceptors;
+
+ /**
+ * Get an instance of {@link DSpaceHttpClientFactory} from the Spring context.
+ * @return the bean instance
+ */
+ public static DSpaceHttpClientFactory getInstance() {
+ return new DSpace().getSingletonService(DSpaceHttpClientFactory.class);
+ }
+
+ /**
+ * Build an instance of {@link HttpClient} setting the proxy if configured.
+ *
+ * @return the client
+ */
+ public CloseableHttpClient build() {
+ return build(HttpClientBuilder.create(), true);
+ }
+
+ /**
+ * return a Builder if an instance of {@link HttpClient} pre-setting the proxy if configured.
+ *
+ * @return the client
+ */
+ public HttpClientBuilder builder(boolean setProxy) {
+ HttpClientBuilder clientBuilder = HttpClientBuilder.create();
+ if (setProxy) {
+ clientBuilder.setRoutePlanner(proxyRoutePlanner);
+ }
+ getRequestInterceptors().forEach(clientBuilder::addInterceptorLast);
+ getResponseInterceptors().forEach(clientBuilder::addInterceptorLast);
+ return clientBuilder;
+ }
+
+ /**
+ * Build an instance of {@link HttpClient} without setting the proxy, even if
+ * configured.
+ *
+ * @return the client
+ */
+ public CloseableHttpClient buildWithoutProxy() {
+ return build(HttpClientBuilder.create(), false);
+ }
+
+ /**
+ * Build an instance of {@link HttpClient} setting the proxy if configured,
+ * disabling automatic retries and setting the maximum total connection.
+ *
+ * @param maxConnTotal the maximum total connection value
+ * @return the client
+ */
+ public CloseableHttpClient buildWithoutAutomaticRetries(int maxConnTotal) {
+ HttpClientBuilder clientBuilder = HttpClientBuilder.create()
+ .disableAutomaticRetries()
+ .setMaxConnTotal(maxConnTotal);
+ return build(clientBuilder, true);
+ }
+
+ /**
+ * Build an instance of {@link HttpClient} setting the proxy if configured with
+ * the given request configuration.
+ * @param requestConfig the request configuration
+ * @return the client
+ */
+ public CloseableHttpClient buildWithRequestConfig(RequestConfig requestConfig) {
+ HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
+ .setDefaultRequestConfig(requestConfig);
+ return build(httpClientBuilder, true);
+ }
+
+ private CloseableHttpClient build(HttpClientBuilder clientBuilder, boolean setProxy) {
+ if (setProxy) {
+ clientBuilder.setRoutePlanner(proxyRoutePlanner);
+ }
+ getRequestInterceptors().forEach(clientBuilder::addInterceptorLast);
+ getResponseInterceptors().forEach(clientBuilder::addInterceptorLast);
+ return clientBuilder.build();
+ }
+
+ public ConfigurationService getConfigurationService() {
+ return configurationService;
+ }
+
+ public void setConfigurationService(ConfigurationService configurationService) {
+ this.configurationService = configurationService;
+ }
+
+ public List getRequestInterceptors() {
+ return emptyIfNull(requestInterceptors);
+ }
+
+ public void setRequestInterceptors(List requestInterceptors) {
+ this.requestInterceptors = requestInterceptors;
+ }
+
+ public List getResponseInterceptors() {
+ return emptyIfNull(responseInterceptors);
+ }
+
+ public void setResponseInterceptors(List responseInterceptors) {
+ this.responseInterceptors = responseInterceptors;
+ }
+
+ public DSpaceProxyRoutePlanner getProxyRoutePlanner() {
+ return proxyRoutePlanner;
+ }
+
+ public void setProxyRoutePlanner(DSpaceProxyRoutePlanner proxyRoutePlanner) {
+ this.proxyRoutePlanner = proxyRoutePlanner;
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/app/client/DSpaceProxyRoutePlanner.java b/dspace-api/src/main/java/org/dspace/app/client/DSpaceProxyRoutePlanner.java
new file mode 100644
index 0000000000..1df7fa4a29
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/client/DSpaceProxyRoutePlanner.java
@@ -0,0 +1,73 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.client;
+
+import java.util.Arrays;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.impl.conn.DefaultRoutePlanner;
+import org.apache.http.protocol.HttpContext;
+import org.dspace.services.ConfigurationService;
+
+/**
+ * Extension of {@link DefaultRoutePlanner} that determine the proxy based on
+ * the configuration service, ignoring configured hosts.
+ *
+ * @author Luca Giamminonni (luca.giamminonni at 4science.it)
+ *
+ */
+public class DSpaceProxyRoutePlanner extends DefaultRoutePlanner {
+
+ private ConfigurationService configurationService;
+
+ public DSpaceProxyRoutePlanner(ConfigurationService configurationService) {
+ super(null);
+ this.configurationService = configurationService;
+ }
+
+ @Override
+ protected HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
+ if (isTargetHostConfiguredToBeIgnored(target)) {
+ return null;
+ }
+ String proxyHost = configurationService.getProperty("http.proxy.host");
+ String proxyPort = configurationService.getProperty("http.proxy.port");
+ if (StringUtils.isAnyBlank(proxyHost, proxyPort)) {
+ return null;
+ }
+ try {
+ return new HttpHost(proxyHost, Integer.parseInt(proxyPort), "http");
+ } catch (NumberFormatException e) {
+ throw new RuntimeException("Invalid proxy port configuration: " + proxyPort);
+ }
+ }
+
+ private boolean isTargetHostConfiguredToBeIgnored(HttpHost target) {
+ String[] hostsToIgnore = configurationService.getArrayProperty("http.proxy.hosts-to-ignore");
+ if (ArrayUtils.isEmpty(hostsToIgnore)) {
+ return false;
+ }
+ return Arrays.stream(hostsToIgnore)
+ .anyMatch(host -> matchesHost(host, target.getHostName()));
+ }
+
+ private boolean matchesHost(String hostPattern, String hostName) {
+ if (hostName.equals(hostPattern)) {
+ return true;
+ } else if (hostPattern.startsWith("*")) {
+ return hostName.endsWith(StringUtils.removeStart(hostPattern, "*"));
+ } else if (hostPattern.endsWith("*")) {
+ return hostName.startsWith(StringUtils.removeEnd(hostPattern, "*"));
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/app/ldn/action/SendLDNMessageAction.java b/dspace-api/src/main/java/org/dspace/app/ldn/action/SendLDNMessageAction.java
index c0ecf04304..c5a60144e6 100644
--- a/dspace-api/src/main/java/org/dspace/app/ldn/action/SendLDNMessageAction.java
+++ b/dspace-api/src/main/java/org/dspace/app/ldn/action/SendLDNMessageAction.java
@@ -18,9 +18,9 @@ import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.app.ldn.model.Notification;
import org.dspace.content.Item;
import org.dspace.core.Context;
@@ -34,21 +34,13 @@ public class SendLDNMessageAction implements LDNAction {
private static final Logger log = LogManager.getLogger(SendLDNMessageAction.class);
- private CloseableHttpClient client = null;
+ private CloseableHttpClient client;
public SendLDNMessageAction() {
- HttpClientBuilder builder = HttpClientBuilder.create();
- client = builder
- .disableAutomaticRetries()
- .setMaxConnTotal(5)
- .build();
}
public SendLDNMessageAction(CloseableHttpClient client) {
- this();
- if (client != null) {
- this.client = client;
- }
+ this.client = client;
}
@Override
@@ -66,9 +58,10 @@ public class SendLDNMessageAction implements LDNAction {
// NOTE: Github believes there is a "Potential server-side request forgery due to a user-provided value"
// This is a false positive because the LDN Service URL is configured by the user from DSpace.
// See the frontend configuration at [dspace.ui.url]/admin/ldn/services
- try (
- CloseableHttpResponse response = client.execute(httpPost);
- ) {
+ if (client == null) {
+ client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5);
+ }
+ try (CloseableHttpResponse response = client.execute(httpPost)) {
if (isSuccessful(response.getStatusLine().getStatusCode())) {
result = LDNActionStatus.CONTINUE;
} else if (isRedirect(response.getStatusLine().getStatusCode())) {
@@ -77,6 +70,7 @@ public class SendLDNMessageAction implements LDNAction {
} catch (Exception e) {
log.error(e);
}
+ client.close();
return result;
}
@@ -91,9 +85,9 @@ public class SendLDNMessageAction implements LDNAction {
statusCode == HttpStatus.SC_TEMPORARY_REDIRECT;
}
- private LDNActionStatus handleRedirect(CloseableHttpResponse oldresponse,
+ private LDNActionStatus handleRedirect(CloseableHttpResponse oldResponse,
HttpPost request) throws HttpException {
- Header[] urls = oldresponse.getHeaders(HttpHeaders.LOCATION);
+ Header[] urls = oldResponse.getHeaders(HttpHeaders.LOCATION);
String url = urls.length > 0 && urls[0] != null ? urls[0].getValue() : null;
if (url == null) {
throw new HttpException("Error following redirect, unable to reach"
@@ -102,17 +96,14 @@ public class SendLDNMessageAction implements LDNAction {
LDNActionStatus result = LDNActionStatus.ABORT;
try {
request.setURI(new URI(url));
- try (
- CloseableHttpResponse response = client.execute(request);
- ) {
+ try (CloseableHttpResponse response = client.execute(request)) {
if (isSuccessful(response.getStatusLine().getStatusCode())) {
- return LDNActionStatus.CONTINUE;
+ result = LDNActionStatus.CONTINUE;
}
}
} catch (Exception e) {
log.error("Error following redirect:", e);
}
-
- return LDNActionStatus.ABORT;
+ return result;
}
}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAService.java b/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAService.java
index 943df5f2a0..1fec20f51f 100644
--- a/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAService.java
+++ b/dspace-api/src/main/java/org/dspace/app/sherpa/SHERPAService.java
@@ -17,15 +17,15 @@ import jakarta.annotation.PostConstruct;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.app.sherpa.v2.SHERPAPublisherResponse;
import org.dspace.app.sherpa.v2.SHERPAResponse;
import org.dspace.app.sherpa.v2.SHERPAUtils;
@@ -45,8 +45,6 @@ import org.springframework.cache.annotation.Cacheable;
*/
public class SHERPAService {
- private CloseableHttpClient client = null;
-
private int maxNumberOfTries;
private long sleepBetweenTimeouts;
private int timeout = 5000;
@@ -59,19 +57,6 @@ public class SHERPAService {
@Autowired
ConfigurationService configurationService;
- /**
- * Create a new HTTP builder with sensible defaults in constructor
- */
- public SHERPAService() {
- HttpClientBuilder builder = HttpClientBuilder.create();
- // httpclient 4.3+ doesn't appear to have any sensible defaults any more. Setting conservative defaults as
- // not to hammer the SHERPA service too much.
- client = builder
- .disableAutomaticRetries()
- .setMaxConnTotal(5)
- .build();
- }
-
/**
* Complete initialization of the Bean.
*/
@@ -132,46 +117,47 @@ public class SHERPAService {
timeout,
sleepBetweenTimeouts));
- try {
+ try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5)) {
Thread.sleep(sleepBetweenTimeouts);
// Construct a default HTTP method (first result)
method = constructHttpGet(type, field, predicate, value, start, limit);
// Execute the method
- HttpResponse response = client.execute(method);
- int statusCode = response.getStatusLine().getStatusCode();
+ try (CloseableHttpResponse response = client.execute(method)) {
+ int statusCode = response.getStatusLine().getStatusCode();
- log.debug(response.getStatusLine().getStatusCode() + ": "
- + response.getStatusLine().getReasonPhrase());
+ log.debug(response.getStatusLine().getStatusCode() + ": "
+ + response.getStatusLine().getReasonPhrase());
- if (statusCode != HttpStatus.SC_OK) {
- sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO return not OK status: "
- + statusCode);
- String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
- log.error("Error from SHERPA HTTP request: " + errorBody);
- }
-
- HttpEntity responseBody = response.getEntity();
-
- // If the response body is valid, pass to SHERPAResponse for parsing as JSON
- if (null != responseBody) {
- log.debug("Non-null SHERPA response received for query of " + value);
- InputStream content = null;
- try {
- content = responseBody.getContent();
- sherpaResponse =
- new SHERPAPublisherResponse(content, SHERPAPublisherResponse.SHERPAFormat.JSON);
- } catch (IOException e) {
- log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
- } finally {
- if (content != null) {
- content.close();
- }
+ if (statusCode != HttpStatus.SC_OK) {
+ sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO return not OK status: "
+ + statusCode);
+ String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
+ log.error("Error from SHERPA HTTP request: " + errorBody);
+ }
+
+ HttpEntity responseBody = response.getEntity();
+
+ // If the response body is valid, pass to SHERPAResponse for parsing as JSON
+ if (null != responseBody) {
+ log.debug("Non-null SHERPA response received for query of " + value);
+ InputStream content = null;
+ try {
+ content = responseBody.getContent();
+ sherpaResponse =
+ new SHERPAPublisherResponse(content, SHERPAPublisherResponse.SHERPAFormat.JSON);
+ } catch (IOException e) {
+ log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
+ } finally {
+ if (content != null) {
+ content.close();
+ }
+ }
+ } else {
+ log.debug("Empty SHERPA response body for query on " + value);
+ sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO returned no response");
}
- } else {
- log.debug("Empty SHERPA response body for query on " + value);
- sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO returned no response");
}
} catch (URISyntaxException e) {
String errorMessage = "Error building SHERPA v2 API URI: " + e.getMessage();
@@ -235,45 +221,46 @@ public class SHERPAService {
timeout,
sleepBetweenTimeouts));
- try {
+ try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5)) {
Thread.sleep(sleepBetweenTimeouts);
// Construct a default HTTP method (first result)
method = constructHttpGet(type, field, predicate, value, start, limit);
// Execute the method
- HttpResponse response = client.execute(method);
- int statusCode = response.getStatusLine().getStatusCode();
+ try (CloseableHttpResponse response = client.execute(method)) {
+ int statusCode = response.getStatusLine().getStatusCode();
- log.debug(response.getStatusLine().getStatusCode() + ": "
- + response.getStatusLine().getReasonPhrase());
+ log.debug(response.getStatusLine().getStatusCode() + ": "
+ + response.getStatusLine().getReasonPhrase());
- if (statusCode != HttpStatus.SC_OK) {
- sherpaResponse = new SHERPAResponse("SHERPA/RoMEO return not OK status: "
- + statusCode);
- String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
- log.error("Error from SHERPA HTTP request: " + errorBody);
- }
-
- HttpEntity responseBody = response.getEntity();
-
- // If the response body is valid, pass to SHERPAResponse for parsing as JSON
- if (null != responseBody) {
- log.debug("Non-null SHERPA response received for query of " + value);
- InputStream content = null;
- try {
- content = responseBody.getContent();
- sherpaResponse = new SHERPAResponse(content, SHERPAResponse.SHERPAFormat.JSON);
- } catch (IOException e) {
- log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
- } finally {
- if (content != null) {
- content.close();
- }
+ if (statusCode != HttpStatus.SC_OK) {
+ sherpaResponse = new SHERPAResponse("SHERPA/RoMEO return not OK status: "
+ + statusCode);
+ String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
+ log.error("Error from SHERPA HTTP request: " + errorBody);
+ }
+
+ HttpEntity responseBody = response.getEntity();
+
+ // If the response body is valid, pass to SHERPAResponse for parsing as JSON
+ if (null != responseBody) {
+ log.debug("Non-null SHERPA response received for query of " + value);
+ InputStream content = null;
+ try {
+ content = responseBody.getContent();
+ sherpaResponse = new SHERPAResponse(content, SHERPAResponse.SHERPAFormat.JSON);
+ } catch (IOException e) {
+ log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
+ } finally {
+ if (content != null) {
+ content.close();
+ }
+ }
+ } else {
+ log.debug("Empty SHERPA response body for query on " + value);
+ sherpaResponse = new SHERPAResponse("SHERPA/RoMEO returned no response");
}
- } else {
- log.debug("Empty SHERPA response body for query on " + value);
- sherpaResponse = new SHERPAResponse("SHERPA/RoMEO returned no response");
}
} catch (URISyntaxException e) {
String errorMessage = "Error building SHERPA v2 API URI: " + e.getMessage();
@@ -283,7 +270,7 @@ public class SHERPAService {
String errorMessage = "Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage();
log.error(errorMessage, e);
sherpaResponse = new SHERPAResponse(errorMessage);
- } catch (InterruptedException e) {
+ } catch (InterruptedException e) {
String errorMessage = "Encountered exception while sleeping thread: " + e.getMessage();
log.error(errorMessage, e);
sherpaResponse = new SHERPAResponse(errorMessage);
diff --git a/dspace-api/src/main/java/org/dspace/app/util/WebAppServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/util/WebAppServiceImpl.java
index 8c22aa6050..82042d6c0b 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/WebAppServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/WebAppServiceImpl.java
@@ -13,12 +13,12 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
-import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.app.util.dao.WebAppDAO;
import org.dspace.app.util.service.WebAppService;
import org.dspace.core.Context;
@@ -77,8 +77,8 @@ public class WebAppServiceImpl implements WebAppService {
for (WebApp app : webApps) {
method = new HttpHead(app.getUrl());
int status;
- try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
- HttpResponse response = client.execute(method);
+ try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
+ CloseableHttpResponse response = client.execute(method);
status = response.getStatusLine().getStatusCode();
}
if (status != HttpStatus.SC_OK) {
diff --git a/dspace-api/src/main/java/org/dspace/authenticate/oidc/impl/OidcClientImpl.java b/dspace-api/src/main/java/org/dspace/authenticate/oidc/impl/OidcClientImpl.java
index 68fffd3fb2..3e3d4b905b 100644
--- a/dspace-api/src/main/java/org/dspace/authenticate/oidc/impl/OidcClientImpl.java
+++ b/dspace-api/src/main/java/org/dspace/authenticate/oidc/impl/OidcClientImpl.java
@@ -22,12 +22,13 @@ import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
-import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
-import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.authenticate.oidc.OidcClient;
import org.dspace.authenticate.oidc.OidcClientException;
import org.dspace.authenticate.oidc.model.OidcTokenResponseDTO;
@@ -83,21 +84,17 @@ public class OidcClientImpl implements OidcClient {
}
private T executeAndParseJson(HttpUriRequest httpUriRequest, Class clazz) {
-
- HttpClient client = HttpClientBuilder.create().build();
-
- return executeAndReturns(() -> {
-
- HttpResponse response = client.execute(httpUriRequest);
-
- if (isNotSuccessfull(response)) {
- throw new OidcClientException(getStatusCode(response), formatErrorMessage(response));
- }
-
- return objectMapper.readValue(getContent(response), clazz);
-
- });
-
+ try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
+ return executeAndReturns(() -> {
+ CloseableHttpResponse response = client.execute(httpUriRequest);
+ if (isNotSuccessfull(response)) {
+ throw new OidcClientException(getStatusCode(response), formatErrorMessage(response));
+ }
+ return objectMapper.readValue(getContent(response), clazz);
+ });
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
private T executeAndReturns(ThrowingSupplier supplier) {
diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java
index 0ed0abe218..77236be9d5 100644
--- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java
+++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java
@@ -11,8 +11,6 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
@@ -21,7 +19,11 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.collections4.CollectionUtils;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.BitstreamFormat;
@@ -1310,13 +1312,12 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester {
if (params.getBooleanProperty("manifestOnly", false)) {
// NOTE: since we are only dealing with a METS manifest,
// we will assume all external files are available via URLs.
- try {
+ try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
// attempt to open a connection to given URL
- URL fileURL = new URL(path);
- URLConnection connection = fileURL.openConnection();
-
- // open stream to access file contents
- return connection.getInputStream();
+ try (CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(path))) {
+ // open stream to access file contents
+ return httpResponse.getEntity().getContent();
+ }
} catch (IOException io) {
log
.error("Unable to retrieve external file from URL '"
diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/BasicLinkChecker.java b/dspace-api/src/main/java/org/dspace/ctask/general/BasicLinkChecker.java
index 9bd08bffdb..fc5ffece30 100644
--- a/dspace-api/src/main/java/org/dspace/ctask/general/BasicLinkChecker.java
+++ b/dspace-api/src/main/java/org/dspace/ctask/general/BasicLinkChecker.java
@@ -9,11 +9,15 @@ package org.dspace.ctask.general;
import java.io.IOException;
import java.net.HttpURLConnection;
-import java.net.URL;
import java.util.ArrayList;
import java.util.List;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
@@ -135,24 +139,20 @@ public class BasicLinkChecker extends AbstractCurationTask {
* @return The HTTP response code (e.g. 200 / 301 / 404 / 500)
*/
protected int getResponseStatus(String url, int redirects) {
- try {
- URL theURL = new URL(url);
- HttpURLConnection connection = (HttpURLConnection) theURL.openConnection();
- connection.setInstanceFollowRedirects(true);
- int statusCode = connection.getResponseCode();
+ RequestConfig config = RequestConfig.custom().setRedirectsEnabled(true).build();
+ try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().buildWithRequestConfig(config)) {
+ CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(url));
+ int statusCode = httpResponse.getStatusLine().getStatusCode();
int maxRedirect = configurationService.getIntProperty("curate.checklinks.max-redirect", 0);
if ((statusCode == HttpURLConnection.HTTP_MOVED_TEMP || statusCode == HttpURLConnection.HTTP_MOVED_PERM ||
statusCode == HttpURLConnection.HTTP_SEE_OTHER)) {
- connection.disconnect();
- String newUrl = connection.getHeaderField("Location");
+ String newUrl = httpResponse.getFirstHeader("Location").getValue();
if (newUrl != null && (maxRedirect >= redirects || maxRedirect == -1)) {
redirects++;
return getResponseStatus(newUrl, redirects);
}
-
}
return statusCode;
-
} catch (IOException ioe) {
// Must be a bad URL
log.debug("Bad link: " + ioe.getMessage());
diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebService.java b/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebService.java
index 5891fa017c..fc62d7a4b2 100644
--- a/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebService.java
+++ b/dspace-api/src/main/java/org/dspace/ctask/general/MetadataWebService.java
@@ -30,13 +30,13 @@ import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
@@ -255,53 +255,50 @@ public class MetadataWebService extends AbstractCurationTask implements Namespac
}
protected int callService(String value, Item item, StringBuilder resultSb) throws IOException {
-
String callUrl = urlTemplate.replaceAll("\\{" + templateParam + "\\}", value);
- CloseableHttpClient client = HttpClientBuilder.create().build();
- HttpGet req = new HttpGet(callUrl);
- for (Map.Entry entry : headers.entrySet()) {
- req.addHeader(entry.getKey(), entry.getValue());
- }
- HttpResponse resp = client.execute(req);
- int status = Curator.CURATE_ERROR;
- int statusCode = resp.getStatusLine().getStatusCode();
- if (statusCode == HttpStatus.SC_OK) {
- HttpEntity entity = resp.getEntity();
- if (entity != null) {
- // boiler-plate handling taken from Apache 4.1 javadoc
- InputStream instream = entity.getContent();
- try {
- // This next line triggers a false-positive XXE warning from LGTM, even though we disallow DTD
- // parsing during initialization of docBuilder in init()
- Document doc = docBuilder.parse(instream); // lgtm [java/xxe]
- status = processResponse(doc, item, resultSb);
- } catch (SAXException saxE) {
- log.error("caught exception: " + saxE);
- resultSb.append(" unable to read response document");
- } catch (RuntimeException ex) {
- // In case of an unexpected exception you may want to abort
- // the HTTP request in order to shut down the underlying
- // connection and release it back to the connection manager.
- req.abort();
- log.error("caught exception: " + ex);
- throw ex;
- } finally {
- // Closing the input stream will trigger connection release
- instream.close();
- }
- // When HttpClient instance is no longer needed,
- // shut down the connection manager to ensure
- // immediate deallocation of all system resources
- client.close();
- } else {
- log.error(" obtained no valid service response");
- resultSb.append("no service response");
+ try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
+ HttpGet req = new HttpGet(callUrl);
+ for (Map.Entry entry : headers.entrySet()) {
+ req.addHeader(entry.getKey(), entry.getValue());
+ }
+ try (CloseableHttpResponse resp = client.execute(req)) {
+ int status = Curator.CURATE_ERROR;
+ int statusCode = resp.getStatusLine().getStatusCode();
+ if (statusCode == HttpStatus.SC_OK) {
+ HttpEntity entity = resp.getEntity();
+ if (entity != null) {
+ // boiler-plate handling taken from Apache 4.1 javadoc
+ InputStream instream = entity.getContent();
+ try {
+ // This next line triggers a false-positive XXE warning from LGTM, even though
+ // we disallow DTD parsing during initialization of docBuilder in init()
+ Document doc = docBuilder.parse(instream); // lgtm [java/xxe]
+ status = processResponse(doc, item, resultSb);
+ } catch (SAXException saxE) {
+ log.error("caught exception: " + saxE);
+ resultSb.append(" unable to read response document");
+ } catch (RuntimeException ex) {
+ // In case of an unexpected exception you may want to abort
+ // the HTTP request in order to shut down the underlying
+ // connection and release it back to the connection manager.
+ req.abort();
+ log.error("caught exception: " + ex);
+ throw ex;
+ } finally {
+ // Closing the input stream will trigger connection release
+ instream.close();
+ }
+ } else {
+ log.error(" obtained no valid service response");
+ resultSb.append("no service response");
+ }
+ } else {
+ log.error("service returned non-OK status: " + statusCode);
+ resultSb.append("no service response");
+ }
+ return status;
}
- } else {
- log.error("service returned non-OK status: " + statusCode);
- resultSb.append("no service response");
}
- return status;
}
protected int processResponse(Document doc, Item item, StringBuilder resultSb) throws IOException {
diff --git a/dspace-api/src/main/java/org/dspace/ctask/general/MicrosoftTranslator.java b/dspace-api/src/main/java/org/dspace/ctask/general/MicrosoftTranslator.java
index 49c0c36a59..af9c2de0c8 100644
--- a/dspace-api/src/main/java/org/dspace/ctask/general/MicrosoftTranslator.java
+++ b/dspace-api/src/main/java/org/dspace/ctask/general/MicrosoftTranslator.java
@@ -12,12 +12,12 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
-import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
@@ -60,22 +60,20 @@ public class MicrosoftTranslator extends AbstractTranslator {
String url = baseUrl + "?appId=" + apiKey;
url += "&to=" + to + "&from=" + from + "&text=" + text;
- try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
+ try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
HttpGet hm = new HttpGet(url);
- HttpResponse httpResponse = client.execute(hm);
- log.debug("Response code from API call is " + httpResponse);
-
- if (httpResponse.getStatusLine().getStatusCode() == 200) {
- String response = IOUtils.toString(httpResponse.getEntity().getContent(),
- StandardCharsets.ISO_8859_1);
- response = response
- .replaceAll("", "");
- response = response.replaceAll("", "");
- translatedText = response;
+ try (CloseableHttpResponse httpResponse = client.execute(hm)) {
+ log.debug("Response code from API call is " + httpResponse);
+ if (httpResponse.getStatusLine().getStatusCode() == 200) {
+ String response = IOUtils.toString(httpResponse.getEntity().getContent(),
+ StandardCharsets.ISO_8859_1);
+ response = response
+ .replaceAll("", "");
+ response = response.replaceAll("", "");
+ translatedText = response;
+ }
}
}
-
return translatedText;
}
-}
-
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/eperson/CaptchaServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/CaptchaServiceImpl.java
index b213675b16..15f92247d6 100644
--- a/dspace-api/src/main/java/org/dspace/eperson/CaptchaServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/eperson/CaptchaServiceImpl.java
@@ -17,15 +17,15 @@ import java.util.regex.Pattern;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
-import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
-import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
-import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.eperson.service.CaptchaService;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -82,18 +82,17 @@ public class CaptchaServiceImpl implements CaptchaService {
throw new RuntimeException(e.getMessage(), e);
}
- HttpClient httpClient = HttpClientBuilder.create().build();
- HttpResponse httpResponse;
- GoogleCaptchaResponse googleResponse;
- final ObjectMapper objectMapper = new ObjectMapper();
- try {
- httpResponse = httpClient.execute(httpPost);
- googleResponse = objectMapper.readValue(httpResponse.getEntity().getContent(), GoogleCaptchaResponse.class);
+ try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
+ final ObjectMapper objectMapper = new ObjectMapper();
+ try (CloseableHttpResponse httpResponse = httpClient.execute(httpPost)) {
+ GoogleCaptchaResponse googleResponse = objectMapper.readValue(httpResponse.getEntity().getContent(),
+ GoogleCaptchaResponse.class);
+ validateGoogleResponse(googleResponse, action);
+ }
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new RuntimeException("Error during verify google recaptcha site", e);
}
- validateGoogleResponse(googleResponse, action);
}
private boolean responseSanityCheck(String response) {
diff --git a/dspace-api/src/main/java/org/dspace/external/OpenaireRestConnector.java b/dspace-api/src/main/java/org/dspace/external/OpenaireRestConnector.java
index 27688df6c7..87af01401a 100644
--- a/dspace-api/src/main/java/org/dspace/external/OpenaireRestConnector.java
+++ b/dspace-api/src/main/java/org/dspace/external/OpenaireRestConnector.java
@@ -27,13 +27,13 @@ import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.StatusLine;
-import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
-import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.app.util.Util;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
@@ -120,33 +120,34 @@ public class OpenaireRestConnector {
params.add(new BasicNameValuePair("grant_type", "client_credentials"));
httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
- HttpClient httpClient = HttpClientBuilder.create().build();
- HttpResponse getResponse = httpClient.execute(httpPost);
+ try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
+ HttpResponse getResponse = httpClient.execute(httpPost);
- JSONObject responseObject = null;
- try (InputStream is = getResponse.getEntity().getContent();
- BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
- String inputStr;
- // verify if we have basic json
- while ((inputStr = streamReader.readLine()) != null && responseObject == null) {
- if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")
- && inputStr.contains("expires_in")) {
- try {
- responseObject = new JSONObject(inputStr);
- } catch (Exception e) {
- // Not as valid as I'd hoped, move along
- responseObject = null;
+ JSONObject responseObject = null;
+ try (InputStream is = getResponse.getEntity().getContent();
+ BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
+ String inputStr;
+ // verify if we have basic json
+ while ((inputStr = streamReader.readLine()) != null && responseObject == null) {
+ if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")
+ && inputStr.contains("expires_in")) {
+ try {
+ responseObject = new JSONObject(inputStr);
+ } catch (Exception e) {
+ // Not as valid as I'd hoped, move along
+ responseObject = null;
+ }
}
}
}
- }
- if (responseObject == null || !responseObject.has("access_token") || !responseObject.has("expires_in")) {
- throw new IOException("Unable to grab the access token using provided service url, client id and secret");
- }
-
- return new OpenaireRestToken(responseObject.get("access_token").toString(),
- Long.valueOf(responseObject.get("expires_in").toString()));
+ if (responseObject == null || !responseObject.has("access_token") || !responseObject.has("expires_in")) {
+ throw new IOException("Unable to grab the access token using provided service url, " +
+ "client id and secret");
+ }
+ return new OpenaireRestToken(responseObject.get("access_token").toString(),
+ Long.valueOf(responseObject.get("expires_in").toString()));
+ }
}
/**
@@ -171,42 +172,43 @@ public class OpenaireRestConnector {
httpGet.addHeader("Authorization", "Bearer " + accessToken);
}
- HttpClient httpClient = HttpClientBuilder.create().build();
- getResponse = httpClient.execute(httpGet);
+ try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
+ getResponse = httpClient.execute(httpGet);
- StatusLine status = getResponse.getStatusLine();
+ StatusLine status = getResponse.getStatusLine();
- // registering errors
- switch (status.getStatusCode()) {
- case HttpStatus.SC_NOT_FOUND:
- // 404 - Not found
- case HttpStatus.SC_FORBIDDEN:
- // 403 - Invalid Access Token
- case 429:
- // 429 - Rate limit abuse for unauthenticated user
- Header[] limitUsed = getResponse.getHeaders("x-ratelimit-used");
- Header[] limitMax = getResponse.getHeaders("x-ratelimit-limit");
+ // registering errors
+ switch (status.getStatusCode()) {
+ case HttpStatus.SC_NOT_FOUND:
+ // 404 - Not found
+ case HttpStatus.SC_FORBIDDEN:
+ // 403 - Invalid Access Token
+ case 429:
+ // 429 - Rate limit abuse for unauthenticated user
+ Header[] limitUsed = getResponse.getHeaders("x-ratelimit-used");
+ Header[] limitMax = getResponse.getHeaders("x-ratelimit-limit");
- if (limitUsed.length > 0) {
- String limitMsg = limitUsed[0].getValue();
- if (limitMax.length > 0) {
- limitMsg = limitMsg.concat(" of " + limitMax[0].getValue());
+ if (limitUsed.length > 0) {
+ String limitMsg = limitUsed[0].getValue();
+ if (limitMax.length > 0) {
+ limitMsg = limitMsg.concat(" of " + limitMax[0].getValue());
+ }
+ getGotError(new NoHttpResponseException(status.getReasonPhrase() + " with usage limit "
+ + limitMsg),
+ url + '/' + file);
+ } else {
+ // 429 - Rate limit abuse
+ getGotError(new NoHttpResponseException(status.getReasonPhrase()), url + '/' + file);
}
- getGotError(
- new NoHttpResponseException(status.getReasonPhrase() + " with usage limit " + limitMsg),
- url + '/' + file);
- } else {
- // 429 - Rate limit abuse
- getGotError(new NoHttpResponseException(status.getReasonPhrase()), url + '/' + file);
- }
- break;
- default:
- // 200 or other
- break;
- }
+ break;
+ default:
+ // 200 or other
+ break;
+ }
- // do not close this httpClient
- result = getResponse.getEntity().getContent();
+ // do not close this httpClient
+ result = getResponse.getEntity().getContent();
+ }
} catch (MalformedURLException e1) {
getGotError(e1, url + '/' + file);
} catch (Exception e) {
diff --git a/dspace-api/src/main/java/org/dspace/external/OrcidRestConnector.java b/dspace-api/src/main/java/org/dspace/external/OrcidRestConnector.java
index d45be7e6b5..aa16af7a52 100644
--- a/dspace-api/src/main/java/org/dspace/external/OrcidRestConnector.java
+++ b/dspace-api/src/main/java/org/dspace/external/OrcidRestConnector.java
@@ -7,17 +7,18 @@
*/
package org.dspace.external;
+import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import org.apache.commons.lang3.StringUtils;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
/**
* @author Antoine Snyers (antoine at atmire.com)
@@ -39,7 +40,7 @@ public class OrcidRestConnector {
}
public InputStream get(String path, String accessToken) {
- HttpResponse getResponse = null;
+ CloseableHttpResponse getResponse = null;
InputStream result = null;
path = trimSlashes(path);
@@ -49,11 +50,13 @@ public class OrcidRestConnector {
httpGet.addHeader("Content-Type", "application/vnd.orcid+xml");
httpGet.addHeader("Authorization","Bearer " + accessToken);
}
- try {
- HttpClient httpClient = HttpClientBuilder.create().build();
+ try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
getResponse = httpClient.execute(httpGet);
- //do not close this httpClient
- result = getResponse.getEntity().getContent();
+ try (InputStream responseStream = getResponse.getEntity().getContent()) {
+ // Read all the content of the response stream into a byte array to prevent TruncatedChunkException
+ byte[] content = responseStream.readAllBytes();
+ result = new ByteArrayInputStream(content);
+ }
} catch (Exception e) {
getGotError(e, fullPath);
}
diff --git a/dspace-api/src/main/java/org/dspace/external/provider/impl/OrcidV3AuthorDataProvider.java b/dspace-api/src/main/java/org/dspace/external/provider/impl/OrcidV3AuthorDataProvider.java
index dfbd07a83a..a9e10f9294 100644
--- a/dspace-api/src/main/java/org/dspace/external/provider/impl/OrcidV3AuthorDataProvider.java
+++ b/dspace-api/src/main/java/org/dspace/external/provider/impl/OrcidV3AuthorDataProvider.java
@@ -169,13 +169,7 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
}
initializeAccessToken();
InputStream bioDocument = orcidRestConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken);
- Person person = converter.convertSinglePerson(bioDocument);
- try {
- bioDocument.close();
- } catch (IOException e) {
- log.error(e.getMessage(), e);
- }
- return person;
+ return converter.convertSinglePerson(bioDocument);
}
/**
@@ -220,11 +214,6 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
}
}
}
- try {
- bioDocument.close();
- } catch (IOException e) {
- log.error(e.getMessage(), e);
- }
return bios.stream().map(bio -> convertToExternalDataObject(bio)).collect(Collectors.toList());
}
diff --git a/dspace-api/src/main/java/org/dspace/google/client/GoogleAnalyticsClientImpl.java b/dspace-api/src/main/java/org/dspace/google/client/GoogleAnalyticsClientImpl.java
index 915bd25b06..bfecb1fb08 100644
--- a/dspace-api/src/main/java/org/dspace/google/client/GoogleAnalyticsClientImpl.java
+++ b/dspace-api/src/main/java/org/dspace/google/client/GoogleAnalyticsClientImpl.java
@@ -18,9 +18,9 @@ import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.google.GoogleAnalyticsEvent;
/**
@@ -42,7 +42,7 @@ public class GoogleAnalyticsClientImpl implements GoogleAnalyticsClient {
public GoogleAnalyticsClientImpl(String keyPrefix, GoogleAnalyticsClientRequestBuilder requestBuilder) {
this.keyPrefix = keyPrefix;
this.requestBuilder = requestBuilder;
- this.httpclient = HttpClients.createDefault();
+ this.httpclient = DSpaceHttpClientFactory.getInstance().build();
}
@Override
diff --git a/dspace-api/src/main/java/org/dspace/identifier/doi/DataCiteConnector.java b/dspace-api/src/main/java/org/dspace/identifier/doi/DataCiteConnector.java
index e56a829423..368662026a 100644
--- a/dspace-api/src/main/java/org/dspace/identifier/doi/DataCiteConnector.java
+++ b/dspace-api/src/main/java/org/dspace/identifier/doi/DataCiteConnector.java
@@ -36,10 +36,10 @@ import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.content.crosswalk.CrosswalkException;
@@ -719,7 +719,7 @@ public class DataCiteConnector
httpContext.setCredentialsProvider(credentialsProvider);
HttpEntity entity = null;
- try ( CloseableHttpClient httpclient = HttpClientBuilder.create().build(); ) {
+ try (CloseableHttpClient httpclient = DSpaceHttpClientFactory.getInstance().build()) {
HttpResponse response = httpclient.execute(req, httpContext);
StatusLine status = response.getStatusLine();
diff --git a/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequest.java b/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequest.java
index bf46c3bf59..c3c95be4b3 100644
--- a/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequest.java
+++ b/dspace-api/src/main/java/org/dspace/identifier/ezid/EZIDRequest.java
@@ -26,9 +26,9 @@ import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.identifier.DOI;
import org.dspace.identifier.IdentifierException;
@@ -87,7 +87,7 @@ public class EZIDRequest {
this.authority = authority;
}
- client = HttpClientBuilder.create().build();
+ client = DSpaceHttpClientFactory.getInstance().build();
httpContext = HttpClientContext.create();
if (null != username) {
URI uri = new URI(scheme, host, path, null);
@@ -124,7 +124,7 @@ public class EZIDRequest {
this.authority = authority;
}
- client = HttpClientBuilder.create().build();
+ client = DSpaceHttpClientFactory.getInstance().build();
httpContext = HttpClientContext.create();
if (null != username) {
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
diff --git a/dspace-api/src/main/java/org/dspace/iiif/IIIFApiQueryServiceImpl.java b/dspace-api/src/main/java/org/dspace/iiif/IIIFApiQueryServiceImpl.java
index 7c6336ed3c..ccb2c170d9 100644
--- a/dspace-api/src/main/java/org/dspace/iiif/IIIFApiQueryServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/iiif/IIIFApiQueryServiceImpl.java
@@ -12,12 +12,14 @@ import static org.dspace.iiif.canvasdimension.Util.checkDimensions;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
-import java.net.URL;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.content.Bitstream;
import org.dspace.iiif.util.IIIFSharedUtils;
@@ -35,14 +37,10 @@ public class IIIFApiQueryServiceImpl implements IIIFApiQueryService {
public int[] getImageDimensions(Bitstream bitstream) {
int[] arr = new int[2];
String path = IIIFSharedUtils.getInfoJsonPath(bitstream);
- URL url;
BufferedReader in = null;
- try {
- url = new URL(path);
- HttpURLConnection con = (HttpURLConnection) url.openConnection();
- con.setRequestMethod("GET");
- in = new BufferedReader(
- new InputStreamReader(con.getInputStream()));
+ try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
+ CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(path));
+ in = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
diff --git a/dspace-api/src/main/java/org/dspace/importer/external/liveimportclient/service/LiveImportClientImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/liveimportclient/service/LiveImportClientImpl.java
index 1a8a7a7861..84475b62c0 100644
--- a/dspace-api/src/main/java/org/dspace/importer/external/liveimportclient/service/LiveImportClientImpl.java
+++ b/dspace-api/src/main/java/org/dspace/importer/external/liveimportclient/service/LiveImportClientImpl.java
@@ -17,19 +17,16 @@ import java.util.Optional;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
-import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -53,16 +50,11 @@ public class LiveImportClientImpl implements LiveImportClient {
@Override
public String executeHttpGetRequest(int timeout, String URL, Map> params) {
HttpGet method = null;
+ RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(timeout).build();
try (CloseableHttpClient httpClient = Optional.ofNullable(this.httpClient)
- .orElseGet(HttpClients::createDefault)) {
-
- Builder requestConfigBuilder = RequestConfig.custom();
- requestConfigBuilder.setConnectionRequestTimeout(timeout);
- RequestConfig defaultRequestConfig = requestConfigBuilder.build();
-
+ .orElse(DSpaceHttpClientFactory.getInstance().buildWithRequestConfig(config))) {
String uri = buildUrl(URL, params.get(URI_PARAMETERS));
method = new HttpGet(uri);
- method.setConfig(defaultRequestConfig);
Map headerParams = params.get(HEADER_PARAMETERS);
if (MapUtils.isNotEmpty(headerParams)) {
@@ -71,7 +63,6 @@ public class LiveImportClientImpl implements LiveImportClient {
}
}
- configureProxy(method, defaultRequestConfig);
if (log.isDebugEnabled()) {
log.debug("Performing GET request to \"" + uri + "\"...");
}
@@ -95,21 +86,17 @@ public class LiveImportClientImpl implements LiveImportClient {
@Override
public String executeHttpPostRequest(String URL, Map> params, String entry) {
HttpPost method = null;
+ RequestConfig config = RequestConfig.custom().build();
try (CloseableHttpClient httpClient = Optional.ofNullable(this.httpClient)
- .orElseGet(HttpClients::createDefault)) {
-
- Builder requestConfigBuilder = RequestConfig.custom();
- RequestConfig defaultRequestConfig = requestConfigBuilder.build();
+ .orElse(DSpaceHttpClientFactory.getInstance().buildWithRequestConfig(config))) {
String uri = buildUrl(URL, params.get(URI_PARAMETERS));
method = new HttpPost(uri);
- method.setConfig(defaultRequestConfig);
if (StringUtils.isNotBlank(entry)) {
method.setEntity(new StringEntity(entry));
}
setHeaderParams(method, params);
- configureProxy(method, defaultRequestConfig);
if (log.isDebugEnabled()) {
log.debug("Performing POST request to \"" + uri + "\"..." );
}
@@ -129,17 +116,6 @@ public class LiveImportClientImpl implements LiveImportClient {
return StringUtils.EMPTY;
}
- private void configureProxy(HttpRequestBase method, RequestConfig defaultRequestConfig) {
- String proxyHost = configurationService.getProperty("http.proxy.host");
- String proxyPort = configurationService.getProperty("http.proxy.port");
- if (StringUtils.isNotBlank(proxyHost) && StringUtils.isNotBlank(proxyPort)) {
- RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
- .setProxy(new HttpHost(proxyHost, Integer.parseInt(proxyPort), "http"))
- .build();
- method.setConfig(requestConfig);
- }
- }
-
/**
* Allows to set the header parameters to the HTTP Post method
*
diff --git a/dspace-api/src/main/java/org/dspace/license/CCLicenseConnectorServiceImpl.java b/dspace-api/src/main/java/org/dspace/license/CCLicenseConnectorServiceImpl.java
index cdecadba52..1d777a2e13 100644
--- a/dspace-api/src/main/java/org/dspace/license/CCLicenseConnectorServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/license/CCLicenseConnectorServiceImpl.java
@@ -10,9 +10,6 @@ package org.dspace.license;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
@@ -28,9 +25,9 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.services.ConfigurationService;
import org.jdom2.Attribute;
import org.jdom2.Document;
@@ -70,12 +67,7 @@ public class CCLicenseConnectorServiceImpl implements CCLicenseConnectorService,
@Override
public void afterPropertiesSet() throws Exception {
- HttpClientBuilder builder = HttpClientBuilder.create();
-
- client = builder
- .disableAutomaticRetries()
- .setMaxConnTotal(5)
- .build();
+ client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5);
// disallow DTD parsing to ensure no XXE attacks can occur.
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
@@ -333,23 +325,13 @@ public class CCLicenseConnectorServiceImpl implements CCLicenseConnectorService,
@Override
public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException {
String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
-
String issueUrl = ccLicenseUrl + "/details?license-uri=" + licenseURI;
-
- URL request_url;
- try {
- request_url = new URL(issueUrl);
- } catch (MalformedURLException e) {
- return null;
- }
- URLConnection connection = request_url.openConnection();
- connection.setDoOutput(true);
- try {
+ try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
+ CloseableHttpResponse httpResponse = httpClient.execute(new HttpPost(issueUrl));
// parsing document from input stream
- InputStream stream = connection.getInputStream();
+ InputStream stream = httpResponse.getEntity().getContent();
Document doc = parser.build(stream);
return doc;
-
} catch (Exception e) {
log.error("Error while retrieving the license document for URI: " + licenseURI, e);
}
diff --git a/dspace-api/src/main/java/org/dspace/orcid/client/OrcidClientImpl.java b/dspace-api/src/main/java/org/dspace/orcid/client/OrcidClientImpl.java
index d691b625ee..c872f5c6ff 100644
--- a/dspace-api/src/main/java/org/dspace/orcid/client/OrcidClientImpl.java
+++ b/dspace-api/src/main/java/org/dspace/orcid/client/OrcidClientImpl.java
@@ -35,13 +35,14 @@ import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
-import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.orcid.OrcidToken;
import org.dspace.orcid.exception.OrcidClientException;
import org.dspace.orcid.model.OrcidEntityType;
@@ -254,10 +255,8 @@ public class OrcidClientImpl implements OrcidClient {
}
private void executeSuccessful(HttpUriRequest httpUriRequest) {
- try {
- HttpClient client = HttpClientBuilder.create().build();
- HttpResponse response = client.execute(httpUriRequest);
-
+ try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
+ CloseableHttpResponse response = client.execute(httpUriRequest);
if (isNotSuccessfull(response)) {
throw new OrcidClientException(
getStatusCode(response),
@@ -272,21 +271,17 @@ public class OrcidClientImpl implements OrcidClient {
}
private T executeAndParseJson(HttpUriRequest httpUriRequest, Class clazz) {
-
- HttpClient client = HttpClientBuilder.create().build();
-
- return executeAndReturns(() -> {
-
- HttpResponse response = client.execute(httpUriRequest);
-
- if (isNotSuccessfull(response)) {
- throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response));
- }
-
- return objectMapper.readValue(response.getEntity().getContent(), clazz);
-
- });
-
+ try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
+ return executeAndReturns(() -> {
+ CloseableHttpResponse response = client.execute(httpUriRequest);
+ if (isNotSuccessfull(response)) {
+ throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response));
+ }
+ return objectMapper.readValue(response.getEntity().getContent(), clazz);
+ });
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
/**
@@ -301,44 +296,37 @@ public class OrcidClientImpl implements OrcidClient {
* @throws OrcidClientException if the incoming response is not successful
*/
private T executeAndUnmarshall(HttpUriRequest httpUriRequest, boolean handleNotFoundAsNull, Class clazz) {
-
- HttpClient client = HttpClientBuilder.create().build();
-
- return executeAndReturns(() -> {
-
- HttpResponse response = client.execute(httpUriRequest);
-
- if (handleNotFoundAsNull && isNotFound(response)) {
- return null;
- }
-
- if (isNotSuccessfull(response)) {
- throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response));
- }
-
- return unmarshall(response.getEntity(), clazz);
-
- });
+ try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
+ return executeAndReturns(() -> {
+ CloseableHttpResponse response = client.execute(httpUriRequest);
+ if (handleNotFoundAsNull && isNotFound(response)) {
+ return null;
+ }
+ if (isNotSuccessfull(response)) {
+ throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response));
+ }
+ return unmarshall(response.getEntity(), clazz);
+ });
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
private OrcidResponse execute(HttpUriRequest httpUriRequest, boolean handleNotFoundAsNull) {
- HttpClient client = HttpClientBuilder.create().build();
-
- return executeAndReturns(() -> {
-
- HttpResponse response = client.execute(httpUriRequest);
-
- if (handleNotFoundAsNull && isNotFound(response)) {
- return new OrcidResponse(getStatusCode(response), null, getContent(response));
- }
-
- if (isNotSuccessfull(response)) {
- throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response));
- }
-
- return new OrcidResponse(getStatusCode(response), getPutCode(response), getContent(response));
-
- });
+ try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
+ return executeAndReturns(() -> {
+ CloseableHttpResponse response = client.execute(httpUriRequest);
+ if (handleNotFoundAsNull && isNotFound(response)) {
+ return new OrcidResponse(getStatusCode(response), null, getContent(response));
+ }
+ if (isNotSuccessfull(response)) {
+ throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response));
+ }
+ return new OrcidResponse(getStatusCode(response), getPutCode(response), getContent(response));
+ });
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
private T executeAndReturns(ThrowingSupplier supplier) {
diff --git a/dspace-api/src/main/java/org/dspace/orcid/model/factory/OrcidFactoryUtils.java b/dspace-api/src/main/java/org/dspace/orcid/model/factory/OrcidFactoryUtils.java
index 38aa611ff3..ce68ab47c2 100644
--- a/dspace-api/src/main/java/org/dspace/orcid/model/factory/OrcidFactoryUtils.java
+++ b/dspace-api/src/main/java/org/dspace/orcid/model/factory/OrcidFactoryUtils.java
@@ -20,7 +20,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.json.JSONObject;
/**
@@ -97,7 +97,7 @@ public final class OrcidFactoryUtils {
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
HttpResponse response;
- try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
+ try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
response = httpClient.execute(httpPost);
}
JSONObject responseObject = null;
diff --git a/dspace-api/src/main/java/org/dspace/qaevent/service/impl/QAEventActionServiceImpl.java b/dspace-api/src/main/java/org/dspace/qaevent/service/impl/QAEventActionServiceImpl.java
index 30875a5105..6b9aea91de 100644
--- a/dspace-api/src/main/java/org/dspace/qaevent/service/impl/QAEventActionServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/qaevent/service/impl/QAEventActionServiceImpl.java
@@ -22,9 +22,9 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.content.Item;
import org.dspace.content.QAEvent;
import org.dspace.content.service.ItemService;
@@ -114,20 +114,19 @@ public class QAEventActionServiceImpl implements QAEventActionService {
* Make acknowledgement to the configured urls for the event status.
*/
private void makeAcknowledgement(String eventId, String source, String status) {
- String[] ackwnoledgeCallbacks = configurationService
+ String[] acknowledgeCallbacks = configurationService
.getArrayProperty("qaevents." + source + ".acknowledge-url");
- if (ackwnoledgeCallbacks != null) {
- for (String ackwnoledgeCallback : ackwnoledgeCallbacks) {
- if (StringUtils.isNotBlank(ackwnoledgeCallback)) {
+ if (acknowledgeCallbacks != null) {
+ for (String acknowledgeCallback : acknowledgeCallbacks) {
+ if (StringUtils.isNotBlank(acknowledgeCallback)) {
ObjectNode node = jsonMapper.createObjectNode();
node.put("eventId", eventId);
node.put("status", status);
StringEntity requestEntity = new StringEntity(node.toString(), ContentType.APPLICATION_JSON);
- CloseableHttpClient httpclient = HttpClients.createDefault();
- HttpPost postMethod = new HttpPost(ackwnoledgeCallback);
- postMethod.setEntity(requestEntity);
- try {
- httpclient.execute(postMethod);
+ try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().buildWithoutProxy()) {
+ HttpPost postMethod = new HttpPost(acknowledgeCallback);
+ postMethod.setEntity(requestEntity);
+ httpClient.execute(postMethod);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
diff --git a/dspace-api/src/main/java/org/dspace/service/impl/HttpConnectionPoolService.java b/dspace-api/src/main/java/org/dspace/service/impl/HttpConnectionPoolService.java
index 31a8ed12c1..f0484a0576 100644
--- a/dspace-api/src/main/java/org/dspace/service/impl/HttpConnectionPoolService.java
+++ b/dspace-api/src/main/java/org/dspace/service/impl/HttpConnectionPoolService.java
@@ -19,11 +19,11 @@ import org.apache.http.HttpResponse;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.services.ConfigurationService;
/**
@@ -112,7 +112,7 @@ public class HttpConnectionPoolService {
* @return the client.
*/
public CloseableHttpClient getClient() {
- CloseableHttpClient httpClient = HttpClientBuilder.create()
+ CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().builder(true).create()
.setKeepAliveStrategy(keepAliveStrategy)
.setConnectionManager(connManager)
.build();
diff --git a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java
index 55fa9c4dd1..442b0e52f5 100644
--- a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java
@@ -54,7 +54,6 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.SolrClient;
@@ -84,6 +83,7 @@ import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.util.NamedList;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
@@ -1208,7 +1208,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
+ "."
+ i
+ ".csv");
- try ( CloseableHttpClient hc = HttpClientBuilder.create().build(); ) {
+ try (CloseableHttpClient hc = DSpaceHttpClientFactory.getInstance().buildWithoutProxy()) {
HttpResponse response = hc.execute(get);
csvInputstream = response.getEntity().getContent();
//Write the csv output to a file !
@@ -1350,7 +1350,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
HttpGet get = new HttpGet(solrRequestUrl);
List rows;
- try ( CloseableHttpClient hc = HttpClientBuilder.create().build(); ) {
+ try (CloseableHttpClient hc = DSpaceHttpClientFactory.getInstance().buildWithoutProxy()) {
HttpResponse response = hc.execute(get);
InputStream csvOutput = response.getEntity().getContent();
Reader csvReader = new InputStreamReader(csvOutput);
diff --git a/dspace-api/src/main/java/org/dspace/statistics/export/service/OpenUrlServiceImpl.java b/dspace-api/src/main/java/org/dspace/statistics/export/service/OpenUrlServiceImpl.java
index e13b3ee677..8e15f4f1d2 100644
--- a/dspace-api/src/main/java/org/dspace/statistics/export/service/OpenUrlServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/statistics/export/service/OpenUrlServiceImpl.java
@@ -15,13 +15,13 @@ import java.time.LocalDate;
import java.util.List;
import org.apache.commons.lang.StringUtils;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.core.Context;
import org.dspace.statistics.export.OpenURLTracker;
import org.springframework.beans.factory.annotation.Autowired;
@@ -69,16 +69,16 @@ public class OpenUrlServiceImpl implements OpenUrlService {
* @throws IOException
*/
protected int getResponseCodeFromUrl(final String urlStr) throws IOException {
- HttpGet httpGet = new HttpGet(urlStr);
- HttpClient httpClient = getHttpClient(getHttpClientRequestConfig());
- HttpResponse httpResponse = httpClient.execute(httpGet);
- return httpResponse.getStatusLine().getStatusCode();
+ try (CloseableHttpClient httpClient = getHttpClient(getHttpClientRequestConfig())) {
+ HttpGet httpGet = new HttpGet(urlStr);
+ try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
+ return httpResponse.getStatusLine().getStatusCode();
+ }
+ }
}
- protected HttpClient getHttpClient(RequestConfig requestConfig) {
- return HttpClientBuilder.create()
- .setDefaultRequestConfig(requestConfig)
- .build();
+ protected CloseableHttpClient getHttpClient(RequestConfig requestConfig) {
+ return DSpaceHttpClientFactory.getInstance().buildWithRequestConfig(requestConfig);
}
protected RequestConfig getHttpClientRequestConfig() {
diff --git a/dspace-api/src/test/java/org/dspace/app/client/DSpaceHttpClientFactoryTest.java b/dspace-api/src/test/java/org/dspace/app/client/DSpaceHttpClientFactoryTest.java
new file mode 100644
index 0000000000..b518f19ff4
--- /dev/null
+++ b/dspace-api/src/test/java/org/dspace/app/client/DSpaceHttpClientFactoryTest.java
@@ -0,0 +1,256 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.client;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.arrayWithSize;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.protocol.HttpContext;
+import org.dspace.services.ConfigurationService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+/**
+ * Unit tests for {@link DSpaceHttpClientFactory}.
+ *
+ * @author Luca Giamminonni (luca.giamminonni at 4science.it)
+ *
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class DSpaceHttpClientFactoryTest {
+
+ @InjectMocks
+ private DSpaceHttpClientFactory httpClientFactory;
+
+ @Mock
+ private ConfigurationService configurationService;
+
+ private MockWebServer mockProxy;
+
+ private MockWebServer mockServer;
+
+ @Before
+ public void init() {
+ this.httpClientFactory.setProxyRoutePlanner(new DSpaceProxyRoutePlanner(configurationService));
+ this.mockProxy = new MockWebServer();
+ this.mockProxy.enqueue(new MockResponse().setResponseCode(200).addHeader("From", "Proxy"));
+ this.mockServer = new MockWebServer();
+ this.mockServer.enqueue(new MockResponse().setResponseCode(200).addHeader("From", "Server"));
+ }
+
+ @Test
+ public void testBuildWithProxyConfigured() throws Exception {
+ setHttpProxyOnConfigurationService();
+ CloseableHttpClient httpClient = httpClientFactory.build();
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(0));
+ CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(mockServer.url("").toString()));
+ assertThat(httpResponse.getHeaders("From"), arrayWithSize(1));
+ assertThat(httpResponse.getHeaders("From")[0].getValue(), is("Proxy"));
+ assertThat(mockProxy.getRequestCount(), is(1));
+ assertThat(mockServer.getRequestCount(), is(0));
+ RecordedRequest request = mockProxy.takeRequest(100, TimeUnit.MILLISECONDS);
+ assertThat(request, notNullValue());
+ assertThat(request.getRequestUrl(), is(mockProxy.url("")));
+ assertThat(request.getRequestLine(), is("GET " + mockServer.url("").toString() + " HTTP/1.1"));
+ verify(configurationService).getProperty("http.proxy.host");
+ verify(configurationService).getProperty("http.proxy.port");
+ verify(configurationService).getArrayProperty("http.proxy.hosts-to-ignore");
+ verifyNoMoreInteractions(configurationService);
+ }
+
+ @Test
+ public void testBuildWithProxyConfiguredAndHostToIgnoreSet() throws Exception {
+ setHttpProxyOnConfigurationService(mockServer.getHostName());
+ CloseableHttpClient httpClient = httpClientFactory.build();
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(0));
+ CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(mockServer.url("").toString()));
+ assertThat(httpResponse.getHeaders("From"), arrayWithSize(1));
+ assertThat(httpResponse.getHeaders("From")[0].getValue(), is("Server"));
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(1));
+ verify(configurationService).getArrayProperty("http.proxy.hosts-to-ignore");
+ verifyNoMoreInteractions(configurationService);
+ }
+
+ @Test
+ public void testBuildWithProxyConfiguredAndHostPrefixToIgnoreSet() throws Exception {
+ setHttpProxyOnConfigurationService("local*", "www.test.com");
+ CloseableHttpClient httpClient = httpClientFactory.build();
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(0));
+ CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(mockServer.url("").toString()));
+ assertThat(httpResponse.getHeaders("From"), arrayWithSize(1));
+ assertThat(httpResponse.getHeaders("From")[0].getValue(), is("Server"));
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(1));
+ verify(configurationService).getArrayProperty("http.proxy.hosts-to-ignore");
+ verifyNoMoreInteractions(configurationService);
+ }
+
+ @Test
+ public void testBuildWithProxyConfiguredAndHostSuffixToIgnoreSet() throws Exception {
+ setHttpProxyOnConfigurationService("www.test.com", "*host");
+ CloseableHttpClient httpClient = httpClientFactory.build();
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(0));
+ CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(mockServer.url("").toString()));
+ assertThat(httpResponse.getHeaders("From"), arrayWithSize(1));
+ assertThat(httpResponse.getHeaders("From")[0].getValue(), is("Server"));
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(1));
+ verify(configurationService).getArrayProperty("http.proxy.hosts-to-ignore");
+ verifyNoMoreInteractions(configurationService);
+ }
+
+ @Test
+ public void testBuildWithoutConfiguredProxy() throws Exception {
+ CloseableHttpClient httpClient = httpClientFactory.build();
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(0));
+ CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(mockServer.url("").toString()));
+ assertThat(httpResponse.getHeaders("From"), arrayWithSize(1));
+ assertThat(httpResponse.getHeaders("From")[0].getValue(), is("Server"));
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(1));
+ RecordedRequest request = mockServer.takeRequest(100, TimeUnit.MILLISECONDS);
+ assertThat(request, notNullValue());
+ assertThat(request.getRequestUrl(), is(mockServer.url("")));
+ assertThat(request.getRequestLine(), is("GET / HTTP/1.1"));
+ verify(configurationService).getProperty("http.proxy.host");
+ verify(configurationService).getProperty("http.proxy.port");
+ verify(configurationService).getArrayProperty("http.proxy.hosts-to-ignore");
+ verifyNoMoreInteractions(configurationService);
+ }
+
+ @Test
+ public void testBuildWithoutProxy() throws Exception {
+ CloseableHttpClient httpClient = httpClientFactory.buildWithoutProxy();
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(0));
+ httpClient.execute(new HttpGet(mockServer.url("").toString()));
+ assertThat(mockServer.getRequestCount(), is(1));
+ assertThat(mockProxy.getRequestCount(), is(0));
+ RecordedRequest request = mockServer.takeRequest(100, TimeUnit.MILLISECONDS);
+ assertThat(request, notNullValue());
+ assertThat(request.getRequestUrl(), is(mockServer.url("")));
+ assertThat(request.getRequestLine(), is("GET / HTTP/1.1"));
+ verifyNoInteractions(configurationService);
+ }
+
+ @Test
+ public void testBuildWithoutAutomaticRetries() throws Exception {
+ setHttpProxyOnConfigurationService("www.test.com");
+ CloseableHttpClient httpClient = httpClientFactory.buildWithoutAutomaticRetries(10);
+ httpClient.execute(new HttpGet(mockServer.url("").toString()));
+ assertThat(mockProxy.getRequestCount(), is(1));
+ assertThat(mockServer.getRequestCount(), is(0));
+ RecordedRequest request = mockProxy.takeRequest(100, TimeUnit.MILLISECONDS);
+ assertThat(request, notNullValue());
+ assertThat(request.getRequestUrl(), is(mockProxy.url("")));
+ assertThat(request.getRequestLine(), is("GET " + mockServer.url("").toString() + " HTTP/1.1"));
+ verify(configurationService).getProperty("http.proxy.host");
+ verify(configurationService).getProperty("http.proxy.port");
+ verify(configurationService).getArrayProperty("http.proxy.hosts-to-ignore");
+ verifyNoMoreInteractions(configurationService);
+ }
+
+ @Test
+ public void testBuildWithHttpRequestInterceptor() throws Exception {
+ setHttpProxyOnConfigurationService("*test.com", "www.dspace.com");
+ AtomicReference contextReference = new AtomicReference();
+ HttpRequestInterceptor interceptor = (request, context) -> contextReference.set(context);
+ httpClientFactory.setRequestInterceptors(List.of(interceptor));
+ CloseableHttpClient httpClient = httpClientFactory.build();
+ httpClient.execute(new HttpGet(mockServer.url("").toString()));
+ assertThat(mockProxy.getRequestCount(), is(1));
+ assertThat(mockServer.getRequestCount(), is(0));
+ HttpContext httpContext = contextReference.get();
+ assertThat(httpContext, notNullValue());
+ Object httpRouteObj = httpContext.getAttribute("http.route");
+ assertThat(httpRouteObj, notNullValue());
+ assertThat(httpRouteObj, instanceOf(HttpRoute.class));
+ HttpRoute httpRoute = (HttpRoute) httpRouteObj;
+ assertThat(httpRoute.getHopCount(), is(2));
+ assertThat(httpRoute.getHopTarget(0).getPort(), is(mockProxy.getPort()));
+ assertThat(httpRoute.getHopTarget(1).getPort(), is(mockServer.getPort()));
+ }
+
+ @Test
+ public void testBuildWithHttpResponseInterceptor() throws Exception {
+ AtomicReference responseReference = new AtomicReference();
+ HttpResponseInterceptor responseInterceptor = (response, context) -> responseReference.set(response);
+ httpClientFactory.setResponseInterceptors(List.of(responseInterceptor));
+ CloseableHttpClient httpClient = httpClientFactory.build();
+ httpClient.execute(new HttpGet(mockServer.url("").toString()));
+ assertThat(mockProxy.getRequestCount(), is(0));
+ assertThat(mockServer.getRequestCount(), is(1));
+ HttpResponse httpResponse = responseReference.get();
+ assertThat(httpResponse, notNullValue());
+ assertThat(httpResponse.getHeaders("From"), arrayWithSize(1));
+ assertThat(httpResponse.getHeaders("From")[0].getValue(), is("Server"));
+ }
+
+ @Test
+ public void testBuildWithRequestConfig() throws Exception {
+ setHttpProxyOnConfigurationService();
+ RequestConfig requestConfig = RequestConfig.custom()
+ .setConnectTimeout(2500)
+ .build();
+ AtomicReference contextReference = new AtomicReference();
+ HttpRequestInterceptor interceptor = (request, context) -> contextReference.set(context);
+ httpClientFactory.setRequestInterceptors(List.of(interceptor));
+ CloseableHttpClient httpClient = httpClientFactory.buildWithRequestConfig(requestConfig);
+ httpClient.execute(new HttpGet(mockServer.url("").toString()));
+ assertThat(mockProxy.getRequestCount(), is(1));
+ assertThat(mockServer.getRequestCount(), is(0));
+ HttpContext httpContext = contextReference.get();
+ assertThat(httpContext, notNullValue());
+ Object httpRequestConfigObj = httpContext.getAttribute("http.request-config");
+ assertThat(httpRequestConfigObj, notNullValue());
+ assertThat(httpRequestConfigObj, instanceOf(RequestConfig.class));
+ assertThat(((RequestConfig) httpRequestConfigObj).getConnectTimeout(), is(2500));
+ verify(configurationService).getProperty("http.proxy.host");
+ verify(configurationService).getProperty("http.proxy.port");
+ verify(configurationService).getArrayProperty("http.proxy.hosts-to-ignore");
+ verifyNoMoreInteractions(configurationService);
+ }
+
+ private void setHttpProxyOnConfigurationService(String... hostsToIgnore) {
+ when(configurationService.getProperty("http.proxy.host")).thenReturn(mockProxy.getHostName());
+ when(configurationService.getProperty("http.proxy.port")).thenReturn(String.valueOf(mockProxy.getPort()));
+ when(configurationService.getArrayProperty("http.proxy.hosts-to-ignore")).thenReturn(hostsToIgnore);
+ }
+}
\ No newline at end of file
diff --git a/dspace-api/src/test/java/org/dspace/statistics/export/service/OpenUrlServiceImplTest.java b/dspace-api/src/test/java/org/dspace/statistics/export/service/OpenUrlServiceImplTest.java
index d0bc16cef7..3cdc7e622d 100644
--- a/dspace-api/src/test/java/org/dspace/statistics/export/service/OpenUrlServiceImplTest.java
+++ b/dspace-api/src/test/java/org/dspace/statistics/export/service/OpenUrlServiceImplTest.java
@@ -25,9 +25,9 @@ import java.sql.SQLException;
import java.time.LocalDate;
import java.util.List;
-import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
-import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.impl.client.CloseableHttpClient;
import org.dspace.core.Context;
import org.dspace.statistics.export.OpenURLTracker;
import org.junit.Before;
@@ -52,7 +52,7 @@ public class OpenUrlServiceImplTest {
private FailedOpenURLTrackerService failedOpenURLTrackerService;
@Mock
- private HttpClient httpClient;
+ private CloseableHttpClient httpClient;
@Before
public void setUp() throws Exception {
@@ -71,11 +71,11 @@ public class OpenUrlServiceImplTest {
* @param statusCode the http status code to use in the mock.
* @return a mocked http response.
*/
- protected HttpResponse createMockHttpResponse(int statusCode) {
+ protected CloseableHttpResponse createMockHttpResponse(int statusCode) {
StatusLine statusLine = mock(StatusLine.class);
when(statusLine.getStatusCode()).thenReturn(statusCode);
- HttpResponse httpResponse = mock(HttpResponse.class);
+ CloseableHttpResponse httpResponse = mock(CloseableHttpResponse.class);
when(httpResponse.getStatusLine()).thenReturn(statusLine);
return httpResponse;
diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg
index fd32f7d0c0..91b0e48fc3 100644
--- a/dspace/config/dspace.cfg
+++ b/dspace/config/dspace.cfg
@@ -411,6 +411,8 @@ http.proxy.host =
# port number of proxy server
http.proxy.port =
+http.proxy.hosts-to-ignore = 127.0.0.1, localhost
+
# If enabled, the logging and the Solr statistics system will look for an X-Forwarded-For header.
# If it finds it, it will use this for the user IP address.
# NOTE: This is required to be enabled if you plan to use the Angular UI, as the server-side rendering provided in
diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml
index e5482cad00..8a0fb535cd 100644
--- a/dspace/config/spring/api/core-services.xml
+++ b/dspace/config/spring/api/core-services.xml
@@ -162,6 +162,9 @@
+
+
+
diff --git a/pom.xml b/pom.xml
index 144e9e2d7e..38e9fab3f5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1746,6 +1746,12 @@
2.3.232
test
+
+ com.squareup.okhttp3
+ mockwebserver
+ 4.12.0
+ test
+