aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/google.golang.org/api/gensupport
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/google.golang.org/api/gensupport')
-rw-r--r--vendor/google.golang.org/api/gensupport/backoff.go51
-rw-r--r--vendor/google.golang.org/api/gensupport/buffer.go79
-rw-r--r--vendor/google.golang.org/api/gensupport/doc.go10
-rw-r--r--vendor/google.golang.org/api/gensupport/header.go22
-rw-r--r--vendor/google.golang.org/api/gensupport/json.go211
-rw-r--r--vendor/google.golang.org/api/gensupport/jsonfloat.go57
-rw-r--r--vendor/google.golang.org/api/gensupport/media.go342
-rw-r--r--vendor/google.golang.org/api/gensupport/params.go51
-rw-r--r--vendor/google.golang.org/api/gensupport/resumable.go216
-rw-r--r--vendor/google.golang.org/api/gensupport/retry.go84
-rw-r--r--vendor/google.golang.org/api/gensupport/send.go87
11 files changed, 1210 insertions, 0 deletions
diff --git a/vendor/google.golang.org/api/gensupport/backoff.go b/vendor/google.golang.org/api/gensupport/backoff.go
new file mode 100644
index 0000000..94b7789
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/backoff.go
@@ -0,0 +1,51 @@
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
5package gensupport
6
7import (
8 "math/rand"
9 "time"
10)
11
12// BackoffStrategy defines the set of functions that a backoff-er must
13// implement.
14type BackoffStrategy interface {
15 // Pause returns the duration of the next pause and true if the operation should be
16 // retried, or false if no further retries should be attempted.
17 Pause() (time.Duration, bool)
18
19 // Reset restores the strategy to its initial state.
20 Reset()
21}
22
23// ExponentialBackoff performs exponential backoff as per https://en.wikipedia.org/wiki/Exponential_backoff.
24// The initial pause time is given by Base.
25// Once the total pause time exceeds Max, Pause will indicate no further retries.
26type ExponentialBackoff struct {
27 Base time.Duration
28 Max time.Duration
29 total time.Duration
30 n uint
31}
32
33// Pause returns the amount of time the caller should wait.
34func (eb *ExponentialBackoff) Pause() (time.Duration, bool) {
35 if eb.total > eb.Max {
36 return 0, false
37 }
38
39 // The next pause is selected from randomly from [0, 2^n * Base).
40 d := time.Duration(rand.Int63n((1 << eb.n) * int64(eb.Base)))
41 eb.total += d
42 eb.n++
43 return d, true
44}
45
46// Reset resets the backoff strategy such that the next Pause call will begin
47// counting from the start. It is not safe to call concurrently with Pause.
48func (eb *ExponentialBackoff) Reset() {
49 eb.n = 0
50 eb.total = 0
51}
diff --git a/vendor/google.golang.org/api/gensupport/buffer.go b/vendor/google.golang.org/api/gensupport/buffer.go
new file mode 100644
index 0000000..3d0817e
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/buffer.go
@@ -0,0 +1,79 @@
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
5package gensupport
6
7import (
8 "bytes"
9 "io"
10
11 "google.golang.org/api/googleapi"
12)
13
14// MediaBuffer buffers data from an io.Reader to support uploading media in
15// retryable chunks. It should be created with NewMediaBuffer.
16type MediaBuffer struct {
17 media io.Reader
18
19 chunk []byte // The current chunk which is pending upload. The capacity is the chunk size.
20 err error // Any error generated when populating chunk by reading media.
21
22 // The absolute position of chunk in the underlying media.
23 off int64
24}
25
26// NewMediaBuffer initializes a MediaBuffer.
27func NewMediaBuffer(media io.Reader, chunkSize int) *MediaBuffer {
28 return &MediaBuffer{media: media, chunk: make([]byte, 0, chunkSize)}
29}
30
31// Chunk returns the current buffered chunk, the offset in the underlying media
32// from which the chunk is drawn, and the size of the chunk.
33// Successive calls to Chunk return the same chunk between calls to Next.
34func (mb *MediaBuffer) Chunk() (chunk io.Reader, off int64, size int, err error) {
35 // There may already be data in chunk if Next has not been called since the previous call to Chunk.
36 if mb.err == nil && len(mb.chunk) == 0 {
37 mb.err = mb.loadChunk()
38 }
39 return bytes.NewReader(mb.chunk), mb.off, len(mb.chunk), mb.err
40}
41
42// loadChunk will read from media into chunk, up to the capacity of chunk.
43func (mb *MediaBuffer) loadChunk() error {
44 bufSize := cap(mb.chunk)
45 mb.chunk = mb.chunk[:bufSize]
46
47 read := 0
48 var err error
49 for err == nil && read < bufSize {
50 var n int
51 n, err = mb.media.Read(mb.chunk[read:])
52 read += n
53 }
54 mb.chunk = mb.chunk[:read]
55 return err
56}
57
58// Next advances to the next chunk, which will be returned by the next call to Chunk.
59// Calls to Next without a corresponding prior call to Chunk will have no effect.
60func (mb *MediaBuffer) Next() {
61 mb.off += int64(len(mb.chunk))
62 mb.chunk = mb.chunk[0:0]
63}
64
65type readerTyper struct {
66 io.Reader
67 googleapi.ContentTyper
68}
69
70// ReaderAtToReader adapts a ReaderAt to be used as a Reader.
71// If ra implements googleapi.ContentTyper, then the returned reader
72// will also implement googleapi.ContentTyper, delegating to ra.
73func ReaderAtToReader(ra io.ReaderAt, size int64) io.Reader {
74 r := io.NewSectionReader(ra, 0, size)
75 if typer, ok := ra.(googleapi.ContentTyper); ok {
76 return readerTyper{r, typer}
77 }
78 return r
79}
diff --git a/vendor/google.golang.org/api/gensupport/doc.go b/vendor/google.golang.org/api/gensupport/doc.go
new file mode 100644
index 0000000..752c4b4
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/doc.go
@@ -0,0 +1,10 @@
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 is an internal implementation detail used by code
6// generated by the google-api-go-generator tool.
7//
8// This package may be modified at any time without regard for backwards
9// compatibility. It should not be used directly by API users.
10package gensupport
diff --git a/vendor/google.golang.org/api/gensupport/header.go b/vendor/google.golang.org/api/gensupport/header.go
new file mode 100644
index 0000000..cb5e67c
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/header.go
@@ -0,0 +1,22 @@
1// Copyright 2017 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
5package gensupport
6
7import (
8 "fmt"
9 "runtime"
10 "strings"
11)
12
13// GoogleClientHeader returns the value to use for the x-goog-api-client
14// header, which is used internally by Google.
15func GoogleClientHeader(generatorVersion, clientElement string) string {
16 elts := []string{"gl-go/" + strings.Replace(runtime.Version(), " ", "_", -1)}
17 if clientElement != "" {
18 elts = append(elts, clientElement)
19 }
20 elts = append(elts, fmt.Sprintf("gdcl/%s", generatorVersion))
21 return strings.Join(elts, " ")
22}
diff --git a/vendor/google.golang.org/api/gensupport/json.go b/vendor/google.golang.org/api/gensupport/json.go
new file mode 100644
index 0000000..c01e321
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/json.go
@@ -0,0 +1,211 @@
1// Copyright 2015 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
5package gensupport
6
7import (
8 "encoding/json"
9 "fmt"
10 "reflect"
11 "strings"
12)
13
14// MarshalJSON returns a JSON encoding of schema containing only selected fields.
15// A field is selected if any of the following is true:
16// * it has a non-empty value
17// * its field name is present in forceSendFields and it is not a nil pointer or nil interface
18// * its field name is present in nullFields.
19// The JSON key for each selected field is taken from the field's json: struct tag.
20func MarshalJSON(schema interface{}, forceSendFields, nullFields []string) ([]byte, error) {
21 if len(forceSendFields) == 0 && len(nullFields) == 0 {
22 return json.Marshal(schema)
23 }
24
25 mustInclude := make(map[string]bool)
26 for _, f := range forceSendFields {
27 mustInclude[f] = true
28 }
29 useNull := make(map[string]bool)
30 useNullMaps := make(map[string]map[string]bool)
31 for _, nf := range nullFields {
32 parts := strings.SplitN(nf, ".", 2)
33 field := parts[0]
34 if len(parts) == 1 {
35 useNull[field] = true
36 } else {
37 if useNullMaps[field] == nil {
38 useNullMaps[field] = map[string]bool{}
39 }
40 useNullMaps[field][parts[1]] = true
41 }
42 }
43
44 dataMap, err := schemaToMap(schema, mustInclude, useNull, useNullMaps)
45 if err != nil {
46 return nil, err
47 }
48 return json.Marshal(dataMap)
49}
50
51func schemaToMap(schema interface{}, mustInclude, useNull map[string]bool, useNullMaps map[string]map[string]bool) (map[string]interface{}, error) {
52 m := make(map[string]interface{})
53 s := reflect.ValueOf(schema)
54 st := s.Type()
55
56 for i := 0; i < s.NumField(); i++ {
57 jsonTag := st.Field(i).Tag.Get("json")
58 if jsonTag == "" {
59 continue
60 }
61 tag, err := parseJSONTag(jsonTag)
62 if err != nil {
63 return nil, err
64 }
65 if tag.ignore {
66 continue
67 }
68
69 v := s.Field(i)
70 f := st.Field(i)
71
72 if useNull[f.Name] {
73 if !isEmptyValue(v) {
74 return nil, fmt.Errorf("field %q in NullFields has non-empty value", f.Name)
75 }
76 m[tag.apiName] = nil
77 continue
78 }
79
80 if !includeField(v, f, mustInclude) {
81 continue
82 }
83
84 // If map fields are explicitly set to null, use a map[string]interface{}.
85 if f.Type.Kind() == reflect.Map && useNullMaps[f.Name] != nil {
86 ms, ok := v.Interface().(map[string]string)
87 if !ok {
88 return nil, fmt.Errorf("field %q has keys in NullFields but is not a map[string]string", f.Name)
89 }
90 mi := map[string]interface{}{}
91 for k, v := range ms {
92 mi[k] = v
93 }
94 for k := range useNullMaps[f.Name] {
95 mi[k] = nil
96 }
97 m[tag.apiName] = mi
98 continue
99 }
100
101 // nil maps are treated as empty maps.
102 if f.Type.Kind() == reflect.Map && v.IsNil() {
103 m[tag.apiName] = map[string]string{}
104 continue
105 }
106
107 // nil slices are treated as empty slices.
108 if f.Type.Kind() == reflect.Slice && v.IsNil() {
109 m[tag.apiName] = []bool{}
110 continue
111 }
112
113 if tag.stringFormat {
114 m[tag.apiName] = formatAsString(v, f.Type.Kind())
115 } else {
116 m[tag.apiName] = v.Interface()
117 }
118 }
119 return m, nil
120}
121
122// formatAsString returns a string representation of v, dereferencing it first if possible.
123func formatAsString(v reflect.Value, kind reflect.Kind) string {
124 if kind == reflect.Ptr && !v.IsNil() {
125 v = v.Elem()
126 }
127
128 return fmt.Sprintf("%v", v.Interface())
129}
130
131// jsonTag represents a restricted version of the struct tag format used by encoding/json.
132// It is used to describe the JSON encoding of fields in a Schema struct.
133type jsonTag struct {
134 apiName string
135 stringFormat bool
136 ignore bool
137}
138
139// parseJSONTag parses a restricted version of the struct tag format used by encoding/json.
140// The format of the tag must match that generated by the Schema.writeSchemaStruct method
141// in the api generator.
142func parseJSONTag(val string) (jsonTag, error) {
143 if val == "-" {
144 return jsonTag{ignore: true}, nil
145 }
146
147 var tag jsonTag
148
149 i := strings.Index(val, ",")
150 if i == -1 || val[:i] == "" {
151 return tag, fmt.Errorf("malformed json tag: %s", val)
152 }
153
154 tag = jsonTag{
155 apiName: val[:i],
156 }
157
158 switch val[i+1:] {
159 case "omitempty":
160 case "omitempty,string":
161 tag.stringFormat = true
162 default:
163 return tag, fmt.Errorf("malformed json tag: %s", val)
164 }
165
166 return tag, nil
167}
168
169// Reports whether the struct field "f" with value "v" should be included in JSON output.
170func includeField(v reflect.Value, f reflect.StructField, mustInclude map[string]bool) bool {
171 // The regular JSON encoding of a nil pointer is "null", which means "delete this field".
172 // Therefore, we could enable field deletion by honoring pointer fields' presence in the mustInclude set.
173 // However, many fields are not pointers, so there would be no way to delete these fields.
174 // Rather than partially supporting field deletion, we ignore mustInclude for nil pointer fields.
175 // Deletion will be handled by a separate mechanism.
176 if f.Type.Kind() == reflect.Ptr && v.IsNil() {
177 return false
178 }
179
180 // The "any" type is represented as an interface{}. If this interface
181 // is nil, there is no reasonable representation to send. We ignore
182 // these fields, for the same reasons as given above for pointers.
183 if f.Type.Kind() == reflect.Interface && v.IsNil() {
184 return false
185 }
186
187 return mustInclude[f.Name] || !isEmptyValue(v)
188}
189
190// isEmptyValue reports whether v is the empty value for its type. This
191// implementation is based on that of the encoding/json package, but its
192// correctness does not depend on it being identical. What's important is that
193// this function return false in situations where v should not be sent as part
194// of a PATCH operation.
195func isEmptyValue(v reflect.Value) bool {
196 switch v.Kind() {
197 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
198 return v.Len() == 0
199 case reflect.Bool:
200 return !v.Bool()
201 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
202 return v.Int() == 0
203 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
204 return v.Uint() == 0
205 case reflect.Float32, reflect.Float64:
206 return v.Float() == 0
207 case reflect.Interface, reflect.Ptr:
208 return v.IsNil()
209 }
210 return false
211}
diff --git a/vendor/google.golang.org/api/gensupport/jsonfloat.go b/vendor/google.golang.org/api/gensupport/jsonfloat.go
new file mode 100644
index 0000000..8377850
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/jsonfloat.go
@@ -0,0 +1,57 @@
1// Copyright 2016 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package gensupport
16
17import (
18 "encoding/json"
19 "errors"
20 "fmt"
21 "math"
22)
23
24// JSONFloat64 is a float64 that supports proper unmarshaling of special float
25// values in JSON, according to
26// https://developers.google.com/protocol-buffers/docs/proto3#json. Although
27// that is a proto-to-JSON spec, it applies to all Google APIs.
28//
29// The jsonpb package
30// (https://github.com/golang/protobuf/blob/master/jsonpb/jsonpb.go) has
31// similar functionality, but only for direct translation from proto messages
32// to JSON.
33type JSONFloat64 float64
34
35func (f *JSONFloat64) UnmarshalJSON(data []byte) error {
36 var ff float64
37 if err := json.Unmarshal(data, &ff); err == nil {
38 *f = JSONFloat64(ff)
39 return nil
40 }
41 var s string
42 if err := json.Unmarshal(data, &s); err == nil {
43 switch s {
44 case "NaN":
45 ff = math.NaN()
46 case "Infinity":
47 ff = math.Inf(1)
48 case "-Infinity":
49 ff = math.Inf(-1)
50 default:
51 return fmt.Errorf("google.golang.org/api/internal: bad float string %q", s)
52 }
53 *f = JSONFloat64(ff)
54 return nil
55 }
56 return errors.New("google.golang.org/api/internal: data not float or string")
57}
diff --git a/vendor/google.golang.org/api/gensupport/media.go b/vendor/google.golang.org/api/gensupport/media.go
new file mode 100644
index 0000000..4cef4ad
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/media.go
@@ -0,0 +1,342 @@
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
5package gensupport
6
7import (
8 "bytes"
9 "fmt"
10 "io"
11 "io/ioutil"
12 "mime/multipart"
13 "net/http"
14 "net/textproto"
15 "strings"
16 "sync"
17
18 "google.golang.org/api/googleapi"
19)
20
21const sniffBuffSize = 512
22
23func newContentSniffer(r io.Reader) *contentSniffer {
24 return &contentSniffer{r: r}
25}
26
27// contentSniffer wraps a Reader, and reports the content type determined by sniffing up to 512 bytes from the Reader.
28type contentSniffer struct {
29 r io.Reader
30 start []byte // buffer for the sniffed bytes.
31 err error // set to any error encountered while reading bytes to be sniffed.
32
33 ctype string // set on first sniff.
34 sniffed bool // set to true on first sniff.
35}
36
37func (cs *contentSniffer) Read(p []byte) (n int, err error) {
38 // Ensure that the content type is sniffed before any data is consumed from Reader.
39 _, _ = cs.ContentType()
40
41 if len(cs.start) > 0 {
42 n := copy(p, cs.start)
43 cs.start = cs.start[n:]
44 return n, nil
45 }
46
47 // We may have read some bytes into start while sniffing, even if the read ended in an error.
48 // We should first return those bytes, then the error.
49 if cs.err != nil {
50 return 0, cs.err
51 }
52
53 // Now we have handled all bytes that were buffered while sniffing. Now just delegate to the underlying reader.
54 return cs.r.Read(p)
55}
56
57// ContentType returns the sniffed content type, and whether the content type was succesfully sniffed.
58func (cs *contentSniffer) ContentType() (string, bool) {
59 if cs.sniffed {
60 return cs.ctype, cs.ctype != ""
61 }
62 cs.sniffed = true
63 // If ReadAll hits EOF, it returns err==nil.
64 cs.start, cs.err = ioutil.ReadAll(io.LimitReader(cs.r, sniffBuffSize))
65
66 // Don't try to detect the content type based on possibly incomplete data.
67 if cs.err != nil {
68 return "", false
69 }
70
71 cs.ctype = http.DetectContentType(cs.start)
72 return cs.ctype, true
73}
74
75// DetermineContentType determines the content type of the supplied reader.
76// If the content type is already known, it can be specified via ctype.
77// Otherwise, the content of media will be sniffed to determine the content type.
78// If media implements googleapi.ContentTyper (deprecated), this will be used
79// instead of sniffing the content.
80// After calling DetectContentType the caller must not perform further reads on
81// media, but rather read from the Reader that is returned.
82func DetermineContentType(media io.Reader, ctype string) (io.Reader, string) {
83 // Note: callers could avoid calling DetectContentType if ctype != "",
84 // but doing the check inside this function reduces the amount of
85 // generated code.
86 if ctype != "" {
87 return media, ctype
88 }
89
90 // For backwards compatability, allow clients to set content
91 // type by providing a ContentTyper for media.
92 if typer, ok := media.(googleapi.ContentTyper); ok {
93 return media, typer.ContentType()
94 }
95
96 sniffer := newContentSniffer(media)
97 if ctype, ok := sniffer.ContentType(); ok {
98 return sniffer, ctype
99 }
100 // If content type could not be sniffed, reads from sniffer will eventually fail with an error.
101 return sniffer, ""
102}
103
104type typeReader struct {
105 io.Reader
106 typ string
107}
108
109// multipartReader combines the contents of multiple readers to create a multipart/related HTTP body.
110// Close must be called if reads from the multipartReader are abandoned before reaching EOF.
111type multipartReader struct {
112 pr *io.PipeReader
113 ctype string
114 mu sync.Mutex
115 pipeOpen bool
116}
117
118func newMultipartReader(parts []typeReader) *multipartReader {
119 mp := &multipartReader{pipeOpen: true}
120 var pw *io.PipeWriter
121 mp.pr, pw = io.Pipe()
122 mpw := multipart.NewWriter(pw)
123 mp.ctype = "multipart/related; boundary=" + mpw.Boundary()
124 go func() {
125 for _, part := range parts {
126 w, err := mpw.CreatePart(typeHeader(part.typ))
127 if err != nil {
128 mpw.Close()
129 pw.CloseWithError(fmt.Errorf("googleapi: CreatePart failed: %v", err))
130 return
131 }
132 _, err = io.Copy(w, part.Reader)
133 if err != nil {
134 mpw.Close()
135 pw.CloseWithError(fmt.Errorf("googleapi: Copy failed: %v", err))
136 return
137 }
138 }
139
140 mpw.Close()
141 pw.Close()
142 }()
143 return mp
144}
145
146func (mp *multipartReader) Read(data []byte) (n int, err error) {
147 return mp.pr.Read(data)
148}
149
150func (mp *multipartReader) Close() error {
151 mp.mu.Lock()
152 if !mp.pipeOpen {
153 mp.mu.Unlock()
154 return nil
155 }
156 mp.pipeOpen = false
157 mp.mu.Unlock()
158 return mp.pr.Close()
159}
160
161// CombineBodyMedia combines a json body with media content to create a multipart/related HTTP body.
162// It returns a ReadCloser containing the combined body, and the overall "multipart/related" content type, with random boundary.
163//
164// The caller must call Close on the returned ReadCloser if reads are abandoned before reaching EOF.
165func CombineBodyMedia(body io.Reader, bodyContentType string, media io.Reader, mediaContentType string) (io.ReadCloser, string) {
166 mp := newMultipartReader([]typeReader{
167 {body, bodyContentType},
168 {media, mediaContentType},
169 })
170 return mp, mp.ctype
171}
172
173func typeHeader(contentType string) textproto.MIMEHeader {
174 h := make(textproto.MIMEHeader)
175 if contentType != "" {
176 h.Set("Content-Type", contentType)
177 }
178 return h
179}
180
181// PrepareUpload determines whether the data in the supplied reader should be
182// uploaded in a single request, or in sequential chunks.
183// chunkSize is the size of the chunk that media should be split into.
184//
185// If chunkSize is zero, media is returned as the first value, and the other
186// two return values are nil, true.
187//
188// Otherwise, a MediaBuffer is returned, along with a bool indicating whether the
189// contents of media fit in a single chunk.
190//
191// After PrepareUpload has been called, media should no longer be used: the
192// media content should be accessed via one of the return values.
193func PrepareUpload(media io.Reader, chunkSize int) (r io.Reader, mb *MediaBuffer, singleChunk bool) {
194 if chunkSize == 0 { // do not chunk
195 return media, nil, true
196 }
197 mb = NewMediaBuffer(media, chunkSize)
198 _, _, _, err := mb.Chunk()
199 // If err is io.EOF, we can upload this in a single request. Otherwise, err is
200 // either nil or a non-EOF error. If it is the latter, then the next call to
201 // mb.Chunk will return the same error. Returning a MediaBuffer ensures that this
202 // error will be handled at some point.
203 return nil, mb, err == io.EOF
204}
205
206// MediaInfo holds information for media uploads. It is intended for use by generated
207// code only.
208type MediaInfo struct {
209 // At most one of Media and MediaBuffer will be set.
210 media io.Reader
211 buffer *MediaBuffer
212 singleChunk bool
213 mType string
214 size int64 // mediaSize, if known. Used only for calls to progressUpdater_.
215 progressUpdater googleapi.ProgressUpdater
216}
217
218// NewInfoFromMedia should be invoked from the Media method of a call. It returns a
219// MediaInfo populated with chunk size and content type, and a reader or MediaBuffer
220// if needed.
221func NewInfoFromMedia(r io.Reader, options []googleapi.MediaOption) *MediaInfo {
222 mi := &MediaInfo{}
223 opts := googleapi.ProcessMediaOptions(options)
224 if !opts.ForceEmptyContentType {
225 r, mi.mType = DetermineContentType(r, opts.ContentType)
226 }
227 mi.media, mi.buffer, mi.singleChunk = PrepareUpload(r, opts.ChunkSize)
228 return mi
229}
230
231// NewInfoFromResumableMedia should be invoked from the ResumableMedia method of a
232// call. It returns a MediaInfo using the given reader, size and media type.
233func NewInfoFromResumableMedia(r io.ReaderAt, size int64, mediaType string) *MediaInfo {
234 rdr := ReaderAtToReader(r, size)
235 rdr, mType := DetermineContentType(rdr, mediaType)
236 return &MediaInfo{
237 size: size,
238 mType: mType,
239 buffer: NewMediaBuffer(rdr, googleapi.DefaultUploadChunkSize),
240 media: nil,
241 singleChunk: false,
242 }
243}
244
245// SetProgressUpdater sets the progress updater for the media info.
246func (mi *MediaInfo) SetProgressUpdater(pu googleapi.ProgressUpdater) {
247 if mi != nil {
248 mi.progressUpdater = pu
249 }
250}
251
252// UploadType determines the type of upload: a single request, or a resumable
253// series of requests.
254func (mi *MediaInfo) UploadType() string {
255 if mi.singleChunk {
256 return "multipart"
257 }
258 return "resumable"
259}
260
261// UploadRequest sets up an HTTP request for media upload. It adds headers
262// as necessary, and returns a replacement for the body and a function for http.Request.GetBody.
263func (mi *MediaInfo) UploadRequest(reqHeaders http.Header, body io.Reader) (newBody io.Reader, getBody func() (io.ReadCloser, error), cleanup func()) {
264 cleanup = func() {}
265 if mi == nil {
266 return body, nil, cleanup
267 }
268 var media io.Reader
269 if mi.media != nil {
270 // This only happens when the caller has turned off chunking. In that
271 // case, we write all of media in a single non-retryable request.
272 media = mi.media
273 } else if mi.singleChunk {
274 // The data fits in a single chunk, which has now been read into the MediaBuffer.
275 // We obtain that chunk so we can write it in a single request. The request can
276 // be retried because the data is stored in the MediaBuffer.
277 media, _, _, _ = mi.buffer.Chunk()
278 }
279 if media != nil {
280 fb := readerFunc(body)
281 fm := readerFunc(media)
282 combined, ctype := CombineBodyMedia(body, "application/json", media, mi.mType)
283 if fb != nil && fm != nil {
284 getBody = func() (io.ReadCloser, error) {
285 rb := ioutil.NopCloser(fb())
286 rm := ioutil.NopCloser(fm())
287 r, _ := CombineBodyMedia(rb, "application/json", rm, mi.mType)
288 return r, nil
289 }
290 }
291 cleanup = func() { combined.Close() }
292 reqHeaders.Set("Content-Type", ctype)
293 body = combined
294 }
295 if mi.buffer != nil && mi.mType != "" && !mi.singleChunk {
296 reqHeaders.Set("X-Upload-Content-Type", mi.mType)
297 }
298 return body, getBody, cleanup
299}
300
301// readerFunc returns a function that always returns an io.Reader that has the same
302// contents as r, provided that can be done without consuming r. Otherwise, it
303// returns nil.
304// See http.NewRequest (in net/http/request.go).
305func readerFunc(r io.Reader) func() io.Reader {
306 switch r := r.(type) {
307 case *bytes.Buffer:
308 buf := r.Bytes()
309 return func() io.Reader { return bytes.NewReader(buf) }
310 case *bytes.Reader:
311 snapshot := *r
312 return func() io.Reader { r := snapshot; return &r }
313 case *strings.Reader:
314 snapshot := *r
315 return func() io.Reader { r := snapshot; return &r }
316 default:
317 return nil
318 }
319}
320
321// ResumableUpload returns an appropriately configured ResumableUpload value if the
322// upload is resumable, or nil otherwise.
323func (mi *MediaInfo) ResumableUpload(locURI string) *ResumableUpload {
324 if mi == nil || mi.singleChunk {
325 return nil
326 }
327 return &ResumableUpload{
328 URI: locURI,
329 Media: mi.buffer,
330 MediaType: mi.mType,
331 Callback: func(curr int64) {
332 if mi.progressUpdater != nil {
333 mi.progressUpdater(curr, mi.size)
334 }
335 },
336 }
337}
338
339// SetGetBody sets the GetBody field of req to f.
340func SetGetBody(req *http.Request, f func() (io.ReadCloser, error)) {
341 req.GetBody = f
342}
diff --git a/vendor/google.golang.org/api/gensupport/params.go b/vendor/google.golang.org/api/gensupport/params.go
new file mode 100644
index 0000000..0e878a4
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/params.go
@@ -0,0 +1,51 @@
1// Copyright 2015 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
5package gensupport
6
7import (
8 "net/url"
9
10 "google.golang.org/api/googleapi"
11)
12
13// URLParams is a simplified replacement for url.Values
14// that safely builds up URL parameters for encoding.
15type URLParams map[string][]string
16
17// Get returns the first value for the given key, or "".
18func (u URLParams) Get(key string) string {
19 vs := u[key]
20 if len(vs) == 0 {
21 return ""
22 }
23 return vs[0]
24}
25
26// Set sets the key to value.
27// It replaces any existing values.
28func (u URLParams) Set(key, value string) {
29 u[key] = []string{value}
30}
31
32// SetMulti sets the key to an array of values.
33// It replaces any existing values.
34// Note that values must not be modified after calling SetMulti
35// so the caller is responsible for making a copy if necessary.
36func (u URLParams) SetMulti(key string, values []string) {
37 u[key] = values
38}
39
40// Encode encodes the values into ``URL encoded'' form
41// ("bar=baz&foo=quux") sorted by key.
42func (u URLParams) Encode() string {
43 return url.Values(u).Encode()
44}
45
46// SetOptions sets the URL params and any additional call options.
47func SetOptions(u URLParams, opts ...googleapi.CallOption) {
48 for _, o := range opts {
49 u.Set(o.Get())
50 }
51}
diff --git a/vendor/google.golang.org/api/gensupport/resumable.go b/vendor/google.golang.org/api/gensupport/resumable.go
new file mode 100644
index 0000000..2552a6a
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/resumable.go
@@ -0,0 +1,216 @@
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
5package gensupport
6
7import (
8 "context"
9 "errors"
10 "fmt"
11 "io"
12 "net/http"
13 "sync"
14 "time"
15)
16
17const (
18 // statusTooManyRequests is returned by the storage API if the
19 // per-project limits have been temporarily exceeded. The request
20 // should be retried.
21 // https://cloud.google.com/storage/docs/json_api/v1/status-codes#standardcodes
22 statusTooManyRequests = 429
23)
24
25// ResumableUpload is used by the generated APIs to provide resumable uploads.
26// It is not used by developers directly.
27type ResumableUpload struct {
28 Client *http.Client
29 // URI is the resumable resource destination provided by the server after specifying "&uploadType=resumable".
30 URI string
31 UserAgent string // User-Agent for header of the request
32 // Media is the object being uploaded.
33 Media *MediaBuffer
34 // MediaType defines the media type, e.g. "image/jpeg".
35 MediaType string
36
37 mu sync.Mutex // guards progress
38 progress int64 // number of bytes uploaded so far
39
40 // Callback is an optional function that will be periodically called with the cumulative number of bytes uploaded.
41 Callback func(int64)
42
43 // If not specified, a default exponential backoff strategy will be used.
44 Backoff BackoffStrategy
45}
46
47// Progress returns the number of bytes uploaded at this point.
48func (rx *ResumableUpload) Progress() int64 {
49 rx.mu.Lock()
50 defer rx.mu.Unlock()
51 return rx.progress
52}
53
54// doUploadRequest performs a single HTTP request to upload data.
55// off specifies the offset in rx.Media from which data is drawn.
56// size is the number of bytes in data.
57// final specifies whether data is the final chunk to be uploaded.
58func (rx *ResumableUpload) doUploadRequest(ctx context.Context, data io.Reader, off, size int64, final bool) (*http.Response, error) {
59 req, err := http.NewRequest("POST", rx.URI, data)
60 if err != nil {
61 return nil, err
62 }
63
64 req.ContentLength = size
65 var contentRange string
66 if final {
67 if size == 0 {
68 contentRange = fmt.Sprintf("bytes */%v", off)
69 } else {
70 contentRange = fmt.Sprintf("bytes %v-%v/%v", off, off+size-1, off+size)
71 }
72 } else {
73 contentRange = fmt.Sprintf("bytes %v-%v/*", off, off+size-1)
74 }
75 req.Header.Set("Content-Range", contentRange)
76 req.Header.Set("Content-Type", rx.MediaType)
77 req.Header.Set("User-Agent", rx.UserAgent)
78
79 // Google's upload endpoint uses status code 308 for a
80 // different purpose than the "308 Permanent Redirect"
81 // since-standardized in RFC 7238. Because of the conflict in
82 // semantics, Google added this new request header which
83 // causes it to not use "308" and instead reply with 200 OK
84 // and sets the upload-specific "X-HTTP-Status-Code-Override:
85 // 308" response header.
86 req.Header.Set("X-GUploader-No-308", "yes")
87
88 return SendRequest(ctx, rx.Client, req)
89}
90
91func statusResumeIncomplete(resp *http.Response) bool {
92 // This is how the server signals "status resume incomplete"
93 // when X-GUploader-No-308 is set to "yes":
94 return resp != nil && resp.Header.Get("X-Http-Status-Code-Override") == "308"
95}
96
97// reportProgress calls a user-supplied callback to report upload progress.
98// If old==updated, the callback is not called.
99func (rx *ResumableUpload) reportProgress(old, updated int64) {
100 if updated-old == 0 {
101 return
102 }
103 rx.mu.Lock()
104 rx.progress = updated
105 rx.mu.Unlock()
106 if rx.Callback != nil {
107 rx.Callback(updated)
108 }
109}
110
111// transferChunk performs a single HTTP request to upload a single chunk from rx.Media.
112func (rx *ResumableUpload) transferChunk(ctx context.Context) (*http.Response, error) {
113 chunk, off, size, err := rx.Media.Chunk()
114
115 done := err == io.EOF
116 if !done && err != nil {
117 return nil, err
118 }
119
120 res, err := rx.doUploadRequest(ctx, chunk, off, int64(size), done)
121 if err != nil {
122 return res, err
123 }
124
125 // We sent "X-GUploader-No-308: yes" (see comment elsewhere in
126 // this file), so we don't expect to get a 308.
127 if res.StatusCode == 308 {
128 return nil, errors.New("unexpected 308 response status code")
129 }
130
131 if res.StatusCode == http.StatusOK {
132 rx.reportProgress(off, off+int64(size))
133 }
134
135 if statusResumeIncomplete(res) {
136 rx.Media.Next()
137 }
138 return res, nil
139}
140
141func contextDone(ctx context.Context) bool {
142 select {
143 case <-ctx.Done():
144 return true
145 default:
146 return false
147 }
148}
149
150// Upload starts the process of a resumable upload with a cancellable context.
151// It retries using the provided back off strategy until cancelled or the
152// strategy indicates to stop retrying.
153// It is called from the auto-generated API code and is not visible to the user.
154// Before sending an HTTP request, Upload calls any registered hook functions,
155// and calls the returned functions after the request returns (see send.go).
156// rx is private to the auto-generated API code.
157// Exactly one of resp or err will be nil. If resp is non-nil, the caller must call resp.Body.Close.
158func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err error) {
159 var pause time.Duration
160 backoff := rx.Backoff
161 if backoff == nil {
162 backoff = DefaultBackoffStrategy()
163 }
164
165 for {
166 // Ensure that we return in the case of cancelled context, even if pause is 0.
167 if contextDone(ctx) {
168 return nil, ctx.Err()
169 }
170 select {
171 case <-ctx.Done():
172 return nil, ctx.Err()
173 case <-time.After(pause):
174 }
175
176 resp, err = rx.transferChunk(ctx)
177
178 var status int
179 if resp != nil {
180 status = resp.StatusCode
181 }
182
183 // Check if we should retry the request.
184 if shouldRetry(status, err) {
185 var retry bool
186 pause, retry = backoff.Pause()
187 if retry {
188 if resp != nil && resp.Body != nil {
189 resp.Body.Close()
190 }
191 continue
192 }
193 }
194
195 // If the chunk was uploaded successfully, but there's still
196 // more to go, upload the next chunk without any delay.
197 if statusResumeIncomplete(resp) {
198 pause = 0
199 backoff.Reset()
200 resp.Body.Close()
201 continue
202 }
203
204 // It's possible for err and resp to both be non-nil here, but we expose a simpler
205 // contract to our callers: exactly one of resp and err will be non-nil. This means
206 // that any response body must be closed here before returning a non-nil error.
207 if err != nil {
208 if resp != nil && resp.Body != nil {
209 resp.Body.Close()
210 }
211 return nil, err
212 }
213
214 return resp, nil
215 }
216}
diff --git a/vendor/google.golang.org/api/gensupport/retry.go b/vendor/google.golang.org/api/gensupport/retry.go
new file mode 100644
index 0000000..fdde3f4
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/retry.go
@@ -0,0 +1,84 @@
1// Copyright 2017 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package gensupport
16
17import (
18 "context"
19 "io"
20 "net"
21 "net/http"
22 "time"
23)
24
25// Retry invokes the given function, retrying it multiple times if the connection failed or
26// the HTTP status response indicates the request should be attempted again. ctx may be nil.
27func Retry(ctx context.Context, f func() (*http.Response, error), backoff BackoffStrategy) (*http.Response, error) {
28 for {
29 resp, err := f()
30
31 var status int
32 if resp != nil {
33 status = resp.StatusCode
34 }
35
36 // Return if we shouldn't retry.
37 pause, retry := backoff.Pause()
38 if !shouldRetry(status, err) || !retry {
39 return resp, err
40 }
41
42 // Ensure the response body is closed, if any.
43 if resp != nil && resp.Body != nil {
44 resp.Body.Close()
45 }
46
47 // Pause, but still listen to ctx.Done if context is not nil.
48 var done <-chan struct{}
49 if ctx != nil {
50 done = ctx.Done()
51 }
52 select {
53 case <-done:
54 return nil, ctx.Err()
55 case <-time.After(pause):
56 }
57 }
58}
59
60// DefaultBackoffStrategy returns a default strategy to use for retrying failed upload requests.
61func DefaultBackoffStrategy() BackoffStrategy {
62 return &ExponentialBackoff{
63 Base: 250 * time.Millisecond,
64 Max: 16 * time.Second,
65 }
66}
67
68// shouldRetry returns true if the HTTP response / error indicates that the
69// request should be attempted again.
70func shouldRetry(status int, err error) bool {
71 if 500 <= status && status <= 599 {
72 return true
73 }
74 if status == statusTooManyRequests {
75 return true
76 }
77 if err == io.ErrUnexpectedEOF {
78 return true
79 }
80 if err, ok := err.(net.Error); ok {
81 return err.Temporary()
82 }
83 return false
84}
diff --git a/vendor/google.golang.org/api/gensupport/send.go b/vendor/google.golang.org/api/gensupport/send.go
new file mode 100644
index 0000000..5799393
--- /dev/null
+++ b/vendor/google.golang.org/api/gensupport/send.go
@@ -0,0 +1,87 @@
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
5package gensupport
6
7import (
8 "context"
9 "encoding/json"
10 "errors"
11 "net/http"
12)
13
14// Hook is the type of a function that is called once before each HTTP request
15// that is sent by a generated API. It returns a function that is called after
16// the request returns.
17// Hooks are not called if the context is nil.
18type Hook func(ctx context.Context, req *http.Request) func(resp *http.Response)
19
20var hooks []Hook
21
22// RegisterHook registers a Hook to be called before each HTTP request by a
23// generated API. Hooks are called in the order they are registered. Each
24// hook can return a function; if it is non-nil, it is called after the HTTP
25// request returns. These functions are called in the reverse order.
26// RegisterHook should not be called concurrently with itself or SendRequest.
27func RegisterHook(h Hook) {
28 hooks = append(hooks, h)
29}
30
31// SendRequest sends a single HTTP request using the given client.
32// If ctx is non-nil, it calls all hooks, then sends the request with
33// req.WithContext, then calls any functions returned by the hooks in
34// reverse order.
35func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
36 // Disallow Accept-Encoding because it interferes with the automatic gzip handling
37 // done by the default http.Transport. See https://github.com/google/google-api-go-client/issues/219.
38 if _, ok := req.Header["Accept-Encoding"]; ok {
39 return nil, errors.New("google api: custom Accept-Encoding headers not allowed")
40 }
41 if ctx == nil {
42 return client.Do(req)
43 }
44 // Call hooks in order of registration, store returned funcs.
45 post := make([]func(resp *http.Response), len(hooks))
46 for i, h := range hooks {
47 fn := h(ctx, req)
48 post[i] = fn
49 }
50
51 // Send request.
52 resp, err := send(ctx, client, req)
53
54 // Call returned funcs in reverse order.
55 for i := len(post) - 1; i >= 0; i-- {
56 if fn := post[i]; fn != nil {
57 fn(resp)
58 }
59 }
60 return resp, err
61}
62
63func send(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
64 if client == nil {
65 client = http.DefaultClient
66 }
67 resp, err := client.Do(req.WithContext(ctx))
68 // If we got an error, and the context has been canceled,
69 // the context's error is probably more useful.
70 if err != nil {
71 select {
72 case <-ctx.Done():
73 err = ctx.Err()
74 default:
75 }
76 }
77 return resp, err
78}
79
80// DecodeResponse decodes the body of res into target. If there is no body,
81// target is unchanged.
82func DecodeResponse(target interface{}, res *http.Response) error {
83 if res.StatusCode == http.StatusNoContent {
84 return nil
85 }
86 return json.NewDecoder(res.Body).Decode(target)
87}