Skip to content

Commit db903c2

Browse files
committed
Align defaults in ServerProperties with defaults at runtime
Closes gh-13821
1 parent 7d54eda commit db903c2

File tree

3 files changed

+218
-43
lines changed

3 files changed

+218
-43
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -640,22 +640,22 @@ public static class Tomcat {
640640
/**
641641
* Delay in seconds between the invocation of backgroundProcess methods.
642642
*/
643-
private int backgroundProcessorDelay = 30; // seconds
643+
private int backgroundProcessorDelay = 10; // seconds
644644

645645
/**
646646
* Maximum amount of worker threads.
647647
*/
648-
private int maxThreads = 0; // Number of threads in protocol handler
648+
private int maxThreads = 200; // Number of threads in protocol handler
649649

650650
/**
651651
* Minimum amount of worker threads.
652652
*/
653-
private int minSpareThreads = 0; // Minimum spare threads in protocol handler
653+
private int minSpareThreads = 10; // Minimum spare threads in protocol handler
654654

655655
/**
656656
* Maximum size in bytes of the HTTP post content.
657657
*/
658-
private int maxHttpPostSize = 0; // bytes
658+
private int maxHttpPostSize = 2097152; // bytes
659659

660660
/**
661661
* Maximum size in bytes of the HTTP message header.
@@ -666,25 +666,25 @@ public static class Tomcat {
666666
* Whether requests to the context root should be redirected by appending a / to
667667
* the path.
668668
*/
669-
private Boolean redirectContextRoot;
669+
private Boolean redirectContextRoot = true;
670670

671671
/**
672672
* Character encoding to use to decode the URI.
673673
*/
674-
private Charset uriEncoding;
674+
private Charset uriEncoding = Charset.forName("UTF-8");
675675

676676
/**
677677
* Maximum number of connections that the server will accept and process at any
678678
* given time. Once the limit has been reached, the operating system may still
679679
* accept connections based on the "acceptCount" property.
680680
*/
681-
private int maxConnections = 0;
681+
private int maxConnections = 10000;
682682

683683
/**
684684
* Maximum queue length for incoming connection requests when all possible request
685685
* processing threads are in use.
686686
*/
687-
private int acceptCount = 0;
687+
private int acceptCount = 100;
688688

689689
/**
690690
* Comma-separated list of additional patterns that match jars to ignore for TLD
@@ -1091,7 +1091,7 @@ public static class Accesslog {
10911091
/**
10921092
* Defer inclusion of the date stamp in the file name until rotate time.
10931093
*/
1094-
private boolean renameOnRotate;
1094+
private boolean renameOnRotate = false;
10951095

10961096
/**
10971097
* Date format to place in log file name.
@@ -1102,7 +1102,7 @@ public static class Accesslog {
11021102
* Set request attributes for IP address, Hostname, protocol and port used for
11031103
* the request.
11041104
*/
1105-
private boolean requestAttributesEnabled;
1105+
private boolean requestAttributesEnabled = false;
11061106

11071107
/**
11081108
* Buffer output such that it is only flushed periodically.
@@ -1198,17 +1198,19 @@ public static class Jetty {
11981198
/**
11991199
* Maximum size in bytes of the HTTP post or put content.
12001200
*/
1201-
private int maxHttpPostSize = 0; // bytes
1201+
private int maxHttpPostSize = 200000; // bytes
12021202

12031203
/**
1204-
* Number of acceptor threads to use.
1204+
* Number of acceptor threads to use. When the value is -1, the default, the
1205+
* number of acceptors is derived from the operating environment.
12051206
*/
1206-
private Integer acceptors;
1207+
private Integer acceptors = -1;
12071208

12081209
/**
1209-
* Number of selector threads to use.
1210+
* Number of selector threads to use. When the value is -1, the default, the
1211+
* number of selectors is derived from the operating environment.
12101212
*/
1211-
private Integer selectors;
1213+
private Integer selectors = -1;
12121214

12131215
public int getMaxHttpPostSize() {
12141216
return this.maxHttpPostSize;
@@ -1359,12 +1361,14 @@ else if (handler instanceof HandlerCollection) {
13591361
public static class Undertow {
13601362

13611363
/**
1362-
* Maximum size in bytes of the HTTP post content.
1364+
* Maximum size in bytes of the HTTP post content. When the value is -1, the
1365+
* default, the size is unlimited.
13631366
*/
1364-
private long maxHttpPostSize = 0; // bytes
1367+
private long maxHttpPostSize = -1; // bytes
13651368

13661369
/**
1367-
* Size of each buffer in bytes.
1370+
* Size of each buffer in bytes. The default is derived from the maximum amount of
1371+
* memory that is available to the JVM.
13681372
*/
13691373
private Integer bufferSize;
13701374

@@ -1375,17 +1379,19 @@ public static class Undertow {
13751379
private Integer buffersPerRegion;
13761380

13771381
/**
1378-
* Number of I/O threads to create for the worker.
1382+
* Number of I/O threads to create for the worker. The default is derived from the
1383+
* number of available processors.
13791384
*/
13801385
private Integer ioThreads;
13811386

13821387
/**
1383-
* Number of worker threads.
1388+
* Number of worker threads. The default is 8 times the number of I/O threads.
13841389
*/
13851390
private Integer workerThreads;
13861391

13871392
/**
1388-
* Allocate buffers outside the Java heap.
1393+
* Allocate buffers outside the Java heap. The default is derived from the maximum
1394+
* amount of memory that is available to the JVM.
13891395
*/
13901396
private Boolean directBuffers;
13911397

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java

Lines changed: 176 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
package org.springframework.boot.autoconfigure.web;
1818

1919
import java.io.File;
20+
import java.io.IOException;
2021
import java.net.InetAddress;
22+
import java.net.URI;
2123
import java.nio.charset.Charset;
2224
import java.util.Collections;
2325
import java.util.EnumSet;
@@ -29,15 +31,23 @@
2931
import javax.servlet.ServletException;
3032
import javax.servlet.SessionCookieConfig;
3133
import javax.servlet.SessionTrackingMode;
34+
import javax.servlet.http.HttpServlet;
35+
import javax.servlet.http.HttpServletRequest;
36+
import javax.servlet.http.HttpServletResponse;
3237

38+
import io.undertow.UndertowOptions;
3339
import org.apache.catalina.Context;
3440
import org.apache.catalina.Valve;
41+
import org.apache.catalina.connector.Connector;
3542
import org.apache.catalina.core.StandardContext;
43+
import org.apache.catalina.core.StandardEngine;
3644
import org.apache.catalina.startup.Tomcat;
3745
import org.apache.catalina.valves.AccessLogValve;
3846
import org.apache.catalina.valves.ErrorReportValve;
3947
import org.apache.catalina.valves.RemoteIpValve;
4048
import org.apache.coyote.AbstractProtocol;
49+
import org.eclipse.jetty.server.HttpChannel;
50+
import org.eclipse.jetty.server.Request;
4151
import org.junit.Before;
4252
import org.junit.Test;
4353
import org.mockito.ArgumentCaptor;
@@ -49,12 +59,21 @@
4959
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
5060
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
5161
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
62+
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainer;
5263
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
5364
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer;
5465
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
5566
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
5667
import org.springframework.boot.web.servlet.ServletContextInitializer;
68+
import org.springframework.http.HttpEntity;
69+
import org.springframework.http.HttpHeaders;
70+
import org.springframework.http.MediaType;
71+
import org.springframework.http.client.ClientHttpResponse;
5772
import org.springframework.mock.env.MockEnvironment;
73+
import org.springframework.util.LinkedMultiValueMap;
74+
import org.springframework.util.MultiValueMap;
75+
import org.springframework.web.client.ResponseErrorHandler;
76+
import org.springframework.web.client.RestTemplate;
5877

5978
import static org.assertj.core.api.Assertions.assertThat;
6079
import static org.mockito.Matchers.anyBoolean;
@@ -256,13 +275,6 @@ public void errorReportValveIsConfiguredToNotReportStackTraces() {
256275
}
257276
}
258277

259-
@Test
260-
public void redirectContextRootIsNotConfiguredByDefault() throws Exception {
261-
bindProperties(new HashMap<String, String>());
262-
ServerProperties.Tomcat tomcat = this.properties.getTomcat();
263-
assertThat(tomcat.getRedirectContextRoot()).isNull();
264-
}
265-
266278
@Test
267279
public void redirectContextRootCanBeConfigured() throws Exception {
268280
Map<String, String> map = new HashMap<String, String>();
@@ -274,6 +286,10 @@ public void redirectContextRootCanBeConfigured() throws Exception {
274286
Context context = (Context) ((TomcatEmbeddedServletContainer) factory
275287
.getEmbeddedServletContainer()).getTomcat().getHost().findChildren()[0];
276288
assertThat(context.getMapperContextRootRedirectEnabled()).isTrue();
289+
this.properties.customize(factory);
290+
context = (Context) ((TomcatEmbeddedServletContainer) factory
291+
.getEmbeddedServletContainer()).getTomcat().getHost().findChildren()[0];
292+
assertThat(context.getMapperContextRootRedirectEnabled()).isFalse();
277293
}
278294

279295
@Test
@@ -517,7 +533,7 @@ public void defaultTomcatBackgroundProcessorDelay() throws Exception {
517533
this.properties.customize(factory);
518534
EmbeddedServletContainer container = factory.getEmbeddedServletContainer();
519535
assertThat(((TomcatEmbeddedServletContainer) container).getTomcat().getEngine()
520-
.getBackgroundProcessorDelay()).isEqualTo(30);
536+
.getBackgroundProcessorDelay()).isEqualTo(10);
521537
container.stop();
522538
}
523539

@@ -819,6 +835,158 @@ public void skipNullElementsForUndertow() throws Exception {
819835
verify(container, never()).setAccessLogEnabled(anyBoolean());
820836
}
821837

838+
@Test
839+
public void tomcatAcceptCountMatchesProtocolDefault() throws Exception {
840+
assertThat(this.properties.getTomcat().getAcceptCount())
841+
.isEqualTo(getDefaultProtocol().getAcceptCount());
842+
}
843+
844+
@Test
845+
public void tomcatMaxConnectionsMatchesProtocolDefault() throws Exception {
846+
assertThat(this.properties.getTomcat().getMaxConnections())
847+
.isEqualTo(getDefaultProtocol().getMaxConnections());
848+
}
849+
850+
@Test
851+
public void tomcatMaxThreadsMatchesProtocolDefault() throws Exception {
852+
assertThat(this.properties.getTomcat().getMaxThreads())
853+
.isEqualTo(getDefaultProtocol().getMaxThreads());
854+
}
855+
856+
@Test
857+
public void tomcatMinSpareThreadsMatchesProtocolDefault() throws Exception {
858+
assertThat(this.properties.getTomcat().getMinSpareThreads())
859+
.isEqualTo(getDefaultProtocol().getMinSpareThreads());
860+
}
861+
862+
@Test
863+
public void tomcatMaxHttpPostSizeMatchesConnectorDefault() throws Exception {
864+
assertThat(this.properties.getTomcat().getMaxHttpPostSize())
865+
.isEqualTo(getDefaultConnector().getMaxPostSize());
866+
}
867+
868+
@Test
869+
public void tomcatBackgroundProcessorDelayMatchesEngineDefault() {
870+
assertThat(this.properties.getTomcat().getBackgroundProcessorDelay())
871+
.isEqualTo(new StandardEngine().getBackgroundProcessorDelay());
872+
}
873+
874+
@Test
875+
public void tomcatUriEncodingMatchesConnectorDefault() throws Exception {
876+
assertThat(this.properties.getTomcat().getUriEncoding().name())
877+
.isEqualTo(getDefaultConnector().getURIEncoding());
878+
}
879+
880+
@Test
881+
public void tomcatRedirectContextRootMatchesDefault() {
882+
assertThat(this.properties.getTomcat().getRedirectContextRoot())
883+
.isEqualTo(new StandardContext().getMapperContextRootRedirectEnabled());
884+
}
885+
886+
@Test
887+
public void tomcatAccessLogRenameOnRotateMatchesDefault() {
888+
assertThat(this.properties.getTomcat().getAccesslog().isRenameOnRotate())
889+
.isEqualTo(new AccessLogValve().isRenameOnRotate());
890+
}
891+
892+
@Test
893+
public void tomcatAccessLogRequestAttributesEnabledMatchesDefault() {
894+
assertThat(
895+
this.properties.getTomcat().getAccesslog().isRequestAttributesEnabled())
896+
.isEqualTo(new AccessLogValve().getRequestAttributesEnabled());
897+
}
898+
899+
@Test
900+
public void jettyMaxHttpPostSizeMatchesDefault() throws Exception {
901+
JettyEmbeddedServletContainerFactory jettyFactory = new JettyEmbeddedServletContainerFactory(
902+
0);
903+
JettyEmbeddedServletContainer jetty = (JettyEmbeddedServletContainer) jettyFactory
904+
.getEmbeddedServletContainer(new ServletContextInitializer() {
905+
906+
@Override
907+
public void onStartup(ServletContext servletContext)
908+
throws ServletException {
909+
servletContext.addServlet("formPost", new HttpServlet() {
910+
911+
@Override
912+
protected void doPost(HttpServletRequest req,
913+
HttpServletResponse resp)
914+
throws ServletException, IOException {
915+
req.getParameterMap();
916+
}
917+
918+
}).addMapping("/form");
919+
}
920+
921+
});
922+
jetty.start();
923+
org.eclipse.jetty.server.Connector connector = jetty.getServer()
924+
.getConnectors()[0];
925+
final AtomicReference<Throwable> failure = new AtomicReference<Throwable>();
926+
connector.addBean(new HttpChannel.Listener() {
927+
928+
@Override
929+
public void onDispatchFailure(Request request, Throwable ex) {
930+
failure.set(ex);
931+
}
932+
933+
});
934+
try {
935+
RestTemplate template = new RestTemplate();
936+
template.setErrorHandler(new ResponseErrorHandler() {
937+
938+
@Override
939+
public boolean hasError(ClientHttpResponse response) throws IOException {
940+
return false;
941+
}
942+
943+
@Override
944+
public void handleError(ClientHttpResponse response) throws IOException {
945+
946+
}
947+
948+
});
949+
HttpHeaders headers = new HttpHeaders();
950+
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
951+
MultiValueMap<String, Object> body = new LinkedMultiValueMap<String, Object>();
952+
StringBuilder data = new StringBuilder();
953+
for (int i = 0; i < 250000; i++) {
954+
data.append("a");
955+
}
956+
body.add("data", data.toString());
957+
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<MultiValueMap<String, Object>>(
958+
body, headers);
959+
template.postForEntity(
960+
URI.create("http://localhost:" + jetty.getPort() + "/form"), entity,
961+
Void.class);
962+
assertThat(failure.get()).isNotNull();
963+
String message = failure.get().getCause().getMessage();
964+
int defaultMaxPostSize = Integer
965+
.valueOf(message.substring(message.lastIndexOf(' ')).trim());
966+
assertThat(this.properties.getJetty().getMaxHttpPostSize())
967+
.isEqualTo(defaultMaxPostSize);
968+
}
969+
finally {
970+
jetty.stop();
971+
}
972+
}
973+
974+
@Test
975+
public void undertowMaxHttpPostSizeMatchesDefault() {
976+
assertThat(this.properties.getUndertow().getMaxHttpPostSize())
977+
.isEqualTo(UndertowOptions.DEFAULT_MAX_ENTITY_SIZE);
978+
}
979+
980+
private Connector getDefaultConnector() throws Exception {
981+
return new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
982+
}
983+
984+
private AbstractProtocol<?> getDefaultProtocol() throws Exception {
985+
return (AbstractProtocol<?>) Class
986+
.forName(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL)
987+
.newInstance();
988+
}
989+
822990
private void bindProperties(Map<String, String> map) {
823991
new RelaxedDataBinder(this.properties, "server")
824992
.bind(new MutablePropertyValues(map));

0 commit comments

Comments
 (0)