You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by re...@apache.org on 2020/07/24 12:37:48 UTC

svn commit: r1880267 - in /jackrabbit/branches/2.20: ./ jackrabbit-jcr-server/ jackrabbit-spi2dav/ jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/ jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/ jackrabbit-spi2dav/src/...

Author: reschke
Date: Fri Jul 24 12:37:48 2020
New Revision: 1880267

URL: http://svn.apache.org/viewvc?rev=1880267&view=rev
Log:
JCR-4536: spi2dav: allow disabling cert and host name checks for TLS connections (also adds test coverage for proxy config) (merged r1879988, r1879996, r1879997, r1879998, and r1880094 into 2.20)

Added:
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/ConnectionOptions.java
      - copied unchanged from r1879988, jackrabbit/trunk/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/ConnectionOptions.java
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionOptionsTest.java
      - copied unchanged from r1879988, jackrabbit/trunk/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionOptionsTest.java
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionTest.java
      - copied, changed from r1879988, jackrabbit/trunk/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionTest.java
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/resources/config.xml
      - copied unchanged from r1879988, jackrabbit/trunk/jackrabbit-spi2dav/src/test/resources/config.xml
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/resources/disabledrepositoryServiceStubImpl.properties
      - copied unchanged from r1879988, jackrabbit/trunk/jackrabbit-spi2dav/src/test/resources/disabledrepositoryServiceStubImpl.properties
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/resources/disabledrepositoryStubImpl.properties
      - copied unchanged from r1879988, jackrabbit/trunk/jackrabbit-spi2dav/src/test/resources/disabledrepositoryStubImpl.properties
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/resources/logback-test.xml
      - copied unchanged from r1879988, jackrabbit/trunk/jackrabbit-spi2dav/src/test/resources/logback-test.xml
Removed:
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/resources/repositoryServiceStubImpl.properties
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/resources/repositoryStubImpl.properties
Modified:
    jackrabbit/branches/2.20/   (props changed)
    jackrabbit/branches/2.20/jackrabbit-jcr-server/pom.xml
    jackrabbit/branches/2.20/jackrabbit-spi2dav/pom.xml
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/Spi2davRepositoryServiceFactory.java
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/RepositoryServiceImpl.java
    jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/Spi2davexRepositoryServiceFactory.java

Propchange: jackrabbit/branches/2.20/
------------------------------------------------------------------------------
  Merged /jackrabbit/trunk:r1879988,1879996-1879998,1880094

Modified: jackrabbit/branches/2.20/jackrabbit-jcr-server/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.20/jackrabbit-jcr-server/pom.xml?rev=1880267&r1=1880266&r2=1880267&view=diff
==============================================================================
--- jackrabbit/branches/2.20/jackrabbit-jcr-server/pom.xml (original)
+++ jackrabbit/branches/2.20/jackrabbit-jcr-server/pom.xml Fri Jul 24 12:37:48 2020
@@ -91,6 +91,18 @@
           </excludes>
         </configuration>
       </plugin>
+      <!-- test dependencies are used downstream (https://maven.apache.org/plugins/maven-jar-plugin/examples/create-test-jar.html) -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>test-jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
     <pluginManagement>
       <plugins>

Modified: jackrabbit/branches/2.20/jackrabbit-spi2dav/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.20/jackrabbit-spi2dav/pom.xml?rev=1880267&r1=1880266&r2=1880267&view=diff
==============================================================================
--- jackrabbit/branches/2.20/jackrabbit-spi2dav/pom.xml (original)
+++ jackrabbit/branches/2.20/jackrabbit-spi2dav/pom.xml Fri Jul 24 12:37:48 2020
@@ -38,10 +38,13 @@
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <skip>true</skip>
           <includes>
-            <include>**/TestAll.java</include>
+            <include>**/ConnectionOptionsTest.java</include>
+            <include>**/spi2dav/ConnectionTest.java</include>
+            <!-- https://issues.apache.org/jira/browse/JCR-4610 -->
+            <!-- <include>**/TestAll.java</include> -->
           </includes>
+          <trimStackTrace>false</trimStackTrace>
           <forkMode>once</forkMode>
           <argLine>${test.opts}</argLine>
           <systemProperties>
@@ -114,6 +117,30 @@
       </plugin>
     </plugins>
   </build>
+  <profiles>
+    <profile>
+      <id>integrationTesting</id>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <configuration>
+              <systemProperties>
+                <property>
+                  <name>jackrabbit.test.integration</name>
+                  <value>true</value>
+                </property>
+                <property>
+                  <name>derby.stream.error.file</name>
+                  <value>target/derby.log</value>
+                </property>
+              </systemProperties>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
   <dependencies>
     <dependency>
       <groupId>org.apache.jackrabbit</groupId>
@@ -185,5 +212,53 @@
       <version>${project.version}</version>
       <scope>test</scope>
     </dependency>
+    <!-- testing classes provided by jcr-server -->
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-jcr-server</artifactId>
+      <classifier>tests</classifier>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-jcr-server</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <!-- transitive dependencies of jackrabbit-jcr-server -->
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-core</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-server</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-servlet</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.derby</groupId>
+      <artifactId>derby</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <!-- for testing connection via a proxy -->
+     <dependency>
+        <groupId>org.littleshoot</groupId>
+        <artifactId>littleproxy</artifactId>
+        <version>1.1.2</version>
+        <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>

Modified: jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java?rev=1880267&r1=1880266&r2=1880267&view=diff
==============================================================================
--- jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java (original)
+++ jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java Fri Jul 24 12:37:48 2020
@@ -23,6 +23,9 @@ import java.io.Reader;
 import java.io.StringWriter;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -50,21 +53,32 @@ import javax.jcr.UnsupportedRepositoryOp
 import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 import javax.jcr.lock.LockException;
+import javax.net.ssl.SSLContext;
 import javax.xml.parsers.ParserConfigurationException;
 
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.AuthCache;
 import org.apache.http.client.CredentialsProvider;
 import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpHead;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.client.methods.HttpRequestBase;
 import org.apache.http.client.methods.HttpUriRequest;
 import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.InputStreamEntity;
 import org.apache.http.entity.StringEntity;
@@ -73,8 +87,11 @@ import org.apache.http.impl.client.Basic
 import org.apache.http.impl.client.BasicCredentialsProvider;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.client.ProxyAuthenticationStrategy;
+import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.protocol.HttpContext;
+import org.apache.http.ssl.SSLContextBuilder;
 import org.apache.jackrabbit.commons.webdav.AtomFeedConstants;
 import org.apache.jackrabbit.commons.webdav.EventUtil;
 import org.apache.jackrabbit.commons.webdav.JcrRemotingConstants;
@@ -243,6 +260,7 @@ public class RepositoryServiceImpl imple
     private final HttpHost httpHost;
     private final ConcurrentMap<Object, HttpClient> clients;
     private final HttpClientBuilder httpClientBuilder;
+    private final Map<AuthScope, org.apache.http.auth.Credentials> commonCredentials;
 
     private final Map<Name, QNodeTypeDefinition> nodeTypeDefinitions = new HashMap<Name, QNodeTypeDefinition>();
 
@@ -258,10 +276,10 @@ public class RepositoryServiceImpl imple
     private Set<String> remoteDavComplianceClasses = null;
 
     /**
-     * Same as {@link #RepositoryServiceImpl(String, IdFactory, NameFactory, PathFactory, QValueFactory, int, int)}
+     * Same as {@link #RepositoryServiceImpl(String, IdFactory, NameFactory, PathFactory, QValueFactory, int, ConnectionOptions)}
      * using {@link ItemInfoCacheImpl#DEFAULT_CACHE_SIZE} as size for the item
      * cache and {@link #MAX_CONNECTIONS_DEFAULT} for the maximum number of
-     * connections on the client.
+     * connections on the client and {@link ConnectionOptions#DEFAULT}.
      *
      * @param uri The server uri.
      * @param idFactory The id factory.
@@ -277,9 +295,9 @@ public class RepositoryServiceImpl imple
     }
 
     /**
-     * Same as {@link #RepositoryServiceImpl(String, IdFactory, NameFactory, PathFactory, QValueFactory, int, int)}
+     * Same as {@link #RepositoryServiceImpl(String, IdFactory, NameFactory, PathFactory, QValueFactory, int, ConnectionOptions)}
      * using {@link #MAX_CONNECTIONS_DEFAULT} for the maximum number of
-     * connections on the client.
+     * connections on the client and {@link ConnectionOptions#DEFAULT}.
      *
      * @param uri The server uri.
      * @param idFactory The id factory.
@@ -292,7 +310,7 @@ public class RepositoryServiceImpl imple
     public RepositoryServiceImpl(String uri, IdFactory idFactory,
                                  NameFactory nameFactory, PathFactory pathFactory,
                                  QValueFactory qValueFactory, int itemInfoCacheSize) throws RepositoryException {
-        this(uri, idFactory, nameFactory, pathFactory, qValueFactory, itemInfoCacheSize, MAX_CONNECTIONS_DEFAULT);
+        this(uri, idFactory, nameFactory, pathFactory, qValueFactory, itemInfoCacheSize, ConnectionOptions.DEFAULT);
     }
 
     /**
@@ -304,15 +322,13 @@ public class RepositoryServiceImpl imple
      * @param pathFactory The path factory.
      * @param qValueFactory The value factory.
      * @param itemInfoCacheSize The size of the item info cache.
-     * @param maximumHttpConnections A int &gt;0 defining the maximum number of
-     * connections per host to be configured on
-     * {@link PoolingHttpClientConnectionManager#setMaxTotal(int)}.
+     * @param connectionOptions The advanced connection options.
      * @throws RepositoryException If an error occurs.
      */
     public RepositoryServiceImpl(String uri, IdFactory idFactory,
                                  NameFactory nameFactory, PathFactory pathFactory,
                                  QValueFactory qValueFactory, int itemInfoCacheSize,
-                                 int maximumHttpConnections ) throws RepositoryException {
+                                 ConnectionOptions connectionOptions) throws RepositoryException {
         if (uri == null || "".equals(uri)) {
             throw new RepositoryException("Invalid repository uri '" + uri + "'.");
         }
@@ -325,6 +341,7 @@ public class RepositoryServiceImpl imple
         this.pathFactory = pathFactory;
         this.qValueFactory = qValueFactory;
         this.itemInfoCacheSize = itemInfoCacheSize;
+        this.commonCredentials = new HashMap<>();
 
         try {
             URI repositoryUri = computeRepositoryUri(uri);
@@ -341,15 +358,71 @@ public class RepositoryServiceImpl imple
             throw new RepositoryException(e);
         }
 
-        PoolingHttpClientConnectionManager cmgr = new PoolingHttpClientConnectionManager();
-        if (maximumHttpConnections > 0) {
-            cmgr.setDefaultMaxPerRoute(maximumHttpConnections);
-            cmgr.setMaxTotal(maximumHttpConnections);
-        }
-        HttpClientBuilder hcb = HttpClients.custom().setConnectionManager(cmgr);
-        if (Boolean.getBoolean("jackrabbit.client.useSystemProperties")) {
+        
+        HttpClientBuilder hcb = HttpClients.custom();
+
+        // request config
+        RequestConfig requestConfig = RequestConfig.custom().
+                setConnectTimeout(connectionOptions.getConnectionTimeoutMs()).
+                setConnectionRequestTimeout(connectionOptions.getRequestTimeoutMs()).
+                setSocketTimeout(connectionOptions.getSocketTimeoutMs()).build();
+        hcb.setDefaultRequestConfig(requestConfig);
+        if (Boolean.getBoolean("jackrabbit.client.useSystemProperties") || connectionOptions.isUseSystemPropertes()) {
+            log.debug("Using system properties for establishing connection!");
             // support Java system proxy? (JCR-3211)
-            hcb = hcb.useSystemProperties();
+            hcb.useSystemProperties();
+        }
+        
+        // TLS settings (via connection manager)
+        final SSLContext sslContext;
+        try {
+            if (connectionOptions.isAllowSelfSignedCertificates()) {
+                log.warn("Nonsecure TLS setting: Accepting self-signed certificates!");
+                    sslContext = SSLContextBuilder.create().loadTrustMaterial(new TrustSelfSignedStrategy()).build();
+                    hcb.setSSLContext(sslContext);
+            } else {
+                sslContext = SSLContextBuilder.create().build();
+            }
+        } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
+            throw new RepositoryException(e);
+        }
+        final SSLConnectionSocketFactory sslSocketFactory;
+        if (connectionOptions.isDisableHostnameVerification()) {
+            log.warn("Nonsecure TLS setting: Host name verification of TLS certificates disabled!");
+            // we can optionally disable hostname verification.
+            sslSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
+        } else {
+            sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
+        }
+        
+        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
+            .register("http", PlainConnectionSocketFactory.getSocketFactory())
+            .register("https", sslSocketFactory)
+            .build();
+        
+        PoolingHttpClientConnectionManager cmgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
+        int maxConnections = connectionOptions.getMaxConnections();
+        if (maxConnections > 0) {
+            cmgr.setDefaultMaxPerRoute(connectionOptions.getMaxConnections());
+            cmgr.setMaxTotal(connectionOptions.getMaxConnections());
+        } else {
+            maxConnections = ConnectionOptions.MAX_CONNECTIONS_DEFAULT;
+        }
+        hcb.setConnectionManager(cmgr);
+
+        if (connectionOptions.getProxyHost() != null) {
+            // https://hc.apache.org/httpcomponents-client-4.5.x/tutorial/html/connmgmt.html#d5e485
+            HttpHost proxy = new HttpHost(connectionOptions.getProxyHost(), connectionOptions.getProxyPort(), connectionOptions.getProxyProtocol());
+            DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
+            hcb.setRoutePlanner(routePlanner);
+            log.debug("Connection via proxy {}", proxy);
+            if (connectionOptions.getProxyUsername() != null) {
+                log.debug("Proxy connection with credentials {}", proxy);
+                commonCredentials.put(
+                        new AuthScope(proxy),
+                        new UsernamePasswordCredentials(connectionOptions.getProxyUsername(), connectionOptions.getProxyPassword()));
+                hcb.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
+            }
         }
         httpClientBuilder = hcb;
 
@@ -357,13 +430,7 @@ public class RepositoryServiceImpl imple
         // concurrency on this map will be equal to the default number of maximum
         // connections allowed on the httpClient level.
         // TODO: review again
-        int concurrencyLevel = MAX_CONNECTIONS_DEFAULT;
-        int initialCapacity = MAX_CONNECTIONS_DEFAULT;
-        if (maximumHttpConnections > 0) {
-            concurrencyLevel = maximumHttpConnections;
-            initialCapacity = maximumHttpConnections;
-        }
-        clients = new ConcurrentHashMap<Object, HttpClient>(concurrencyLevel, .75f, initialCapacity);
+        clients = new ConcurrentHashMap<Object, HttpClient>(maxConnections, .75f, maxConnections);
     }
 
     private static void checkSessionInfo(SessionInfo sessionInfo) throws RepositoryException {
@@ -544,16 +611,20 @@ public class RepositoryServiceImpl imple
 
     protected HttpContext getContext(SessionInfo sessionInfo) throws RepositoryException {
         HttpClientContext result = HttpClientContext.create();
+        CredentialsProvider credsProvider = new BasicCredentialsProvider();
+        result.setCredentialsProvider(credsProvider);
+        // take over default credentials (e.g. for proxy)
+        for (Map.Entry<AuthScope, org.apache.http.auth.Credentials> entry : commonCredentials.entrySet()) {
+            credsProvider.setCredentials(entry.getKey(), entry.getValue());
+        }
         if (sessionInfo != null) {
             checkSessionInfo(sessionInfo);
             org.apache.http.auth.Credentials creds = ((SessionInfoImpl) sessionInfo).getCredentials().getHttpCredentials();
             if (creds != null) {
-                CredentialsProvider credsProvider = new BasicCredentialsProvider();
                 credsProvider.setCredentials(new org.apache.http.auth.AuthScope(httpHost.getHostName(), httpHost.getPort()), creds);
                 BasicScheme basicAuth = new BasicScheme();
                 AuthCache authCache = new BasicAuthCache();
                 authCache.put(httpHost, basicAuth);
-                result.setCredentialsProvider(credsProvider);
                 result.setAuthCache(authCache);
             }
         }
@@ -806,7 +877,7 @@ public class RepositoryServiceImpl imple
                 throw new LoginException("Login failed: Unknown workspace '" + workspaceName + "'.");
             }
         } catch (IOException e) {
-            throw new RepositoryException(e.getMessage());
+            throw new RepositoryException(e.getMessage(), e);
         } catch (DavException e) {
             throw ExceptionConverter.generate(e);
         } finally {

Modified: jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/Spi2davRepositoryServiceFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/Spi2davRepositoryServiceFactory.java?rev=1880267&r1=1880266&r2=1880267&view=diff
==============================================================================
--- jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/Spi2davRepositoryServiceFactory.java (original)
+++ jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/Spi2davRepositoryServiceFactory.java Fri Jul 24 12:37:48 2020
@@ -35,7 +35,9 @@ import org.apache.jackrabbit.spi.commons
 
 /**
  * This {@link RepositoryServiceFactory} implementation is responsible
- * for creating {@link RepositoryServiceImpl} instances.
+ * for creating {@link RepositoryServiceImpl} instances which communicate via WebDAV.
+ * All parameter keys defined in this class and in addition the ones from {@link ConnectionOptions} 
+ * are supported as arguments for {@link #createRepositoryService(Map)}.
  */
 public class Spi2davRepositoryServiceFactory implements RepositoryServiceFactory {
 
@@ -79,6 +81,7 @@ public class Spi2davRepositoryServiceFac
      * Optional configuration parameter: It's value defines the
      * maximumConnectionsPerHost value on the HttpClient configuration and
      * must be an int greater than zero.
+     * Rather use {@link ConnectionOptions#PARAM_MAX_CONNECTIONS} instead.
      */
     public static final String PARAM_MAX_CONNECTIONS = "org.apache.jackrabbit.spi2dav.MaxConnections";
 
@@ -136,22 +139,6 @@ public class Spi2davRepositoryServiceFac
                 // ignore, use default
             }
         }
-
-        // max connections config
-        int maximumHttpConnections = 0;
-        param = parameters.get(PARAM_MAX_CONNECTIONS);
-        if (param != null) {
-            try {
-                maximumHttpConnections = Integer.parseInt(param.toString());
-            } catch ( NumberFormatException e ) {
-                // using default
-            }
-        }
-        
-        if (maximumHttpConnections > 0) {
-            return new RepositoryServiceImpl(uri, idFactory, nameFactory, pathFactory, vFactory, itemInfoCacheSize, maximumHttpConnections);
-        } else {
-            return new RepositoryServiceImpl(uri, idFactory, nameFactory, pathFactory, vFactory, itemInfoCacheSize);
-        }
+        return new RepositoryServiceImpl(uri, idFactory, nameFactory, pathFactory, vFactory, itemInfoCacheSize, ConnectionOptions.fromServiceFactoryParameters(parameters));
     }
 }

Modified: jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/RepositoryServiceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/RepositoryServiceImpl.java?rev=1880267&r1=1880266&r2=1880267&view=diff
==============================================================================
--- jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/RepositoryServiceImpl.java (original)
+++ jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/RepositoryServiceImpl.java Fri Jul 24 12:37:48 2020
@@ -71,6 +71,7 @@ import org.apache.jackrabbit.spi.commons
 import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
 import org.apache.jackrabbit.spi.commons.tree.AbstractTree;
 import org.apache.jackrabbit.spi.commons.value.ValueFormat;
+import org.apache.jackrabbit.spi2dav.ConnectionOptions;
 import org.apache.jackrabbit.spi2dav.ExceptionConverter;
 import org.apache.jackrabbit.spi2dav.ItemResourceConstants;
 import org.apache.jackrabbit.util.Text;
@@ -149,34 +150,19 @@ public class RepositoryServiceImpl exten
     private final Map<SessionInfo, QValueFactoryImpl> qvFactories = new HashMap<SessionInfo, QValueFactoryImpl>();
 
     /**
-     * Same as {@link #RepositoryServiceImpl(String, String, BatchReadConfig, int, int)}
+     * Same as {@link #RepositoryServiceImpl(String, String, BatchReadConfig, int, ConnectionOptions)}
      * using <code>null</code> workspace name, {@link ItemInfoCacheImpl#DEFAULT_CACHE_SIZE}
-     * as size for the item cache and {@link #MAX_CONNECTIONS_DEFAULT} for the
-     * maximum number of connections on the client.
+     * as size for the item cache, {@link #MAX_CONNECTIONS_DEFAULT} for the
+     * maximum number of connections on the client and {@link ConnectionOptions#DEFAULT}.
      *
      * @param jcrServerURI The server uri.
      * @param batchReadConfig The batch read configuration.
      * @throws RepositoryException If an exception occurs.
      */
     public RepositoryServiceImpl(String jcrServerURI, BatchReadConfig batchReadConfig) throws RepositoryException {
-        this(jcrServerURI, null, batchReadConfig, ItemInfoCacheImpl.DEFAULT_CACHE_SIZE);
+        this(jcrServerURI, null, batchReadConfig, ItemInfoCacheImpl.DEFAULT_CACHE_SIZE, ConnectionOptions.DEFAULT);
     }
 
-    /**
-     * Same as {@link #RepositoryServiceImpl(String, String, BatchReadConfig, int, int)}
-     * using {@link #MAX_CONNECTIONS_DEFAULT} for the maximum number of
-     * connections on the client.
-     *
-     * @param jcrServerURI The server uri.
-     * @param defaultWorkspaceName The default workspace name.
-     * @param batchReadConfig The batch read configuration.
-     * @param itemInfoCacheSize The size of the item info cache.
-     * @throws RepositoryException If an exception occurs.
-     */
-    public RepositoryServiceImpl(String jcrServerURI, String defaultWorkspaceName,
-                                 BatchReadConfig batchReadConfig, int itemInfoCacheSize) throws RepositoryException {
-        this(jcrServerURI, defaultWorkspaceName, batchReadConfig, itemInfoCacheSize, MAX_CONNECTIONS_DEFAULT);
-    }
 
     /**
      * Creates a new instance of this repository service.
@@ -185,17 +171,14 @@ public class RepositoryServiceImpl exten
      * @param defaultWorkspaceName The default workspace name.
      * @param batchReadConfig The batch read configuration.
      * @param itemInfoCacheSize The size of the item info cache.
-     * @param maximumHttpConnections maximumHttpConnections A int &gt;0 defining
-     * the maximum number of connections per host to be configured on
-     * {@link org.apache.http.impl.conn.PoolingHttpClientConnectionManager#setDefaultMaxPerRoute(int)}.
+     * @param connectionOptions advanced connection options.
      * @throws RepositoryException If an exception occurs.
      */
     public RepositoryServiceImpl(String jcrServerURI, String defaultWorkspaceName,
-                                 BatchReadConfig batchReadConfig, int itemInfoCacheSize,
-                                 int maximumHttpConnections) throws RepositoryException {
+                                 BatchReadConfig batchReadConfig, int itemInfoCacheSize, ConnectionOptions connectionOptions) throws RepositoryException {
 
         super(jcrServerURI, IdFactoryImpl.getInstance(), NameFactoryImpl.getInstance(),
-                PathFactoryImpl.getInstance(), new QValueFactoryImpl(), itemInfoCacheSize, maximumHttpConnections);
+                PathFactoryImpl.getInstance(), new QValueFactoryImpl(), itemInfoCacheSize, connectionOptions);
 
         try {
             URI repositoryUri = computeRepositoryUri(jcrServerURI);

Modified: jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/Spi2davexRepositoryServiceFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/Spi2davexRepositoryServiceFactory.java?rev=1880267&r1=1880266&r2=1880267&view=diff
==============================================================================
--- jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/Spi2davexRepositoryServiceFactory.java (original)
+++ jackrabbit/branches/2.20/jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2davex/Spi2davexRepositoryServiceFactory.java Fri Jul 24 12:37:48 2020
@@ -25,10 +25,13 @@ import org.apache.jackrabbit.spi.ItemInf
 import org.apache.jackrabbit.spi.RepositoryService;
 import org.apache.jackrabbit.spi.RepositoryServiceFactory;
 import org.apache.jackrabbit.spi.commons.ItemInfoCacheImpl;
+import org.apache.jackrabbit.spi2dav.ConnectionOptions;
 
 /**
  * This {@link RepositoryServiceFactory} implementation is responsible
- * for creating {@link RepositoryServiceImpl} instances.
+ * for creating {@link RepositoryServiceImpl} instances which communicate via <a href="https://jackrabbit.apache.org/archive/wiki/JCR/RemoteAccess_115513494.html#RemoteAccess-DavEx">DavEx</a>.
+ * All parameter keys defined in this class and in addition the ones from {@link ConnectionOptions} 
+ * are supported as arguments for {@link #createRepositoryService(Map)}.
  */
 public class Spi2davexRepositoryServiceFactory implements RepositoryServiceFactory {
 
@@ -62,6 +65,7 @@ public class Spi2davexRepositoryServiceF
      * Optional configuration parameter: It's value defines the
      * maximumConnectionsPerHost value on the HttpClient configuration and 
      * must be an int greater than zero.
+     * Rather use {@link ConnectionOptions#PARAM_MAX_CONNECTIONS} instead.
      */
     public static final String PARAM_MAX_CONNECTIONS = "org.apache.jackrabbit.spi2davex.MaxConnections";
 
@@ -90,7 +94,6 @@ public class Spi2davexRepositoryServiceF
         // load other optional configuration parameters
         BatchReadConfig brc = null;
         int itemInfoCacheSize = ItemInfoCacheImpl.DEFAULT_CACHE_SIZE;
-        int maximumHttpConnections = 0;
 
         // since JCR-4120 the default workspace name is no longer set to 'default'
         // note: if running with JCR Server < 1.5 a default workspace name must therefore be configured
@@ -113,27 +116,13 @@ public class Spi2davexRepositoryServiceF
                 }
             }
 
-            // max connections config
-            param = parameters.get(PARAM_MAX_CONNECTIONS);
-            if (param != null) {
-                try {
-                    maximumHttpConnections = Integer.parseInt(param.toString());
-                } catch ( NumberFormatException e ) {
-                    // using default
-                }
-            }
-
             param = parameters.get(PARAM_WORKSPACE_NAME_DEFAULT);
             if (param != null) {
                 workspaceNameDefault = param.toString();
             }
         }
 
-        if (maximumHttpConnections > 0) {
-            return new RepositoryServiceImpl(uri, workspaceNameDefault, brc, itemInfoCacheSize, maximumHttpConnections);
-        } else {
-            return new RepositoryServiceImpl(uri, workspaceNameDefault, brc, itemInfoCacheSize);
-        }
+        return new RepositoryServiceImpl(uri, workspaceNameDefault, brc, itemInfoCacheSize, ConnectionOptions.fromServiceFactoryParameters(parameters));
     }
 
 }

Copied: jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionTest.java (from r1879988, jackrabbit/trunk/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionTest.java?p2=jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionTest.java&p1=jackrabbit/trunk/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionTest.java&r1=1879988&r2=1880267&rev=1880267&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionTest.java (original)
+++ jackrabbit/branches/2.20/jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/ConnectionTest.java Fri Jul 24 12:37:48 2020
@@ -84,7 +84,6 @@ public class ConnectionTest extends WebD
         RepositoryService repositoryService = createRepositoryService(true, parameters);
         try {
             repositoryService.obtain(new SimpleCredentials("admin", "admin".toCharArray()), null);
-            
         } catch (RepositoryException e) {
             Throwable cause = ExceptionUtils.getRootCause(e);
             if (!(cause instanceof SSLPeerUnverifiedException)) {
@@ -105,13 +104,13 @@ public class ConnectionTest extends WebD
 
     public void testObtainViaProxy() throws URISyntaxException, RepositoryException {
         HttpProxyServer proxyServer = DefaultHttpProxyServer.bootstrap()
-                .withPort(8080)
+                .withPort(0) // use arbitrary port
                 .start();
         try {
             Map<String, String> parameters = new HashMap<>();
             ConnectionOptions.Builder builder = ConnectionOptions.builder();
             builder.proxyHost("127.0.0.1");
-            builder.proxyPort(8080);
+            builder.proxyPort(proxyServer.getListenAddress().getPort());
             parameters.putAll(builder.build().toServiceFactoryParameters());
             RepositoryService repositoryService = createRepositoryService(false, parameters);
             repositoryService.obtain(new SimpleCredentials("admin", "admin".toCharArray()), null);
@@ -134,14 +133,14 @@ public class ConnectionTest extends WebD
             }
         };
         HttpProxyServer proxyServer = DefaultHttpProxyServer.bootstrap()
-                .withPort(8080)
+                .withPort(0) // use arbitrary port
                 .withProxyAuthenticator(authenticator)
                 .start();
         try {
             Map<String, String> parameters = new HashMap<>();
             ConnectionOptions.Builder builder = ConnectionOptions.builder();
             builder.proxyHost("127.0.0.1");
-            builder.proxyPort(8080);
+            builder.proxyPort(proxyServer.getListenAddress().getPort());
             builder.proxyUsername("test");
             builder.proxyPassword("invalid");
             parameters.putAll(builder.build().toServiceFactoryParameters());
@@ -149,8 +148,7 @@ public class ConnectionTest extends WebD
             try {
                 repositoryService.obtain(new SimpleCredentials("admin", "admin".toCharArray()), null);
                 fail("should have failed with proxy authentication failure!");
-            } catch (RepositoryException e) {
-                
+            } catch (RepositoryException expected) {
             }
         } finally {
             proxyServer.stop();
@@ -174,14 +172,14 @@ public class ConnectionTest extends WebD
             }
         };
         HttpProxyServer proxyServer = DefaultHttpProxyServer.bootstrap()
-                .withPort(8080)
+                .withPort(0) // use arbitrary port
                 .withProxyAuthenticator(authenticator)
                 .start();
         try {
             Map<String, String> parameters = new HashMap<>();
             ConnectionOptions.Builder builder = ConnectionOptions.builder();
             builder.proxyHost("127.0.0.1");
-            builder.proxyPort(8080);
+            builder.proxyPort(proxyServer.getListenAddress().getPort());
             builder.proxyUsername("test");
             builder.proxyPassword("valid");
             parameters.putAll(builder.build().toServiceFactoryParameters());
@@ -202,7 +200,7 @@ public class ConnectionTest extends WebD
         // overwrite URI (use non-routable IP to run into connection timeout)
         parameters.put(Spi2davexRepositoryServiceFactory.PARAM_REPOSITORY_URI, "http://10.0.0.0");
         RepositoryService repositoryService = createRepositoryService(true, parameters);
-        
+
         long beforeTimeMs = System.currentTimeMillis();
         try {
             repositoryService.obtain(new SimpleCredentials("admin", "admin".toCharArray()), null);