-
Notifications
You must be signed in to change notification settings - Fork 760
Description
Describe the bug
If I manually compress a JSON file with brotli and upload it to RustFS bucket with "Content-Encoding: br", "Content-Type: application/json" the object no longer has Content-Encoding when I download it (GET) from the bucket. This behaviour is different from MinIO and AWS S3.
To Reproduce
Reproduction using docker compose:
services:
rustfs:
image: rustfs/rustfs:latest
environment:
RUSTFS_ACCESS_KEY: rustfs-user
RUSTFS_SECRET_KEY: rustfs-password
ports:
- "9000:9000"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/health"]
interval: 2s
timeout: 2s
retries: 10
minio:
image: minio/minio:latest
environment:
MINIO_ROOT_USER: rustfs-user
MINIO_ROOT_PASSWORD: rustfs-password
command: server /data
ports:
- "9000:9000"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 2s
timeout: 2s
retries: 10
tester:
image: alpine:latest
environment:
RUSTFS_ACCESS_KEY: rustfs-user
RUSTFS_SECRET_KEY: rustfs-password
ENDPOINT: http://rustfs:9000
entrypoint: ["/bin/sh", "-c"]
command:
- |
set -e
apk add --no-cache curl brotli
echo Ensure bucket exists...
curl -sf --aws-sigv4 "aws:amz:us-east-1:s3" -u "$$RUSTFS_ACCESS_KEY:$$RUSTFS_SECRET_KEY" -X PUT "$$ENDPOINT/bucket" || true
echo Applying public policy to bucket...
curl -sf --aws-sigv4 "aws:amz:us-east-1:s3" -u "$$RUSTFS_ACCESS_KEY:$$RUSTFS_SECRET_KEY" -X PUT "$$ENDPOINT/bucket?policy" -H "Content-Type: application/json" -d '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":["*"]},"Action":["s3:GetObject","s3:PutObject"],"Resource":["arn:aws:s3:::bucket/*"]}]}'
echo Creating JSON file...
printf '{"msg":"hello"}' > data.json
echo Compressing with brotli...
brotli -f data.json
echo Uploading to pre-compressed file to bucket via PUT...
curl -v -X PUT -H "content-encoding: br" -H "content-type: application/json" --data-binary @data.json.br "$$ENDPOINT/bucket/data.json"
echo Downloading file back...
curl -v -s --compressed -o downloaded.json "$$ENDPOINT/bucket/data.json"
echo Show original file...
cat data.json
printf "\n"
echo Show downloaded file...
cat downloaded.json
printf "\n"
echo Comparing raw bytes...
if cmp -s data.json downloaded.json; then
echo 'SUCCESS: Files match';
exit 0;
else
echo 'ERROR: Files differ (mishandling Content-Encoding?).';
exit 1;
fi
docker compose up rustfs -ddocker compose run -e ENDPOINT=http://rustfs:9000 tester
You can see that Content-Encoding was present when uploading the object, but it is missing when downloading the object (there is some user-defined meta data x-amz-meta-content-encoding: br instead):
> PUT /bucket/data.json HTTP/1.1
> Host: rustfs:9000
> User-Agent: curl/8.17.0
> Accept: */*
> content-encoding: br
> content-type: application/json
> Content-Length: 20
>
* upload completely sent off: 20 bytes
< HTTP/1.1 200 OK
< etag: "46d9a8f8877d8ad8ee4b8758b6e0719f"
< vary: accept-encoding
< vary: origin, access-control-request-method, access-control-request-headers
< access-control-allow-origin: *
< access-control-expose-headers: *
< x-request-id: 8c870519-9f85-4c3e-b54c-0d95921c75c5
< content-length: 0
< date: Mon, 08 Dec 2025 09:53:52 GMT
<
* Connection #0 to host rustfs:9000 left intact
Downloading file back...
* Host rustfs:9000 was resolved.
* IPv6: (none)
* IPv4: 172.18.0.2
* Trying 172.18.0.2:9000...
* Established connection to rustfs (172.18.0.2 port 9000) from 172.18.0.3 port 34272
* using HTTP/1.x
> GET /bucket/data.json HTTP/1.1
> Host: rustfs:9000
> User-Agent: curl/8.17.0
> Accept: */*
> Accept-Encoding: deflate, gzip, br, zstd
>
* Request completely sent off
< HTTP/1.1 200 OK
< accept-ranges: bytes
< content-length: 20
< content-type: application/json
< etag: "46d9a8f8877d8ad8ee4b8758b6e0719f"
< last-modified: Mon, 08 Dec 2025 09:53:52 GMT
< x-amz-meta-content-type: application/json
< x-amz-meta-content-encoding: br
< vary: origin, access-control-request-method, access-control-request-headers
< access-control-allow-origin: *
< access-control-expose-headers: *
< x-request-id: 2cdb586f-c368-4614-b930-6ecf2ea6dc14
< date: Mon, 08 Dec 2025 09:53:52 GMT
<
{ [20 bytes data]
* Connection #0 to host rustfs:9000 left intact
Show original file...
{"msg":"hello"}
Show downloaded file...
!8{"msg":"hello"}
Comparing raw bytes...
ERROR: Files differ (mishandling Content-Encoding?).
Expected behavior
Downloading the object should have Content-Encoding: br.
This is how MinIO and AWS S3 work. This allows a web browser to download the display JSON file correctly if you just point the URL to the object and browser would automatically decompress it. With RustFS this doesn't work at the moment, browser will just display the uncompressed file.
You can compare behavior to MinIO by running:
docker compose down
docker-compose up minio -d
docker compose run -e ENDPOINT=http://minio:9000 tester
> PUT /bucket/data.json HTTP/1.1
> Host: minio:9000
> User-Agent: curl/8.17.0
> Accept: */*
> content-encoding: br
> content-type: application/json
> Content-Length: 20
>
* upload completely sent off: 20 bytes
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Length: 0
< ETag: "46d9a8f8877d8ad8ee4b8758b6e0719f"
< Server: MinIO
< Strict-Transport-Security: max-age=31536000; includeSubDomains
< Vary: Origin
< Vary: Accept-Encoding
< X-Amz-Id-2: dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8
< X-Amz-Request-Id: 187F359E3401C054
< X-Content-Type-Options: nosniff
< X-Ratelimit-Limit: 4482
< X-Ratelimit-Remaining: 4482
< X-Xss-Protection: 1; mode=block
< Date: Mon, 08 Dec 2025 10:08:52 GMT
<
* Connection #0 to host minio:9000 left intact
Downloading file back...
* Host minio:9000 was resolved.
* IPv6: (none)
* IPv4: 172.18.0.2
* Trying 172.18.0.2:9000...
* Established connection to minio (172.18.0.2 port 9000) from 172.18.0.3 port 38650
* using HTTP/1.x
> GET /bucket/data.json HTTP/1.1
> Host: minio:9000
> User-Agent: curl/8.17.0
> Accept: */*
> Accept-Encoding: deflate, gzip, br, zstd
>
* Request completely sent off
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Encoding: br
< Content-Length: 20
< Content-Type: application/json
< ETag: "46d9a8f8877d8ad8ee4b8758b6e0719f"
< Last-Modified: Mon, 08 Dec 2025 10:08:52 GMT
< Server: MinIO
< Strict-Transport-Security: max-age=31536000; includeSubDomains
< Vary: Origin
< Vary: Accept-Encoding
< X-Amz-Id-2: dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8
< X-Amz-Request-Id: 187F359E3473EB85
< X-Content-Type-Options: nosniff
< X-Ratelimit-Limit: 4482
< X-Ratelimit-Remaining: 4482
< X-Xss-Protection: 1; mode=block
< Date: Mon, 08 Dec 2025 10:08:52 GMT
<
{ [20 bytes data]
* Connection #0 to host minio:9000 left intact
Show original file...
{"msg":"hello"}
Show downloaded file...
{"msg":"hello"}
Comparing raw bytes...
SUCCESS: Files match
Desktop (please complete the following information):
Rancher Desktop (on Windows host) running rustfs docker image:
rustfs 1.0.0-alpha.72
build time : 2025-12-05 05:18:43 +00:00
build profile: release
build os : linux-x86_64
rust version : rustc 1.91.1 (ed61e7d7e 2025-11-07)
rust channel : stable-x86_64-unknown-linux-gnu
git branch :
git commit : 63d846ed145cbab606437ac6f6d5f38ceae24bcb
git tag : 1.0.0-alpha.72
git status :
Additional context
Is there some setting we need to adjust in RustFS to make it behave the same way as MinIO and AWS S3 when using Content-Encoding for uploaded objects?