This commit adds support for origins with a trailing slash or a path,
in order to avoid printing a stacktrace in the logs when
WebUtils#isSameOrigin(HttpRequest) parses such invalid Origin header
value.
Issue: SPR-13478
This commit migrates all remaining tests from JUnit 3 to JUnit 4, with
the exception of Spring's legacy JUnit 3.8 based testing framework that
is still in use in the spring-orm module.
Issue: SPR-13514
This commit introduces support for attribute overrides for
@ResponseStatus when @ResponseStatus is used as a meta-annotation on
a custom composed annotation.
Specifically, this commit migrates all code that looks up
@ResponseStatus from using AnnotationUtils.findAnnotation() to using
AnnotatedElementUtils.findMergedAnnotation().
Issue: SPR-13441
Includes a revision for consistent and defensive Servlet 3.0 method calls across Spring's web abstraction (in particular, also working in debug mode where method references may get resolved early, so ternary expressions are to be avoided).
Issue: SPR-13420
Prior to this commit, ServletWebRequest would call
HttpServletResponse.getStatus(), which is a Servlet 3.x method.
This commit checks if this method is available before calling it, thus
keeping Servlet 2.5 compatibility.
Issue: SPR-13396
Before this commit UriComponents was capable of expanding URI vars that
may have contained a regular expressions (as supported with
@RequestMapping for example). However if the regular expressions
contained any nested "{}" the expand did not work correctly.
This commit sanitizes a URI template source removing any content
between nested "{}" prior to expanding. This works since we only care
about the URI variable name.
Issue: SPR-13311
Prior to this change, trying to set an unquoted ETag with
`ResponseEntity`'s API would throw an `IllegalArgumentException`.
This commit automatically quotes ETag values set using ResponseEntity.
Issue: SPR-13378
In an attempt to make our Jetty-based integration tests more robust,
this commit discontinues use of SocketUtils for picking a random,
available port and instead lets the Jetty Server pick its own port.
Before this commit RequestPartServletServerHttpRequest simply did an
instanceof check for MultipartHttpServletRequest. That hasn't failed
because request wrapping typically happens in filters before the
DispatcherServlet calls the MultipartResolver.
With Spring MVC Test and the Spring Security integraiton however,
this order is reversed since there we prepare the multipart request
upfront, i.e. there is no actual parsing.
The commit unwraps the request if necessary.
Issue: SPR-13317
This change ensures that an onError outcome from an async request is
also routed to onCompletion handlers registered with
StandardServletAsyncWebRequest.
Issue: SPR-13292
Prior to this commit, the `ResponseStatusExceptionResolver` would use:
* `HttpServletResponse.sendError` if both a status and a reason are set
on the `@ResponseStatus` annotation
* `HttpServletResponse.setStatus` if only a status is set on the
`@ResponseStatus` annotation
This is actually a change of behavior, since this Resolver was using
`sendError` in all cases previously.
Because this change can create issues such as
https://github.com/spring-projects/spring-boot/issues/3623
this commit rollbacks those changes and clarifies the behavior on the
javadoc of the annotation itself.
Issue: SPR-11193, SPR-13226
SPR-11512 introduced support for annotation attribute aliases via
@AliasFor, requiring the explicit declaration of the 'attribute'
attribute. However, for aliases within an annotation, this explicit
declaration is unnecessary.
This commit improves the readability of alias pairs declared within an
annotation by introducing a 'value' attribute in @AliasFor that is an
alias for the existing 'attribute' attribute. This allows annotations
such as @ContextConfiguration from the spring-test module to declare
aliases as follows.
public @interface ContextConfiguration {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
// ...
}
Issue: SPR-13289
Prior to this change, calling the `setDateHeader` method on a
Spring Test MockHttpServletResponse instance would just store the given
long value in a Map, not writing it as a formatted date String.
Also, calling `getDateHeader` on a MockHttpServletRequest would not
support date strings and could not parse those values.
This can be problematic when testing features related to date headers
such as "Expires", "If-Modified-Since", "Last-Modified", etc.
This commit adds formatting and parsing capabilities to Servlet Mocks
for date strings in HTTP headers.
When formatting dates to Strings, the date format used is the one
preferred by the HTTP RFC. When parsing date Strings, multiple date
formats are supported for better compatibility.
Issue: SPR-11912
Prior to this change, calling the `setDateHeader` method on a
MockHttpServletResponse instance (internal implementation for testing
the spring-web module) would just store the given long value in a Map,
not writing it as a formatted date String.
This can be problematic when testing features related to date headers
such as "Expires", "If-Modified-Since", "Last-Modified", etc.
This commit formats long dates into date Strings using the date format
recommended by the RFC and the GMT time zone.
When using an Apache Http components based infrastructure, a null header
value is handled as the empty string. The exact same infrastructure using
HttpURLConnection generates a header with no colon. This is actually not
proper HTTP and some components fail to read such request.
We now make sure to call HttpURLConnection#addRequestProperty with the
empty String for a null header value.
Issue: SPR-13225
Browsers like Chrome or Safari include an Origin header for same-origin
POST/PUT/DELETE requests, not only for cross-origin requests.
Before this commit, these same-origin requests would have been detected
as potential cross-origin requests, and rejected if the same-origin domain
is not part of the configured allowedOrigins.
This commit avoid to reject same-origin requests by reusing the logic
introduced in Spring 4.1 for detecting reliably Websocket/SockJS
same-origin requests with the WebUtils.isValidOrigin() method. This
logic has been extracted in a new WebUtils.isSameOrigin() method.
Issue: SPR-13206
This commit introduces the following changes:
- The new CorsConfigurationMapping class allows to share the mapped
CorsConfiguration logic between AbstractHandlerMapping and CorsFilter
- In AbstractHandlerMapping, the Map<String, CorsConfiguration>
corsConfiguration property has been renamed to corsConfigurations
- CorsFilter allows to process CORS requests at filter level, using any
CorsConfigurationSource implementation (for example
CorsConfigurationMapping)
Issue: SPR-13192
When using Appache Commons FileUpload, multi parts with binary data
(i.e. that are not actual files) are saved and then accessed as
String request parameters.
Before this change however the RequestPartServletServerHttpRequest
used a fixed encoding (UTF-8) while the parsing code in
CommonsFileUploadSupport/Resolver used the encoding from the
content-type header, or the request, or the FileUpload component.
This change does a best effort to determine the encoding of the
request parameter using a similar algorithm as the parsing side
that should work the same unless the encoding comes from the
FileUpload component which is not accessible.
Issue: SPR-13096
This split avoids a package tangle (between core and core.annotation) and also allows for selective use of raw annotation exposure versus synthesized annotations, with the latter primarily applicable to web and message handler processing at this point.
Issue: SPR-13153
Prior to this commit, `HttpEntityMethodProcessor` would rely on
`ServletWebRequest` to process conditional requests and with incoming
`"If-Modified-Since"` / `"If-None-Match"` request headers.
This approach is problematic since in that class:
* response is wrapped in a `ServletServerHttpResponse`
* this wrapped response does not write response headers right away
* `ServletWebRequest.checkNotModified` methods can't apply their
logic with incomplete response headers
This solution adds some minimal code duplication and applies
the conditional request logic within the Processor.
A possible alternative would be to improve the
`ServletServerHttpResponse$ServletResponseHttpHeaders` implementation
with write methods - but this solution would only work for Servlet 3.x
applications.
Issue: SPR-13090
This commit introduces the following changes:
- In AbstractMessageConverterMethodProcessor, the type aware variant of
canWrite() is now called when the converter implements
GenericHttpMessageConverter.
- The Javadoc has been updated in GenericHttpMessageConverter to make it clear
that the type aware canRead() and canWrite() methods should perform the same
checks than non type aware ones.
- AbstractGenericHttpMessageConverter now implements default type aware
canRead() and canWrite() methods than just call the non type aware variants.
Due to this, if subclasses just override the non type aware variants,
they still have the right behavior.
Issue: SPR-13161
Prior to this commit, Spring's MimeType checked for equality between
two MIME types based on the equality of their properties maps; however,
the properties maps contain string representations of the "charset"
values. Thus, "UTF-8" is never equal to "utf-8" which breaks the
contract for character set names which must be compared in a
case-insensitive manner.
This commit addresses this issue by ensuring that "charset" properties
in MimeType instances are compared as Java Charset instances, thereby
ignoring case when checking for equality between charset names.
Issue: SPR-13157
This commit adds canWrite() and write() methods to the
GenericHttpMessageConverter interface. These are type aware variants
of the methods available in HttpMessageConverter, in order to keep
parametrized type information when serializing objects.
AbstractMessageConverterMethodProcessor now calls those type aware
methods when the message converter implements GenericHttpMessageConverter.
AbstractJackson2HttpMessageConverter and GsonHttpMessageConverter uses
these new methods to make @ResponseBody method return type available
for type resolution instead of just letting the JSON serializer trying
to guess the type to use from the object to serialize.
Issue: SPR-12811
- Simplified "check" algorithms in CorsConfiguration
- Improved robustness of setter methods in CorsConfiguration in order to
avoid attempts to modify immutable lists
- Improved CORS documentation and fixed typo
- Introduced constants in CorsConfiguration
- Removed auto-boxing in CorsRegistration
Before this change HandlerMethodReturnValueHandler's were invoked in a
specific order (type-based, annotation-based, custom). However handlers
that deal with asynchronous return value handling need to always be
considered first. This affects custom handlers in particular since they
are normally ordered last.
This change introduces an AsyncHandlerMethodReturnValueHandler
sub-interface with a single method to determine if the return value is
asynchronous and if it is to look for a matching handler only among
those that are of type AsyncHandlerMethodReturnValueHandler.
Issue: SPR-13083
Before this change a missing path variable value resulted in a 400
error where in fact the error is due to a mismatch between the
declared @PathVariable and the URI template, i.e. a 500 error.
This change introduced a MissingPathVariableException as a sub-class
of ServletRequestBindingException (the exception previously thrown)
and results in a response status code of 500 by default.
Issue: SPR-13121
Prior to this change, the `"Last-Modified"` and "`Etag`" support had
been improved with SPR-11324: HTTP response headers are now
automatically added for conditional requests and more.
This commit fixes the format of the "`Last-Modified`" and "`ETag`"
values, which were using an epoch timestamp rather than an HTTP-date
format defined in RFC 7231 section 7.1.1.1.
Also, Conditional responses are only applied when the given response
applies, i.e. when it has an compatible HTTP status (2xx).
Issue: SPR-13090
This commit introduces support for RFC 7239: Forwarded HTTP Extension in
the UriComponentsBuilder. Unfortunately, RFC 7239 is not a complete
replacement for the X-Forwarded-* headers: specifically, there is not
direct replacement for X-Forwarded-Port. The JIRA contains more
information.
Issue: SPR-11856
This commit introduces first-class support for aliases for annotation
attributes. Specifically, this commit introduces a new @AliasFor
annotation that can be used to declare a pair of aliased attributes
within a single annotation or an alias from an attribute in a custom
composed annotation to an attribute in a meta-annotation.
To support @AliasFor within annotation instances, AnnotationUtils has
been overhauled to "synthesize" any annotations returned by "get" and
"find" searches. A SynthesizedAnnotation is an annotation that is
wrapped in a JDK dynamic proxy which provides run-time support for
@AliasFor semantics. SynthesizedAnnotationInvocationHandler is the
actual handler behind the proxy.
In addition, the contract for @AliasFor is fully validated, and an
AnnotationConfigurationException is thrown in case invalid
configuration is detected.
For example, @ContextConfiguration from the spring-test module is now
declared as follows:
public @interface ContextConfiguration {
@AliasFor(attribute = "locations")
String[] value() default {};
@AliasFor(attribute = "value")
String[] locations() default {};
// ...
}
The following annotations and their related support classes have been
modified to use @AliasFor.
- @ManagedResource
- @ContextConfiguration
- @ActiveProfiles
- @TestExecutionListeners
- @TestPropertySource
- @Sql
- @ControllerAdvice
- @RequestMapping
Similarly, support for AnnotationAttributes has been reworked to
support @AliasFor as well. This allows for fine-grained control over
exactly which attributes are overridden within an annotation hierarchy.
In fact, it is now possible to declare an alias for the 'value'
attribute of a meta-annotation.
For example, given the revised declaration of @ContextConfiguration
above, one can now develop a composed annotation with a custom
attribute override as follows.
@ContextConfiguration
public @interface MyTestConfig {
@AliasFor(
annotation = ContextConfiguration.class,
attribute = "locations"
)
String[] xmlFiles();
// ...
}
Consequently, the following are functionally equivalent.
- @MyTestConfig(xmlFiles = "test.xml")
- @ContextConfiguration("test.xml")
- @ContextConfiguration(locations = "test.xml").
Issue: SPR-11512, SPR-11513
`BeanWrapperImpl` and `DirectFieldAccessor` are two
`ConfigurablePropertyAccessor` implementations with different features
set.
This commit harmonizes the two implementations to use a common base class
that delegates the actual property handling to the sub-classes:
* `BeanWrapperImpl`: `PropertyDescriptor` and introspection utilities
* `DirectFieldAccessor`: reflection on `java.lang.Field`
Issues: SPR-12206 - SPR-12805
This commit introduces support for OkHttp
(http://square.github.io/okhttp/) as a backing implementation for
ClientHttpRequestFactory and AsyncClientHttpRequestFactory.
Issue: SPR-12893
After this change CorsProcessor has a single processRequest method and
it also explicitly deals with a null CorsConfiguration, which for
pre-flight requests results in a rejection while for simple requests
results in no CORS headers added.
The AbstractHandlerMapping now uses a LinkedHashMap to preserve the
order in which global patterns are provided.
This commit adds JavaConfig based global CORS configuration
capabilities to Spring MVC. It is now possible to specify
multiple CORS configurations, each mapped on a path pattern,
by overriding
WebMvcConfigurerAdapter#configureCrossOrigin(CrossOriginConfigurer).
It is also possible to combine global and @CrossOrigin based
CORS configuration.
Issue: SPR-12933