2

My application uses spring-boot 2.5.5.

I set a property for Tomcat at application startup to allow encoded slash in @PathVariable :

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
        SpringApplication.run(App.class, args);
    }

}

Everything works fine when I start the app, except in my integration tests :

@ActiveProfiles("test-connected")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(SpringExtension.class)
class GlobalFullTest {

When I debug the org.apache.tomcat.util.buf.UDecoder class : I see that the property org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH is null when class is loaded, so a default value false is set.

I tried the following :

  • Adding System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true"); in the @BeforeAll method of my test
  • Adding properties = { "org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true" } in the @SpringBootTest annotation.
  • Adding org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH: true in my application-test-connected.yaml
  • Using WebServerFactoryCustomizer :
@Configuration
public class WebServerConfiguration {

    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> customizer() {
        return factory -> factory.addConnectorCustomizers(connector -> connector.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true"));
    }

}

But none of these worked : when the property is retrieved by org.apache.tomcat.util.buf.UDecoder class, its value is always null.

How could I set the property before the org.apache.tomcat.util.buf.UDecoder class is loaded ?

Dartz
  • 165
  • 12
  • I would suggest to remove that line and figure out a way using a `TomcatCustomizer` instead. That way it works regardless of your environment. – M. Deinum Oct 04 '22 at 12:37
  • `TomcatCustomizer ` doesn't seem to exist in spring-boot 2.5.5. I found a [WebServerFactoryCustomizer](https://www.baeldung.com/embeddedservletcontainercustomizer-configurableembeddedservletcontainer-spring-boot) but even after setting the property with it, it is still null (corresponding code has been added to the original question) – Dartz Oct 04 '22 at 13:28
  • 1
    You should call `setEncodedSolidusHandling` on the connector and set it to `decode`. The system property you are setting is actually deprecated (and used as a migration path). – M. Deinum Oct 04 '22 at 14:01
  • @M.Deinum oh you're right ! I didn't know there were a _real_ programatic way to enable the slash decoding without the property. Thanks ! – Dartz Oct 04 '22 at 15:13

1 Answers1

2

Referring to How to set environment variable or system property in spring tests?

The simplest way

Follow add static initializer in the class

...
class GlobalFullTest {
    static {
        System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
    }
...
}
down side is we need to copy that for every test.

Clean way

create ApplicationContextInitializer, which can be reused in the Spring application and any other test.

public class CustomApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext)
    {
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
    }
}

...
@ContextConfiguration(initializers = CustomApplicationContextInitializer.class,...)
class GlobalFullTest {
...

samabcde
  • 6,988
  • 2
  • 25
  • 41