b2: fixed regression when uploading zero-length blobs introduced by #1589 (#1593)

Turns out B2 library will treat seekable readers in a special way
and will pass those directly to http.NewRequest() for upload. Other
readers are copied to a temporary buffer first.

The #1589 made the reader io.ReadSeeker so it was passed to http.NewRequest(),
which for payloads of length zero uses heuristics to determine if the
Content-Length should be passed as zero or not passed at all.

https://cs.opensource.google/go/go/+/refs/tags/go1.17.5:src/net/http/request.go;l=890;drc=e6dda19888180c5159460486d30c0412e4980748

Since reader was not one of the magic types, Content-Length was not
passed at all, causing B2 server to choke on zero-length files.
This commit is contained in:
Jarek Kowalski
2021-12-16 15:20:07 -08:00
committed by GitHub
parent 3d907481e1
commit 6d38db0623

View File

@@ -4,6 +4,7 @@
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"time"
@@ -139,7 +140,16 @@ func translateError(err error) error {
func (s *b2Storage) PutBlob(ctx context.Context, id blob.ID, data blob.Bytes, opts blob.PutOptions) error {
fileName := s.getObjectNameString(id)
_, err := s.bucket.UploadFile(fileName, nil, data.Reader())
// Backblaze always expects Content-Length to be set, even in http.Request ContentLength==0
// can mean "unknown" or "zero". http.Request used by B2 client requires http.NoBody to
// reliably pass zero length to the server as opposed to not passing it at all.
var r io.Reader = data.Reader()
if data.Length() == 0 {
r = http.NoBody
}
_, err := s.bucket.UploadFile(fileName, nil, r)
return translateError(err)
}