Skip to content

Commit 2e1988f

Browse files
committed
Rework welcome page so that it only handles reqs that accept text/html
Closes gh-6668
1 parent 1c294dd commit 2e1988f

File tree

5 files changed

+91
-127
lines changed

5 files changed

+91
-127
lines changed

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

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Map.Entry;
2525

2626
import javax.servlet.Servlet;
27+
import javax.servlet.http.HttpServletRequest;
2728

2829
import org.apache.commons.logging.Log;
2930
import org.apache.commons.logging.LogFactory;
@@ -57,6 +58,7 @@
5758
import org.springframework.format.Formatter;
5859
import org.springframework.format.FormatterRegistry;
5960
import org.springframework.format.datetime.DateFormatter;
61+
import org.springframework.http.HttpHeaders;
6062
import org.springframework.http.MediaType;
6163
import org.springframework.http.converter.HttpMessageConverter;
6264
import org.springframework.validation.DefaultMessageCodesResolver;
@@ -79,13 +81,14 @@
7981
import org.springframework.web.servlet.config.annotation.ResourceChainRegistration;
8082
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration;
8183
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
82-
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
8384
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
8485
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
8586
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
87+
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
8688
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
8789
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
8890
import org.springframework.web.servlet.i18n.FixedLocaleResolver;
91+
import org.springframework.web.servlet.mvc.ParameterizableViewController;
8992
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
9093
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
9194
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@@ -288,6 +291,12 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) {
288291
}
289292
}
290293

294+
@Bean
295+
public WelcomePageHandlerMapping welcomePageHandlerMapping(
296+
ResourceProperties resourceProperties) {
297+
return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage());
298+
}
299+
291300
private void customizeResourceHandlerRegistration(
292301
ResourceHandlerRegistration registration) {
293302
if (this.resourceHandlerRegistrationCustomizer != null) {
@@ -296,15 +305,6 @@ private void customizeResourceHandlerRegistration(
296305

297306
}
298307

299-
@Override
300-
public void addViewControllers(ViewControllerRegistry registry) {
301-
Resource page = this.resourceProperties.getWelcomePage();
302-
if (page != null) {
303-
logger.info("Adding welcome page: " + page);
304-
registry.addViewController("/").setViewName("forward:index.html");
305-
}
306-
}
307-
308308
@Bean
309309
@ConditionalOnMissingBean({ RequestContextListener.class,
310310
RequestContextFilter.class })
@@ -498,4 +498,32 @@ private ResourceResolver getVersionResourceResolver(
498498

499499
}
500500

501+
static final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping {
502+
503+
private static final Log logger = LogFactory
504+
.getLog(WelcomePageHandlerMapping.class);
505+
506+
private WelcomePageHandlerMapping(Resource welcomePage) {
507+
if (welcomePage != null) {
508+
logger.info("Adding welcome page: " + welcomePage);
509+
ParameterizableViewController controller = new ParameterizableViewController();
510+
controller.setViewName("forward:index.html");
511+
setRootHandler(controller);
512+
setOrder(0);
513+
}
514+
}
515+
516+
@Override
517+
public Object getHandlerInternal(HttpServletRequest request) throws Exception {
518+
for (MediaType mediaType : MediaType
519+
.parseMediaTypes(request.getHeader(HttpHeaders.ACCEPT))) {
520+
if (mediaType.includes(MediaType.TEXT_HTML)) {
521+
return super.getHandlerInternal(request);
522+
}
523+
}
524+
return null;
525+
}
526+
527+
}
528+
501529
}

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

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
4040
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
4141
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter;
42+
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WelcomePageHandlerMapping;
4243
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
4344
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor;
4445
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
@@ -52,8 +53,11 @@
5253
import org.springframework.core.io.Resource;
5354
import org.springframework.format.support.FormattingConversionService;
5455
import org.springframework.http.HttpHeaders;
56+
import org.springframework.http.MediaType;
5557
import org.springframework.mock.web.MockHttpServletRequest;
5658
import org.springframework.test.util.ReflectionTestUtils;
59+
import org.springframework.test.web.servlet.MockMvc;
60+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
5761
import org.springframework.util.ReflectionUtils;
5862
import org.springframework.util.StringUtils;
5963
import org.springframework.web.accept.ContentNegotiationManager;
@@ -90,6 +94,9 @@
9094
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
9195

9296
import static org.assertj.core.api.Assertions.assertThat;
97+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
98+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
99+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
93100

94101
/**
95102
* Tests for {@link WebMvcAutoConfiguration}.
@@ -132,7 +139,7 @@ public void handlerAdaptersCreated() throws Exception {
132139
public void handlerMappingsCreated() throws Exception {
133140
load();
134141
assertThat(this.context.getBeanNamesForType(HandlerMapping.class).length)
135-
.isEqualTo(6);
142+
.isEqualTo(7);
136143
}
137144

138145
@Test
@@ -540,6 +547,51 @@ public void customLogResolvedException() {
540547
testLogResolvedExceptionCustomization(true);
541548
}
542549

550+
@Test
551+
public void welcomePageMappingProducesNotFoundResponseWhenThereIsNoWelcomePage()
552+
throws Exception {
553+
load("spring.resources.static-locations:classpath:/no-welcome-page/");
554+
assertThat(this.context.getBeansOfType(WelcomePageHandlerMapping.class))
555+
.hasSize(1);
556+
MockMvcBuilders.webAppContextSetup(this.context).build()
557+
.perform(get("/").accept(MediaType.TEXT_HTML))
558+
.andExpect(status().isNotFound());
559+
}
560+
561+
@Test
562+
public void welcomePageMappingHandlesRequestsThatAcceptTextHtml() throws Exception {
563+
load("spring.resources.static-locations:classpath:/welcome-page/");
564+
assertThat(this.context.getBeansOfType(WelcomePageHandlerMapping.class))
565+
.hasSize(1);
566+
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
567+
mockMvc.perform(get("/").accept(MediaType.TEXT_HTML)).andExpect(status().isOk())
568+
.andExpect(forwardedUrl("index.html"));
569+
mockMvc.perform(get("/").accept("*/*")).andExpect(status().isOk())
570+
.andExpect(forwardedUrl("index.html"));
571+
}
572+
573+
@Test
574+
public void welcomePageMappingOnlyHandlesRequestsThatAcceptTextHtml()
575+
throws Exception {
576+
load("spring.resources.static-locations:classpath:/welcome-page/");
577+
assertThat(this.context.getBeansOfType(WelcomePageHandlerMapping.class))
578+
.hasSize(1);
579+
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
580+
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
581+
.andExpect(status().isNotFound());
582+
}
583+
584+
@Test
585+
public void welcomePageMappingWorksWithNoTrailingSlashOnResourceLocation()
586+
throws Exception {
587+
load("spring.resources.static-locations:classpath:/welcome-page");
588+
assertThat(this.context.getBeansOfType(WelcomePageHandlerMapping.class))
589+
.hasSize(1);
590+
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
591+
mockMvc.perform(get("/").accept(MediaType.TEXT_HTML)).andExpect(status().isOk())
592+
.andExpect(forwardedUrl("index.html"));
593+
}
594+
543595
private void testLogResolvedExceptionCustomization(final boolean expected) {
544596
HandlerExceptionResolver exceptionResolver = this.context
545597
.getBean(HandlerExceptionResolver.class);

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

Lines changed: 0 additions & 115 deletions
This file was deleted.

spring-boot-autoconfigure/src/test/resources/custom/index.html

Lines changed: 0 additions & 1 deletion
This file was deleted.

spring-boot-autoconfigure/src/test/resources/welcome-page/index.html

Whitespace-only changes.

0 commit comments

Comments
 (0)