Announcements icon indicating copy to clipboard operation
Announcements copied to clipboard

[Breaking change]: Updated empty body detection in MVC Model Binding

Open brunolins16 opened this issue 2 years ago • 0 comments

Description

The mechanism to detect an empty request body during the MVC Model Binding now uses the IHttpRequestBodyDetectionFeature.CanHaveBody, that is currently implemented by the following behavior:

  • true when:

    • It's an HTTP/1.x request with a non-zero Content-Length or a Transfer-Encoding: chunked header.
    • It's an HTTP/2 request that did not set the END_STREAM flag on the initial headers frame.
  • false when:

    • It's an HTTP/1.x request with no Content-Length or Transfer-Encoding: chunked header, or the Content-Length is 0.
    • It's an HTTP/1.x request with Connection: Upgrade (e.g. WebSockets). There is no HTTP request body for these requests and no data should be received until after the upgrade.
    • It's an HTTP/2 request that set END_STREAM on the initial headers frame.

Since the previous behavior was a simple validation of the Content-Length == 0, in some scenarios when requests are not sending all needed HTTP information, could now be detected as empty request and report a failure to the client.

Version

7.0.0-preview3

Previous behavior

Before if you have a Controller's action that bind a parameter from body:

 [HttpPost()]
        public IActionResult Required([FromBody] TestClass value) => Ok(value);

And the client request does not include a Content-Length header, eg.:

curl --request POST -k -i "[action]" -H "Content-Type: application/json"

This request will cause an internal exception during the body deserialization:

Eg.: When using the System.Text.Json input formatter

System.Text.Json.JsonException: 'The input does not contain any JSON tokens. 
Expected the input to start with a valid JSON token, when isFinalBlock is true. 
Path: $ | LineNumber: 0 | BytePositionInLine: 0.'

Also, a response payload similar to this will be receive by the client:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-34e98b5841b88bfb5476965efd9d9c8c-5bb16bc50dfbabb7-00",
  "errors": {
    "$": [
+      "The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0."
    ],
    "value": [
      "The value field is required."
    ]
  }
}

New behavior

With the updated detection mechanism, the deserialization will not be trigger since an empty request body will be detected and only a validation message will be reported back to the client. Eg.:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-0f87920dc675fdfdf8d7638d3be66577-bd6bdbf32d21b714-00",
  "errors": {
    "": [
+      "A non-empty request body is required."
    ],
    "value": [
      "The value field is required."
    ]
  }
}

Type of breaking change

  • [X] Binary incompatible: Existing binaries may encounter a breaking change in behavior, such as failure to load/execute or different run-time behavior.
  • [ ] Source incompatible: Source code may encounter a breaking change in behavior when targeting the new runtime/component/SDK, such as compile errors or different run-time behavior.

Reason for change

This change is an alignment with other parts of the framework that were already using the IHttpRequestBodyDetectionFeature.CanHaveBody and also a fix to a reported issue dotnet/aspnetcore/issues/29570

Recommended action

No change is required, however, if you getting an unexpected behavior is recommended to review if your client's requests are sending the appropriated headers/information.

Affected APIs

MVC Action Controllers

brunolins16 avatar Apr 01 '22 19:04 brunolins16