From ea76e46faa0842639fc1b5b4bc9ad21ac6167fb6 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Feb 2025 10:52:56 +0000 Subject: [PATCH] Apply charset to Mustache's content type Fixes gh-44053 --- .../mustache/MustacheProperties.java | 26 +++++++++++++++++-- .../MustacheAutoConfigurationTests.java | 7 ++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheProperties.java index 0298dee69c4..031c9b9e5ef 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,10 @@ package org.springframework.boot.autoconfigure.mustache; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.function.Supplier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.http.MediaType; @@ -41,7 +44,7 @@ public class MustacheProperties { public static final String DEFAULT_SUFFIX = ".mustache"; - private final Servlet servlet = new Servlet(); + private final Servlet servlet = new Servlet(this::getCharset); private final Reactive reactive = new Reactive(); @@ -190,6 +193,16 @@ public class MustacheProperties { */ private boolean exposeSpringMacroHelpers = true; + private final Supplier charset; + + public Servlet() { + this.charset = () -> null; + } + + private Servlet(Supplier charset) { + this.charset = charset; + } + public boolean isAllowRequestOverride() { return this.allowRequestOverride; } @@ -215,6 +228,15 @@ public class MustacheProperties { } public MimeType getContentType() { + if (this.contentType != null && this.contentType.getCharset() == null) { + Charset charset = this.charset.get(); + if (charset != null) { + Map parameters = new LinkedHashMap<>(); + parameters.put("charset", charset.name()); + parameters.putAll(this.contentType.getParameters()); + return new MimeType(this.contentType, parameters); + } + } return this.contentType; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mustache/MustacheAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mustache/MustacheAutoConfigurationTests.java index 7d1d54fc1da..7c2075e34a2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mustache/MustacheAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mustache/MustacheAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -117,6 +117,7 @@ class MustacheAutoConfigurationTests { assertThat(viewResolver).extracting("allowSessionOverride", InstanceOfAssertFactories.BOOLEAN).isFalse(); assertThat(viewResolver).extracting("cache", InstanceOfAssertFactories.BOOLEAN).isFalse(); assertThat(viewResolver).extracting("charset").isEqualTo("UTF-8"); + assertThat(viewResolver).extracting("contentType").isEqualTo("text/html;charset=UTF-8"); assertThat(viewResolver).extracting("exposeRequestAttributes", InstanceOfAssertFactories.BOOLEAN).isFalse(); assertThat(viewResolver).extracting("exposeSessionAttributes", InstanceOfAssertFactories.BOOLEAN).isFalse(); assertThat(viewResolver).extracting("exposeSpringMacroHelpers", InstanceOfAssertFactories.BOOLEAN).isTrue(); @@ -161,6 +162,10 @@ class MustacheAutoConfigurationTests { @EnumSource(ViewResolverKind.class) void charsetCanBeCustomizedOnViewResolver(ViewResolverKind kind) { assertViewResolverProperty(kind, "spring.mustache.charset=UTF-16", "charset", "UTF-16"); + if (kind == ViewResolverKind.SERVLET) { + assertViewResolverProperty(kind, "spring.mustache.charset=UTF-16", "contentType", + "text/html;charset=UTF-16"); + } } @Test