Skip to content

Commit 2c3e863

Browse files
cojencotritone
andauthored
fix(gensupport): allow initial request for resumable uploads to retry w/ non-nil getBody (#1690)
This allows retries when initiating a resumable upload session. Add support in media.go to return a getBody function so the request body can be recreated during retry attempts. Tests pass locally in google-cloud-go/storage Updates googleapis/google-cloud-go#6652 Co-authored-by: Chris Cotter <cjcotter@google.com>
1 parent f427ee3 commit 2c3e863

2 files changed

Lines changed: 22 additions & 12 deletions

File tree

internal/gensupport/media.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -289,13 +289,12 @@ func (mi *MediaInfo) UploadRequest(reqHeaders http.Header, body io.Reader) (newB
289289
// be retried because the data is stored in the MediaBuffer.
290290
media, _, _, _ = mi.buffer.Chunk()
291291
}
292+
toCleanup := []io.Closer{}
292293
if media != nil {
293294
fb := readerFunc(body)
294295
fm := readerFunc(media)
295296
combined, ctype := CombineBodyMedia(body, "application/json", media, mi.mType)
296-
toCleanup := []io.Closer{
297-
combined,
298-
}
297+
toCleanup = append(toCleanup, combined)
299298
if fb != nil && fm != nil {
300299
getBody = func() (io.ReadCloser, error) {
301300
rb := ioutil.NopCloser(fb())
@@ -309,18 +308,30 @@ func (mi *MediaInfo) UploadRequest(reqHeaders http.Header, body io.Reader) (newB
309308
return r, nil
310309
}
311310
}
312-
cleanup = func() {
313-
for _, closer := range toCleanup {
314-
_ = closer.Close()
315-
}
316-
317-
}
318311
reqHeaders.Set("Content-Type", ctype)
319312
body = combined
320313
}
321314
if mi.buffer != nil && mi.mType != "" && !mi.singleChunk {
315+
// This happens when initiating a resumable upload session.
316+
// The initial request contains a JSON body rather than media.
317+
// It can be retried with a getBody function that re-creates the request body.
318+
fb := readerFunc(body)
319+
if fb != nil {
320+
getBody = func() (io.ReadCloser, error) {
321+
rb := ioutil.NopCloser(fb())
322+
toCleanup = append(toCleanup, rb)
323+
return rb, nil
324+
}
325+
}
322326
reqHeaders.Set("X-Upload-Content-Type", mi.mType)
323327
}
328+
// Ensure that any bodies created in getBody are cleaned up.
329+
cleanup = func() {
330+
for _, closer := range toCleanup {
331+
_ = closer.Close()
332+
}
333+
334+
}
324335
return body, getBody, cleanup
325336
}
326337

internal/gensupport/media_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,12 +309,11 @@ func TestUploadRequestGetBody(t *testing.T) {
309309
wantGetBody: true,
310310
},
311311
{
312-
desc: "chunk size < data size: MediaBuffer, >1 chunk, no getBody",
313-
// No getBody here, because the initial request contains no media data
312+
desc: "chunk size < data size: MediaBuffer, >1 chunk, getBody",
314313
// Note that ChunkSize = 1 is rounded up to googleapi.MinUploadChunkSize.
315314
r: &nullReader{2 * googleapi.MinUploadChunkSize},
316315
chunkSize: 1,
317-
wantGetBody: false,
316+
wantGetBody: true,
318317
},
319318
} {
320319
cryptorand.Reader = mathrand.New(mathrand.NewSource(int64(i)))

0 commit comments

Comments
 (0)