Skip to content

Some valid POST requests with no body are rejected in 9.1 #133408

@swallez

Description

@swallez

We had users report that their application using the Java client was working fine with ES 9.0, but that some API calls were failing with 9.1. After some investigation, @l-trotta and found it was caused by PR #129302, released in 9.1.

This PR changed how Request.hasContent() is implemented. This is causing issues with some POST requests with no body and no Content-Type header, in particular http/2 requests relayed by the Cloud proxy (and converted to http/1). The ES server will assume these requests have a content while they actually do not.

If these requests do not have a Content-Type header, API version compatibility will fail and the request will be rejected.

Steps to reproduce

Create a 9.0.0 cluster on Elastic Cloud, and run this command (adding -v will show that http/2 is used):

curl -X POST \
  -H "Authorization: ApiKey <redacted> \
  -H "Accept: application/vnd.elasticsearch+json; compatible-with=9" \
  "https://<cluster-id>.elastic-cloud.com/_count"
{"count":103,"_shards":{"total":18,"successful":18,"skipped":0,"failed":0}}

Run that same command on a 9.1.0 cluster. It fails, indicating that a Content-Type=null is not compatible with the Accept header value:

{"error":{"root_cause":[{"type":"media_type_header_exception","reason":"Invalid media-type value on headers [Accept, Content-Type]"}],"type":"media_type_header_exception","reason":"Invalid media-type value on headers [Accept, Content-Type]","caused_by":{"type":"status_exception","reason":"A compatible version is required on both Content-Type and Accept headers if either one has requested a compatible version. Accept=application/vnd.elasticsearch+json; compatible-with=9, Content-Type=null"}},"status":400}

Adding ?error_trace=true shows the root exception:

Caused by: org.elasticsearch.ElasticsearchStatusException: A compatible version is required on both Content-Type and Accept headers if either one has requested a compatible version. Accept=application/vnd.elasticsearch+json; compatible-with=9, Content-Type=null
    at [email protected]/org.elasticsearch.rest.RestCompatibleVersionHelper.getCompatibleVersion(RestCompatibleVersionHelper.java:76)

This exception means that contentTypeHeader is null as expected, but that hasContent is true which isn't expected. This probably comes from HttpBody.isEmpty() where the body is likely set, and to a HttpBody.Stream instance.

Workarounds

There are some workarounds, although they can be considered counter-intuitive:

  • Force http/1: add --http1.1 to the curl command. Most modern http clients will automatically negotiate and upgrade to http/2 when available. Works with Elastic Cloud, but may not be effective in all environments.
  • Add a Content-Type header: add -H 'Content-Type: application/vnd.elasticsearch+json; compatible-with=9 to the curl command. Many users and client libraries will not add a Content-Type to an empty request.

Note that setting Content-Length: 0 doesn't solve the issue.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions