mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
Merge branch '7.0.x'
This commit is contained in:
+4
-5
@@ -24,7 +24,6 @@ import jakarta.servlet.jsp.tagext.DynamicAttributes;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -40,6 +39,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Rob Harrop
|
||||
* @author Jeremy Grelle
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
@@ -429,8 +429,7 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
|
||||
*/
|
||||
protected void writeOptionalAttributes(TagWriter tagWriter) throws JspException {
|
||||
tagWriter.writeOptionalAttributeValue(CLASS_ATTRIBUTE, resolveCssClass());
|
||||
tagWriter.writeOptionalAttributeValue(STYLE_ATTRIBUTE,
|
||||
ObjectUtils.getDisplayString(evaluate("cssStyle", getCssStyle())));
|
||||
writeOptionalAttribute(tagWriter, STYLE_ATTRIBUTE, getCssStyle());
|
||||
writeOptionalAttribute(tagWriter, LANG_ATTRIBUTE, getLang());
|
||||
writeOptionalAttribute(tagWriter, TITLE_ATTRIBUTE, getTitle());
|
||||
writeOptionalAttribute(tagWriter, DIR_ATTRIBUTE, getDir());
|
||||
@@ -459,10 +458,10 @@ public abstract class AbstractHtmlElementTag extends AbstractDataBoundFormElemen
|
||||
*/
|
||||
protected String resolveCssClass() throws JspException {
|
||||
if (getBindStatus().isError() && StringUtils.hasText(getCssErrorClass())) {
|
||||
return ObjectUtils.getDisplayString(evaluate("cssErrorClass", getCssErrorClass()));
|
||||
return getDisplayString(evaluate("cssErrorClass", getCssErrorClass()));
|
||||
}
|
||||
else {
|
||||
return ObjectUtils.getDisplayString(evaluate("cssClass", getCssClass()));
|
||||
return getDisplayString(evaluate("cssClass", getCssClass()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ import org.springframework.core.Conventions;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
@@ -239,6 +238,7 @@ import org.springframework.web.util.UriUtils;
|
||||
* @author Juergen Hoeller
|
||||
* @author Scott Andrews
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
@@ -719,7 +719,7 @@ public class FormTag extends AbstractHtmlElementTag {
|
||||
*/
|
||||
@Override
|
||||
protected String resolveCssClass() throws JspException {
|
||||
return ObjectUtils.getDisplayString(evaluate("cssClass", getCssClass()));
|
||||
return getDisplayString(evaluate("cssClass", getCssClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+13
-2
@@ -20,7 +20,9 @@ import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.servlet.RequestToViewNameTranslator;
|
||||
import org.springframework.web.util.ServletRequestPathUtils;
|
||||
|
||||
@@ -50,6 +52,7 @@ import org.springframework.web.util.ServletRequestPathUtils;
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @author Sebastien Deleuze
|
||||
* @since 2.0
|
||||
* @see org.springframework.web.servlet.RequestToViewNameTranslator
|
||||
* @see org.springframework.web.servlet.ViewResolver
|
||||
@@ -127,13 +130,21 @@ public class DefaultRequestToViewNameTranslator implements RequestToViewNameTran
|
||||
* into the view name based on the configured parameters.
|
||||
* @throws IllegalArgumentException if neither a parsed RequestPath, nor a
|
||||
* String lookupPath have been resolved and cached as a request attribute.
|
||||
* @throws ResponseStatusException with a 400 error code if the path contains a "redirect:" or a "forward:" prefix
|
||||
* @see ServletRequestPathUtils#getCachedPath(ServletRequest)
|
||||
* @see #transformPath
|
||||
*/
|
||||
@Override
|
||||
public String getViewName(HttpServletRequest request) {
|
||||
String path = ServletRequestPathUtils.getCachedPathValue(request);
|
||||
return (this.prefix + transformPath(path) + this.suffix);
|
||||
String viewName = this.prefix + transformPath(path) + this.suffix;
|
||||
if (viewName.startsWith(UrlBasedViewResolver.REDIRECT_URL_PREFIX)) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Rejected path '" + path + "' with 'redirect:' prefix");
|
||||
}
|
||||
if (viewName.startsWith(UrlBasedViewResolver.FORWARD_URL_PREFIX)) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Rejected path '" + path + "' with 'forward:' prefix");
|
||||
}
|
||||
return viewName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,7 +155,7 @@ public class DefaultRequestToViewNameTranslator implements RequestToViewNameTran
|
||||
* @return the transformed path, with slashes and extensions stripped
|
||||
* if desired
|
||||
*/
|
||||
protected @Nullable String transformPath(String lookupPath) {
|
||||
protected String transformPath(String lookupPath) {
|
||||
String path = lookupPath;
|
||||
if (this.stripLeadingSlash && path.startsWith(SLASH)) {
|
||||
path = path.substring(1);
|
||||
|
||||
+14
@@ -129,6 +129,20 @@ class FormTagTests extends AbstractHtmlElementTagTests {
|
||||
assertContainsAttribute(output, dynamicAttribute2, dynamicAttribute2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeFormWithHtmlEscaping() throws Exception {
|
||||
this.tag.setCssClass("\"class\"");
|
||||
this.tag.setCssStyle("\"style\"");
|
||||
|
||||
this.tag.doStartTag();
|
||||
this.tag.doEndTag();
|
||||
this.tag.doFinally();
|
||||
|
||||
String output = getOutput();
|
||||
assertContainsAttribute(output, "class", ""class"");
|
||||
assertContainsAttribute(output, "style", ""style"");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withActionFromRequest() throws Exception {
|
||||
String commandName = "myCommand";
|
||||
|
||||
+22
@@ -314,6 +314,28 @@ class InputTagTests extends AbstractFormTagTests {
|
||||
assertContainsAttribute(output, "class", "bad");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withErrorsAndHtmlEscaping() throws Exception {
|
||||
this.tag.setPath("name");
|
||||
this.tag.setCssClass("\"good\"");
|
||||
this.tag.setCssErrorClass("\"bad\"");
|
||||
|
||||
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(this.rob, COMMAND_NAME);
|
||||
errors.rejectValue("name", "some.code", "Default Message");
|
||||
errors.rejectValue("name", "too.short", "Too Short");
|
||||
exposeBindingResult(errors);
|
||||
|
||||
assertThat(this.tag.doStartTag()).isEqualTo(Tag.SKIP_BODY);
|
||||
|
||||
String output = getOutput();
|
||||
assertTagOpened(output);
|
||||
assertTagClosed(output);
|
||||
|
||||
assertContainsAttribute(output, "type", getType());
|
||||
assertValueAttribute(output, "Rob");
|
||||
assertContainsAttribute(output, "class", ""bad"");
|
||||
}
|
||||
|
||||
@Test
|
||||
void disabledFalse() throws Exception {
|
||||
this.tag.setPath("name");
|
||||
|
||||
+20
@@ -21,15 +21,19 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Named;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.servlet.handler.PathPatternsParameterizedTest;
|
||||
import org.springframework.web.servlet.handler.PathPatternsTestUtils;
|
||||
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* @author Rick Evans
|
||||
* @author Juergen Hoeller
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
class DefaultRequestToViewNameTranslatorTests {
|
||||
|
||||
@@ -121,6 +125,22 @@ class DefaultRequestToViewNameTranslatorTests {
|
||||
assertViewName(request, VIEW_NAME);
|
||||
}
|
||||
|
||||
@PathPatternsParameterizedTest
|
||||
void getViewNameWithRedirectPrefixFails(Function<String, MockHttpServletRequest> requestFactory) {
|
||||
MockHttpServletRequest request = requestFactory.apply(UrlBasedViewResolver.REDIRECT_URL_PREFIX + VIEW_NAME);
|
||||
assertThatExceptionOfType(ResponseStatusException.class)
|
||||
.isThrownBy(() -> this.translator.getViewName(request))
|
||||
.satisfies(ex -> assertThat(ex.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST));
|
||||
}
|
||||
|
||||
@PathPatternsParameterizedTest
|
||||
void getViewNameWithForwardPrefixFails(Function<String, MockHttpServletRequest> requestFactory) {
|
||||
MockHttpServletRequest request = requestFactory.apply(UrlBasedViewResolver.FORWARD_URL_PREFIX + VIEW_NAME);
|
||||
assertThatExceptionOfType(ResponseStatusException.class)
|
||||
.isThrownBy(() -> this.translator.getViewName(request))
|
||||
.satisfies(ex -> assertThat(ex.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST));
|
||||
}
|
||||
|
||||
|
||||
private void assertViewName(MockHttpServletRequest request, String expectedViewName) {
|
||||
String actualViewName = this.translator.getViewName(request);
|
||||
|
||||
Reference in New Issue
Block a user