Add Validation to HTTP Inbound (#2978)

* Add Validation to HTTP Inbound

* Pull a validation functionality from `WebFluxInboundEndpoint` to its
super class `BaseHttpInboundEndpoint` making a validation available for
the `HttpRequestHandlingEndpointSupport` as well
* Do the same for the `validator()` option in DSL for the
`HttpInboundEndpointSupportSpec`
* Add `validator` XML attribute for both HTTP and WebFlux inbound
endpoint XSDs
* Test parsers for a new `validator` option
* Document validation in the `http.adoc`
* Apply some polishing in the `http.adoc`, as well as in the
`HttpRequestHandlingEndpointSupport` JavaDocs
* Clarify in `webflux.adoc` that validation is applied for the
`Publisher` items before the payload is finally built for the message to
send.
* Add WebFlux into the table of endpoints in the `endpoint-summary.adoc`

* * Remove unused imports
* Fix `SimpleMessageListenerContainerSpec` for deprecated `txSize` option
This commit is contained in:
Artem Bilan
2019-06-27 09:47:45 -04:00
committed by Gary Russell
parent c5ec2d94c6
commit c18c2e2141
19 changed files with 293 additions and 130 deletions

View File

@@ -90,6 +90,12 @@ The following table summarizes the various endpoints with quick links to the app
| <<./http.adoc#http-inbound,Http Inbound Components>>
| <<./http.adoc#http-outbound,HTTP Outbound Components>>
| *WebFlux*
| <<./webflux.adoc#webflux-namespace,WebFlux Namespace Support>>
| <<./webflux.adoc#webflux-namespace,WebFlux Namespace Support>>
| <<./webflux.adoc#webflux-inbound,WebFlux Inbound Components>>
| <<./webflux.adoc#webflux-outbound,WebFlux Outbound Components>>
| *JDBC*
| <<./jdbc.adoc#jdbc-inbound-channel-adapter,Inbound Channel Adapter>> and <<./jdbc.adoc#stored-procedure-inbound-channel-adapter,Stored Procedure Inbound Channel Adapter>>
| <<./jdbc.adoc#jdbc-outbound-channel-adapter,Outbound Channel Adapter>> and <<./jdbc.adoc#stored-procedure-outbound-channel-adapter,Stored Procedure Outbound Channel Adapter>>

View File

@@ -32,8 +32,7 @@ The `javax.servlet:javax.servlet-api` dependency must be provided on the target
To receive messages over HTTP, you need to use an HTTP inbound channel adapter or an HTTP inbound gateway.
To support the HTTP inbound adapters, they need to be deployed within a servlet container such as https://tomcat.apache.org/[Apache Tomcat] or https://www.eclipse.org/jetty/[Jetty].
The easiest way to do this is to use Spring's
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/context/support/HttpRequestHandlerServlet.html[`HttpRequestHandlerServlet`], by providing the following servlet definition in the `web.xml` file:
The easiest way to do this is to use Spring's https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/context/support/HttpRequestHandlerServlet.html[`HttpRequestHandlerServlet`], by providing the following servlet definition in the `web.xml` file:
====
[source,xml]
@@ -46,9 +45,7 @@ https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/c
====
Notice that the servlet name matches the bean name.
For more information on using the `HttpRequestHandlerServlet`, see
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/remoting.html[Remoting and web services using Spring],
which is part of the Spring Framework Reference documentation.
For more information on using the `HttpRequestHandlerServlet`, see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/remoting.html[Remoting and web services using Spring], which is part of the Spring Framework Reference documentation.
If you are running within a Spring MVC application, then the aforementioned explicit servlet definition is not necessary.
In that case, the bean name for your gateway can be matched against the URL path as you would for a Spring MVC Controller bean.
@@ -79,8 +76,7 @@ An additional flag (`mergeWithDefaultConverters`) can be set along with the list
By default, this flag is set to `false`, meaning that the custom converters replace the default list.
The message conversion process uses the (optional) `requestPayloadType` property and the incoming `Content-Type` header.
Starting with version 4.3, if a request has no content type header, `application/octet-stream` is assumed, as
recommended by `RFC 2616`.
Starting with version 4.3, if a request has no content type header, `application/octet-stream` is assumed, as recommended by `RFC 2616`.
Previously, the body of such messages was ignored.
Spring Integration 2.0 implemented multipart file support.
@@ -146,10 +142,17 @@ The preceding example also shows how to customize the HTTP methods accepted by t
The reply message is available in the model map.
By default, the key for that map entry is 'reply', but you can override this default by setting the 'replyKey' property on the endpoint's configuration.
[[http-validation]]
==== Payload Validation
Starting with version 5.2, the HTTP inbound endpoints can be supplied with a `Validator` to check a payload before sending into the channel.
This payload is already a result of conversion and extraction after `payloadExpression` to narrow a validation scope in regards to the valuable data.
The validation failure handling is fully the same what we have in Spring MVC https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-exceptionhandlers[Error Handling].
[[http-outbound]]
=== HTTP Outbound Components
This section describes Spring Integration's HTTP outbound components
This section describes Spring Integration's HTTP outbound components.
==== Using `HttpRequestExecutingMessageHandler`
@@ -205,8 +208,7 @@ If `transfer-cookies` is `false`, any `Set-Cookie` header received remains as `S
HTTP is a request-response protocol.
However, the response may not have a body, only headers.
In this case, the `HttpRequestExecutingMessageHandler` produces a reply `Message` with the payload being an `org.springframework.http.ResponseEntity`, regardless of any provided `expected-response-type`.
According to the https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html[HTTP RFC Status Code Definitions], there are many statuses that mandate that a response must not contain a message-body (for example,
`204 No Content`).
According to the https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html[HTTP RFC Status Code Definitions], there are many statuses that mandate that a response must not contain a message-body (for example, `204 No Content`).
There are also cases where calls to the same URL might or might not return a response body.
For example, the first request to an HTTP resource returns content, but the second does not (returning a `304 Not Modified`).
In all cases, however, the `http_statusCode` message header is populated.
@@ -350,8 +352,7 @@ For more information regarding handler mappings, see https://docs.spring.io/spri
[[http-cors]]
==== Cross-origin Resource Sharing (CORS) Support
Starting with version 4.2, you can configure the `<http:inbound-channel-adapter>` and `<http:inbound-gateway>` with
a `<cross-origin>` element.
Starting with version 4.2, you can configure the `<http:inbound-channel-adapter>` and `<http:inbound-gateway>` with a `<cross-origin>` element.
It represents the same options as Spring MVC's `@CrossOrigin` for `@Controller` annotations and allows the configuration of cross-origin resource sharing (CORS) for Spring Integration HTTP endpoints:
* `origin`: List of allowed origins.
@@ -376,8 +377,7 @@ This property controls the value of the `Access-Control-Max-Age` header in the p
A value of `-1` means undefined.
The default value is 1800 seconds (30 minutes).
The CORS Java Configuration is represented by the `org.springframework.integration.http.inbound.CrossOrigin` class,
instances of which can be injected into the `HttpRequestHandlingEndpointSupport` beans.
The CORS Java Configuration is represented by the `org.springframework.integration.http.inbound.CrossOrigin` class, instances of which can be injected into the `HttpRequestHandlingEndpointSupport` beans.
[[http-response-statuscode]]
==== Response Status Code
@@ -403,8 +403,7 @@ The following example shows how to set the status code to `ACCEPTED`:
====
The `<http:inbound-gateway>` resolves the 'status code' from the `http_statusCode` header of the reply `Message`.
Starting with version 4.2, the default response status code when no reply is received within the `reply-timeout`
is `500 Internal Server Error`.
Starting with version 4.2, the default response status code when no reply is received within the `reply-timeout` is `500 Internal Server Error`.
There are two ways to modify this behavior:
* Add a `reply-timeout-status-code-expression`.
@@ -427,8 +426,7 @@ The payload of the `ErrorMessage` is a `MessageTimeoutException`.
It must be transformed to something that can be converted by the gateway, such as a `String`.
A good candidate is the exception's message property, which is the value used when you use the `expression` technique.
If the error flow times out after a main flow timeout, `500 Internal Server Error` is returned, or, if the
`reply-timeout-status-code-expression` is present, it is evaluated.
If the error flow times out after a main flow timeout, `500 Internal Server Error` is returned, or, if the `reply-timeout-status-code-expression` is present, it is evaluated.
NOTE: Previously, the default status code for a timeout was `200 OK`.
To restore that behavior, set `reply-timeout-status-code-expression="200"`.
@@ -655,7 +653,7 @@ The `uriVariablesExpression` property provides a very powerful mechanism for eva
We anticipate that people mostly use simple expressions, such as the preceding example.
However, you can also configure something such as `"@uriVariablesBean.populate(#root)"` with an expression in the returned map being `variables.put("thing1", EXPRESSION_PARSER.parseExpression(message.getHeaders().get("thing2", String.class)));`, where the expression is dynamically provided in the message header named `thing2`.
Since the header may come from an untrusted source, the HTTP outbound endpoints use `SimpleEvaluationContext` when evaluating these expressions.
`SimpleEvaluationContext` uses only a subset of SpEL features.
The `SimpleEvaluationContext` uses only a subset of SpEL features.
If you trust your message sources and wish to use the restricted SpEL constructs, set the `trustedSpel` property of the outbound endpoint to `true`.
====
@@ -830,8 +828,7 @@ image::images/http-outbound-gateway.png[align="center"]
//TODO These images are too small, and the text within them is much too small.
You may want to configure the HTTP related timeout behavior, when making active HTTP requests by using the HTTP outbound gateway or the HTTP outbound channel adapter.
In those instances, these two components use Spring's
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html[`RestTemplate`] support to execute HTTP requests.
In those instances, these two components use Spring's https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html[`RestTemplate`] support to execute HTTP requests.
To configure timeouts for the HTTP outbound gateway and the HTTP outbound channel adapter, you can either reference a `RestTemplate` bean directly (by using the `rest-template` attribute) or you can provide a reference to a https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/client/ClientHttpRequestFactory.html[`ClientHttpRequestFactory`] bean (by using the `request-factory` attribute).
Spring provides the following implementations of the `ClientHttpRequestFactory` interface:

View File

@@ -91,8 +91,14 @@ See <<./http.adoc#http-request-mapping,Request Mapping Support>> and <<./http.ad
When the request body is empty or `payloadExpression` returns `null`, the request params (`MultiValueMap<String, String>`) is used for a `payload` of the target message to process.
[[webflux-validation]]
==== Payload Validation
Starting with version 5.2, the `WebFluxInboundEndpoint` can be configured with a `Validator`.
It is used to validate elements in the `Publisher` to which a request has been converted by the `HttpMessageReader`.
Unlike the MVC validation in the <<./http.adoc#http-validation,HTTP Support>>, it is used to validate elements in the `Publisher` to which a request has been converted by the `HttpMessageReader`, before performing a fallback and `payloadExpression` functions.
The Framework can't assume how complex the `Publisher` object can be after building the final payload.
If there is a requirements to restrict validation visibility for exactly final payload (or its `Publisher` elements), the validation should go downstream instead of WebFlux endpoint.
See more information in the Spring WebFlux https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/web-reactive.html#webflux-fn-handler-validation[documentation].
An invalid payload is rejected with an `IntegrationWebExchangeBindException` (a `WebExchangeBindException` extension), containing all the validation `Errors`.
See more in Spring Framework https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#validation[Reference Manual] about validation.

View File

@@ -95,6 +95,12 @@ See <<./ip.adoc#tcp-connection-factory, TCP Connection Factories>> for more info
The `AbstractMailReceiver` has now an `autoCloseFolder` option (`true` by default), to disable an automatic folder close after a fetch, but populate `IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE` header instead for downstream interaction.
See <<./mail.adoc#mail-inbound,Mail-receiving Channel Adapter>> for more information.
[[x5.2-http]]
==== HTTP Changes
The HTTP inbound endpoint now support a request payload validation.
See <<./http.adoc#http,HTTP Support>> for more information.
[[x5.2-webflux]]
==== WebFlux Changes