How to set max-swallow-size in spring boot 2? - spring-boot

I'm trying to set max-swallow-size property of tomcat to -1 in springboot microservice while upgrading to springboot version 2; my earlier code was working but in upgrade some classes have changed so it stopped working.
I tried to set property in two ways but both are not working;
with service configuration
#Bean
public ServletWebServerFactory servletContainerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
#Override
public void customize(Connector connector) {
if(connector.getProtocolHandler() instanceof AbstractHttp11Protocol) {
logger.debug("Setting maxSwallowSize for server connector as "+maxSwallowSize);
((AbstractHttp11Protocol <?>) connector.getProtocolHandler()).setMaxSwallowSize(maxSwallowSize);
}
}
});
return factory;
}
In control flow, I can see the debug line printed but it have not taken effect as end -point response is 502(Bad gateway) instead of 400
Second way :
2. through application.properties file with property
server.tomcat.max-swallow-size=-1
This is also not honored.
Now, How can I verify the property value whether it is actually set or not ?
or Am I setting the value in correct way ?

This New class has resolved my issue
#Component
public class TomcatCustomizer implements
WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
#Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
#Override
public void customize(Connector connector) {
if(connector.getProtocolHandler() instanceof AbstractHttp11Protocol) {
((AbstractHttp11Protocol <?>) connector.getProtocolHandler()).setMaxSwallowSize(maxSwallowSize);
}
}
});
}
}
and I have used updated properties in spring boot 2.0
spring.servlet.multipart.max-file-size= XX MB
spring.servlet.multipart.max-request-size= YY MB

Related

Changing the samesite session cookie attribute in a spring webflux application

I am trying to change the same site attribute of my springboot application using WebSessionIdResolver as described here : https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-webflux-custom-cookie.html
#Configuration
public class CookieConfiguration {
#Bean
public WebSessionIdResolver webSessionIdResolver() {
CookieWebSessionIdResolver resolver = new CookieWebSessionIdResolver();
resolver.addCookieInitializer(builder -> builder.sameSite("None"));
return resolver;
}
}
I don't understand what is going, when debugging I can see the bean being initialized,but on every http call a session cookie is written with the default sameSite attribute "Lax", and the default CookieWebSessionIdResolver.cookieInitializer being null.
I was able to solve this adding 'spring-session-core' dependency and using the following config :
#EnableSpringWebSession
#Configuration
public class CookieConfiguration {
#Bean
public WebSessionIdResolver webSessionIdResolver() {
CookieWebSessionIdResolver resolver = new CookieWebSessionIdResolver();
resolver.addCookieInitializer(builder -> builder.sameSite("None"));
return resolver;
}
#Bean
public ReactiveMapSessionRepository reactiveSessionRepository() {
return new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
}
}

Configure Spring Boot with two ports

I'm trying configure an application in Spring Boot with two differents ports, but I haven't got still.
My first aproximation has been with two controllers and I have defined a #Bean inside the two controller with container.setPort(8080);
And my second aproximation has been add the actuator dependency and change the port of the managament, but my application don't run. "Address already in use: bind",
How can I confiure an application with two ports? I want one port for admin and the other port is for consults of my api.
As is has been mentioned before, server.port and management.port along with management.context-path properties could be set to make the embedded container to listen on different ports (management-related properties to access Actuator endpoints).
To listen on ports other than server.port and management.port:
#Configuration
public class EmbeddedTomcatConfiguration {
#Value("${server.additionalPorts}")
private String additionalPorts;
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
Connector[] additionalConnectors = this.additionalConnector();
if (additionalConnectors != null && additionalConnectors.length > 0) {
tomcat.addAdditionalTomcatConnectors(additionalConnectors);
}
return tomcat;
}
private Connector[] additionalConnector() {
if (StringUtils.isBlank(this.additionalPorts)) {
return null;
}
String[] ports = this.additionalPorts.split(",");
List<Connector> result = new ArrayList<>();
for (String port : ports) {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(Integer.valueOf(port));
result.add(connector);
}
return result.toArray(new Connector[] {});
}
}
application.yml
server:
port: ${appPort:8800}
additionalPorts: 8881,8882
Application.java
#SpringBootApplication
#ComponentScan(...)
#Import(EmbeddedTomcatConfiguration.class)
public Application {
public static void main(String[] args) {
SpringApplication.run(Application .class, args);
}
}
I recently blogged about this topic at http://tech.asimio.net/2016/12/15/Configuring-Tomcat-to-Listen-on-Multiple-ports-using-Spring-Boot.html
Since springboot 2, EmbeddedServletContainerFactory mentioned in ootero solution is no longer available, so you should use either TomcatServletWebServerFactory or TomcatReactiveWebServerFactory according to your context.
The solution stays the same aside from the factory injection :
#Bean
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
Connector[] additionalConnectors = this.additionalConnector();
if (additionalConnectors != null && additionalConnectors.length > 0) {
tomcat.addAdditionalTomcatConnectors(additionalConnectors);
}
return tomcat;
}
To change Actuator management port you can use property
management.port=8081
See full list of properties here
Update:
Actuator creates one more Embedded Tomcat(servlet container) instance in this case.
See here and here
To run 2 or more applications within a single project or change the default port, you can perform the action like this
#SpringBootApplication
public class NewApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(NewApplication .class);
app.setDefaultProperties(Collections.singletonMap("server.port", "8083"));
app.run(args);
}
}
If only one additional port is to be opened, the following is sufficient (Kotlin):
#Configuration
class AdditionalEndpointConfig {
#Bean
#ConditionalOnProperty(PORT_PROPERTY)
fun tomcatServletWebServerFactory(#Value("\${$PORT_PROPERTY}") additionalPort: Int) =
TomcatServletWebServerFactory().apply {
addAdditionalTomcatConnectors(
Connector("org.apache.coyote.http11.Http11NioProtocol").apply {
scheme = "http"
port = additionalPort
})
}
companion object {
const val PORT_PROPERTY = "server.additional.port"
}
}

Spring SimpMessagingTemplate

I have an application which receive some data from RabbitMQ. Everything works fine, I mean in class where I have annotation #EnableScheduling.
#Scheduled(fixedDelay = 5000)
public void volumeGraphData() {
Random r = new Random();
Graph graph = new Graph();
graph.setVolume(r.nextInt(500));
String json = gson.toJson(graph);
MessageBuilder<byte[]> messageBuilder = MessageBuilder.withPayload(json.getBytes());
simpMessagingTemplate.send("/" + volumeGraph, messageBuilder.build());
}
But when I would like to process messages received by Queue Listener from RabbitMQ (this works too) and pass them through to specific context for Stomp WebSocket using SimpMessagingTemplate I cannot do that. SimpMessagingTemplate is defined in dispatcher-servlet.xml, but configuration related with RabbitMQ is in root context. I tried to move everything to one context, but it does not work. Anyone has similar case that one I have ?
I finally managed to fix this. So, basically you need move your beans related with Spring Messaging/WebSocket to one common bean.
That's why in my root context I have such lines :
<!-- Fix for IntelliJ 13.1 https://youtrack.jetbrains.com/issue/IDEA-123964 -->
<context:component-scan base-package="org.springframework.web.socket.config"/>
where in package pl.garciapl.program.service.config is located class responsible for configuration of WebSockets :
#Configuration
#EnableWebSocketMessageBroker
#Component("messageBroker")
public class MessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/test").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry messageBrokerRegistry) {
}
#Override
public void configureClientInboundChannel(ChannelRegistration channelRegistration) {
}
#Override
public void configureClientOutboundChannel(ChannelRegistration channelRegistration) {
}
#Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
messageConverters.add(new MappingJackson2MessageConverter());
return false;
}
}
Remember to store your beans which use SimpMessagingTemplate in the same context where you defined this above class.

Spring Boot - replace default embedded Tomcat connector

I need to add an AJP connector to embedded Tomcat and disable (or replace) the default connector that listens on 8080.
I've tried customizing this with EmbeddedServletContainerCustomizer, but I can't get a handle on the Tomcat object to replace the default connector created there. As a result I end up with the http port on 8080 in addition to my AJP ports.
Next, I've tried extending TomcatEmbeddedServletContainerFactory and overriding its getTomcatEmbeddedServletContainer method. Per the JavaDoc, this appears to be the perfect place to replace the default connector, but it still ends up being enabled (and doesn't create my AJP connector either). Any ideas what I might be missing? I've verified with the debugger that my configuration is being run.
Per answer below, here's the cleanest solution:
#Bean
public EmbeddedServletContainerFactory tomcat() {
TomcatEmbeddedServletContainerFactory myFactory = new TomcatEmbeddedServletContainerFactory();
myFactory.setProtocol("AJP/1.3");
myFactory.setPort(9000);
return myFactory;
}
#Bean
public EmbeddedServletContainerCustomizer containerCustomizer2() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container;
tomcat.addConnectorCustomizers(new TomcatConnectorCustomizer() {
#Override
public void customize(Connector connector) {
connector.setRedirectPort(9001);
}
});
}
};
}
You can use a TomcatConnectorCustomizer to configure the existing connector to use AJP by adding it to the TomcatEmbeddedServletContainerFactory.
Just create a EmbeddedServletContainerCustomizer bean and reconfigure it to AJP:
#Configuration
public class ServletConfig {
// AJP port defined in properties (default 666)
#Value("${tomcat.ajp.port:666}")
private Integer ajpPort;
#Bean
public EmbeddedServletContainerCustomizer ajpContainerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container;
tomcat.setProtocol("AJP/1.3");
tomcat.setPort(ajpPort);
}
};
}
}

Spring Boot with Tomcat container security

I'm trying to add Tomcat container security to a Spring Boot application (to take advantage of some legacy custom valves). With the snippet below (starting from the example at https://github.com/spring-guides/gs-rest-service.git) I expected basic authentication would kick in, but it doesn't. Tried with both Spring Boot 1.1.6 and 1.1.7.
The same configuration when starting an embedded Tomcat "manually" (without involving Boot at all) works as expected.
#Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer factory) {
if(factory instanceof TomcatEmbeddedServletContainerFactory){
TomcatEmbeddedServletContainerFactory containerFactory = (TomcatEmbeddedServletContainerFactory) factory;
containerFactory.addContextCustomizers(new TomcatContextCustomizer() {
#Override
public void customize(Context context) {
LoginConfig config = new LoginConfig();
config.setAuthMethod("BASIC");
context.setLoginConfig(config);
context.addSecurityRole("admin");
SecurityConstraint constraint = new SecurityConstraint();
constraint.addAuthRole("admin");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
constraint.addCollection(collection);
context.addConstraint(constraint);
}
});
}
}
};
}

Resources