"Fossies" - the Fresh Open Source Software Archive 
Member "gdrive-2.1.1/vendor/google.golang.org/api/gensupport/resumable.go" (28 May 2021, 5543 Bytes) of package /linux/misc/gdrive-2.1.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package gensupport
6
7 import (
8 "fmt"
9 "io"
10 "net/http"
11 "sync"
12 "time"
13
14 "golang.org/x/net/context"
15 "golang.org/x/net/context/ctxhttp"
16 )
17
18 const (
19 // statusResumeIncomplete is the code returned by the Google uploader
20 // when the transfer is not yet complete.
21 statusResumeIncomplete = 308
22
23 // statusTooManyRequests is returned by the storage API if the
24 // per-project limits have been temporarily exceeded. The request
25 // should be retried.
26 // https://cloud.google.com/storage/docs/json_api/v1/status-codes#standardcodes
27 statusTooManyRequests = 429
28 )
29
30 // ResumableUpload is used by the generated APIs to provide resumable uploads.
31 // It is not used by developers directly.
32 type ResumableUpload struct {
33 Client *http.Client
34 // URI is the resumable resource destination provided by the server after specifying "&uploadType=resumable".
35 URI string
36 UserAgent string // User-Agent for header of the request
37 // Media is the object being uploaded.
38 Media *ResumableBuffer
39 // MediaType defines the media type, e.g. "image/jpeg".
40 MediaType string
41
42 mu sync.Mutex // guards progress
43 progress int64 // number of bytes uploaded so far
44
45 // Callback is an optional function that will be periodically called with the cumulative number of bytes uploaded.
46 Callback func(int64)
47
48 // If not specified, a default exponential backoff strategy will be used.
49 Backoff BackoffStrategy
50 }
51
52 // Progress returns the number of bytes uploaded at this point.
53 func (rx *ResumableUpload) Progress() int64 {
54 rx.mu.Lock()
55 defer rx.mu.Unlock()
56 return rx.progress
57 }
58
59 // doUploadRequest performs a single HTTP request to upload data.
60 // off specifies the offset in rx.Media from which data is drawn.
61 // size is the number of bytes in data.
62 // final specifies whether data is the final chunk to be uploaded.
63 func (rx *ResumableUpload) doUploadRequest(ctx context.Context, data io.Reader, off, size int64, final bool) (*http.Response, error) {
64 req, err := http.NewRequest("POST", rx.URI, data)
65 if err != nil {
66 return nil, err
67 }
68
69 req.ContentLength = size
70 var contentRange string
71 if final {
72 if size == 0 {
73 contentRange = fmt.Sprintf("bytes */%v", off)
74 } else {
75 contentRange = fmt.Sprintf("bytes %v-%v/%v", off, off+size-1, off+size)
76 }
77 } else {
78 contentRange = fmt.Sprintf("bytes %v-%v/*", off, off+size-1)
79 }
80 req.Header.Set("Content-Range", contentRange)
81 req.Header.Set("Content-Type", rx.MediaType)
82 req.Header.Set("User-Agent", rx.UserAgent)
83 return ctxhttp.Do(ctx, rx.Client, req)
84
85 }
86
87 // reportProgress calls a user-supplied callback to report upload progress.
88 // If old==updated, the callback is not called.
89 func (rx *ResumableUpload) reportProgress(old, updated int64) {
90 if updated-old == 0 {
91 return
92 }
93 rx.mu.Lock()
94 rx.progress = updated
95 rx.mu.Unlock()
96 if rx.Callback != nil {
97 rx.Callback(updated)
98 }
99 }
100
101 // transferChunk performs a single HTTP request to upload a single chunk from rx.Media.
102 func (rx *ResumableUpload) transferChunk(ctx context.Context) (*http.Response, error) {
103 chunk, off, size, err := rx.Media.Chunk()
104
105 done := err == io.EOF
106 if !done && err != nil {
107 return nil, err
108 }
109
110 res, err := rx.doUploadRequest(ctx, chunk, off, int64(size), done)
111 if err != nil {
112 return res, err
113 }
114
115 if res.StatusCode == statusResumeIncomplete || res.StatusCode == http.StatusOK {
116 rx.reportProgress(off, off+int64(size))
117 }
118
119 if res.StatusCode == statusResumeIncomplete {
120 rx.Media.Next()
121 }
122 return res, nil
123 }
124
125 func contextDone(ctx context.Context) bool {
126 select {
127 case <-ctx.Done():
128 return true
129 default:
130 return false
131 }
132 }
133
134 // Upload starts the process of a resumable upload with a cancellable context.
135 // It retries using the provided back off strategy until cancelled or the
136 // strategy indicates to stop retrying.
137 // It is called from the auto-generated API code and is not visible to the user.
138 // rx is private to the auto-generated API code.
139 // Exactly one of resp or err will be nil. If resp is non-nil, the caller must call resp.Body.Close.
140 func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err error) {
141 var pause time.Duration
142 backoff := rx.Backoff
143 if backoff == nil {
144 backoff = DefaultBackoffStrategy()
145 }
146
147 for {
148 // Ensure that we return in the case of cancelled context, even if pause is 0.
149 if contextDone(ctx) {
150 return nil, ctx.Err()
151 }
152 select {
153 case <-ctx.Done():
154 return nil, ctx.Err()
155 case <-time.After(pause):
156 }
157
158 resp, err = rx.transferChunk(ctx)
159
160 var status int
161 if resp != nil {
162 status = resp.StatusCode
163 }
164
165 // Check if we should retry the request.
166 if shouldRetry(status, err) {
167 var retry bool
168 pause, retry = backoff.Pause()
169 if retry {
170 if resp != nil && resp.Body != nil {
171 resp.Body.Close()
172 }
173 continue
174 }
175 }
176
177 // If the chunk was uploaded successfully, but there's still
178 // more to go, upload the next chunk without any delay.
179 if status == statusResumeIncomplete {
180 pause = 0
181 backoff.Reset()
182 resp.Body.Close()
183 continue
184 }
185
186 // It's possible for err and resp to both be non-nil here, but we expose a simpler
187 // contract to our callers: exactly one of resp and err will be non-nil. This means
188 // that any response body must be closed here before returning a non-nil error.
189 if err != nil {
190 if resp != nil && resp.Body != nil {
191 resp.Body.Close()
192 }
193 return nil, err
194 }
195
196 return resp, nil
197 }
198 }