content-length
on HEAD
object #805
Labels
No labels
action
check-aws
action
discussion-needed
action
for-external-contributors
action
for-newcomers
action
more-info-needed
action
need-funding
action
triage-required
kind
correctness
kind
ideas
kind
improvement
kind
performance
kind
testing
kind
usability
kind
wrong-behavior
prio
critical
prio
low
scope
admin-api
scope
background-healing
scope
build
scope
documentation
scope
k8s
scope
layout
scope
metadata
scope
ops
scope
rpc
scope
s3-api
scope
security
scope
telemetry
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Deuxfleurs/garage#805
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Hey,
I just stumbled about a difference to the behavior of Minio, which I have been using until now, on
HEAD
requests for an object.When I do a
HEAD
, Minio sets thecontent-length
header to the actual file / object size in bytes, while Garage seems to set the value to the length of the actualHEAD
request itself (I guess).I used
HEAD
to fetch information about file sizes of my object on S3. This logic breaks of course when Garage is returning a different value.I am not sure which is the correct implementation. I am currently writing a minimal, fast s3 bucket crud client with connection pooling and being optimized to serve lots of files frequently. The currently existing Rust implementations have all their flaws unfortunately.
I just stumbled about it because some of my test cases started failing when I switched to Garage.
I am currently running
Edit:
I just created a new container image for v1.0.0 and tested with it, which returns the same results.
Does this work correctly on older versions such as 0.9.0 and 0.8.6?
The code should return the size of the object as saved in the object's metadata, bit maybe that information is wrong, although that would be strange as it should cause asserts or errors at other places
I can do some tests later. So far I tested only 0.9.3 and the stable v1.0.0.
I did add some integration tests for the library and when Minio returns exactly
128_000
in thecontent_length
for my exactly 128kB file, I got something like 221 back from Garage.I will report back when I tested against 0.9.0 or 0.8.6. I just have to build container images for this, because I am using it inside K8s and I did not find a way to interact with the cluster easily without having access to the
garage
binary inside the container. Maybe I missed something there, but I basically build my own images with almalinux:minimal to then be able toalias garage='kubectl -n garage exec -it garage-0 -- ./garage'
.But I will do tests and give feedback.
I could also extract the raw answer from Garage from the test case.
I was actually able to solve it.
I digged deeper into the problem and it was partly my fault as well.
I did not check the return code, only extracted headers and saw the
content-length
not being correct.What I actually got back from Garage was an
HTTP 400
with an empty body, body the following headers:The reason for this was actually pretty tricky. I only found it because I found problems with
DeleteObject
andGetObjectRange
as well, which returned the following error:The
content-length
was present. I always added it to the signed headers by default, even when there was no content and thencontent-length
was actually0
. This worked fine with Minio, but Garage returned an error that the header would not be there, even when it was. I don't know the reason for this.As soon as I added excluded the
content-length: 0
for:DeleteObject
GetObjectRange
HeadObject
the problems all went away.
There is a difference in API behavior to Minio though, which I am using as a reference here, but this was partly my fault, sorry about the issue in that case.
I know that a few currently existing rust s3 crates add the
content-length: 0
as well, because I re-used parts of the signature algorithm from existing crates, but with the exclusion it works for Minio and Garage at the same time, so I will just leave it out for compatibility.I don't know if you want to investigate this difference further, but I guess the issue can be closed.
Edit:
There is just one additional thing I noticed in this case.
Even when I add
content-length: 0
while doing aGetObjectRange
, I receive anHTTP 400
but actually with the body I would only expect from anHTTP 206
.Hello @sebadob -- I am stuck on the same issue as you, but because I've been trying to use the ExAws.S3 library for Elixir with garage, I am at a loss at how to work around this.
"As soon as I added excluded the content-length: 0" -> should I add or exclude this header parameter for garage?
I'm using bruno (postman alternative) to make a HEAD request to the bucket for a known existing key. I'm using AWS Sig V4 authentication settings and provide my Access Key ID, my Secret Access Key, and the "garage" bucket.
This is the response headers.
Interestingly, generating a presigned URL for a GET request works. However, generating a presigned URL for a HEAD request results in this:
There must be a mismatch between what the signature signs (which includes the headers) and what the actual headers are. Any ideas?
Here's something new I found out when enabling debug logs:
Also, using awscli works:
This is what I get in the garage logs:
Here,
content-length
is entirely missing.Edit: I fixed it by overriding ExAws's code for
head_object
to avoid adding thecontent-length
header and thus also not including it into theSignedHeaders
list of theauthorization
header.Can we conclude from this that the spec is that
content-length
should not be included in the headers for HeadObject?Related PR on
ex_aws
on Github