Previously `HandlerMapping` implementation were heavily relying on
`String` path patterns, `PathMatcher` implementations and dedicated maps
for matching incoming request URL to an actual request handler.
This commit adds the `PathPatternRegistry` that holds `PathPattern`
instances and the associated request handler — matching results are then
shared as `PathMatchResult` instances. `AbstractUrlHandlerMapping` will
use this registry directly, but other components dealing with request
matching (like `PatternsRequestCondition`) will directly use ordered
`PathPattern` collections since ordering is important there.
This opens the door for faster request matching and simplifies the
design of this part.
Issue: SPR-15608
This commit enables trailing slash matching in `PathPatternParser` by
default - this mirrors the default configuration in `PathMatcher`
implementations in MVC.
The use of the undecoded URL path by default and the removal of suffix
pattern matching effectively means HttpRequestPathHelper is no longer
needed.
Issue: SPR-15640, SPR-15639
Introduce pathWithinApplication() in ServerHttpRequest and use it for
request mapping purposes instead of LookupPath.
In turn this means that for request mapping purposes:
1) the path is not decoded
2) suffix pattern matching is not supported
Issue: SPR-15640
Before this commit there was no special handling for URL encoding
of the path pattern string coming into the path pattern parser. No
assumptions were made about it being in an encoded form or not.
With this change it is assumed incoming path patterns are not
encoded and as part of parsing the parser builds PathPattern
objects that include encoded elements. For example parsing "/f o"
will create a path pattern of the form "/f%20o". In this form
it can then be used to match against encoded paths.
Handling encoded characters is not trivial and has resulted in
some loss in matching speed but care has been taken to
avoid unnecessary creation of additional heap objects. When
matching variables the variable values are return in a
decoded form. It is hoped the speed can be recovered, at least
for the common case of non-encoded incoming paths.
Issue: SPR-15640
This commit also removes nullability from two common spots: ResolvableType.getType() and TargetSource.getTarget(), both of which are never effectively null with any regular implementation. For such scenarios, a non-null empty type/target is the cleaner contract.
Issue: SPR-15540
Beyond just formally declaring the current behavior, this revision actually enforces non-null behavior in selected signatures now, not tolerating null values anymore when not explicitly documented. It also changes some utility methods with historic null-in/null-out tolerance towards enforced non-null return values, making them a proper citizen in non-null assignments.
Some issues are left as to-do: in particular a thorough revision of spring-test, and a few tests with unclear failures (ignored as "TODO: NULLABLE") to be sorted out in a follow-up commit.
Issue: SPR-15540
Without this change the comparator thinks "/{foo}"
is more specific than "/{foo}.*". The minimal fix here
to address it is to copy what the AntPathMatcher
comparator does which is to consider '.*' as *not*
a usage of a wildcard. See PatternInfo#initCounters()
for the AntPathMatcher handling of this.
This change ensures the PathPattern comparator now produces
the expected result but suffix usage in general needs more
thought at some point.
Issue: SPR-15597
Restore matrix variable parsing code not resorting to the use of
WebUtils which brings Servlet API dependencies with it.
Instead the parsing logic is now exposed through HttpRequestPathHelper
which already contained the decoding logic and also the knowledge of
whether to decode the parsed variables or not.
Issue: SPR-15397
This commit adds the `LookupPath` class that contains the full
request path relative to the web context; the application can
get from it various information, including the file extension
and path parameters (if any).
Since that operation is done multiple times for each request, this
object is stored as an attribute at the `ServerWebExchange` level.
Issue: SPR-15397
With the new `ParsingPathMatcher` implementation, new patterns are now
allowed, such as `"/foo/{*bar}". The `"{*bar}"` segment will capture
everything until the end of the given path. Adding other elements after
that segment is illegal and will throw exceptions.
One can configure on a `PathMatchConfigurer` various options like
`useTrailingSlashMatch` and `useSuffixPatternMatch`; those options, when
enabled, will try to append suffixes like `".*"` and `"/"` to existing
path patterns. In case of a "capture the rest" pattern segment, those
options won't be honored.
This is why this commit ensures that an exception is thrown at the start
of the application if an illegal configuration is applied to the
`PathMatchConfigurer`.
Issue: SPR-15303, SPR-15558
When an exception happens while writing/flushing, the exception handling
for Servlet 3.1 based implementation will happen when
WriteListener#onError and AsyncListener#onError events are received
When reading more that once for a given request, the position/limit of
the buffer provided by Undertow should be reset in order to use the
full capacity of the buffer.
This commit fixes the implementation of
ExtractingResponseErrorHandler.hasError to allow for null values,
indicating an override of the behavior inherited from
DefaultResponseErrorHandler.
Issue: SPR-15544
This commit introduces ExtractingResponseErrorHandler: an alternative
ResponseErrorHandler that uses `HttpMessageConverter`s to convert HTTP
error responses to `RestClientException`.
Issue: SPR-15544
Simplify the internals of the DefaultCodecs implementation favoring
explicit fields per override vs a generic list of readers and writers
for overrides.
This commit introduces 2 new @Nullable and @NonNullApi
annotations that leverage JSR 305 (dormant but available via
Findbugs jsr305 dependency and already used by libraries
like OkHttp) meta-annotations to specify explicitly
null-safety of Spring Framework parameters and return values.
In order to avoid adding too much annotations, the
default is set at package level with @NonNullApi and
@Nullable annotations are added when needed at parameter or
return value level. These annotations are intended to be used
on Spring Framework itself but also by other Spring projects.
@Nullable annotations have been introduced based on Javadoc
and search of patterns like "return null;". It is expected that
nullability of Spring Framework API will be polished with
complementary commits.
In practice, this will make the whole Spring Framework API
null-safe for Kotlin projects (when KT-10942 will be fixed)
since Kotlin will be able to leverage these annotations to
know if a parameter or a return value is nullable or not. But
this is also useful for Java developers as well since IntelliJ
IDEA, for example, also understands these annotations to
generate warnings when unsafe nullable usages are detected.
Issue: SPR-15540
This commit introduces a new method in HttpRequest:
`String getMethodValue`, which returns the HTTP method as a String.
Furthermore, HttpRequest.getMethod() has been given a default
implementation using this String value in combination with
`HttpMethod.resolve`.
Issue: SPR-15545
HttpMessageConverter's are client and server and arguably shouldn't
contain a server-side concept such a response status.
The status field is recent, it was added to differentiate 400 vs 500
errors with Jackson 2.9+ but there is no need for it since the same
distinction is reflected in raising an HttpMessageNotReadableException
vs a general HttpMessageConversionException.
Issue: SPR-15516
Starting with removing a package cycle on the use of
ResponseStatusException in the codec package, this commit generally
refines codec exception handling.
The new [Encoding|Decoding]Exception mirror the existing
HttpMessageNot[Readable|Writable]Exception and are used similarly
especially to differentiate betwen 400 and 500 errors when parsing
server request body content.
The commit also aligns some of the exception handling of JSON and XML
on the WebFlux side with that on the Spring MVC side.
Issue: SPR-15516
This comment extends the use of the charset property in
FormHttpMessageConverter to also include multipart headers with a
default of UTF-8.
We now also set the charset parameter of the "Content-Type" header to
indicate to the server side how to decode correctly.
Issue: SPR-15205
The MultipartHttpMessageWriter now directly encodes part header values
defaulting to UTF-8 and also specifies the charset in the
Content-Type header for the entire request.
This should work with something commonly used like Apache Commons
FileUpload which checks request.getCharacterEncoding() and uses it
for reading headers.
This commit turns the Synchronoss NIO Multipart HttpMessageReader into
a reader of Flux<Part> and creates a separate reader that aggregates
the parts into a MultiValueMap<String, Part>.
Issue: SPR-14546
This commit properly closes the opened channels in the SynchronossPart,
and also makes sure that the entire contents is copied, not just the
first batch.
Change the `StringHttpMessageConverter` to defer calling
Charset.availableCharsets() until absolutely necessary to help improve
startup times.
Issue: SPR-15502
With this commit, ServerCodecConfigurer is now exposed as a bean in
order to be provided to DefaultServerWebExchange via
WebHttpHandlerBuilder and HttpWebHandlerAdapter. This allows
DefaultServerWebExchange to get configured codecs for reading form or
multipart requests.
Issue: SPR-14546
This commit introduces reactive multipart support by adding a new
MultipartHttpMessageReader interface (with default methods) and a
SynchronossMultipartHttpMessageReader implementation based on
the Synchronoss NIO Multipart implementation
(https://github.com/synchronoss/nio-multipart).
Issue: SPR-14546
According to RFC-6265 that there should be a space between the ; and
the attribute name, i.e. the header should be something like
name=value; Domain=localhost; HttpOnly rather than
name=value;Domain=localhost;HttpOnly
Issue: SPR-15225
This commit adds the ability for path patterns to automatically
match a trailing separator (so there is no need to add two
variants of a pattern, one with and one without). This behaviour
is currently turned off but a simple tweak in PathPatternParser
can make it the default. If made default other parts of Spring
may need altering (simplifying hopefully) to cope with this.
Issue: SPR-15260
Without this change it was necessary to call getPathRemaining and
then chop up the path and make a call to matchAndExtract to get the
bound variables for the path part that matched. With this change
this is all done in the call to getPathRemaining which returns
an object holding the remaining path and the bound variables.
Issue: SPR-15419
This commit refactors the CodecConfigurer, with it's subtypes
ServerCodecConfigurer and ClientCodecConfigurerTests, into interfaces
instead of classes.
- Renamed `defaultCodec` to `defaultCodecs`, and `customCodec` to
`customCodecs`
- Added `@Override` annotations where necessary
- Fixed non-parameterized usage for parameterized types.
Previously a requestURI that contained ';' would have the value incorrectly stripped out when using
ForwardedHeaderFilter.
This commit ensures that the ';' is preserved when using ForwardedHeaderFilter.
Issue: SPR-15428
Previously ForwardedHeaderFilter would override the requestURI with a URL decoded value. This would cause
problems when using a URL encoded requestURI since downstream Filters would not see the URL encoded
value as they should.
This commit resolves this issue by ensuring that the requestURI is properly encoded.
Issues SPR-15422
This commit makes CodecException handling consistent between functional
and annotation-based APIs. It now returns by default 4xx status code
for decoding error and 5xx for encoding error + print the error reason
in logs without the full stack trace in both variants.
Issue: SPR-15355
Previously ForwardedHeaderFilter would return the same StringBuffer for every invocation. This
meant that users that modified the StringBuffer changed the state of the HttpServletRequest.
This commit ensures that a new StringBuffer is always returned for ForwardedHeaderFilter.
Issue: SPR-15423
With this change there is a new getPathRemaining() method on
PathPattern objects. It is called with a path and returns
the path remaining once the path pattern in question has
matched as much as it can of that path. For example if the
pattern is /fo* and the path is /foo/bar then getPathRemaining
will return /bar. This allows for a set of pathpatterns
to work together in sequence to match a complete entire path.
Issue: SPR-15336
InvalidDefinitionException has been introduced in Jackson 2.9 to be
able to differentiate invalid data sent from the client (should still
generate a 4xx HTTP status code) from server side errors like beans with
no default constructor (should generate a 5xx HTTP status code).
Issue: SPR-14925
- ServletServerHttpResponse.ResponseAsyncListener#onError/onTimeout
must complete the async operation
- ServletHttpHandlerAdapter.HandlerResultSubscriber#onComplete must
check that the async operation is not completed
Issue: SPR-15412
Revise Javadoc on AsyncHandlerMethodReturnValueHandler to clarify its
main purpose is to prioritze custom async return value handlers ahead
of built-in ones. Also replace the interface from built-in handlers
which are prioritized already.
Remove DeferredResultAdapter and ResponseBodyEmitterAdapter --
introduced in 4.3 for custom async return value handling, since for
5.0 we will add built-in support for reactive types and the value of
these contracts becomes very marginal.
Issue: SPR-15365
Restore the correct client-side default for whether StringDecoder
should split on new lines. It is true forthe server and false for the
client by default.
The regression was introduced in the recent refactoring:
f8a21ab11b (diff-0175d58138b2e8b2bec087ffe0495340)
This commit deprecates `AsyncRestTemplate` and related types
(`AsyncClientHttpRequestFactory` etc.) in favor of the Spring 5.0
`WebClient`.
Issue: SPR-15294
This commit folds ServerHttpMessage[Reader|Writer] into its parent
HttpMessage[Reader|Writer] with the server methods pre-implemented
by default to be simple pass-through delegates.
Includes a new overloaded ModelAndView constructor with an HttpStatus argument, as well as a HandlerMethodArgumentResolverSupport refactoring (revised checkParameterType signature, actually implementing the HandlerMethodArgumentResolver interface).
Issue: SPR-15199
Follow-up to:
3d68c496f1
StringDecoder can be created in text-only vs "*/*" mode which in turn
allows a more intuitive order of client side decoders, e.g. SSE does
not have to be ahead of StringDecoder.
The commit also explicitly disables String from the supported types in
Jackson2Decoder leaving it to the StringDecoder in "*/*" mode which
comes after. This does not change the current arrangement since the
the StringDecoder ahead having "*/*" picks up JSON content just the
same.
From a broader perspective this change allows any decoder to deal with
String if it wants to after examining the content type be it the SSE
or another, custom decoder. For Jackson there is very little value in
decoding to String which works only if the output contains a single
JSON string but will fail to parse anything else (JSON object/array)
while StringDecoder in "*/*" mode will not fail.
Issue: SPR-15374
This commit introduces a `useRegisteredExtensionsOnly` property that
indicates whether classes that use the `MediaTypeFactory` for supplying
default media types can do so.
- In classes that were introduced in Spring 5.0, the
`useRegisteredExtensionsOnly` property takes the place of the
`useJaf` property that was removed in 0aaa652
- In classes that existed before Spring 5.0, the
`useRegisteredExtensionsOnly` property is added in addition to the
deprecated `useJaf`, the latter delegating to the former, but with
flipped behavior.
Issue: SPR-14908
This commit changes the `MediaTypeFactory` to return
`Optional<MediaType>` (instead of a plain `MediaType`) for the
`getMediaType` methods.
Issue: SPR-14908
CharSequenceEncoder now supports all MIME types, however since encoding
Flux<String> can overlap with other encoders (e.g. SSE) there are now
two ways to create a CharSequenceEncoder -- with support for text/plain
only or with support for any MIME type.
In WebFlux configuration we insert one CharSequenceEncoder for
text/plain (as we have so far) and a second instance with support for
any MIME type at the very end.
Issue: SPR-15374
Push the knowledge of what media types represent "streaming" down to
the Encoder level where knowledge is required (e.g. to encode a
JSON array vs a stream of JSON elements).
Instead of accepting List<Encoder|Decoder> and then look for the first
to support JSON, always expect a single JSON [Encoder|Decoder] and use
that unconditionally.
When writing use the nested ResolvableType instead of the Class of the
actual value which should better support generics.
Remove the SSE hint and pass "text/event-stream" as the media type
instead to serve as a hint. We are expecting a JSON encoder and using
it unconditionally in any case so this should be good enough.
Consolidate JsonView hint extraction in shared base class.
Rename base class from AbstractJackson2Codec to Jackson2CodecSupport
since the class mainly provides support methods.
Support for flushing in EncoderHttpMessageWriter is now driven from a
configurable list of "streaming" media types with the list including
"application/stream+json" by default.
As a result Jackson2ServerHttpMessageWriter is no longer needed.
ServerHttpEncoder and ServerHttpDecoder are HTTP-specific
specializations that can prepare encoding and decoding hints from
extra information available on the server side.
As a result Jackson2ServerHttpMessageReader is no longer needed.
There is a natural way to implement ServerHttpMessage[Reader|Writer]
from [Encoder|Decoder]HttpMessageWriter by resolving hints first via
a protected method and then delegating to the regular read or write.
There is no downside either since it does not prevent
[Encoder|Decoder]HttpMessageWriter from being used for both client and
server scenarios while they're more useful.
As a positive side effect AbstractServerHttpMessage[Reader|Writer] can
be removed further simplfications can be made (in a future commit) to
accept ServerHttpMessageWriter for configuration purposes on the server
side and remove instanceof checks for ServerHttpMessageWriter.
This commit changes the `MockServletContext.getMimeType` method to use
`MediaTypeFactory` instead of JAF. It also adds a `addMimeType(String,
MediaType)` method to customize the mime types returned from said
method.
Issue: SPR-14908
This commit updates the main code base to conform to the dropped JAF
dependency in MediaTypeFactory. Specifically, it
- Removes JAF detection (JAF_PRESENT constants)
- Deprecated useJaf properties, with no direct replacement.
- Updated docs to remove JAF references, in favor of MediaTypeFactory.
Issue: SPR-14908
This commit drops the Java Activation Framework dependency from the
MediaTypeFactory, in favor of parsing our own `mime.types` file, which
was obtained from Apache HTTPD.
Issue: SPR-14908
Fold ResourceRegionHttpMessageWriter into ResourceHttpMessageWriter.
The latter was a private helper (not meant to be exposed) and the two
have much in common now sharing a number of private helper methods.
The combined class does not extend AbstractServerHttpMessageConverter
from which it was not using anything.
Internally the combined class now delegates directly to ResourceEncoder
or ResourceRegionEncoder as needed. The former is no longer wrapped
with EncoderHttpMessageWriter which is not required since "resource"
MediaType determination is a bit different.
The consolidation makes it easy to see the entire algorithm in one
place especially for server side rendering (and HTTP ranges). It
also allows for consistent determination of the "resource" MediaType
via MediaTypeFactory for all use cases.
ResourceRegionHttpMessageWriter no longer extends from
EncoderHttpMessageWriter freeing it to pass the correct content type
into the encoder.
Considering that the main benefit of EncoderHttpMessageWriter is to
deal with content type fallback cases, there is nothing to be missed.
Furthermore ResourceRegionHttpMessageWriter is a package private class
that is used internally within ResourceHttpMessageWriter and never
exposed externally as a an actual HttpMessageWriter.
Issue: SPR-15358
When CodecHttpMessageConverter was split into DecoderHttpMessageReader
and EncoderHttpMessageWriter the null checks were never removed.
This commit makes the Encoder and Decoder instances provided to their
respective wrappers required.
CompositeHttpHandler is public and called ContextPathCompositeHandler.
Also an overhaul of the Javadoc on HttpHandler, WebHttpHandlerAdapter,
and ContextPathCompositeHandler.
Extract CompositeHttpHandler to a package private class and add direct
support via `HttpHandler.of(...)`. This removes the need for the
`HttpHandlerAdapterSupport` class.
Currently the BOM versions are:
* reactor-core 3.0.6.BUILD-SNAPSHOT
* reactor-netty 0.6.2.BUILD-SNAPSHOT
This commit fixes as well a few deprecations in reactor-core.
The SSE reader is ordered ahead of StringDecoder because with
response.decodeToFlux(String.class) we actually want the SSE reader
to get involved first based on the content-type.
At the same time with response.decodeToMono(String.class) there is
nothing the SSE reader can do while the StringDecoder could read the
entore content as one String, as long as the server does terminate
the stream which can happen in a testing scenario.
This commit updates ServerSentEventHttpMessageReader#readMono in
to support String.class by delegating to StringDecoder. Since
reading to a Mono is an explicit choice there is not much possibility
for interfering with decoding to Flux.
Issue: SPR-15331
This commit simplifies the use of DataBufferFactory in the SSE reader
which is used only to wrap a byte[] as a DataBuffer. There is no actual
benefit to use anything other than a DefaultDataBufferFactory.
From spring-webflux to spring-web test sources since it is perfectly
usable for testing Spring MVC annotation method support.
Potentially to be promoted further up for use in any module that has
annotation method support. It has spring-core dependencies only
`PathPatternParser` is now thread-safe and creates a new internal parser
for each `parse` call, since this operation is cheap.
This commit removes the `ThreadLocal` based instances of
`PathPatternParser` in `ParsingPathMatcher` which are not required
anymore.
Issue: SPR-15246
With this change the original PathPatternParser is renamed
InternalPathPatternParser and a new PathPatternParser class is added.
This new PathPatternParser class is a very simple thread-safe wrapper for
the InternalPathPatternParser. It achieves this by creating a new
InternalPathPatternParser for each new parse request. This follows the
model used for SpEL parsing.
Prior to this commit, the `ShallowEtagHeaderFilter` could participate in
the response and set its ETag/Content-Length headers, even for HEAD
requests. Since the response body is empty, the filter implementation
would set a `"Content-Length: 0"`.
The RFC states that responses to HEAD requests should exhibit identical
response headers to GET (with the possible exception of payload related
headers such as Content-Length.
With this commit, `ShallowEtagHeaderFilter` now ignores HEAD requests
since the proper values may be set already for payload related headers
by the handler. The filter has no way to generate a proper ETag value
nor calculate the content length without the actual body.
Issue: SPR-15261
The first fix for issue 15264 covered the case of using a single
variable (the case mentioned in the bug report). However, when
more than one variable is used a different PathElement is built.
This RegexPathElement needs a similar change that checks the
path includes data to bind.
Issue: SPR-15264
This commit checks that a "Content-Length" request header isn't already
present before adding one in `Netty4ClientHttpRequestFactory`.
`HttpMessageConverter` implementations can write that request header so
the Netty request factory should only write that value when the header
is missing.
If that header is not written (and since we're not dealing with
the HTTP exchange in a chunked-based fashion), the HTTP client might not
send the request body at all.
Issue: SPR-15241
This commit ensures that the `PathPatternParser` and the associated
cache map are used in a threadsafe fashion, since the PathMatcher
instance can be used for concurrent requests.
Issue: SPR-15246
This commit reduces the exposition of `PathPattern` instances throughout
the `HandlerMapping` API and removes some methods from its public API.
Issue: SPR-14544
Since the introduction of `PathPatternRegistry`, the various path match
configuration flags are no longer needed in several places and that
configuration can live in the registry itself.
Issue: SPR-14544