Closed riftsin closed 7 months ago
PutObject does not add Content-Length in the headers when it is specified in the parameters and the body is not Seekable
I don't think this is the case. Consider the following snippet, built with the express purpose of testing this claim (based heavily on what you provided, but removing the asynchronous aspect):
package main
import (
"context"
"io"
"log"
"github.com/aws/aws-sdk-go-v2/aws"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
type reader string
var _ io.Reader = reader("")
func (r reader) Read(p []byte) (int, error) {
copy(p, r)
return len(r), nil
}
func main() {
cfg, err := config.LoadDefaultConfig(context.Background())
if err != nil {
log.Fatal(err)
}
s3Client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.ClientLogMode = aws.LogRequest | aws.LogResponse
})
str := reader("just some random data")
_, err = s3Client.PutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String("<bucket>"),
Key: aws.String("screenshot.png"),
Body: str,
ContentLength: aws.Int64(int64(len(str))),
}, s3.WithAPIOptions(v4.SwapComputePayloadSHA256ForUnsignedPayloadMiddleware))
if err != nil {
log.Println(err)
}
}
I'm seeing this upload successfully (with the content-length header included in the request) against the latest modules.
I have a few followup asks, related to your snippet as posted:
1. We can't see the source of
s3Client.optionFunc
, which may very well matter. Given its unexportedness I assume you've wrapped our client with your own structure that has this field.2. You mentioned you removed some boilerplate, but your snippet as it's presented here isn't really functional because the inner goroutine that calls the operation is basically guaranteed to get dropped before it completes, since the outer main
is going to return first. I can only assume there's other things going on in your application surrounding this, which are almost certainly going to be relevant as far as root-causing this is concerned.
I missed the chunked
Transfer-Encoding on the first pass. With some basic WaitGroup
ops surrounding your snippet I can reproduce this.
We appear to have a special case internally for io.PipeReader
that is causing us to send invalid signatures with this request configuration.
Since we've demonstrated that content-length + non-seekable body does work in the general sense, I'm going to close this issue and open a new one to track the PipeReader
issue separately.
This issue is now closed. Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one.
Describe the bug
Hello,
When you do a PutObject like this:
You get a
SignatureDoesMatchError
.The reason for this is that the header Content-Length is not set in the Request as you can see in the following logs (even though it is set in the canonical request)
Expected Behavior
I would expect the content length to be set when I specifiy it using the Content-Length parameter of PutObject.
Current Behavior
The Content-Length header is not set and therefore the request fails with a SignatureDoesNotMatch error.
Reproduction Steps
Just use the code in the example (left out the boiler plate)
Possible Solution
No response
Additional Information/Context
No response
AWS Go SDK V2 Module Versions Used
In the example this was used
However I have tested it with aws-sdk-go-v2 v1.25.0 and I get the same behavior
Compiler and Version used
1.22 darwin/arm64
Operating System and version
MacOS Ventura