diff --git a/internal/gensupport/resumable.go b/internal/gensupport/resumable.go index 0fb74606c3a..6796a07c984 100644 --- a/internal/gensupport/resumable.go +++ b/internal/gensupport/resumable.go @@ -177,6 +177,22 @@ func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err return prepareReturn(resp, err) } + // Check for context cancellation or timeout once more. If more than one + // case in the select statement above was satisfied at the same time, Go + // will choose one arbitrarily. + // That can cause an operation to go through even if the context was + // canceled before or the timeout was reached. + select { + case <-ctx.Done(): + if err == nil { + err = ctx.Err() + } + return prepareReturn(resp, err) + case <-quitAfter: + return prepareReturn(resp, err) + default: + } + resp, err = rx.transferChunk(ctx) var status int diff --git a/internal/gensupport/resumable_test.go b/internal/gensupport/resumable_test.go index 44544f7d71c..bffd88098e2 100644 --- a/internal/gensupport/resumable_test.go +++ b/internal/gensupport/resumable_test.go @@ -213,9 +213,6 @@ func TestCancelUploadFast(t *testing.T) { tr := &interruptibleTransport{ buf: make([]byte, 0, mediaSize), - // Shouldn't really need an event, but sometimes the test loses the - // race. So, this is just a filler event. - events: []event{{"bytes 0-9/*", http.StatusServiceUnavailable}}, } pr := progressRecorder{}