Skip to content

Commit 448305c

Browse files
authored
Allow uploading files with zero size (#274)
* Allow uploading files with zero size * Fix test so that it actually fails without the fix
1 parent 93b33aa commit 448305c

2 files changed

Lines changed: 38 additions & 1 deletion

File tree

pkg/storage/repo.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,16 @@ func (r *Repo) List(ctx context.Context, ownerId, region, cursor string, limit i
133133

134134
// UploadToPresignedURL uploads file content to a presigned URL
135135
func (r *Repo) UploadToPresignedURL(ctx context.Context, presignedURL string, content io.Reader, contentLength int64) error {
136-
req, err := http.NewRequestWithContext(ctx, http.MethodPut, presignedURL, content)
136+
body := content
137+
if contentLength == 0 {
138+
// In Go's net/http, a ContentLength of 0 with a non-nil Body is treated as
139+
// unknown, causing the client to use chunked transfer encoding. Presigned S3
140+
// URLs do not support chunked encoding, so we use http.NoBody to ensure
141+
// Content-Length: 0 is sent instead.
142+
body = http.NoBody
143+
}
144+
145+
req, err := http.NewRequestWithContext(ctx, http.MethodPut, presignedURL, body)
137146
if err != nil {
138147
return fmt.Errorf("failed to create upload request: %w", err)
139148
}

pkg/storage/repo_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package storage
33
import (
44
"bytes"
55
"context"
6+
"io"
67
"net/http"
78
"net/http/httptest"
89
"strings"
@@ -253,3 +254,30 @@ func TestUploadToPresignedURL_Success(t *testing.T) {
253254
require.NoError(t, err)
254255
require.Equal(t, content, receivedContent.String())
255256
}
257+
258+
func TestUploadToPresignedURL_ZeroLength(t *testing.T) {
259+
var receivedContentLength int64
260+
var receivedTransferEncoding []string
261+
262+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
263+
receivedContentLength = r.ContentLength
264+
receivedTransferEncoding = r.TransferEncoding
265+
w.WriteHeader(http.StatusOK)
266+
}))
267+
defer server.Close()
268+
269+
repo := &Repo{
270+
httpClient: server.Client(),
271+
}
272+
273+
// NopCloser wraps the buffer so net/http can't type-switch on it.
274+
// Without this, net/http detects the empty body and skips chunked
275+
// encoding, which would mask the bug this test is meant to catch.
276+
body := io.NopCloser(&bytes.Buffer{})
277+
278+
err := repo.UploadToPresignedURL(context.Background(), server.URL, body, 0)
279+
280+
require.NoError(t, err)
281+
require.Equal(t, int64(0), receivedContentLength, "server should receive Content-Length: 0")
282+
require.Empty(t, receivedTransferEncoding, "should not use chunked transfer encoding")
283+
}

0 commit comments

Comments
 (0)