diff --git a/pom.xml b/pom.xml
index 2f0ae4e9..de68d6af 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.7.17
+ 2.7.18
@@ -32,14 +32,13 @@
17
- 2.7.17
+ 2.7.18
italiangrid_storm-webdav
italiangrid
https://sonarcloud.io
- 0.4.6.v20220506
2.7.1.7
2.3
@@ -58,6 +57,7 @@
6.0.2
5.5.1
1.76
+ 3.3.2
org.italiangrid.storm.webdav.WebdavService
@@ -348,34 +348,6 @@
metrics-servlets
-
- org.italiangrid
- jetty-utils
- ${jetty-utils.version}
-
-
- javax.activation
- activation
-
-
- javax.mail
- mail
-
-
- org.eclipse.jetty.aggregate
- jetty-all
-
-
- ch.qos.logback
- logback-core
-
-
- ch.qos.logback
- logback-classic
-
-
-
-
org.bouncycastle
bcpkix-jdk18on
@@ -388,7 +360,6 @@
${bouncycastle.version}
-
ch.qos.logback
logback-access
@@ -419,6 +390,34 @@
org.eclipse.jetty
jetty-rewrite
+
+ org.eclipse.jetty
+ jetty-server
+
+
+ org.eclipse.jetty
+ jetty-http
+
+
+ org.eclipse.jetty
+ jetty-util
+
+
+ org.eclipse.jetty
+ jetty-alpn-server
+
+
+ org.eclipse.jetty.http2
+ http2-server
+
+
+ org.eclipse.jetty.http2
+ http2-common
+
+
+ org.eclipse.jetty
+ jetty-alpn-conscrypt-server
+
commons-lang
@@ -463,6 +462,12 @@
${milton.version}
+
+ org.italiangrid
+ voms-api-java
+ ${voms-api-java.version}
+
+
commons-cli
commons-cli
diff --git a/src/main/java/org/italiangrid/storm/webdav/server/DefaultJettyServerCustomizer.java b/src/main/java/org/italiangrid/storm/webdav/server/DefaultJettyServerCustomizer.java
index 4e798c4e..8bbd9b1a 100644
--- a/src/main/java/org/italiangrid/storm/webdav/server/DefaultJettyServerCustomizer.java
+++ b/src/main/java/org/italiangrid/storm/webdav/server/DefaultJettyServerCustomizer.java
@@ -32,7 +32,7 @@
import org.italiangrid.storm.webdav.config.ServiceConfiguration;
import org.italiangrid.storm.webdav.config.ServiceConfigurationProperties;
import org.italiangrid.storm.webdav.config.StorageAreaConfiguration;
-import org.italiangrid.utils.jetty.TLSServerConnectorBuilder;
+import org.italiangrid.storm.webdav.server.util.TLSServerConnectorBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.ServerProperties;
diff --git a/src/main/java/org/italiangrid/storm/webdav/server/DefaultWebServerFactory.java b/src/main/java/org/italiangrid/storm/webdav/server/DefaultWebServerFactory.java
index b2fb8dfb..b5535a66 100644
--- a/src/main/java/org/italiangrid/storm/webdav/server/DefaultWebServerFactory.java
+++ b/src/main/java/org/italiangrid/storm/webdav/server/DefaultWebServerFactory.java
@@ -16,7 +16,7 @@
package org.italiangrid.storm.webdav.server;
import org.italiangrid.storm.webdav.config.ServiceConfiguration;
-import org.italiangrid.utils.jetty.ThreadPoolBuilder;
+import org.italiangrid.storm.webdav.server.util.ThreadPoolBuilder;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
diff --git a/src/main/java/org/italiangrid/storm/webdav/server/util/TLSConnectorBuilderError.java b/src/main/java/org/italiangrid/storm/webdav/server/util/TLSConnectorBuilderError.java
new file mode 100644
index 00000000..8e3de4da
--- /dev/null
+++ b/src/main/java/org/italiangrid/storm/webdav/server/util/TLSConnectorBuilderError.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2012-2019.
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.italiangrid.storm.webdav.server.util;
+
+public class TLSConnectorBuilderError extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public TLSConnectorBuilderError(Throwable cause) {
+ super(cause);
+ }
+
+ public TLSConnectorBuilderError(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public TLSConnectorBuilderError(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/org/italiangrid/storm/webdav/server/util/TLSServerConnectorBuilder.java b/src/main/java/org/italiangrid/storm/webdav/server/util/TLSServerConnectorBuilder.java
new file mode 100644
index 00000000..e61ff2d0
--- /dev/null
+++ b/src/main/java/org/italiangrid/storm/webdav/server/util/TLSServerConnectorBuilder.java
@@ -0,0 +1,662 @@
+/**
+ * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2012-2019.
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.italiangrid.storm.webdav.server.util;
+
+import static java.util.Objects.isNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.security.cert.CertificateException;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.conscrypt.OpenSSLProvider;
+import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http2.HTTP2Cipher;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.server.ConnectionFactory;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.jetty9.InstrumentedConnectionFactory;
+
+import eu.emi.security.authn.x509.X509CertChainValidatorExt;
+import eu.emi.security.authn.x509.helpers.ssl.SSLTrustManager;
+import eu.emi.security.authn.x509.impl.PEMCredential;
+
+/**
+ * A builder that configures a Jetty server TLS connector integrated with CANL
+ * {@link X509CertChainValidatorExt} certificate validation services.
+ *
+ */
+public class TLSServerConnectorBuilder {
+
+ /**
+ * Conscrypt provider name.
+ */
+ public static final String CONSCRYPT_PROVIDER = "Conscrypt";
+
+ /**
+ * Default service certificate file.
+ */
+ public static final String DEFAULT_CERTIFICATE_FILE = "/etc/grid-security/hostcert.pem";
+
+ /**
+ * Default service certificate private key file.
+ */
+ public static final String DEFAULT_CERTIFICATE_KEY_FILE = "/etc/grid-security/hostcert.pem";
+
+ /**
+ * The port for this connector.
+ */
+ private int port;
+
+ /**
+ * The certificate file location.
+ */
+ private String certificateFile = DEFAULT_CERTIFICATE_FILE;
+
+ /**
+ * The certificate private key file location.
+ */
+ private String certificateKeyFile = DEFAULT_CERTIFICATE_KEY_FILE;
+
+ /**
+ * The password to decrypt the certificate private key file.
+ */
+ private char[] certicateKeyPassword = null;
+
+ /**
+ * The certificate validator used by this connector builder.
+ */
+ private final X509CertChainValidatorExt certificateValidator;
+
+ /**
+ * Whether client auth will be required for this connector.
+ */
+ private boolean tlsNeedClientAuth = false;
+
+ /**
+ * Whether cluent auth is supported for this connector.
+ */
+ private boolean tlsWantClientAuth = true;
+
+ /**
+ * Supported SSL protocols.
+ */
+ private String[] includeProtocols;
+
+ /**
+ * Disabled SSL protocols.
+ */
+ private String[] excludeProtocols;
+
+ /**
+ * Supported cipher suites.
+ */
+ private String[] includeCipherSuites;
+
+ /**
+ * Disabled cipher suites.
+ */
+ private String[] excludeCipherSuites;
+
+ /**
+ * The HTTP configuration for the connector being created.
+ */
+ private HttpConfiguration httpConfiguration;
+
+ /**
+ * The key manager to use for the connector being created.
+ */
+ private KeyManager keyManager;
+
+ /**
+ * The server for which the connector is being created.
+ */
+ private final Server server;
+
+ /**
+ * The metric name to associate to the connector being built.
+ */
+ private String metricName;
+
+ /**
+ * The metric registry.
+ */
+ private MetricRegistry registry;
+
+ /**
+ * Whether the Conscrypt provider should be used instead of the default JSSE implementation
+ */
+ private boolean useConscrypt = false;
+
+
+ /**
+ * Whether HTTP/2 should be configured
+ */
+ private boolean enableHttp2 = false;
+
+ /**
+ * Which TLS protocol string should be used
+ */
+ private String tlsProtocol = "TLSv1.2";
+
+ /**
+ * Custom TLS hostname verifier
+ */
+ private HostnameVerifier hostnameVerifier = null;
+
+ /**
+ * Disable JSSE hostname verification
+ */
+ private boolean disableJsseHostnameVerification = false;
+
+ /**
+ * Number of acceptors threads for the connector
+ */
+ private int acceptors = -1;
+
+ /**
+ * Number of selector threads for the connector
+ */
+ private int selectors = -1;
+
+ /**
+ * Returns an instance of the {@link TLSServerConnectorBuilder}.
+ *
+ * @param s the {@link Server} for which the connector is being created
+ * @param certificateValidator a {@link X509CertChainValidatorExt} used to validate certificates
+ * @return an instance of the {@link TLSServerConnectorBuilder}
+ */
+ public static TLSServerConnectorBuilder instance(Server s,
+ X509CertChainValidatorExt certificateValidator) {
+
+ return new TLSServerConnectorBuilder(s, certificateValidator);
+ }
+
+ /**
+ * Private ctor.
+ *
+ * @param s the {@link Server} for which the connector is being created
+ * @param certificateValidator a {@link X509CertChainValidatorExt} used to validate certificates
+ */
+ private TLSServerConnectorBuilder(Server s, X509CertChainValidatorExt certificateValidator) {
+
+ if (s == null) {
+ throw new IllegalArgumentException("Server cannot be null");
+ }
+
+ if (certificateValidator == null) {
+ throw new IllegalArgumentException("certificateValidator cannot be null");
+ }
+
+ this.server = s;
+ this.certificateValidator = certificateValidator;
+ }
+
+ private void credentialsSanityChecks() {
+
+ checkFileExistsAndIsReadable(new File(certificateFile), "Error accessing certificate file");
+
+ checkFileExistsAndIsReadable(new File(certificateKeyFile),
+ "Error accessing certificate key file");
+
+ }
+
+ private void loadCredentials() {
+
+ credentialsSanityChecks();
+
+ PEMCredential serviceCredentials = null;
+
+ try {
+
+ serviceCredentials =
+ new PEMCredential(certificateKeyFile, certificateFile, certicateKeyPassword);
+
+ } catch (KeyStoreException | CertificateException | IOException e) {
+
+ throw new TLSConnectorBuilderError("Error setting up service credentials", e);
+ }
+
+ keyManager = serviceCredentials.getKeyManager();
+ }
+
+ /**
+ * Configures SSL session parameters for the jetty {@link SslContextFactory}.
+ *
+ * @param contextFactory the {@link SslContextFactory} being configured
+ */
+ private void configureContextFactory(SslContextFactory.Server contextFactory) {
+
+ if (excludeProtocols != null) {
+ contextFactory.setExcludeProtocols(excludeProtocols);
+ }
+
+ if (includeProtocols != null) {
+ contextFactory.setIncludeProtocols(includeProtocols);
+ }
+
+ if (excludeCipherSuites != null) {
+ contextFactory.setExcludeCipherSuites(excludeCipherSuites);
+ }
+
+ if (includeCipherSuites != null) {
+ contextFactory.setIncludeCipherSuites(includeCipherSuites);
+ }
+
+ contextFactory.setWantClientAuth(tlsWantClientAuth);
+ contextFactory.setNeedClientAuth(tlsNeedClientAuth);
+
+ if (useConscrypt) {
+ contextFactory.setProvider(CONSCRYPT_PROVIDER);
+ } else {
+ contextFactory.setProvider(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ if (hostnameVerifier != null) {
+ contextFactory.setHostnameVerifier(hostnameVerifier);
+ }
+
+ if (disableJsseHostnameVerification) {
+ contextFactory.setEndpointIdentificationAlgorithm(null);
+ }
+
+ }
+
+ /**
+ * Builds a default {@link HttpConfiguration} for the TLS-enabled connector being created
+ *
+ * @return the default {@link HttpConfiguration}
+ */
+ private HttpConfiguration defaultHttpConfiguration() {
+
+ HttpConfiguration httpsConfig = new HttpConfiguration();
+
+ httpsConfig.setSecureScheme("https");
+
+ httpsConfig.setSecurePort(port);
+
+ httpsConfig.setOutputBufferSize(32768);
+ httpsConfig.setRequestHeaderSize(8192);
+ httpsConfig.setResponseHeaderSize(8192);
+
+ httpsConfig.setSendServerVersion(true);
+ httpsConfig.setSendDateHeader(false);
+
+ httpsConfig.addCustomizer(new SecureRequestCustomizer());
+
+ return httpsConfig;
+
+ }
+
+ /**
+ * Gives access to the {@link HttpConfiguration} used for the TLS-enabled connector being created.
+ * If the configuration is not set, it creates it using {@link #defaultHttpConfiguration()}.
+ *
+ * @return the {@link HttpConfiguration} being used for the TLS-enabled connector.
+ */
+ public HttpConfiguration httpConfiguration() {
+
+ if (httpConfiguration == null) {
+ httpConfiguration = defaultHttpConfiguration();
+ }
+
+ return httpConfiguration;
+
+ }
+
+ /**
+ * Sets the port for the connector being created.
+ *
+ * @param port the port for the connector
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withPort(int port) {
+
+ this.port = port;
+ return this;
+ }
+
+ /**
+ * Sets the certificate file for the connector being created.
+ *
+ * @param certificateFile the certificate file
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withCertificateFile(String certificateFile) {
+
+ this.certificateFile = certificateFile;
+ return this;
+ }
+
+ /**
+ * Sets the certificate key file for the connector being created.
+ *
+ * @param certificateKeyFile the certificate key file
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withCertificateKeyFile(String certificateKeyFile) {
+
+ this.certificateKeyFile = certificateKeyFile;
+ return this;
+ }
+
+ /**
+ * The the certificate key password for the connector being built
+ *
+ * @param certificateKeyPassword the certificate key password
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withCertificateKeyPassword(char[] certificateKeyPassword) {
+
+ this.certicateKeyPassword = certificateKeyPassword;
+ return this;
+ }
+
+ /**
+ * Sets the if client authentication is required or not.
+ *
+ * @param needClientAuth true if client authentication is required
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withNeedClientAuth(boolean needClientAuth) {
+
+ this.tlsNeedClientAuth = needClientAuth;
+ return this;
+ }
+
+ /**
+ * Sets if client authentication is wanted or not.
+ *
+ * @param wantClientAuth true if client authentication is wanted
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withWantClientAuth(boolean wantClientAuth) {
+
+ this.tlsWantClientAuth = wantClientAuth;
+ return this;
+ }
+
+ /**
+ * Sets SSL included protocols. See {@link SslContextFactory#setIncludeProtocols(String...)}.
+ *
+ * @param includeProtocols the array of included protocol names
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withIncludeProtocols(String... includeProtocols) {
+
+ this.includeProtocols = includeProtocols;
+ return this;
+ }
+
+ /**
+ * Sets SSL excluded protocols. See {@link SslContextFactory#setExcludeProtocols(String...)}.
+ *
+ * @param excludeProtocols the array of excluded protocol names
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withExcludeProtocols(String... excludeProtocols) {
+
+ this.excludeProtocols = excludeProtocols;
+ return this;
+ }
+
+ /**
+ * Sets the SSL included cipher suites.
+ *
+ * @param includeCipherSuites the array of included cipher suites.
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withIncludeCipherSuites(String... includeCipherSuites) {
+
+ this.includeCipherSuites = includeCipherSuites;
+ return this;
+ }
+
+ /**
+ * Sets the SSL ecluded cipher suites.
+ *
+ * @param excludeCipherSuites the array of excluded cipher suites.
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withExcludeCipherSuites(String... excludeCipherSuites) {
+
+ this.excludeCipherSuites = excludeCipherSuites;
+ return this;
+ }
+
+ /**
+ * Sets the {@link HttpConfiguration} for the connector being built.
+ *
+ * @param conf the {@link HttpConfiguration} to use
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withHttpConfiguration(HttpConfiguration conf) {
+
+ this.httpConfiguration = conf;
+ return this;
+ }
+
+ /**
+ * Sets the {@link KeyManager} for the connector being built.
+ *
+ * @param km the {@link KeyManager} to use
+ * @return this builder
+ */
+ public TLSServerConnectorBuilder withKeyManager(KeyManager km) {
+
+ this.keyManager = km;
+ return this;
+ }
+
+ public TLSServerConnectorBuilder withConscrypt(boolean conscryptEnabled) {
+ this.useConscrypt = conscryptEnabled;
+ return this;
+ }
+
+ public TLSServerConnectorBuilder withHttp2(boolean http2Enabled) {
+ this.enableHttp2 = http2Enabled;
+ return this;
+ }
+
+ public TLSServerConnectorBuilder metricRegistry(MetricRegistry registry) {
+ this.registry = registry;
+ return this;
+ }
+
+ public TLSServerConnectorBuilder metricName(String metricName) {
+ this.metricName = metricName;
+ return this;
+ }
+
+ public TLSServerConnectorBuilder withTlsProtocol(String tlsProtocol) {
+ this.tlsProtocol = tlsProtocol;
+ return this;
+ }
+
+ public TLSServerConnectorBuilder withHostnameVerifier(HostnameVerifier verifier) {
+ this.hostnameVerifier = verifier;
+ return this;
+ }
+
+ public TLSServerConnectorBuilder withDisableJsseHostnameVerification(
+ boolean disableJsseHostnameVerification) {
+ this.disableJsseHostnameVerification = disableJsseHostnameVerification;
+ return this;
+ }
+
+ public TLSServerConnectorBuilder withAcceptors(int acceptors) {
+ this.acceptors = acceptors;
+ return this;
+ }
+
+ public TLSServerConnectorBuilder withSelectors(int selectors) {
+ this.selectors = selectors;
+ return this;
+ }
+
+ private SSLContext buildSSLContext() {
+
+ SSLContext sslCtx;
+
+ try {
+
+ KeyManager[] kms = new KeyManager[] {keyManager};
+ SSLTrustManager tm = new SSLTrustManager(certificateValidator);
+
+ if (useConscrypt) {
+
+ if (isNull(Security.getProvider(CONSCRYPT_PROVIDER))) {
+ Security.addProvider(new OpenSSLProvider());
+ }
+
+ sslCtx = SSLContext.getInstance(tlsProtocol, CONSCRYPT_PROVIDER);
+ } else {
+ sslCtx = SSLContext.getInstance(tlsProtocol);
+ }
+
+ sslCtx.init(kms, new TrustManager[] {tm}, null);
+
+ } catch (NoSuchAlgorithmException e) {
+
+ throw new TLSConnectorBuilderError("TLS protocol not supported: " + e.getMessage(), e);
+ } catch (KeyManagementException e) {
+ throw new TLSConnectorBuilderError(e);
+ } catch (NoSuchProviderException e) {
+ throw new TLSConnectorBuilderError("TLS provider error: " + e.getMessage(), e);
+ }
+
+ return sslCtx;
+ }
+
+ /**
+ * Builds a {@link ServerConnector} based on the {@link TLSServerConnectorBuilder} parameters
+ *
+ * @return a {@link ServerConnector}
+ */
+ public ServerConnector build() {
+
+ if (keyManager == null) {
+ loadCredentials();
+ }
+
+ SSLContext sslContext = buildSSLContext();
+ SslContextFactory.Server cf = new SslContextFactory.Server();
+
+ cf.setSslContext(sslContext);
+
+
+ configureContextFactory(cf);
+
+ if (httpConfiguration == null) {
+ httpConfiguration = defaultHttpConfiguration();
+ }
+
+
+ HttpConnectionFactory httpConnFactory = new HttpConnectionFactory(httpConfiguration);
+ ConnectionFactory connFactory = null;
+
+ if (registry != null) {
+ connFactory = new InstrumentedConnectionFactory(httpConnFactory, registry.timer(metricName));
+ } else {
+ connFactory = httpConnFactory;
+ }
+
+
+ ConnectionFactory h2ConnFactory = null;
+ ServerConnector connector = null;
+
+ if (enableHttp2) {
+
+ HTTP2ServerConnectionFactory h2cf = new HTTP2ServerConnectionFactory(httpConfiguration);
+
+ if (registry != null) {
+ h2ConnFactory = new InstrumentedConnectionFactory(h2cf, registry.timer(metricName));
+ } else {
+ h2ConnFactory = h2cf;
+ }
+ ALPNServerConnectionFactory alpn = createAlpnProtocolFactory(httpConnFactory);
+ cf.setCipherComparator(HTTP2Cipher.COMPARATOR);
+ cf.setUseCipherSuitesOrder(true);
+
+ SslConnectionFactory sslCf = new SslConnectionFactory(cf, alpn.getProtocol());
+
+ connector = new ServerConnector(server, acceptors, selectors, sslCf, alpn, h2ConnFactory,
+ httpConnFactory);
+
+ } else {
+
+ connector = new ServerConnector(server, acceptors, selectors,
+ new SslConnectionFactory(cf, HttpVersion.HTTP_1_1.asString()), connFactory);
+ }
+
+ connector.setPort(port);
+ return connector;
+ }
+
+ private ALPNServerConnectionFactory createAlpnProtocolFactory(
+ HttpConnectionFactory httpConnectionFactory) {
+ ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
+ alpn.setDefaultProtocol(httpConnectionFactory.getProtocol());
+ return alpn;
+ }
+
+
+ /**
+ * Checks that file exists and is readable.
+ *
+ * @param f the {@link File} to be checked
+ * @param prefix A prefix string for the error message, in case the file does not exist and is not
+ * readable
+ * @throws RuntimeException if the file does not exist or is not readable
+ */
+ private void checkFileExistsAndIsReadable(File f, String prefix) {
+
+ String errorMessage = null;
+
+ if (!f.exists()) {
+ errorMessage = "File does not exists";
+ } else if (!f.canRead()) {
+ errorMessage = "File is not readable";
+ } else if (f.isDirectory()) {
+ errorMessage = "File is a directory";
+ }
+
+ if (errorMessage != null) {
+ String msg = String.format("%s: %s [%s]", prefix, errorMessage, f.getAbsolutePath());
+ throw new TLSConnectorBuilderError(msg);
+ }
+
+ }
+}
diff --git a/src/main/java/org/italiangrid/storm/webdav/server/util/ThreadPoolBuilder.java b/src/main/java/org/italiangrid/storm/webdav/server/util/ThreadPoolBuilder.java
new file mode 100644
index 00000000..3d7db1cc
--- /dev/null
+++ b/src/main/java/org/italiangrid/storm/webdav/server/util/ThreadPoolBuilder.java
@@ -0,0 +1,206 @@
+/**
+ * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2012-2019.
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.italiangrid.storm.webdav.server.util;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.eclipse.jetty.util.thread.ThreadPool;
+
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.jetty9.InstrumentedQueuedThreadPool;
+
+/**
+ *
+ * A builder to support thread pool configuration for a Jetty server.
+ *
+ */
+public class ThreadPoolBuilder {
+
+ /**
+ *
+ */
+ public static final int DEFAULT_MAX_REQUEST_QUEUE_SIZE = 200;
+
+ public static final int DEFAULT_MAX_THREADS = 50;
+ public static final int DEFAULT_MIN_THREADS = 1;
+
+ public static final int DEFAULT_IDLE_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(60);
+
+ public static final String DEFAULT_THREAD_POOL_METRIC_NAME = "thread-pool";
+ public static final String DEFAULT_THREAD_POOL_METRIC_PREFIX = "jetty";
+
+ private int maxThreads = DEFAULT_MAX_THREADS;
+ private int minThreads = DEFAULT_MIN_THREADS;
+
+ private int idleTimeout = DEFAULT_IDLE_TIMEOUT;
+ private int maxRequestQueueSize = DEFAULT_MAX_REQUEST_QUEUE_SIZE;
+
+ private String name = DEFAULT_THREAD_POOL_METRIC_NAME;
+ private String prefix = DEFAULT_THREAD_POOL_METRIC_PREFIX;
+
+ private MetricRegistry registry;
+
+ /**
+ * Returns a new {@link ThreadPoolBuilder} instance.
+ *
+ * @return a {@link ThreadPoolBuilder}
+ */
+ public static ThreadPoolBuilder instance() {
+
+ return new ThreadPoolBuilder();
+ }
+
+ /**
+ * Sets the max number of threads for the thread pool.
+ *
+ * @param maxNumberOfThreads the max number of threads
+ *
+ * @return this builder
+ *
+ */
+ public ThreadPoolBuilder withMaxThreads(int maxNumberOfThreads) {
+
+ this.maxThreads = maxNumberOfThreads;
+ return this;
+ }
+
+ /**
+ * Sets the minimum number of threads for the thread pool.
+ *
+ * @param minNumberOfThreads the minimum number of threads
+ * @return this builder
+ */
+ public ThreadPoolBuilder withMinThreads(int minNumberOfThreads) {
+
+ this.minThreads = minNumberOfThreads;
+ return this;
+ }
+
+ /**
+ * Sets the maximum request queue size for this thread pool.
+ *
+ * @param queueSize the maximum request queue size.
+ *
+ * @return this builder
+ */
+ public ThreadPoolBuilder withMaxRequestQueueSize(int queueSize) {
+
+ this.maxRequestQueueSize = queueSize;
+ return this;
+ }
+
+ /**
+ * Sets the registry for this thread pool
+ *
+ * @param registry the metric registry
+ * @return this builder
+ */
+ public ThreadPoolBuilder registry(MetricRegistry registry) {
+ this.registry = registry;
+ return this;
+ }
+
+ /**
+ * Sets the idle timeout in msec for this thread pool
+ *
+ * @param idleTimeout the timeout in milliseconds
+ * @return this builder
+ */
+ public ThreadPoolBuilder withIdleTimeoutMsec(int idleTimeout) {
+ this.idleTimeout = idleTimeout;
+ return this;
+ }
+
+ /**
+ * Sets the name for this thread pool
+ *
+ * @param name the thread pool name
+ * @return this builder
+ */
+ public ThreadPoolBuilder withName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Sets the name prefix for this thread pool
+ *
+ * @param prefix the thread pool name prefix
+ * @return this builder
+ */
+ public ThreadPoolBuilder withPrefix(String prefix) {
+ this.prefix = prefix;
+ return this;
+ }
+
+
+ /**
+ * ctor.
+ *
+ */
+ private ThreadPoolBuilder() {
+
+ }
+
+ /**
+ * Builds a {@link ThreadPool} based on the parameters of this builder
+ *
+ * @return a {@link ThreadPool}
+ */
+ public ThreadPool build() {
+
+ if (maxRequestQueueSize <= 0) {
+ maxRequestQueueSize = DEFAULT_MAX_REQUEST_QUEUE_SIZE;
+ }
+
+ if (maxThreads <= 0) {
+ maxThreads = DEFAULT_MAX_THREADS;
+ }
+
+ if (minThreads <= 0) {
+ minThreads = DEFAULT_MIN_THREADS;
+ }
+
+ if (idleTimeout <= 0) {
+ idleTimeout = DEFAULT_IDLE_TIMEOUT;
+ }
+
+ if (prefix.isEmpty()) {
+ prefix = DEFAULT_THREAD_POOL_METRIC_PREFIX;
+ }
+
+ BlockingQueue queue = new ArrayBlockingQueue(maxRequestQueueSize);
+
+ QueuedThreadPool tp = null;
+
+ if (registry == null) {
+ tp = new QueuedThreadPool(maxThreads, minThreads, idleTimeout, queue);
+ } else {
+ tp = new InstrumentedQueuedThreadPool(registry, maxThreads, minThreads, idleTimeout, queue, prefix);
+ }
+
+ if (name.isEmpty()) {
+ name = DEFAULT_THREAD_POOL_METRIC_NAME;
+ }
+ tp.setName(name);
+
+ return tp;
+
+ }
+}
diff --git a/src/main/java/org/italiangrid/storm/webdav/spring/AppConfig.java b/src/main/java/org/italiangrid/storm/webdav/spring/AppConfig.java
index ce9a7a88..b31efd4a 100644
--- a/src/main/java/org/italiangrid/storm/webdav/spring/AppConfig.java
+++ b/src/main/java/org/italiangrid/storm/webdav/spring/AppConfig.java
@@ -16,7 +16,6 @@
package org.italiangrid.storm.webdav.spring;
import static java.util.Objects.isNull;
-import static org.italiangrid.utils.jetty.TLSServerConnectorBuilder.CONSCRYPT_PROVIDER;
import java.io.IOException;
import java.net.MalformedURLException;
@@ -129,6 +128,7 @@
public class AppConfig implements TransferConstants {
public static final Logger LOG = LoggerFactory.getLogger(AppConfig.class);
+ public static final String CONSCRYPT_PROVIDER = "Conscrypt";
@Bean
Clock systemClock() {
diff --git a/src/main/java/org/italiangrid/storm/webdav/tpc/utils/ClientInfo.java b/src/main/java/org/italiangrid/storm/webdav/tpc/utils/ClientInfo.java
index a3ceca4d..600eac26 100644
--- a/src/main/java/org/italiangrid/storm/webdav/tpc/utils/ClientInfo.java
+++ b/src/main/java/org/italiangrid/storm/webdav/tpc/utils/ClientInfo.java
@@ -20,7 +20,7 @@
import java.util.Map;
-import org.apache.log4j.MDC;
+import org.slf4j.MDC;
import com.google.common.base.Splitter;
import com.google.common.base.Splitter.MapSplitter;