Copyright 2016 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package gensupport

import (
	
	
	
	
	
	
	

	gax 
)
Backoff is an interface around gax.Backoff's Pause method, allowing tests to provide their own implementation.
type Backoff interface {
	Pause() time.Duration
}
These are declared as global variables so that tests can overwrite them.
var (
	retryDeadline = 32 * time.Second
	backoff       = func() Backoff {
		return &gax.Backoff{Initial: 100 * time.Millisecond}
isRetryable is a platform-specific hook, specified in retryable_linux.go
	syscallRetryable func(error) bool = func( error) bool { return false }
)

statusTooManyRequests is returned by the storage API if the per-project limits have been temporarily exceeded. The request should be retried. https://cloud.google.com/storage/docs/json_api/v1/status-codes#standardcodes
ResumableUpload is used by the generated APIs to provide resumable uploads. It is not used by developers directly.
type ResumableUpload struct {
URI is the resumable resource destination provided by the server after specifying "&uploadType=resumable".
Media is the object being uploaded.
MediaType defines the media type, e.g. "image/jpeg".
	MediaType string

	mu       sync.Mutex // guards progress
	progress int64      // number of bytes uploaded so far
Callback is an optional function that will be periodically called with the cumulative number of bytes uploaded.
	Callback func(int64)
}
Progress returns the number of bytes uploaded at this point.
func ( *ResumableUpload) () int64 {
	.mu.Lock()
	defer .mu.Unlock()
	return .progress
}
doUploadRequest performs a single HTTP request to upload data. off specifies the offset in rx.Media from which data is drawn. size is the number of bytes in data. final specifies whether data is the final chunk to be uploaded.
func ( *ResumableUpload) ( context.Context,  io.Reader, ,  int64,  bool) (*http.Response, error) {
	,  := http.NewRequest("POST", .URI, )
	if  != nil {
		return nil, 
	}

	.ContentLength = 
	var  string
	if  {
		if  == 0 {
			 = fmt.Sprintf("bytes */%v", )
		} else {
			 = fmt.Sprintf("bytes %v-%v/%v", , +-1, +)
		}
	} else {
		 = fmt.Sprintf("bytes %v-%v/*", , +-1)
	}
	.Header.Set("Content-Range", )
	.Header.Set("Content-Type", .MediaType)
	.Header.Set("User-Agent", .UserAgent)
Google's upload endpoint uses status code 308 for a different purpose than the "308 Permanent Redirect" since-standardized in RFC 7238. Because of the conflict in semantics, Google added this new request header which causes it to not use "308" and instead reply with 200 OK and sets the upload-specific "X-HTTP-Status-Code-Override: 308" response header.
	.Header.Set("X-GUploader-No-308", "yes")

	return SendRequest(, .Client, )
}

This is how the server signals "status resume incomplete" when X-GUploader-No-308 is set to "yes":
	return  != nil && .Header.Get("X-Http-Status-Code-Override") == "308"
}
reportProgress calls a user-supplied callback to report upload progress. If old==updated, the callback is not called.
func ( *ResumableUpload) (,  int64) {
	if - == 0 {
		return
	}
	.mu.Lock()
	.progress = 
	.mu.Unlock()
	if .Callback != nil {
		.Callback()
	}
}
transferChunk performs a single HTTP request to upload a single chunk from rx.Media.
func ( *ResumableUpload) ( context.Context) (*http.Response, error) {
	, , ,  := .Media.Chunk()

	 :=  == io.EOF
	if ! &&  != nil {
		return nil, 
	}

	,  := .doUploadRequest(, , , int64(), )
	if  != nil {
		return , 
	}
We sent "X-GUploader-No-308: yes" (see comment elsewhere in this file), so we don't expect to get a 308.
	if .StatusCode == 308 {
		return nil, errors.New("unexpected 308 response status code")
	}

	if .StatusCode == http.StatusOK {
		.reportProgress(, +int64())
	}

	if statusResumeIncomplete() {
		.Media.Next()
	}
	return , nil
}
Upload starts the process of a resumable upload with a cancellable context. It retries using the provided back off strategy until cancelled or the strategy indicates to stop retrying. It is called from the auto-generated API code and is not visible to the user. Before sending an HTTP request, Upload calls any registered hook functions, and calls the returned functions after the request returns (see send.go). rx is private to the auto-generated API code. Exactly one of resp or err will be nil. If resp is non-nil, the caller must call resp.Body.Close.
func ( *ResumableUpload) ( context.Context) ( *http.Response,  error) {
There are a couple of cases where it's possible for err and resp to both be non-nil. However, we expose a simpler contract to our callers: exactly one of resp and err will be non-nil. This means that any response body must be closed here before returning a non-nil error.
	var  = func( *http.Response,  error) (*http.Response, error) {
		if  != nil {
			if  != nil && .Body != nil {
				.Body.Close()
			}
			return nil, 
		}
		return , nil
	}
Send all chunks.
	for {
		var  time.Duration
Each chunk gets its own initialized-at-zero retry.
		 := backoff()
		 := time.After(retryDeadline)
Retry loop for a single chunk.
		for {
			select {
			case <-.Done():
				if  == nil {
					 = .Err()
				}
				return (, )
			case <-time.After():
			case <-:
				return (, )
			}

			,  = .transferChunk()

			var  int
			if  != nil {
				 = .StatusCode
			}
Check if we should retry the request.
			if !shouldRetry(, ) {
				break
			}

			 = .Pause()
			if  != nil && .Body != nil {
				.Body.Close()
			}
		}
If the chunk was uploaded successfully, but there's still more to go, upload the next chunk without any delay.
		if statusResumeIncomplete() {
			.Body.Close()
			continue
		}

		return (, )
	}
}
shouldRetry indicates whether an error is retryable for the purposes of this package, following guidance from https://cloud.google.com/storage/docs/exponential-backoff .
func ( int,  error) bool {
	if 500 <=  &&  <= 599 {
		return true
	}
	if  == statusTooManyRequests {
		return true
	}
	if  == io.ErrUnexpectedEOF {
		return true
Transient network errors should be retried.
	if syscallRetryable() {
		return true
	}
	if ,  := .(interface{ () bool });  {
		if .() {
			return true
		}
If Go 1.13 error unwrapping is available, use this to examine wrapped errors.
	if ,  := .(interface{ () error });  {
		return (, .())
	}
	return false