Ensure default mime mappings are applied

Fixes gh-40860
This commit is contained in:
Andy Wilkinson 2024-05-22 12:19:31 +01:00
parent baf34c43f3
commit da4c2db3a7
7 changed files with 55 additions and 9 deletions

View File

@ -120,7 +120,7 @@ public class ServerProperties {
/** /**
* Custom MIME mappings in addition to the default MIME mappings. * Custom MIME mappings in addition to the default MIME mappings.
*/ */
private final MimeMappings mimeMappings = MimeMappings.lazyCopy(MimeMappings.DEFAULT); private final MimeMappings mimeMappings = new MimeMappings();
@NestedConfigurationProperty @NestedConfigurationProperty
private final Http2 http2 = new Http2(); private final Http2 http2 = new Http2();

View File

@ -95,7 +95,7 @@ public class ServletWebServerFactoryCustomizer
map.from(() -> this.cookieSameSiteSuppliers) map.from(() -> this.cookieSameSiteSuppliers)
.whenNot(CollectionUtils::isEmpty) .whenNot(CollectionUtils::isEmpty)
.to(factory::setCookieSameSiteSuppliers); .to(factory::setCookieSameSiteSuppliers);
map.from(this.serverProperties::getMimeMappings).to(factory::setMimeMappings); map.from(this.serverProperties::getMimeMappings).to(factory::addMimeMappings);
this.webListenerRegistrars.forEach((registrar) -> registrar.register(factory)); this.webListenerRegistrars.forEach((registrar) -> registrar.register(factory));
} }

View File

@ -187,13 +187,12 @@ class ServerPropertiesTests {
@Test @Test
void testDefaultMimeMapping() { void testDefaultMimeMapping() {
assertThat(this.properties.getMimeMappings()) assertThat(this.properties.getMimeMappings()).isEmpty();
.containsExactly(MimeMappings.DEFAULT.getAll().toArray(new Mapping[0]));
} }
@Test @Test
void testCustomizedMimeMapping() { void testCustomizedMimeMapping() {
MimeMappings expectedMappings = MimeMappings.lazyCopy(MimeMappings.DEFAULT); MimeMappings expectedMappings = new MimeMappings();
expectedMappings.add("mjs", "text/javascript"); expectedMappings.add("mjs", "text/javascript");
bind("server.mime-mappings.mjs", "text/javascript"); bind("server.mime-mappings.mjs", "text/javascript");
assertThat(this.properties.getMimeMappings()) assertThat(this.properties.getMimeMappings())

View File

@ -22,6 +22,7 @@ import java.util.Map;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Bindable;
@ -29,6 +30,7 @@ import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.boot.web.server.Cookie; import org.springframework.boot.web.server.Cookie;
import org.springframework.boot.web.server.MimeMappings;
import org.springframework.boot.web.server.Shutdown; import org.springframework.boot.web.server.Shutdown;
import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
@ -74,10 +76,25 @@ class ServletWebServerFactoryCustomizerTests {
} }
@Test @Test
void testCustomMimeMappings() { void withNoCustomMimeMappingsThenEmptyMimeMappingsIsAdded() {
ConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class); ConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);
this.customizer.customize(factory); this.customizer.customize(factory);
then(factory).should().setMimeMappings(this.properties.getMimeMappings()); ArgumentCaptor<MimeMappings> mimeMappingsCaptor = ArgumentCaptor.forClass(MimeMappings.class);
then(factory).should().addMimeMappings(mimeMappingsCaptor.capture());
MimeMappings mimeMappings = mimeMappingsCaptor.getValue();
assertThat(mimeMappings.getAll()).isEmpty();
}
@Test
void withCustomMimeMappingsThenPopulatedMimeMappingsIsAdded() {
this.properties.getMimeMappings().add("a", "alpha");
this.properties.getMimeMappings().add("b", "bravo");
ConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);
this.customizer.customize(factory);
ArgumentCaptor<MimeMappings> mimeMappingsCaptor = ArgumentCaptor.forClass(MimeMappings.class);
then(factory).should().addMimeMappings(mimeMappingsCaptor.capture());
MimeMappings mimeMappings = mimeMappingsCaptor.getValue();
assertThat(mimeMappings.getAll()).hasSize(2);
} }
@Test @Test

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2023 the original author or authors. * Copyright 2012-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -178,6 +178,11 @@ public abstract class AbstractServletWebServerFactory extends AbstractConfigurab
this.mimeMappings = new MimeMappings(mimeMappings); this.mimeMappings = new MimeMappings(mimeMappings);
} }
@Override
public void addMimeMappings(MimeMappings mimeMappings) {
mimeMappings.forEach((mapping) -> this.mimeMappings.add(mapping.getExtension(), mapping.getMimeType()));
}
/** /**
* Returns the document root which will be used by the web context to serve static * Returns the document root which will be used by the web context to serve static
* files. * files.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -82,6 +82,13 @@ public interface ConfigurableServletWebServerFactory
*/ */
void setMimeMappings(MimeMappings mimeMappings); void setMimeMappings(MimeMappings mimeMappings);
/**
* Adds mime-type mappings.
* @param mimeMappings the mime type mappings to add
* @since 3.3.0
*/
void addMimeMappings(MimeMappings mimeMappings);
/** /**
* Sets the document root directory which will be used by the web context to serve * Sets the document root directory which will be used by the web context to serve
* static files. * static files.

View File

@ -34,6 +34,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
@ -1010,6 +1011,23 @@ public abstract class AbstractServletWebServerFactoryTests {
assertThat(configuredMimeMappings).containsExactlyInAnyOrderElementsOf(expectedMimeMappings); assertThat(configuredMimeMappings).containsExactlyInAnyOrderElementsOf(expectedMimeMappings);
} }
@Test
void additionalMimeMappingsCanBeConfigured() {
AbstractServletWebServerFactory factory = getFactory();
MimeMappings additionalMimeMappings = new MimeMappings();
additionalMimeMappings.add("a", "alpha");
additionalMimeMappings.add("b", "bravo");
factory.addMimeMappings(additionalMimeMappings);
this.webServer = factory.getWebServer();
Collection<MimeMappings.Mapping> configuredMimeMappings = getActualMimeMappings().entrySet()
.stream()
.map((entry) -> new MimeMappings.Mapping(entry.getKey(), entry.getValue()))
.toList();
List<MimeMappings.Mapping> expectedMimeMappings = new ArrayList<>(MimeMappings.DEFAULT.getAll());
expectedMimeMappings.addAll(additionalMimeMappings.getAll());
assertThat(configuredMimeMappings).containsExactlyInAnyOrderElementsOf(expectedMimeMappings);
}
@Test @Test
void rootServletContextResource() { void rootServletContextResource() {
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();