Skip to main content

request-decompress

The request-decompress plugin decompresses a request body sent with a Content-Encoding of gzip or deflate, which RFC 9110 allows, and rewrites the request with the plain body. Every plugin that runs after it reads the decompressed content, so plugins such as oas-validator and request-validation work on a compressed request the same way they do on a plain one. Logging plugins also record the decompressed body, unless forward_compressed is enabled.

The plugin is available in API7 Enterprise from version 3.10.9.

A request without a Content-Encoding header passes through untouched and its body is never read, so the same route serves both compressed and uncompressed clients. A gzip body may carry several members concatenated, which RFC 1952 allows: every member is decompressed, and max_req_body_size bounds their total.

By default, the upstream also receives the decompressed body and the Content-Encoding header is removed. Set forward_compressed to true to send a compressed body upstream instead.

The plugin rejects the following requests:

ConditionStatus codeNotes
A coding other than gzip, deflate or identity, such as br415The response carries an Accept-Encoding: gzip, deflate header.
A malformed compressed body, or bytes trailing the last gzip member400
A compressed body beyond max_req_body_size, as received or once decompressed413A request without Content-Encoding is not checked.

Plugin Order​

request-decompress runs in the rewrite phase with a priority of 2850. That places it after the plugins that reject a request cheaply, so a blocked request is never decompressed, and before every plugin that reads the request body. A route that configures the plugin takes precedence over a global rule that also configures it, so the request body is handled once with the route's settings.

Both of the following can be changed with the _meta.priority setting of the affected plugin:

  • hmac-auth with validate_request_body enabled hashes the decompressed body on a route that also enables this plugin. A client that signs the compressed bytes needs hmac-auth configured with a priority above 2850.
  • Decompression happens before authentication, so an unauthenticated client can cause decompression work. It is bounded by max_req_body_size and by the gateway's client_max_body_size.

With forward_compressed enabled, the compressed body is restored just before the request is proxied, so the plugins that read the body in the log phase see the compressed bytes.

caution

During an upgrade, enable this plugin only after every gateway instance of the gateway group runs version 3.10.9 or later. An older gateway instance does not have the plugin and discards the configuration that uses it.

Examples​

The examples below demonstrate how you can configure request-decompress for different scenarios.

If Admin API authentication is enabled, export an admin-role key before continuing:

export ADMIN_API_KEY=replace-with-admin-api-key

Decompress a Request Body​

The following example demonstrates how to decompress a gzip request body and forward the plain body to the upstream.

Create a route with the request-decompress plugin:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "request-decompress-route",
"uri": "/anything",
"plugins": {
"request-decompress": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Send a gzip-compressed body to the route:

echo -n '{"name":"world"}' | gzip | curl "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-H "Content-Encoding: gzip" \
--data-binary @-

You should see a response similar to the following, showing that the upstream received the plain body and no Content-Encoding header:

{
"data": "{\"name\":\"world\"}",
"headers": {
"Content-Type": "application/json",
...
},
...
}

Send a body compressed with an unsupported coding:

echo -n '{"name":"world"}' | curl -i "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-H "Content-Encoding: br" \
--data-binary @-

You should receive an HTTP/1.1 415 Unsupported Media Type response with an Accept-Encoding: gzip, deflate header.

Forward a Compressed Body to the Upstream​

The following example demonstrates how to keep the upstream receiving a compressed body while the plugins on the route still read the plain one.

Create a route with the request-decompress plugin:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "request-decompress-route",
"uri": "/anything",
"plugins": {
"request-decompress": {
"forward_compressed": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Send a gzip-compressed body to the route:

echo -n '{"name":"world"}' | gzip | curl "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-H "Content-Encoding: gzip" \
--data-binary @-

The upstream receives the body still compressed, with the Content-Encoding: gzip header restored. When no plugin modified the body, the bytes are forwarded exactly as the client sent them. When a plugin rewrote the body, it is compressed again with the coding the client used.