001/*
002 * Copyright 2012-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.autoconfigure.web;
018
019import java.io.File;
020import java.net.InetAddress;
021import java.nio.charset.Charset;
022import java.util.ArrayList;
023import java.util.Collection;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Map;
027import java.util.Set;
028
029import javax.servlet.ServletContext;
030import javax.servlet.ServletException;
031import javax.servlet.SessionCookieConfig;
032import javax.servlet.SessionTrackingMode;
033
034import io.undertow.Undertow.Builder;
035import io.undertow.UndertowOptions;
036import org.apache.catalina.Context;
037import org.apache.catalina.connector.Connector;
038import org.apache.catalina.valves.AccessLogValve;
039import org.apache.catalina.valves.RemoteIpValve;
040import org.apache.coyote.AbstractProtocol;
041import org.apache.coyote.ProtocolHandler;
042import org.apache.coyote.http11.AbstractHttp11Protocol;
043import org.eclipse.jetty.server.AbstractConnector;
044import org.eclipse.jetty.server.ConnectionFactory;
045import org.eclipse.jetty.server.Handler;
046import org.eclipse.jetty.server.HttpConfiguration;
047import org.eclipse.jetty.server.Server;
048import org.eclipse.jetty.server.handler.ContextHandler;
049import org.eclipse.jetty.server.handler.HandlerCollection;
050import org.eclipse.jetty.server.handler.HandlerWrapper;
051
052import org.springframework.boot.autoconfigure.web.ServerProperties.Session.Cookie;
053import org.springframework.boot.cloud.CloudPlatform;
054import org.springframework.boot.context.embedded.Compression;
055import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
056import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
057import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor;
058import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
059import org.springframework.boot.context.embedded.InitParameterConfiguringServletContextInitializer;
060import org.springframework.boot.context.embedded.JspServlet;
061import org.springframework.boot.context.embedded.Ssl;
062import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
063import org.springframework.boot.context.embedded.jetty.JettyServerCustomizer;
064import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
065import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
066import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
067import org.springframework.boot.context.embedded.undertow.UndertowBuilderCustomizer;
068import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
069import org.springframework.boot.context.properties.ConfigurationProperties;
070import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
071import org.springframework.boot.context.properties.NestedConfigurationProperty;
072import org.springframework.boot.web.servlet.ServletContextInitializer;
073import org.springframework.context.EnvironmentAware;
074import org.springframework.core.Ordered;
075import org.springframework.core.env.Environment;
076import org.springframework.util.Assert;
077import org.springframework.util.ObjectUtils;
078import org.springframework.util.StringUtils;
079
080/**
081 * {@link ConfigurationProperties} for a web server (e.g. port and path settings). Will be
082 * used to customize an {@link EmbeddedServletContainerFactory} when an
083 * {@link EmbeddedServletContainerCustomizerBeanPostProcessor} is active.
084 *
085 * @author Dave Syer
086 * @author Stephane Nicoll
087 * @author Andy Wilkinson
088 * @author Ivan Sopov
089 * @author Marcos Barbero
090 * @author Eddú Meléndez
091 * @author Quinten De Swaef
092 * @author Venil Noronha
093 * @author Aurélien Leboulanger
094 */
095@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
096public class ServerProperties
097                implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered {
098
099        /**
100         * Server HTTP port.
101         */
102        private Integer port;
103
104        /**
105         * Network address to which the server should bind to.
106         */
107        private InetAddress address;
108
109        /**
110         * Context path of the application.
111         */
112        private String contextPath;
113
114        /**
115         * Display name of the application.
116         */
117        private String displayName = "application";
118
119        @NestedConfigurationProperty
120        private ErrorProperties error = new ErrorProperties();
121
122        /**
123         * Path of the main dispatcher servlet.
124         */
125        private String servletPath = "/";
126
127        /**
128         * ServletContext parameters.
129         */
130        private final Map<String, String> contextParameters = new HashMap<String, String>();
131
132        /**
133         * If X-Forwarded-* headers should be applied to the HttpRequest.
134         */
135        private Boolean useForwardHeaders;
136
137        /**
138         * Value to use for the Server response header (no header is sent if empty).
139         */
140        private String serverHeader;
141
142        /**
143         * Maximum size in bytes of the HTTP message header.
144         */
145        private int maxHttpHeaderSize = 0; // bytes
146
147        /**
148         * Maximum size in bytes of the HTTP post content.
149         */
150        private int maxHttpPostSize = 0; // bytes
151
152        /**
153         * Time in milliseconds that connectors will wait for another HTTP request before
154         * closing the connection. When not set, the connector's container-specific default
155         * will be used. Use a value of -1 to indicate no (i.e. infinite) timeout.
156         */
157        private Integer connectionTimeout;
158
159        private Session session = new Session();
160
161        @NestedConfigurationProperty
162        private Ssl ssl;
163
164        @NestedConfigurationProperty
165        private Compression compression = new Compression();
166
167        @NestedConfigurationProperty
168        private JspServlet jspServlet;
169
170        private final Tomcat tomcat = new Tomcat();
171
172        private final Jetty jetty = new Jetty();
173
174        private final Undertow undertow = new Undertow();
175
176        private Environment environment;
177
178        @Override
179        public int getOrder() {
180                return 0;
181        }
182
183        @Override
184        public void setEnvironment(Environment environment) {
185                this.environment = environment;
186        }
187
188        @Override
189        public void customize(ConfigurableEmbeddedServletContainer container) {
190                if (getPort() != null) {
191                        container.setPort(getPort());
192                }
193                if (getAddress() != null) {
194                        container.setAddress(getAddress());
195                }
196                if (getContextPath() != null) {
197                        container.setContextPath(getContextPath());
198                }
199                if (getDisplayName() != null) {
200                        container.setDisplayName(getDisplayName());
201                }
202                if (getSession().getTimeout() != null) {
203                        container.setSessionTimeout(getSession().getTimeout());
204                }
205                container.setPersistSession(getSession().isPersistent());
206                container.setSessionStoreDir(getSession().getStoreDir());
207                if (getSsl() != null) {
208                        container.setSsl(getSsl());
209                }
210                if (getJspServlet() != null) {
211                        container.setJspServlet(getJspServlet());
212                }
213                if (getCompression() != null) {
214                        container.setCompression(getCompression());
215                }
216                container.setServerHeader(getServerHeader());
217                if (container instanceof TomcatEmbeddedServletContainerFactory) {
218                        getTomcat().customizeTomcat(this,
219                                        (TomcatEmbeddedServletContainerFactory) container);
220                }
221                if (container instanceof JettyEmbeddedServletContainerFactory) {
222                        getJetty().customizeJetty(this,
223                                        (JettyEmbeddedServletContainerFactory) container);
224                }
225
226                if (container instanceof UndertowEmbeddedServletContainerFactory) {
227                        getUndertow().customizeUndertow(this,
228                                        (UndertowEmbeddedServletContainerFactory) container);
229                }
230                container.addInitializers(new SessionConfiguringInitializer(this.session));
231                container.addInitializers(new InitParameterConfiguringServletContextInitializer(
232                                getContextParameters()));
233        }
234
235        public String getServletMapping() {
236                if (this.servletPath.equals("") || this.servletPath.equals("/")) {
237                        return "/";
238                }
239                if (this.servletPath.contains("*")) {
240                        return this.servletPath;
241                }
242                if (this.servletPath.endsWith("/")) {
243                        return this.servletPath + "*";
244                }
245                return this.servletPath + "/*";
246        }
247
248        public String getPath(String path) {
249                String prefix = getServletPrefix();
250                if (!path.startsWith("/")) {
251                        path = "/" + path;
252                }
253                return prefix + path;
254        }
255
256        public String getServletPrefix() {
257                String result = this.servletPath;
258                if (result.contains("*")) {
259                        result = result.substring(0, result.indexOf("*"));
260                }
261                if (result.endsWith("/")) {
262                        result = result.substring(0, result.length() - 1);
263                }
264                return result;
265        }
266
267        public String[] getPathsArray(Collection<String> paths) {
268                String[] result = new String[paths.size()];
269                int i = 0;
270                for (String path : paths) {
271                        result[i++] = getPath(path);
272                }
273                return result;
274        }
275
276        public String[] getPathsArray(String[] paths) {
277                String[] result = new String[paths.length];
278                int i = 0;
279                for (String path : paths) {
280                        result[i++] = getPath(path);
281                }
282                return result;
283        }
284
285        public void setLoader(String value) {
286                // no op to support Tomcat running as a traditional container (not embedded)
287        }
288
289        public Integer getPort() {
290                return this.port;
291        }
292
293        public void setPort(Integer port) {
294                this.port = port;
295        }
296
297        public InetAddress getAddress() {
298                return this.address;
299        }
300
301        public void setAddress(InetAddress address) {
302                this.address = address;
303        }
304
305        public String getContextPath() {
306                return this.contextPath;
307        }
308
309        public void setContextPath(String contextPath) {
310                this.contextPath = cleanContextPath(contextPath);
311        }
312
313        private String cleanContextPath(String contextPath) {
314                if (StringUtils.hasText(contextPath) && contextPath.endsWith("/")) {
315                        return contextPath.substring(0, contextPath.length() - 1);
316                }
317                return contextPath;
318        }
319
320        public String getDisplayName() {
321                return this.displayName;
322        }
323
324        public void setDisplayName(String displayName) {
325                this.displayName = displayName;
326        }
327
328        public String getServletPath() {
329                return this.servletPath;
330        }
331
332        public void setServletPath(String servletPath) {
333                Assert.notNull(servletPath, "ServletPath must not be null");
334                this.servletPath = servletPath;
335        }
336
337        public Map<String, String> getContextParameters() {
338                return this.contextParameters;
339        }
340
341        public Boolean isUseForwardHeaders() {
342                return this.useForwardHeaders;
343        }
344
345        public void setUseForwardHeaders(Boolean useForwardHeaders) {
346                this.useForwardHeaders = useForwardHeaders;
347        }
348
349        public String getServerHeader() {
350                return this.serverHeader;
351        }
352
353        public void setServerHeader(String serverHeader) {
354                this.serverHeader = serverHeader;
355        }
356
357        public int getMaxHttpHeaderSize() {
358                return this.maxHttpHeaderSize;
359        }
360
361        public void setMaxHttpHeaderSize(int maxHttpHeaderSize) {
362                this.maxHttpHeaderSize = maxHttpHeaderSize;
363        }
364
365        @Deprecated
366        @DeprecatedConfigurationProperty(reason = "Use dedicated property for each container.")
367        public int getMaxHttpPostSize() {
368                return this.maxHttpPostSize;
369        }
370
371        @Deprecated
372        public void setMaxHttpPostSize(int maxHttpPostSize) {
373                this.maxHttpPostSize = maxHttpPostSize;
374                this.jetty.setMaxHttpPostSize(maxHttpPostSize);
375                this.tomcat.setMaxHttpPostSize(maxHttpPostSize);
376                this.undertow.setMaxHttpPostSize(maxHttpPostSize);
377        }
378
379        protected final boolean getOrDeduceUseForwardHeaders() {
380                if (this.useForwardHeaders != null) {
381                        return this.useForwardHeaders;
382                }
383                CloudPlatform platform = CloudPlatform.getActive(this.environment);
384                return (platform == null ? false : platform.isUsingForwardHeaders());
385        }
386
387        public Integer getConnectionTimeout() {
388                return this.connectionTimeout;
389        }
390
391        public void setConnectionTimeout(Integer connectionTimeout) {
392                this.connectionTimeout = connectionTimeout;
393        }
394
395        public ErrorProperties getError() {
396                return this.error;
397        }
398
399        public Session getSession() {
400                return this.session;
401        }
402
403        public void setSession(Session session) {
404                this.session = session;
405        }
406
407        public Ssl getSsl() {
408                return this.ssl;
409        }
410
411        public void setSsl(Ssl ssl) {
412                this.ssl = ssl;
413        }
414
415        public Compression getCompression() {
416                return this.compression;
417        }
418
419        public JspServlet getJspServlet() {
420                return this.jspServlet;
421        }
422
423        public void setJspServlet(JspServlet jspServlet) {
424                this.jspServlet = jspServlet;
425        }
426
427        public Tomcat getTomcat() {
428                return this.tomcat;
429        }
430
431        public Jetty getJetty() {
432                return this.jetty;
433        }
434
435        public Undertow getUndertow() {
436                return this.undertow;
437        }
438
439        public static class Session {
440
441                /**
442                 * Session timeout in seconds.
443                 */
444                private Integer timeout;
445
446                /**
447                 * Session tracking modes (one or more of the following: "cookie", "url", "ssl").
448                 */
449                private Set<SessionTrackingMode> trackingModes;
450
451                /**
452                 * Persist session data between restarts.
453                 */
454                private boolean persistent;
455
456                /**
457                 * Directory used to store session data.
458                 */
459                private File storeDir;
460
461                private Cookie cookie = new Cookie();
462
463                public Cookie getCookie() {
464                        return this.cookie;
465                }
466
467                public Integer getTimeout() {
468                        return this.timeout;
469                }
470
471                public void setTimeout(Integer sessionTimeout) {
472                        this.timeout = sessionTimeout;
473                }
474
475                public Set<SessionTrackingMode> getTrackingModes() {
476                        return this.trackingModes;
477                }
478
479                public void setTrackingModes(Set<SessionTrackingMode> trackingModes) {
480                        this.trackingModes = trackingModes;
481                }
482
483                public boolean isPersistent() {
484                        return this.persistent;
485                }
486
487                public void setPersistent(boolean persistent) {
488                        this.persistent = persistent;
489                }
490
491                public File getStoreDir() {
492                        return this.storeDir;
493                }
494
495                public void setStoreDir(File storeDir) {
496                        this.storeDir = storeDir;
497                }
498
499                public static class Cookie {
500
501                        /**
502                         * Session cookie name.
503                         */
504                        private String name;
505
506                        /**
507                         * Domain for the session cookie.
508                         */
509                        private String domain;
510
511                        /**
512                         * Path of the session cookie.
513                         */
514                        private String path;
515
516                        /**
517                         * Comment for the session cookie.
518                         */
519                        private String comment;
520
521                        /**
522                         * "HttpOnly" flag for the session cookie.
523                         */
524                        private Boolean httpOnly;
525
526                        /**
527                         * "Secure" flag for the session cookie.
528                         */
529                        private Boolean secure;
530
531                        /**
532                         * Maximum age of the session cookie in seconds.
533                         */
534                        private Integer maxAge;
535
536                        public String getName() {
537                                return this.name;
538                        }
539
540                        public void setName(String name) {
541                                this.name = name;
542                        }
543
544                        public String getDomain() {
545                                return this.domain;
546                        }
547
548                        public void setDomain(String domain) {
549                                this.domain = domain;
550                        }
551
552                        public String getPath() {
553                                return this.path;
554                        }
555
556                        public void setPath(String path) {
557                                this.path = path;
558                        }
559
560                        public String getComment() {
561                                return this.comment;
562                        }
563
564                        public void setComment(String comment) {
565                                this.comment = comment;
566                        }
567
568                        public Boolean getHttpOnly() {
569                                return this.httpOnly;
570                        }
571
572                        public void setHttpOnly(Boolean httpOnly) {
573                                this.httpOnly = httpOnly;
574                        }
575
576                        public Boolean getSecure() {
577                                return this.secure;
578                        }
579
580                        public void setSecure(Boolean secure) {
581                                this.secure = secure;
582                        }
583
584                        public Integer getMaxAge() {
585                                return this.maxAge;
586                        }
587
588                        public void setMaxAge(Integer maxAge) {
589                                this.maxAge = maxAge;
590                        }
591
592                }
593
594        }
595
596        public static class Tomcat {
597
598                /**
599                 * Access log configuration.
600                 */
601                private final Accesslog accesslog = new Accesslog();
602
603                /**
604                 * Regular expression that matches proxies that are to be trusted.
605                 */
606                private String internalProxies = "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" // 10/8
607                                + "192\\.168\\.\\d{1,3}\\.\\d{1,3}|" // 192.168/16
608                                + "169\\.254\\.\\d{1,3}\\.\\d{1,3}|" // 169.254/16
609                                + "127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" // 127/8
610                                + "172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" // 172.16/12
611                                + "172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|"
612                                + "172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}";
613
614                /**
615                 * Header that holds the incoming protocol, usually named "X-Forwarded-Proto".
616                 */
617                private String protocolHeader;
618
619                /**
620                 * Value of the protocol header that indicates that the incoming request uses SSL.
621                 */
622                private String protocolHeaderHttpsValue = "https";
623
624                /**
625                 * Name of the HTTP header used to override the original port value.
626                 */
627                private String portHeader = "X-Forwarded-Port";
628
629                /**
630                 * Name of the http header from which the remote ip is extracted..
631                 */
632                private String remoteIpHeader;
633
634                /**
635                 * Tomcat base directory. If not specified a temporary directory will be used.
636                 */
637                private File basedir;
638
639                /**
640                 * Delay in seconds between the invocation of backgroundProcess methods.
641                 */
642                private int backgroundProcessorDelay = 30; // seconds
643
644                /**
645                 * Maximum amount of worker threads.
646                 */
647                private int maxThreads = 0; // Number of threads in protocol handler
648
649                /**
650                 * Minimum amount of worker threads.
651                 */
652                private int minSpareThreads = 0; // Minimum spare threads in protocol handler
653
654                /**
655                 * Maximum size in bytes of the HTTP post content.
656                 */
657                private int maxHttpPostSize = 0; // bytes
658
659                /**
660                 * Maximum size in bytes of the HTTP message header.
661                 */
662                private int maxHttpHeaderSize = 0; // bytes
663
664                /**
665                 * Whether requests to the context root should be redirected by appending a / to
666                 * the path.
667                 */
668                private Boolean redirectContextRoot;
669
670                /**
671                 * Character encoding to use to decode the URI.
672                 */
673                private Charset uriEncoding;
674
675                /**
676                 * Maximum number of connections that the server will accept and process at any
677                 * given time. Once the limit has been reached, the operating system may still
678                 * accept connections based on the "acceptCount" property.
679                 */
680                private int maxConnections = 0;
681
682                /**
683                 * Maximum queue length for incoming connection requests when all possible request
684                 * processing threads are in use.
685                 */
686                private int acceptCount = 0;
687
688                /**
689                 * Comma-separated list of additional patterns that match jars to ignore for TLD
690                 * scanning. The special '?' and '*' characters can be used in the pattern to
691                 * match one and only one character and zero or more characters respectively.
692                 */
693                private List<String> additionalTldSkipPatterns = new ArrayList<String>();
694
695                public int getMaxThreads() {
696                        return this.maxThreads;
697                }
698
699                public void setMaxThreads(int maxThreads) {
700                        this.maxThreads = maxThreads;
701                }
702
703                public int getMinSpareThreads() {
704                        return this.minSpareThreads;
705                }
706
707                public void setMinSpareThreads(int minSpareThreads) {
708                        this.minSpareThreads = minSpareThreads;
709                }
710
711                public int getMaxHttpPostSize() {
712                        return this.maxHttpPostSize;
713                }
714
715                public void setMaxHttpPostSize(int maxHttpPostSize) {
716                        this.maxHttpPostSize = maxHttpPostSize;
717                }
718
719                public Accesslog getAccesslog() {
720                        return this.accesslog;
721                }
722
723                public int getBackgroundProcessorDelay() {
724                        return this.backgroundProcessorDelay;
725                }
726
727                public void setBackgroundProcessorDelay(int backgroundProcessorDelay) {
728                        this.backgroundProcessorDelay = backgroundProcessorDelay;
729                }
730
731                public File getBasedir() {
732                        return this.basedir;
733                }
734
735                public void setBasedir(File basedir) {
736                        this.basedir = basedir;
737                }
738
739                public String getInternalProxies() {
740                        return this.internalProxies;
741                }
742
743                public void setInternalProxies(String internalProxies) {
744                        this.internalProxies = internalProxies;
745                }
746
747                public String getProtocolHeader() {
748                        return this.protocolHeader;
749                }
750
751                public void setProtocolHeader(String protocolHeader) {
752                        this.protocolHeader = protocolHeader;
753                }
754
755                public String getProtocolHeaderHttpsValue() {
756                        return this.protocolHeaderHttpsValue;
757                }
758
759                public void setProtocolHeaderHttpsValue(String protocolHeaderHttpsValue) {
760                        this.protocolHeaderHttpsValue = protocolHeaderHttpsValue;
761                }
762
763                public String getPortHeader() {
764                        return this.portHeader;
765                }
766
767                public void setPortHeader(String portHeader) {
768                        this.portHeader = portHeader;
769                }
770
771                public Boolean getRedirectContextRoot() {
772                        return this.redirectContextRoot;
773                }
774
775                public void setRedirectContextRoot(Boolean redirectContextRoot) {
776                        this.redirectContextRoot = redirectContextRoot;
777                }
778
779                public String getRemoteIpHeader() {
780                        return this.remoteIpHeader;
781                }
782
783                public void setRemoteIpHeader(String remoteIpHeader) {
784                        this.remoteIpHeader = remoteIpHeader;
785                }
786
787                public Charset getUriEncoding() {
788                        return this.uriEncoding;
789                }
790
791                public void setUriEncoding(Charset uriEncoding) {
792                        this.uriEncoding = uriEncoding;
793                }
794
795                public int getMaxConnections() {
796                        return this.maxConnections;
797                }
798
799                public void setMaxConnections(int maxConnections) {
800                        this.maxConnections = maxConnections;
801                }
802
803                public int getAcceptCount() {
804                        return this.acceptCount;
805                }
806
807                public void setAcceptCount(int acceptCount) {
808                        this.acceptCount = acceptCount;
809                }
810
811                public List<String> getAdditionalTldSkipPatterns() {
812                        return this.additionalTldSkipPatterns;
813                }
814
815                public void setAdditionalTldSkipPatterns(List<String> additionalTldSkipPatterns) {
816                        this.additionalTldSkipPatterns = additionalTldSkipPatterns;
817                }
818
819                void customizeTomcat(ServerProperties serverProperties,
820                                TomcatEmbeddedServletContainerFactory factory) {
821                        if (getBasedir() != null) {
822                                factory.setBaseDirectory(getBasedir());
823                        }
824                        factory.setBackgroundProcessorDelay(Tomcat.this.backgroundProcessorDelay);
825                        customizeRemoteIpValve(serverProperties, factory);
826                        if (this.maxThreads > 0) {
827                                customizeMaxThreads(factory);
828                        }
829                        if (this.minSpareThreads > 0) {
830                                customizeMinThreads(factory);
831                        }
832                        int maxHttpHeaderSize = (serverProperties.getMaxHttpHeaderSize() > 0
833                                        ? serverProperties.getMaxHttpHeaderSize() : this.maxHttpHeaderSize);
834                        if (maxHttpHeaderSize > 0) {
835                                customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize);
836                        }
837                        if (this.maxHttpPostSize != 0) {
838                                customizeMaxHttpPostSize(factory, this.maxHttpPostSize);
839                        }
840                        if (this.accesslog.enabled) {
841                                customizeAccessLog(factory);
842                        }
843                        if (getUriEncoding() != null) {
844                                factory.setUriEncoding(getUriEncoding());
845                        }
846                        if (serverProperties.getConnectionTimeout() != null) {
847                                customizeConnectionTimeout(factory,
848                                                serverProperties.getConnectionTimeout());
849                        }
850                        if (this.redirectContextRoot != null) {
851                                customizeRedirectContextRoot(factory, this.redirectContextRoot);
852                        }
853                        if (this.maxConnections > 0) {
854                                customizeMaxConnections(factory);
855                        }
856                        if (this.acceptCount > 0) {
857                                customizeAcceptCount(factory);
858                        }
859                        if (!ObjectUtils.isEmpty(this.additionalTldSkipPatterns)) {
860                                factory.getTldSkipPatterns().addAll(this.additionalTldSkipPatterns);
861                        }
862                }
863
864                private void customizeAcceptCount(TomcatEmbeddedServletContainerFactory factory) {
865                        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
866
867                                @Override
868                                @SuppressWarnings("deprecation")
869                                public void customize(Connector connector) {
870                                        ProtocolHandler handler = connector.getProtocolHandler();
871                                        if (handler instanceof AbstractProtocol) {
872                                                AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
873                                                protocol.setBacklog(Tomcat.this.acceptCount);
874                                        }
875                                }
876
877                        });
878                }
879
880                private void customizeMaxConnections(
881                                TomcatEmbeddedServletContainerFactory factory) {
882                        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
883
884                                @Override
885                                public void customize(Connector connector) {
886                                        ProtocolHandler handler = connector.getProtocolHandler();
887                                        if (handler instanceof AbstractProtocol) {
888                                                AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
889                                                protocol.setMaxConnections(Tomcat.this.maxConnections);
890                                        }
891                                }
892
893                        });
894                }
895
896                private void customizeConnectionTimeout(
897                                TomcatEmbeddedServletContainerFactory factory,
898                                final int connectionTimeout) {
899                        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
900
901                                @Override
902                                public void customize(Connector connector) {
903                                        ProtocolHandler handler = connector.getProtocolHandler();
904                                        if (handler instanceof AbstractProtocol) {
905                                                AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
906                                                protocol.setConnectionTimeout(connectionTimeout);
907                                        }
908                                }
909
910                        });
911                }
912
913                private void customizeRemoteIpValve(ServerProperties properties,
914                                TomcatEmbeddedServletContainerFactory factory) {
915                        String protocolHeader = getProtocolHeader();
916                        String remoteIpHeader = getRemoteIpHeader();
917                        // For back compatibility the valve is also enabled if protocol-header is set
918                        if (StringUtils.hasText(protocolHeader) || StringUtils.hasText(remoteIpHeader)
919                                        || properties.getOrDeduceUseForwardHeaders()) {
920                                RemoteIpValve valve = new RemoteIpValve();
921                                valve.setProtocolHeader(StringUtils.hasLength(protocolHeader)
922                                                ? protocolHeader : "X-Forwarded-Proto");
923                                if (StringUtils.hasLength(remoteIpHeader)) {
924                                        valve.setRemoteIpHeader(remoteIpHeader);
925                                }
926                                // The internal proxies default to a white list of "safe" internal IP
927                                // addresses
928                                valve.setInternalProxies(getInternalProxies());
929                                valve.setPortHeader(getPortHeader());
930                                valve.setProtocolHeaderHttpsValue(getProtocolHeaderHttpsValue());
931                                // ... so it's safe to add this valve by default.
932                                factory.addEngineValves(valve);
933                        }
934                }
935
936                @SuppressWarnings("rawtypes")
937                private void customizeMaxThreads(TomcatEmbeddedServletContainerFactory factory) {
938                        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
939                                @Override
940                                public void customize(Connector connector) {
941
942                                        ProtocolHandler handler = connector.getProtocolHandler();
943                                        if (handler instanceof AbstractProtocol) {
944                                                AbstractProtocol protocol = (AbstractProtocol) handler;
945                                                protocol.setMaxThreads(Tomcat.this.maxThreads);
946                                        }
947
948                                }
949                        });
950                }
951
952                @SuppressWarnings("rawtypes")
953                private void customizeMinThreads(TomcatEmbeddedServletContainerFactory factory) {
954                        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
955                                @Override
956                                public void customize(Connector connector) {
957
958                                        ProtocolHandler handler = connector.getProtocolHandler();
959                                        if (handler instanceof AbstractProtocol) {
960                                                AbstractProtocol protocol = (AbstractProtocol) handler;
961                                                protocol.setMinSpareThreads(Tomcat.this.minSpareThreads);
962                                        }
963
964                                }
965                        });
966                }
967
968                @SuppressWarnings("rawtypes")
969                private void customizeMaxHttpHeaderSize(
970                                TomcatEmbeddedServletContainerFactory factory,
971                                final int maxHttpHeaderSize) {
972                        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
973
974                                @Override
975                                public void customize(Connector connector) {
976                                        ProtocolHandler handler = connector.getProtocolHandler();
977                                        if (handler instanceof AbstractHttp11Protocol) {
978                                                AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler;
979                                                protocol.setMaxHttpHeaderSize(maxHttpHeaderSize);
980                                        }
981                                }
982
983                        });
984                }
985
986                private void customizeMaxHttpPostSize(
987                                TomcatEmbeddedServletContainerFactory factory,
988                                final int maxHttpPostSize) {
989                        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
990
991                                @Override
992                                public void customize(Connector connector) {
993                                        connector.setMaxPostSize(maxHttpPostSize);
994                                }
995
996                        });
997                }
998
999                private void customizeAccessLog(TomcatEmbeddedServletContainerFactory factory) {
1000                        AccessLogValve valve = new AccessLogValve();
1001                        valve.setPattern(this.accesslog.getPattern());
1002                        valve.setDirectory(this.accesslog.getDirectory());
1003                        valve.setPrefix(this.accesslog.getPrefix());
1004                        valve.setSuffix(this.accesslog.getSuffix());
1005                        valve.setRenameOnRotate(this.accesslog.isRenameOnRotate());
1006                        valve.setRequestAttributesEnabled(
1007                                        this.accesslog.isRequestAttributesEnabled());
1008                        valve.setRotatable(this.accesslog.isRotate());
1009                        valve.setBuffered(this.accesslog.isBuffered());
1010                        valve.setFileDateFormat(this.accesslog.getFileDateFormat());
1011                        factory.addEngineValves(valve);
1012                }
1013
1014                private void customizeRedirectContextRoot(
1015                                TomcatEmbeddedServletContainerFactory factory,
1016                                final boolean redirectContextRoot) {
1017                        factory.addContextCustomizers(new TomcatContextCustomizer() {
1018
1019                                @Override
1020                                public void customize(Context context) {
1021                                        context.setMapperContextRootRedirectEnabled(redirectContextRoot);
1022                                }
1023
1024                        });
1025                }
1026
1027                public static class Accesslog {
1028
1029                        /**
1030                         * Enable access log.
1031                         */
1032                        private boolean enabled = false;
1033
1034                        /**
1035                         * Format pattern for access logs.
1036                         */
1037                        private String pattern = "common";
1038
1039                        /**
1040                         * Directory in which log files are created. Can be relative to the tomcat
1041                         * base dir or absolute.
1042                         */
1043                        private String directory = "logs";
1044
1045                        /**
1046                         * Log file name prefix.
1047                         */
1048                        protected String prefix = "access_log";
1049
1050                        /**
1051                         * Log file name suffix.
1052                         */
1053                        private String suffix = ".log";
1054
1055                        /**
1056                         * Enable access log rotation.
1057                         */
1058                        private boolean rotate = true;
1059
1060                        /**
1061                         * Defer inclusion of the date stamp in the file name until rotate time.
1062                         */
1063                        private boolean renameOnRotate;
1064
1065                        /**
1066                         * Date format to place in log file name.
1067                         */
1068                        private String fileDateFormat = ".yyyy-MM-dd";
1069
1070                        /**
1071                         * Set request attributes for IP address, Hostname, protocol and port used for
1072                         * the request.
1073                         */
1074                        private boolean requestAttributesEnabled;
1075
1076                        /**
1077                         * Buffer output such that it is only flushed periodically.
1078                         */
1079                        private boolean buffered = true;
1080
1081                        public boolean isEnabled() {
1082                                return this.enabled;
1083                        }
1084
1085                        public void setEnabled(boolean enabled) {
1086                                this.enabled = enabled;
1087                        }
1088
1089                        public String getPattern() {
1090                                return this.pattern;
1091                        }
1092
1093                        public void setPattern(String pattern) {
1094                                this.pattern = pattern;
1095                        }
1096
1097                        public String getDirectory() {
1098                                return this.directory;
1099                        }
1100
1101                        public void setDirectory(String directory) {
1102                                this.directory = directory;
1103                        }
1104
1105                        public String getPrefix() {
1106                                return this.prefix;
1107                        }
1108
1109                        public void setPrefix(String prefix) {
1110                                this.prefix = prefix;
1111                        }
1112
1113                        public String getSuffix() {
1114                                return this.suffix;
1115                        }
1116
1117                        public void setSuffix(String suffix) {
1118                                this.suffix = suffix;
1119                        }
1120
1121                        public boolean isRotate() {
1122                                return this.rotate;
1123                        }
1124
1125                        public void setRotate(boolean rotate) {
1126                                this.rotate = rotate;
1127                        }
1128
1129                        public boolean isRenameOnRotate() {
1130                                return this.renameOnRotate;
1131                        }
1132
1133                        public void setRenameOnRotate(boolean renameOnRotate) {
1134                                this.renameOnRotate = renameOnRotate;
1135                        }
1136
1137                        public String getFileDateFormat() {
1138                                return this.fileDateFormat;
1139                        }
1140
1141                        public void setFileDateFormat(String fileDateFormat) {
1142                                this.fileDateFormat = fileDateFormat;
1143                        }
1144
1145                        public boolean isRequestAttributesEnabled() {
1146                                return this.requestAttributesEnabled;
1147                        }
1148
1149                        public void setRequestAttributesEnabled(boolean requestAttributesEnabled) {
1150                                this.requestAttributesEnabled = requestAttributesEnabled;
1151                        }
1152
1153                        public boolean isBuffered() {
1154                                return this.buffered;
1155                        }
1156
1157                        public void setBuffered(boolean buffered) {
1158                                this.buffered = buffered;
1159                        }
1160
1161                }
1162
1163        }
1164
1165        public static class Jetty {
1166
1167                /**
1168                 * Maximum size in bytes of the HTTP post or put content.
1169                 */
1170                private int maxHttpPostSize = 0; // bytes
1171
1172                /**
1173                 * Number of acceptor threads to use.
1174                 */
1175                private Integer acceptors;
1176
1177                /**
1178                 * Number of selector threads to use.
1179                 */
1180                private Integer selectors;
1181
1182                public int getMaxHttpPostSize() {
1183                        return this.maxHttpPostSize;
1184                }
1185
1186                public void setMaxHttpPostSize(int maxHttpPostSize) {
1187                        this.maxHttpPostSize = maxHttpPostSize;
1188                }
1189
1190                public Integer getAcceptors() {
1191                        return this.acceptors;
1192                }
1193
1194                public void setAcceptors(Integer acceptors) {
1195                        this.acceptors = acceptors;
1196                }
1197
1198                public Integer getSelectors() {
1199                        return this.selectors;
1200                }
1201
1202                public void setSelectors(Integer selectors) {
1203                        this.selectors = selectors;
1204                }
1205
1206                void customizeJetty(final ServerProperties serverProperties,
1207                                JettyEmbeddedServletContainerFactory factory) {
1208                        factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders());
1209                        if (this.acceptors != null) {
1210                                factory.setAcceptors(this.acceptors);
1211                        }
1212                        if (this.selectors != null) {
1213                                factory.setSelectors(this.selectors);
1214                        }
1215                        if (serverProperties.getMaxHttpHeaderSize() > 0) {
1216                                customizeMaxHttpHeaderSize(factory,
1217                                                serverProperties.getMaxHttpHeaderSize());
1218                        }
1219                        if (this.maxHttpPostSize > 0) {
1220                                customizeMaxHttpPostSize(factory, this.maxHttpPostSize);
1221                        }
1222
1223                        if (serverProperties.getConnectionTimeout() != null) {
1224                                customizeConnectionTimeout(factory,
1225                                                serverProperties.getConnectionTimeout());
1226                        }
1227                }
1228
1229                private void customizeConnectionTimeout(
1230                                JettyEmbeddedServletContainerFactory factory,
1231                                final int connectionTimeout) {
1232                        factory.addServerCustomizers(new JettyServerCustomizer() {
1233
1234                                @Override
1235                                public void customize(Server server) {
1236                                        for (org.eclipse.jetty.server.Connector connector : server
1237                                                        .getConnectors()) {
1238                                                if (connector instanceof AbstractConnector) {
1239                                                        ((AbstractConnector) connector)
1240                                                                        .setIdleTimeout(connectionTimeout);
1241                                                }
1242                                        }
1243                                }
1244
1245                        });
1246                }
1247
1248                private void customizeMaxHttpHeaderSize(
1249                                JettyEmbeddedServletContainerFactory factory,
1250                                final int maxHttpHeaderSize) {
1251                        factory.addServerCustomizers(new JettyServerCustomizer() {
1252
1253                                @Override
1254                                public void customize(Server server) {
1255                                        for (org.eclipse.jetty.server.Connector connector : server
1256                                                        .getConnectors()) {
1257                                                try {
1258                                                        for (ConnectionFactory connectionFactory : connector
1259                                                                        .getConnectionFactories()) {
1260                                                                if (connectionFactory instanceof HttpConfiguration.ConnectionFactory) {
1261                                                                        customize(
1262                                                                                        (HttpConfiguration.ConnectionFactory) connectionFactory);
1263                                                                }
1264                                                        }
1265                                                }
1266                                                catch (NoSuchMethodError ex) {
1267                                                        customizeOnJetty8(connector, maxHttpHeaderSize);
1268                                                }
1269                                        }
1270
1271                                }
1272
1273                                private void customize(HttpConfiguration.ConnectionFactory factory) {
1274                                        HttpConfiguration configuration = factory.getHttpConfiguration();
1275                                        configuration.setRequestHeaderSize(maxHttpHeaderSize);
1276                                        configuration.setResponseHeaderSize(maxHttpHeaderSize);
1277                                }
1278
1279                                private void customizeOnJetty8(
1280                                                org.eclipse.jetty.server.Connector connector,
1281                                                int maxHttpHeaderSize) {
1282                                        try {
1283                                                connector.getClass().getMethod("setRequestHeaderSize", int.class)
1284                                                                .invoke(connector, maxHttpHeaderSize);
1285                                                connector.getClass().getMethod("setResponseHeaderSize", int.class)
1286                                                                .invoke(connector, maxHttpHeaderSize);
1287                                        }
1288                                        catch (Exception ex) {
1289                                                throw new RuntimeException(ex);
1290                                        }
1291                                }
1292
1293                        });
1294                }
1295
1296                private void customizeMaxHttpPostSize(
1297                                JettyEmbeddedServletContainerFactory factory, final int maxHttpPostSize) {
1298                        factory.addServerCustomizers(new JettyServerCustomizer() {
1299
1300                                @Override
1301                                public void customize(Server server) {
1302                                        setHandlerMaxHttpPostSize(maxHttpPostSize, server.getHandlers());
1303                                }
1304
1305                                private void setHandlerMaxHttpPostSize(int maxHttpPostSize,
1306                                                Handler... handlers) {
1307                                        for (Handler handler : handlers) {
1308                                                if (handler instanceof ContextHandler) {
1309                                                        ((ContextHandler) handler)
1310                                                                        .setMaxFormContentSize(maxHttpPostSize);
1311                                                }
1312                                                else if (handler instanceof HandlerWrapper) {
1313                                                        setHandlerMaxHttpPostSize(maxHttpPostSize,
1314                                                                        ((HandlerWrapper) handler).getHandler());
1315                                                }
1316                                                else if (handler instanceof HandlerCollection) {
1317                                                        setHandlerMaxHttpPostSize(maxHttpPostSize,
1318                                                                        ((HandlerCollection) handler).getHandlers());
1319                                                }
1320                                        }
1321                                }
1322
1323                        });
1324                }
1325
1326        }
1327
1328        public static class Undertow {
1329
1330                /**
1331                 * Maximum size in bytes of the HTTP post content.
1332                 */
1333                private long maxHttpPostSize = 0; // bytes
1334
1335                /**
1336                 * Size of each buffer in bytes.
1337                 */
1338                private Integer bufferSize;
1339
1340                /**
1341                 * Number of buffer per region.
1342                 */
1343                @Deprecated
1344                private Integer buffersPerRegion;
1345
1346                /**
1347                 * Number of I/O threads to create for the worker.
1348                 */
1349                private Integer ioThreads;
1350
1351                /**
1352                 * Number of worker threads.
1353                 */
1354                private Integer workerThreads;
1355
1356                /**
1357                 * Allocate buffers outside the Java heap.
1358                 */
1359                private Boolean directBuffers;
1360
1361                private final Accesslog accesslog = new Accesslog();
1362
1363                public long getMaxHttpPostSize() {
1364                        return this.maxHttpPostSize;
1365                }
1366
1367                public void setMaxHttpPostSize(long maxHttpPostSize) {
1368                        this.maxHttpPostSize = maxHttpPostSize;
1369                }
1370
1371                public Integer getBufferSize() {
1372                        return this.bufferSize;
1373                }
1374
1375                public void setBufferSize(Integer bufferSize) {
1376                        this.bufferSize = bufferSize;
1377                }
1378
1379                @DeprecatedConfigurationProperty(reason = "The property is not used by Undertow. See https://issues.jboss.org/browse/UNDERTOW-587 for details")
1380                public Integer getBuffersPerRegion() {
1381                        return this.buffersPerRegion;
1382                }
1383
1384                public void setBuffersPerRegion(Integer buffersPerRegion) {
1385                        this.buffersPerRegion = buffersPerRegion;
1386                }
1387
1388                public Integer getIoThreads() {
1389                        return this.ioThreads;
1390                }
1391
1392                public void setIoThreads(Integer ioThreads) {
1393                        this.ioThreads = ioThreads;
1394                }
1395
1396                public Integer getWorkerThreads() {
1397                        return this.workerThreads;
1398                }
1399
1400                public void setWorkerThreads(Integer workerThreads) {
1401                        this.workerThreads = workerThreads;
1402                }
1403
1404                public Boolean getDirectBuffers() {
1405                        return this.directBuffers;
1406                }
1407
1408                public void setDirectBuffers(Boolean directBuffers) {
1409                        this.directBuffers = directBuffers;
1410                }
1411
1412                public Accesslog getAccesslog() {
1413                        return this.accesslog;
1414                }
1415
1416                void customizeUndertow(final ServerProperties serverProperties,
1417                                UndertowEmbeddedServletContainerFactory factory) {
1418                        if (this.bufferSize != null) {
1419                                factory.setBufferSize(this.bufferSize);
1420                        }
1421                        if (this.ioThreads != null) {
1422                                factory.setIoThreads(this.ioThreads);
1423                        }
1424                        if (this.workerThreads != null) {
1425                                factory.setWorkerThreads(this.workerThreads);
1426                        }
1427                        if (this.directBuffers != null) {
1428                                factory.setDirectBuffers(this.directBuffers);
1429                        }
1430                        if (this.accesslog.enabled != null) {
1431                                factory.setAccessLogEnabled(this.accesslog.enabled);
1432                        }
1433                        factory.setAccessLogDirectory(this.accesslog.dir);
1434                        factory.setAccessLogPattern(this.accesslog.pattern);
1435                        factory.setAccessLogPrefix(this.accesslog.prefix);
1436                        factory.setAccessLogSuffix(this.accesslog.suffix);
1437                        factory.setAccessLogRotate(this.accesslog.rotate);
1438                        factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders());
1439                        if (serverProperties.getMaxHttpHeaderSize() > 0) {
1440                                customizeMaxHttpHeaderSize(factory,
1441                                                serverProperties.getMaxHttpHeaderSize());
1442                        }
1443                        if (this.maxHttpPostSize > 0) {
1444                                customizeMaxHttpPostSize(factory, this.maxHttpPostSize);
1445                        }
1446
1447                        if (serverProperties.getConnectionTimeout() != null) {
1448                                customizeConnectionTimeout(factory,
1449                                                serverProperties.getConnectionTimeout());
1450                        }
1451                }
1452
1453                private void customizeConnectionTimeout(
1454                                UndertowEmbeddedServletContainerFactory factory,
1455                                final int connectionTimeout) {
1456                        factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
1457                                @Override
1458                                public void customize(Builder builder) {
1459                                        builder.setSocketOption(UndertowOptions.NO_REQUEST_TIMEOUT,
1460                                                        connectionTimeout);
1461                                }
1462                        });
1463                }
1464
1465                private void customizeMaxHttpHeaderSize(
1466                                UndertowEmbeddedServletContainerFactory factory,
1467                                final int maxHttpHeaderSize) {
1468                        factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
1469
1470                                @Override
1471                                public void customize(Builder builder) {
1472                                        builder.setServerOption(UndertowOptions.MAX_HEADER_SIZE,
1473                                                        maxHttpHeaderSize);
1474                                }
1475
1476                        });
1477                }
1478
1479                private void customizeMaxHttpPostSize(
1480                                UndertowEmbeddedServletContainerFactory factory,
1481                                final long maxHttpPostSize) {
1482                        factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
1483
1484                                @Override
1485                                public void customize(Builder builder) {
1486                                        builder.setServerOption(UndertowOptions.MAX_ENTITY_SIZE,
1487                                                        maxHttpPostSize);
1488                                }
1489
1490                        });
1491                }
1492
1493                public static class Accesslog {
1494
1495                        /**
1496                         * Enable access log.
1497                         */
1498                        private Boolean enabled;
1499
1500                        /**
1501                         * Format pattern for access logs.
1502                         */
1503                        private String pattern = "common";
1504
1505                        /**
1506                         * Log file name prefix.
1507                         */
1508                        protected String prefix = "access_log.";
1509
1510                        /**
1511                         * Log file name suffix.
1512                         */
1513                        private String suffix = "log";
1514
1515                        /**
1516                         * Undertow access log directory.
1517                         */
1518                        private File dir = new File("logs");
1519
1520                        /**
1521                         * Enable access log rotation.
1522                         */
1523                        private boolean rotate = true;
1524
1525                        public Boolean getEnabled() {
1526                                return this.enabled;
1527                        }
1528
1529                        public void setEnabled(Boolean enabled) {
1530                                this.enabled = enabled;
1531                        }
1532
1533                        public String getPattern() {
1534                                return this.pattern;
1535                        }
1536
1537                        public void setPattern(String pattern) {
1538                                this.pattern = pattern;
1539                        }
1540
1541                        public String getPrefix() {
1542                                return this.prefix;
1543                        }
1544
1545                        public void setPrefix(String prefix) {
1546                                this.prefix = prefix;
1547                        }
1548
1549                        public String getSuffix() {
1550                                return this.suffix;
1551                        }
1552
1553                        public void setSuffix(String suffix) {
1554                                this.suffix = suffix;
1555                        }
1556
1557                        public File getDir() {
1558                                return this.dir;
1559                        }
1560
1561                        public void setDir(File dir) {
1562                                this.dir = dir;
1563                        }
1564
1565                        public boolean isRotate() {
1566                                return this.rotate;
1567                        }
1568
1569                        public void setRotate(boolean rotate) {
1570                                this.rotate = rotate;
1571                        }
1572
1573                }
1574
1575        }
1576
1577        /**
1578         * {@link ServletContextInitializer} to apply appropriate parts of the {@link Session}
1579         * configuration.
1580         */
1581        private static class SessionConfiguringInitializer
1582                        implements ServletContextInitializer {
1583
1584                private final Session session;
1585
1586                SessionConfiguringInitializer(Session session) {
1587                        this.session = session;
1588                }
1589
1590                @Override
1591                public void onStartup(ServletContext servletContext) throws ServletException {
1592                        if (this.session.getTrackingModes() != null) {
1593                                servletContext.setSessionTrackingModes(this.session.getTrackingModes());
1594                        }
1595                        configureSessionCookie(servletContext.getSessionCookieConfig());
1596                }
1597
1598                private void configureSessionCookie(SessionCookieConfig config) {
1599                        Cookie cookie = this.session.getCookie();
1600                        if (cookie.getName() != null) {
1601                                config.setName(cookie.getName());
1602                        }
1603                        if (cookie.getDomain() != null) {
1604                                config.setDomain(cookie.getDomain());
1605                        }
1606                        if (cookie.getPath() != null) {
1607                                config.setPath(cookie.getPath());
1608                        }
1609                        if (cookie.getComment() != null) {
1610                                config.setComment(cookie.getComment());
1611                        }
1612                        if (cookie.getHttpOnly() != null) {
1613                                config.setHttpOnly(cookie.getHttpOnly());
1614                        }
1615                        if (cookie.getSecure() != null) {
1616                                config.setSecure(cookie.getSecure());
1617                        }
1618                        if (cookie.getMaxAge() != null) {
1619                                config.setMaxAge(cookie.getMaxAge());
1620                        }
1621                }
1622
1623        }
1624
1625}