Change DMI server from Tomcat to Jetty 72/141172/3
authoregernug <gerard.nugent@est.tech>
Mon, 9 Jun 2025 15:17:49 +0000 (16:17 +0100)
committeregernug <gerard.nugent@est.tech>
Tue, 10 Jun 2025 10:25:43 +0000 (11:25 +0100)
- Excluded Tomcat from Springboot in both dmi-service and dmi-stub-app
- Added dependency for spring-boot-starter-jetty
- Added JettyConfig  to allowAmbiguousPathSeparators

Issue-ID: CPS-2846

Change-Id: I202366bb0a24b0d591dbbd84c6ae3f89b062e44f
Signed-off-by: egernug <gerard.nugent@est.tech>
dmi-service/pom.xml
dmi-service/src/main/java/org/onap/cps/ncmp/dmi/config/JettyConfig.java [new file with mode: 0644]
dmi-service/src/test/groovy/org/onap/cps/ncmp/dmi/config/JettyConfigSpec.groovy [new file with mode: 0644]
dmi-stub/dmi-stub-app/pom.xml

index 56ff654..bc41ca5 100644 (file)
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jetty</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
diff --git a/dmi-service/src/main/java/org/onap/cps/ncmp/dmi/config/JettyConfig.java b/dmi-service/src/main/java/org/onap/cps/ncmp/dmi/config/JettyConfig.java
new file mode 100644 (file)
index 0000000..1c1b422
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025 OpenInfra Foundation Europe. All rights reserved.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.dmi.config;
+
+import java.util.EnumSet;
+import org.eclipse.jetty.http.UriCompliance;
+import org.eclipse.jetty.server.ConnectionFactory;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
+import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class JettyConfig implements WebServerFactoryCustomizer<JettyServletWebServerFactory> {
+
+    /**
+     * Customizes the Jetty server factory to allow encoded slashes in URI paths.
+     *
+     * @param jettyServletWebServerFactory the Jetty servlet web server factory to customize
+     */
+    @Override
+    public void customize(final JettyServletWebServerFactory jettyServletWebServerFactory) {
+        jettyServletWebServerFactory.addServerCustomizers(server -> {
+            for (final Connector connector : server.getConnectors()) {
+                for (final ConnectionFactory connectionFactory : connector.getConnectionFactories()) {
+                    if (connectionFactory instanceof HttpConnectionFactory) {
+                        final HttpConfiguration httpConfiguration
+                                = ((HttpConnectionFactory) connectionFactory).getHttpConfiguration();
+                        httpConfiguration.setUriCompliance(UriCompliance.from(EnumSet.of(
+                                UriCompliance.Violation.AMBIGUOUS_PATH_SEPARATOR)));
+                    }
+                }
+            }
+        });
+    }
+}
diff --git a/dmi-service/src/test/groovy/org/onap/cps/ncmp/dmi/config/JettyConfigSpec.groovy b/dmi-service/src/test/groovy/org/onap/cps/ncmp/dmi/config/JettyConfigSpec.groovy
new file mode 100644 (file)
index 0000000..605d423
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025 OpenInfra Foundation Europe. All rights reserved.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.dmi.config
+
+import org.eclipse.jetty.server.ConnectionFactory
+import org.eclipse.jetty.server.Connector
+import org.eclipse.jetty.server.HttpConfiguration
+import org.eclipse.jetty.server.HttpConnectionFactory
+import org.eclipse.jetty.server.Server
+import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory
+import spock.lang.Specification
+
+class JettyConfigSpec extends Specification{
+
+    def objectUnderTest = new JettyConfig()
+    def server = Mock(Server)
+    def connector = Mock(Connector)
+
+    def 'Enable support for ambiguous path separators in Jetty Http configuration'() {
+        given: 'a Jetty server factory'
+            def jettyServletWebServerFactory = new JettyServletWebServerFactory()
+        and: 'a mocked connection factory (Http or Non-Http)'
+            def connectionFactory = connectionFactoryType == 'http' ? Mock(HttpConnectionFactory) : Mock(ConnectionFactory)
+        and: 'optional mock for HttpConfiguration if applicable'
+            def httpConfig = null
+            if (connectionFactory instanceof HttpConnectionFactory) {
+                httpConfig = Mock(HttpConfiguration)
+                connectionFactory.getHttpConfiguration() >> httpConfig
+            }
+        and: 'mocked components return expected values'
+            connector.getConnectionFactories() >> [connectionFactory]
+            server.getConnectors() >> [connector]
+        when: 'JettyConfig customization is triggered on the server factory'
+            objectUnderTest.customize(jettyServletWebServerFactory)
+        and: 'a server customizer is extracted from the configured factory'
+            def serverCustomizer = jettyServletWebServerFactory.serverCustomizers.first()
+        and: 'the customizer is applied to the mocked Jetty server'
+            serverCustomizer.customize(server)
+        then: 'only the HTTP configuration is updated to allow ambiguous path separators'
+            expectedCalls * httpConfig.setUriCompliance({ it.toString().contains('AMBIGUOUS_PATH_SEPARATOR') })
+        where: 'type of connection factories'
+            scenario                                                 | connectionFactoryType || expectedCalls
+            'HttpConnectionFactory - should configure UriCompliance' | 'http'                || 1
+            'Non-HttpConnectionFactory - should do nothing'          | 'non-http'            || 0
+    }
+}
index 99c2601..ff83c15 100644 (file)
                 <exclusion>
                     <groupId>org.slf4j</groupId>
                     <artifactId>slf4j-api</artifactId>
-                </exclusion></exclusions>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jetty</artifactId>
         </dependency>
         <dependency>
             <groupId>ch.qos.logback</groupId>