summaryrefslogtreecommitdiff
path: root/vendor/google.golang.org/api/internal
diff options
context:
space:
mode:
authorn1c00o <n@nc0.fr>2023-02-05 14:05:26 +0100
committerNicolas <34602094+n1c00o@users.noreply.github.com>2023-02-06 22:35:54 +0100
commitb371cb11a5877ede8847351e95c7847b5024a551 (patch)
tree958227cf8562503246976744b89370d389de5f66 /vendor/google.golang.org/api/internal
parent03e0c597ad5f3539ad33976fe02c11a9e39f34d6 (diff)
Init Go module
Diffstat (limited to 'vendor/google.golang.org/api/internal')
-rw-r--r--vendor/google.golang.org/api/internal/conn_pool.go30
-rw-r--r--vendor/google.golang.org/api/internal/creds.go159
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/buffer.go79
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/doc.go10
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/error.go24
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/json.go236
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/jsonfloat.go47
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/media.go312
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/params.go57
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/resumable.go265
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/retry.go121
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/retryable_linux.go16
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/send.go180
-rw-r--r--vendor/google.golang.org/api/internal/gensupport/version.go53
-rw-r--r--vendor/google.golang.org/api/internal/impersonate/impersonate.go128
-rw-r--r--vendor/google.golang.org/api/internal/settings.go142
-rw-r--r--vendor/google.golang.org/api/internal/third_party/uritemplates/LICENSE27
-rw-r--r--vendor/google.golang.org/api/internal/third_party/uritemplates/METADATA14
-rw-r--r--vendor/google.golang.org/api/internal/third_party/uritemplates/uritemplates.go248
-rw-r--r--vendor/google.golang.org/api/internal/third_party/uritemplates/utils.go17
-rw-r--r--vendor/google.golang.org/api/internal/version.go8
21 files changed, 2173 insertions, 0 deletions
diff --git a/vendor/google.golang.org/api/internal/conn_pool.go b/vendor/google.golang.org/api/internal/conn_pool.go
new file mode 100644
index 0000000..fedcce1
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/conn_pool.go
@@ -0,0 +1,30 @@
+// Copyright 2020 Google LLC.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+import (
+ "google.golang.org/grpc"
+)
+
+// ConnPool is a pool of grpc.ClientConns.
+type ConnPool interface {
+ // Conn returns a ClientConn from the pool.
+ //
+ // Conns aren't returned to the pool.
+ Conn() *grpc.ClientConn
+
+ // Num returns the number of connections in the pool.
+ //
+ // It will always return the same value.
+ Num() int
+
+ // Close closes every ClientConn in the pool.
+ //
+ // The error returned by Close may be a single error or multiple errors.
+ Close() error
+
+ // ConnPool implements grpc.ClientConnInterface to enable it to be used directly with generated proto stubs.
+ grpc.ClientConnInterface
+}
diff --git a/vendor/google.golang.org/api/internal/creds.go b/vendor/google.golang.org/api/internal/creds.go
new file mode 100644
index 0000000..32d5241
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/creds.go
@@ -0,0 +1,159 @@
+// Copyright 2017 Google LLC.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+
+ "golang.org/x/oauth2"
+ "google.golang.org/api/internal/impersonate"
+
+ "golang.org/x/oauth2/google"
+)
+
+// Creds returns credential information obtained from DialSettings, or if none, then
+// it returns default credential information.
+func Creds(ctx context.Context, ds *DialSettings) (*google.Credentials, error) {
+ creds, err := baseCreds(ctx, ds)
+ if err != nil {
+ return nil, err
+ }
+ if ds.ImpersonationConfig != nil {
+ return impersonateCredentials(ctx, creds, ds)
+ }
+ return creds, nil
+}
+
+func baseCreds(ctx context.Context, ds *DialSettings) (*google.Credentials, error) {
+ if ds.InternalCredentials != nil {
+ return ds.InternalCredentials, nil
+ }
+ if ds.Credentials != nil {
+ return ds.Credentials, nil
+ }
+ if ds.CredentialsJSON != nil {
+ return credentialsFromJSON(ctx, ds.CredentialsJSON, ds)
+ }
+ if ds.CredentialsFile != "" {
+ data, err := ioutil.ReadFile(ds.CredentialsFile)
+ if err != nil {
+ return nil, fmt.Errorf("cannot read credentials file: %v", err)
+ }
+ return credentialsFromJSON(ctx, data, ds)
+ }
+ if ds.TokenSource != nil {
+ return &google.Credentials{TokenSource: ds.TokenSource}, nil
+ }
+ cred, err := google.FindDefaultCredentials(ctx, ds.GetScopes()...)
+ if err != nil {
+ return nil, err
+ }
+ if len(cred.JSON) > 0 {
+ return credentialsFromJSON(ctx, cred.JSON, ds)
+ }
+ // For GAE and GCE, the JSON is empty so return the default credentials directly.
+ return cred, nil
+}
+
+// JSON key file type.
+const (
+ serviceAccountKey = "service_account"
+)
+
+// credentialsFromJSON returns a google.Credentials from the JSON data
+//
+// - A self-signed JWT flow will be executed if the following conditions are
+// met:
+//
+// (1) At least one of the following is true:
+// (a) No scope is provided
+// (b) Scope for self-signed JWT flow is enabled
+// (c) Audiences are explicitly provided by users
+// (2) No service account impersontation
+//
+// - Otherwise, executes standard OAuth 2.0 flow
+// More details: google.aip.dev/auth/4111
+func credentialsFromJSON(ctx context.Context, data []byte, ds *DialSettings) (*google.Credentials, error) {
+ // By default, a standard OAuth 2.0 token source is created
+ cred, err := google.CredentialsFromJSON(ctx, data, ds.GetScopes()...)
+ if err != nil {
+ return nil, err
+ }
+
+ // Override the token source to use self-signed JWT if conditions are met
+ isJWTFlow, err := isSelfSignedJWTFlow(data, ds)
+ if err != nil {
+ return nil, err
+ }
+ if isJWTFlow {
+ ts, err := selfSignedJWTTokenSource(data, ds)
+ if err != nil {
+ return nil, err
+ }
+ cred.TokenSource = ts
+ }
+
+ return cred, err
+}
+
+func isSelfSignedJWTFlow(data []byte, ds *DialSettings) (bool, error) {
+ if (ds.EnableJwtWithScope || ds.HasCustomAudience()) &&
+ ds.ImpersonationConfig == nil {
+ // Check if JSON is a service account and if so create a self-signed JWT.
+ var f struct {
+ Type string `json:"type"`
+ // The rest JSON fields are omitted because they are not used.
+ }
+ if err := json.Unmarshal(data, &f); err != nil {
+ return false, err
+ }
+ return f.Type == serviceAccountKey, nil
+ }
+ return false, nil
+}
+
+func selfSignedJWTTokenSource(data []byte, ds *DialSettings) (oauth2.TokenSource, error) {
+ if len(ds.GetScopes()) > 0 && !ds.HasCustomAudience() {
+ // Scopes are preferred in self-signed JWT unless the scope is not available
+ // or a custom audience is used.
+ return google.JWTAccessTokenSourceWithScope(data, ds.GetScopes()...)
+ } else if ds.GetAudience() != "" {
+ // Fallback to audience if scope is not provided
+ return google.JWTAccessTokenSourceFromJSON(data, ds.GetAudience())
+ } else {
+ return nil, errors.New("neither scopes or audience are available for the self-signed JWT")
+ }
+}
+
+// QuotaProjectFromCreds returns the quota project from the JSON blob in the provided credentials.
+//
+// NOTE(cbro): consider promoting this to a field on google.Credentials.
+func QuotaProjectFromCreds(cred *google.Credentials) string {
+ var v struct {
+ QuotaProject string `json:"quota_project_id"`
+ }
+ if err := json.Unmarshal(cred.JSON, &v); err != nil {
+ return ""
+ }
+ return v.QuotaProject
+}
+
+func impersonateCredentials(ctx context.Context, creds *google.Credentials, ds *DialSettings) (*google.Credentials, error) {
+ if len(ds.ImpersonationConfig.Scopes) == 0 {
+ ds.ImpersonationConfig.Scopes = ds.GetScopes()
+ }
+ ts, err := impersonate.TokenSource(ctx, creds.TokenSource, ds.ImpersonationConfig)
+ if err != nil {
+ return nil, err
+ }
+ return &google.Credentials{
+ TokenSource: ts,
+ ProjectID: creds.ProjectID,
+ }, nil
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/buffer.go b/vendor/google.golang.org/api/internal/gensupport/buffer.go
new file mode 100644
index 0000000..3d0817e
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/buffer.go
@@ -0,0 +1,79 @@
+// 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 (
+ "bytes"
+ "io"
+
+ "google.golang.org/api/googleapi"
+)
+
+// MediaBuffer buffers data from an io.Reader to support uploading media in
+// retryable chunks. It should be created with NewMediaBuffer.
+type MediaBuffer struct {
+ media io.Reader
+
+ chunk []byte // The current chunk which is pending upload. The capacity is the chunk size.
+ err error // Any error generated when populating chunk by reading media.
+
+ // The absolute position of chunk in the underlying media.
+ off int64
+}
+
+// NewMediaBuffer initializes a MediaBuffer.
+func NewMediaBuffer(media io.Reader, chunkSize int) *MediaBuffer {
+ return &MediaBuffer{media: media, chunk: make([]byte, 0, chunkSize)}
+}
+
+// Chunk returns the current buffered chunk, the offset in the underlying media
+// from which the chunk is drawn, and the size of the chunk.
+// Successive calls to Chunk return the same chunk between calls to Next.
+func (mb *MediaBuffer) Chunk() (chunk io.Reader, off int64, size int, err error) {
+ // There may already be data in chunk if Next has not been called since the previous call to Chunk.
+ if mb.err == nil && len(mb.chunk) == 0 {
+ mb.err = mb.loadChunk()
+ }
+ return bytes.NewReader(mb.chunk), mb.off, len(mb.chunk), mb.err
+}
+
+// loadChunk will read from media into chunk, up to the capacity of chunk.
+func (mb *MediaBuffer) loadChunk() error {
+ bufSize := cap(mb.chunk)
+ mb.chunk = mb.chunk[:bufSize]
+
+ read := 0
+ var err error
+ for err == nil && read < bufSize {
+ var n int
+ n, err = mb.media.Read(mb.chunk[read:])
+ read += n
+ }
+ mb.chunk = mb.chunk[:read]
+ return err
+}
+
+// Next advances to the next chunk, which will be returned by the next call to Chunk.
+// Calls to Next without a corresponding prior call to Chunk will have no effect.
+func (mb *MediaBuffer) Next() {
+ mb.off += int64(len(mb.chunk))
+ mb.chunk = mb.chunk[0:0]
+}
+
+type readerTyper struct {
+ io.Reader
+ googleapi.ContentTyper
+}
+
+// ReaderAtToReader adapts a ReaderAt to be used as a Reader.
+// If ra implements googleapi.ContentTyper, then the returned reader
+// will also implement googleapi.ContentTyper, delegating to ra.
+func ReaderAtToReader(ra io.ReaderAt, size int64) io.Reader {
+ r := io.NewSectionReader(ra, 0, size)
+ if typer, ok := ra.(googleapi.ContentTyper); ok {
+ return readerTyper{r, typer}
+ }
+ return r
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/doc.go b/vendor/google.golang.org/api/internal/gensupport/doc.go
new file mode 100644
index 0000000..752c4b4
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/doc.go
@@ -0,0 +1,10 @@
+// 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 is an internal implementation detail used by code
+// generated by the google-api-go-generator tool.
+//
+// This package may be modified at any time without regard for backwards
+// compatibility. It should not be used directly by API users.
+package gensupport
diff --git a/vendor/google.golang.org/api/internal/gensupport/error.go b/vendor/google.golang.org/api/internal/gensupport/error.go
new file mode 100644
index 0000000..886c653
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/error.go
@@ -0,0 +1,24 @@
+// Copyright 2022 Google LLC. 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 (
+ "errors"
+
+ "github.com/googleapis/gax-go/v2/apierror"
+ "google.golang.org/api/googleapi"
+)
+
+// WrapError creates an [apierror.APIError] from err, wraps it in err, and
+// returns err. If err is not a [googleapi.Error] (or a
+// [google.golang.org/grpc/status.Status]), it returns err without modification.
+func WrapError(err error) error {
+ var herr *googleapi.Error
+ apiError, ok := apierror.ParseError(err, false)
+ if ok && errors.As(err, &herr) {
+ herr.Wrap(apiError)
+ }
+ return err
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/json.go b/vendor/google.golang.org/api/internal/gensupport/json.go
new file mode 100644
index 0000000..eab49a1
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/json.go
@@ -0,0 +1,236 @@
+// Copyright 2015 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 (
+ "encoding/json"
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+// MarshalJSON returns a JSON encoding of schema containing only selected fields.
+// A field is selected if any of the following is true:
+// - it has a non-empty value
+// - its field name is present in forceSendFields and it is not a nil pointer or nil interface
+// - its field name is present in nullFields.
+//
+// The JSON key for each selected field is taken from the field's json: struct tag.
+func MarshalJSON(schema interface{}, forceSendFields, nullFields []string) ([]byte, error) {
+ if len(forceSendFields) == 0 && len(nullFields) == 0 {
+ return json.Marshal(schema)
+ }
+
+ mustInclude := make(map[string]bool)
+ for _, f := range forceSendFields {
+ mustInclude[f] = true
+ }
+ useNull := make(map[string]bool)
+ useNullMaps := make(map[string]map[string]bool)
+ for _, nf := range nullFields {
+ parts := strings.SplitN(nf, ".", 2)
+ field := parts[0]
+ if len(parts) == 1 {
+ useNull[field] = true
+ } else {
+ if useNullMaps[field] == nil {
+ useNullMaps[field] = map[string]bool{}
+ }
+ useNullMaps[field][parts[1]] = true
+ }
+ }
+
+ dataMap, err := schemaToMap(schema, mustInclude, useNull, useNullMaps)
+ if err != nil {
+ return nil, err
+ }
+ return json.Marshal(dataMap)
+}
+
+func schemaToMap(schema interface{}, mustInclude, useNull map[string]bool, useNullMaps map[string]map[string]bool) (map[string]interface{}, error) {
+ m := make(map[string]interface{})
+ s := reflect.ValueOf(schema)
+ st := s.Type()
+
+ for i := 0; i < s.NumField(); i++ {
+ jsonTag := st.Field(i).Tag.Get("json")
+ if jsonTag == "" {
+ continue
+ }
+ tag, err := parseJSONTag(jsonTag)
+ if err != nil {
+ return nil, err
+ }
+ if tag.ignore {
+ continue
+ }
+
+ v := s.Field(i)
+ f := st.Field(i)
+
+ if useNull[f.Name] {
+ if !isEmptyValue(v) {
+ return nil, fmt.Errorf("field %q in NullFields has non-empty value", f.Name)
+ }
+ m[tag.apiName] = nil
+ continue
+ }
+
+ if !includeField(v, f, mustInclude) {
+ continue
+ }
+
+ // If map fields are explicitly set to null, use a map[string]interface{}.
+ if f.Type.Kind() == reflect.Map && useNullMaps[f.Name] != nil {
+ ms, ok := v.Interface().(map[string]string)
+ if !ok {
+ mi, err := initMapSlow(v, f.Name, useNullMaps)
+ if err != nil {
+ return nil, err
+ }
+ m[tag.apiName] = mi
+ continue
+ }
+ mi := map[string]interface{}{}
+ for k, v := range ms {
+ mi[k] = v
+ }
+ for k := range useNullMaps[f.Name] {
+ mi[k] = nil
+ }
+ m[tag.apiName] = mi
+ continue
+ }
+
+ // nil maps are treated as empty maps.
+ if f.Type.Kind() == reflect.Map && v.IsNil() {
+ m[tag.apiName] = map[string]string{}
+ continue
+ }
+
+ // nil slices are treated as empty slices.
+ if f.Type.Kind() == reflect.Slice && v.IsNil() {
+ m[tag.apiName] = []bool{}
+ continue
+ }
+
+ if tag.stringFormat {
+ m[tag.apiName] = formatAsString(v, f.Type.Kind())
+ } else {
+ m[tag.apiName] = v.Interface()
+ }
+ }
+ return m, nil
+}
+
+// initMapSlow uses reflection to build up a map object. This is slower than
+// the default behavior so it should be used only as a fallback.
+func initMapSlow(rv reflect.Value, fieldName string, useNullMaps map[string]map[string]bool) (map[string]interface{}, error) {
+ mi := map[string]interface{}{}
+ iter := rv.MapRange()
+ for iter.Next() {
+ k, ok := iter.Key().Interface().(string)
+ if !ok {
+ return nil, fmt.Errorf("field %q has keys in NullFields but is not a map[string]any", fieldName)
+ }
+ v := iter.Value().Interface()
+ mi[k] = v
+ }
+ for k := range useNullMaps[fieldName] {
+ mi[k] = nil
+ }
+ return mi, nil
+}
+
+// formatAsString returns a string representation of v, dereferencing it first if possible.
+func formatAsString(v reflect.Value, kind reflect.Kind) string {
+ if kind == reflect.Ptr && !v.IsNil() {
+ v = v.Elem()
+ }
+
+ return fmt.Sprintf("%v", v.Interface())
+}
+
+// jsonTag represents a restricted version of the struct tag format used by encoding/json.
+// It is used to describe the JSON encoding of fields in a Schema struct.
+type jsonTag struct {
+ apiName string
+ stringFormat bool
+ ignore bool
+}
+
+// parseJSONTag parses a restricted version of the struct tag format used by encoding/json.
+// The format of the tag must match that generated by the Schema.writeSchemaStruct method
+// in the api generator.
+func parseJSONTag(val string) (jsonTag, error) {
+ if val == "-" {
+ return jsonTag{ignore: true}, nil
+ }
+
+ var tag jsonTag
+
+ i := strings.Index(val, ",")
+ if i == -1 || val[:i] == "" {
+ return tag, fmt.Errorf("malformed json tag: %s", val)
+ }
+
+ tag = jsonTag{
+ apiName: val[:i],
+ }
+
+ switch val[i+1:] {
+ case "omitempty":
+ case "omitempty,string":
+ tag.stringFormat = true
+ default:
+ return tag, fmt.Errorf("malformed json tag: %s", val)
+ }
+
+ return tag, nil
+}
+
+// Reports whether the struct field "f" with value "v" should be included in JSON output.
+func includeField(v reflect.Value, f reflect.StructField, mustInclude map[string]bool) bool {
+ // The regular JSON encoding of a nil pointer is "null", which means "delete this field".
+ // Therefore, we could enable field deletion by honoring pointer fields' presence in the mustInclude set.
+ // However, many fields are not pointers, so there would be no way to delete these fields.
+ // Rather than partially supporting field deletion, we ignore mustInclude for nil pointer fields.
+ // Deletion will be handled by a separate mechanism.
+ if f.Type.Kind() == reflect.Ptr && v.IsNil() {
+ return false
+ }
+
+ // The "any" type is represented as an interface{}. If this interface
+ // is nil, there is no reasonable representation to send. We ignore
+ // these fields, for the same reasons as given above for pointers.
+ if f.Type.Kind() == reflect.Interface && v.IsNil() {
+ return false
+ }
+
+ return mustInclude[f.Name] || !isEmptyValue(v)
+}
+
+// isEmptyValue reports whether v is the empty value for its type. This
+// implementation is based on that of the encoding/json package, but its
+// correctness does not depend on it being identical. What's important is that
+// this function return false in situations where v should not be sent as part
+// of a PATCH operation.
+func isEmptyValue(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len() == 0
+ case reflect.Bool:
+ return !v.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return v.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return v.Float() == 0
+ case reflect.Interface, reflect.Ptr:
+ return v.IsNil()
+ }
+ return false
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/jsonfloat.go b/vendor/google.golang.org/api/internal/gensupport/jsonfloat.go
new file mode 100644
index 0000000..13c2f93
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/jsonfloat.go
@@ -0,0 +1,47 @@
+// Copyright 2016 Google LLC.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gensupport
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math"
+)
+
+// JSONFloat64 is a float64 that supports proper unmarshaling of special float
+// values in JSON, according to
+// https://developers.google.com/protocol-buffers/docs/proto3#json. Although
+// that is a proto-to-JSON spec, it applies to all Google APIs.
+//
+// The jsonpb package
+// (https://github.com/golang/protobuf/blob/master/jsonpb/jsonpb.go) has
+// similar functionality, but only for direct translation from proto messages
+// to JSON.
+type JSONFloat64 float64
+
+func (f *JSONFloat64) UnmarshalJSON(data []byte) error {
+ var ff float64
+ if err := json.Unmarshal(data, &ff); err == nil {
+ *f = JSONFloat64(ff)
+ return nil
+ }
+ var s string
+ if err := json.Unmarshal(data, &s); err == nil {
+ switch s {
+ case "NaN":
+ ff = math.NaN()
+ case "Infinity":
+ ff = math.Inf(1)
+ case "-Infinity":
+ ff = math.Inf(-1)
+ default:
+ return fmt.Errorf("google.golang.org/api/internal: bad float string %q", s)
+ }
+ *f = JSONFloat64(ff)
+ return nil
+ }
+ return errors.New("google.golang.org/api/internal: data not float or string")
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/media.go b/vendor/google.golang.org/api/internal/gensupport/media.go
new file mode 100644
index 0000000..8356e7f
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/media.go
@@ -0,0 +1,312 @@
+// 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 (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "mime"
+ "mime/multipart"
+ "net/http"
+ "net/textproto"
+ "strings"
+ "sync"
+ "time"
+
+ gax "github.com/googleapis/gax-go/v2"
+ "google.golang.org/api/googleapi"
+)
+
+type typeReader struct {
+ io.Reader
+ typ string
+}
+
+// multipartReader combines the contents of multiple readers to create a multipart/related HTTP body.
+// Close must be called if reads from the multipartReader are abandoned before reaching EOF.
+type multipartReader struct {
+ pr *io.PipeReader
+ ctype string
+ mu sync.Mutex
+ pipeOpen bool
+}
+
+// boundary optionally specifies the MIME boundary
+func newMultipartReader(parts []typeReader, boundary string) *multipartReader {
+ mp := &multipartReader{pipeOpen: true}
+ var pw *io.PipeWriter
+ mp.pr, pw = io.Pipe()
+ mpw := multipart.NewWriter(pw)
+ if boundary != "" {
+ mpw.SetBoundary(boundary)
+ }
+ mp.ctype = "multipart/related; boundary=" + mpw.Boundary()
+ go func() {
+ for _, part := range parts {
+ w, err := mpw.CreatePart(typeHeader(part.typ))
+ if err != nil {
+ mpw.Close()
+ pw.CloseWithError(fmt.Errorf("googleapi: CreatePart failed: %v", err))
+ return
+ }
+ _, err = io.Copy(w, part.Reader)
+ if err != nil {
+ mpw.Close()
+ pw.CloseWithError(fmt.Errorf("googleapi: Copy failed: %v", err))
+ return
+ }
+ }
+
+ mpw.Close()
+ pw.Close()
+ }()
+ return mp
+}
+
+func (mp *multipartReader) Read(data []byte) (n int, err error) {
+ return mp.pr.Read(data)
+}
+
+func (mp *multipartReader) Close() error {
+ mp.mu.Lock()
+ if !mp.pipeOpen {
+ mp.mu.Unlock()
+ return nil
+ }
+ mp.pipeOpen = false
+ mp.mu.Unlock()
+ return mp.pr.Close()
+}
+
+// CombineBodyMedia combines a json body with media content to create a multipart/related HTTP body.
+// It returns a ReadCloser containing the combined body, and the overall "multipart/related" content type, with random boundary.
+//
+// The caller must call Close on the returned ReadCloser if reads are abandoned before reaching EOF.
+func CombineBodyMedia(body io.Reader, bodyContentType string, media io.Reader, mediaContentType string) (io.ReadCloser, string) {
+ return combineBodyMedia(body, bodyContentType, media, mediaContentType, "")
+}
+
+// combineBodyMedia is CombineBodyMedia but with an optional mimeBoundary field.
+func combineBodyMedia(body io.Reader, bodyContentType string, media io.Reader, mediaContentType, mimeBoundary string) (io.ReadCloser, string) {
+ mp := newMultipartReader([]typeReader{
+ {body, bodyContentType},
+ {media, mediaContentType},
+ }, mimeBoundary)
+ return mp, mp.ctype
+}
+
+func typeHeader(contentType string) textproto.MIMEHeader {
+ h := make(textproto.MIMEHeader)
+ if contentType != "" {
+ h.Set("Content-Type", contentType)
+ }
+ return h
+}
+
+// PrepareUpload determines whether the data in the supplied reader should be
+// uploaded in a single request, or in sequential chunks.
+// chunkSize is the size of the chunk that media should be split into.
+//
+// If chunkSize is zero, media is returned as the first value, and the other
+// two return values are nil, true.
+//
+// Otherwise, a MediaBuffer is returned, along with a bool indicating whether the
+// contents of media fit in a single chunk.
+//
+// After PrepareUpload has been called, media should no longer be used: the
+// media content should be accessed via one of the return values.
+func PrepareUpload(media io.Reader, chunkSize int) (r io.Reader, mb *MediaBuffer, singleChunk bool) {
+ if chunkSize == 0 { // do not chunk
+ return media, nil, true
+ }
+ mb = NewMediaBuffer(media, chunkSize)
+ _, _, _, err := mb.Chunk()
+ // If err is io.EOF, we can upload this in a single request. Otherwise, err is
+ // either nil or a non-EOF error. If it is the latter, then the next call to
+ // mb.Chunk will return the same error. Returning a MediaBuffer ensures that this
+ // error will be handled at some point.
+ return nil, mb, err == io.EOF
+}
+
+// MediaInfo holds information for media uploads. It is intended for use by generated
+// code only.
+type MediaInfo struct {
+ // At most one of Media and MediaBuffer will be set.
+ media io.Reader
+ buffer *MediaBuffer
+ singleChunk bool
+ mType string
+ size int64 // mediaSize, if known. Used only for calls to progressUpdater_.
+ progressUpdater googleapi.ProgressUpdater
+ chunkRetryDeadline time.Duration
+}
+
+// NewInfoFromMedia should be invoked from the Media method of a call. It returns a
+// MediaInfo populated with chunk size and content type, and a reader or MediaBuffer
+// if needed.
+func NewInfoFromMedia(r io.Reader, options []googleapi.MediaOption) *MediaInfo {
+ mi := &MediaInfo{}
+ opts := googleapi.ProcessMediaOptions(options)
+ if !opts.ForceEmptyContentType {
+ mi.mType = opts.ContentType
+ if mi.mType == "" {
+ r, mi.mType = gax.DetermineContentType(r)
+ }
+ }
+ mi.chunkRetryDeadline = opts.ChunkRetryDeadline
+ mi.media, mi.buffer, mi.singleChunk = PrepareUpload(r, opts.ChunkSize)
+ return mi
+}
+
+// NewInfoFromResumableMedia should be invoked from the ResumableMedia method of a
+// call. It returns a MediaInfo using the given reader, size and media type.
+func NewInfoFromResumableMedia(r io.ReaderAt, size int64, mediaType string) *MediaInfo {
+ rdr := ReaderAtToReader(r, size)
+ mType := mediaType
+ if mType == "" {
+ rdr, mType = gax.DetermineContentType(rdr)
+ }
+
+ return &MediaInfo{
+ size: size,
+ mType: mType,
+ buffer: NewMediaBuffer(rdr, googleapi.DefaultUploadChunkSize),
+ media: nil,
+ singleChunk: false,
+ }
+}
+
+// SetProgressUpdater sets the progress updater for the media info.
+func (mi *MediaInfo) SetProgressUpdater(pu googleapi.ProgressUpdater) {
+ if mi != nil {
+ mi.progressUpdater = pu
+ }
+}
+
+// UploadType determines the type of upload: a single request, or a resumable
+// series of requests.
+func (mi *MediaInfo) UploadType() string {
+ if mi.singleChunk {
+ return "multipart"
+ }
+ return "resumable"
+}
+
+// UploadRequest sets up an HTTP request for media upload. It adds headers
+// as necessary, and returns a replacement for the body and a function for http.Request.GetBody.
+func (mi *MediaInfo) UploadRequest(reqHeaders http.Header, body io.Reader) (newBody io.Reader, getBody func() (io.ReadCloser, error), cleanup func()) {
+ cleanup = func() {}
+ if mi == nil {
+ return body, nil, cleanup
+ }
+ var media io.Reader
+ if mi.media != nil {
+ // This only happens when the caller has turned off chunking. In that
+ // case, we write all of media in a single non-retryable request.
+ media = mi.media
+ } else if mi.singleChunk {
+ // The data fits in a single chunk, which has now been read into the MediaBuffer.
+ // We obtain that chunk so we can write it in a single request. The request can
+ // be retried because the data is stored in the MediaBuffer.
+ media, _, _, _ = mi.buffer.Chunk()
+ }
+ toCleanup := []io.Closer{}
+ if media != nil {
+ fb := readerFunc(body)
+ fm := readerFunc(media)
+ combined, ctype := CombineBodyMedia(body, "application/json", media, mi.mType)
+ toCleanup = append(toCleanup, combined)
+ if fb != nil && fm != nil {
+ getBody = func() (io.ReadCloser, error) {
+ rb := ioutil.NopCloser(fb())
+ rm := ioutil.NopCloser(fm())
+ var mimeBoundary string
+ if _, params, err := mime.ParseMediaType(ctype); err == nil {
+ mimeBoundary = params["boundary"]
+ }
+ r, _ := combineBodyMedia(rb, "application/json", rm, mi.mType, mimeBoundary)
+ toCleanup = append(toCleanup, r)
+ return r, nil
+ }
+ }
+ reqHeaders.Set("Content-Type", ctype)
+ body = combined
+ }
+ if mi.buffer != nil && mi.mType != "" && !mi.singleChunk {
+ // This happens when initiating a resumable upload session.
+ // The initial request contains a JSON body rather than media.
+ // It can be retried with a getBody function that re-creates the request body.
+ fb := readerFunc(body)
+ if fb != nil {
+ getBody = func() (io.ReadCloser, error) {
+ rb := ioutil.NopCloser(fb())
+ toCleanup = append(toCleanup, rb)
+ return rb, nil
+ }
+ }
+ reqHeaders.Set("X-Upload-Content-Type", mi.mType)
+ }
+ // Ensure that any bodies created in getBody are cleaned up.
+ cleanup = func() {
+ for _, closer := range toCleanup {
+ _ = closer.Close()
+ }
+
+ }
+ return body, getBody, cleanup
+}
+
+// readerFunc returns a function that always returns an io.Reader that has the same
+// contents as r, provided that can be done without consuming r. Otherwise, it
+// returns nil.
+// See http.NewRequest (in net/http/request.go).
+func readerFunc(r io.Reader) func() io.Reader {
+ switch r := r.(type) {
+ case *bytes.Buffer:
+ buf := r.Bytes()
+ return func() io.Reader { return bytes.NewReader(buf) }
+ case *bytes.Reader:
+ snapshot := *r
+ return func() io.Reader { r := snapshot; return &r }
+ case *strings.Reader:
+ snapshot := *r
+ return func() io.Reader { r := snapshot; return &r }
+ default:
+ return nil
+ }
+}
+
+// ResumableUpload returns an appropriately configured ResumableUpload value if the
+// upload is resumable, or nil otherwise.
+func (mi *MediaInfo) ResumableUpload(locURI string) *ResumableUpload {
+ if mi == nil || mi.singleChunk {
+ return nil
+ }
+ return &ResumableUpload{
+ URI: locURI,
+ Media: mi.buffer,
+ MediaType: mi.mType,
+ Callback: func(curr int64) {
+ if mi.progressUpdater != nil {
+ mi.progressUpdater(curr, mi.size)
+ }
+ },
+ ChunkRetryDeadline: mi.chunkRetryDeadline,
+ }
+}
+
+// SetGetBody sets the GetBody field of req to f. This was once needed
+// to gracefully support Go 1.7 and earlier which didn't have that
+// field.
+//
+// Deprecated: the code generator no longer uses this as of
+// 2019-02-19. Nothing else should be calling this anyway, but we
+// won't delete this immediately; it will be deleted in as early as 6
+// months.
+func SetGetBody(req *http.Request, f func() (io.ReadCloser, error)) {
+ req.GetBody = f
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/params.go b/vendor/google.golang.org/api/internal/gensupport/params.go
new file mode 100644
index 0000000..1a30d2c
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/params.go
@@ -0,0 +1,57 @@
+// Copyright 2015 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 (
+ "net/url"
+
+ "google.golang.org/api/googleapi"
+)
+
+// URLParams is a simplified replacement for url.Values
+// that safely builds up URL parameters for encoding.
+type URLParams map[string][]string
+
+// Get returns the first value for the given key, or "".
+func (u URLParams) Get(key string) string {
+ vs := u[key]
+ if len(vs) == 0 {
+ return ""
+ }
+ return vs[0]
+}
+
+// Set sets the key to value.
+// It replaces any existing values.
+func (u URLParams) Set(key, value string) {
+ u[key] = []string{value}
+}
+
+// SetMulti sets the key to an array of values.
+// It replaces any existing values.
+// Note that values must not be modified after calling SetMulti
+// so the caller is responsible for making a copy if necessary.
+func (u URLParams) SetMulti(key string, values []string) {
+ u[key] = values
+}
+
+// Encode encodes the values into “URL encoded” form
+// ("bar=baz&foo=quux") sorted by key.
+func (u URLParams) Encode() string {
+ return url.Values(u).Encode()
+}
+
+// SetOptions sets the URL params and any additional `CallOption` or
+// `MultiCallOption` passed in.
+func SetOptions(u URLParams, opts ...googleapi.CallOption) {
+ for _, o := range opts {
+ m, ok := o.(googleapi.MultiCallOption)
+ if ok {
+ u.SetMulti(m.GetMulti())
+ continue
+ }
+ u.Set(o.Get())
+ }
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/resumable.go b/vendor/google.golang.org/api/internal/gensupport/resumable.go
new file mode 100644
index 0000000..ee8e9f3
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/resumable.go
@@ -0,0 +1,265 @@
+// 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 (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/google/uuid"
+ "google.golang.org/api/internal"
+)
+
+// ResumableUpload is used by the generated APIs to provide resumable uploads.
+// It is not used by developers directly.
+type ResumableUpload struct {
+ Client *http.Client
+ // URI is the resumable resource destination provided by the server after specifying "&uploadType=resumable".
+ URI string
+ UserAgent string // User-Agent for header of the request
+ // Media is the object being uploaded.
+ Media *MediaBuffer
+ // 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)
+
+ // Retry optionally configures retries for requests made against the upload.
+ Retry *RetryConfig
+
+ // ChunkRetryDeadline configures the per-chunk deadline after which no further
+ // retries should happen.
+ ChunkRetryDeadline time.Duration
+
+ // Track current request invocation ID and attempt count for retry metric
+ // headers.
+ invocationID string
+ attempts int
+}
+
+// Progress returns the number of bytes uploaded at this point.
+func (rx *ResumableUpload) Progress() int64 {
+ rx.mu.Lock()
+ defer rx.mu.Unlock()
+ return rx.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 (rx *ResumableUpload) doUploadRequest(ctx context.Context, data io.Reader, off, size int64, final bool) (*http.Response, error) {
+ req, err := http.NewRequest("POST", rx.URI, data)
+ if err != nil {
+ return nil, err
+ }
+
+ req.ContentLength = size
+ var contentRange string
+ if final {
+ if size == 0 {
+ contentRange = fmt.Sprintf("bytes */%v", off)
+ } else {
+ contentRange = fmt.Sprintf("bytes %v-%v/%v", off, off+size-1, off+size)
+ }
+ } else {
+ contentRange = fmt.Sprintf("bytes %v-%v/*", off, off+size-1)
+ }
+ req.Header.Set("Content-Range", contentRange)
+ req.Header.Set("Content-Type", rx.MediaType)
+ req.Header.Set("User-Agent", rx.UserAgent)
+
+ baseXGoogHeader := "gl-go/" + GoVersion() + " gdcl/" + internal.Version
+ invocationHeader := fmt.Sprintf("gccl-invocation-id/%s gccl-attempt-count/%d", rx.invocationID, rx.attempts)
+ req.Header.Set("X-Goog-Api-Client", strings.Join([]string{baseXGoogHeader, invocationHeader}, " "))
+
+ // 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.
+ req.Header.Set("X-GUploader-No-308", "yes")
+
+ return SendRequest(ctx, rx.Client, req)
+}
+
+func statusResumeIncomplete(resp *http.Response) bool {
+ // This is how the server signals "status resume incomplete"
+ // when X-GUploader-No-308 is set to "yes":
+ return resp != nil && resp.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 (rx *ResumableUpload) reportProgress(old, updated int64) {
+ if updated-old == 0 {
+ return
+ }
+ rx.mu.Lock()
+ rx.progress = updated
+ rx.mu.Unlock()
+ if rx.Callback != nil {
+ rx.Callback(updated)
+ }
+}
+
+// transferChunk performs a single HTTP request to upload a single chunk from rx.Media.
+func (rx *ResumableUpload) transferChunk(ctx context.Context) (*http.Response, error) {
+ chunk, off, size, err := rx.Media.Chunk()
+
+ done := err == io.EOF
+ if !done && err != nil {
+ return nil, err
+ }
+
+ res, err := rx.doUploadRequest(ctx, chunk, off, int64(size), done)
+ if err != nil {
+ return res, err
+ }
+
+ // We sent "X-GUploader-No-308: yes" (see comment elsewhere in
+ // this file), so we don't expect to get a 308.
+ if res.StatusCode == 308 {
+ return nil, errors.New("unexpected 308 response status code")
+ }
+
+ if res.StatusCode == http.StatusOK {
+ rx.reportProgress(off, off+int64(size))
+ }
+
+ if statusResumeIncomplete(res) {
+ rx.Media.Next()
+ }
+ return res, 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 (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err 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 prepareReturn = func(resp *http.Response, err error) (*http.Response, error) {
+ if err != nil {
+ if resp != nil && resp.Body != nil {
+ resp.Body.Close()
+ }
+ return nil, err
+ }
+ // This case is very unlikely but possible only if rx.ChunkRetryDeadline is
+ // set to a very small value, in which case no requests will be sent before
+ // the deadline. Return an error to avoid causing a panic.
+ if resp == nil {
+ return nil, fmt.Errorf("upload request to %v not sent, choose larger value for ChunkRetryDealine", rx.URI)
+ }
+ return resp, nil
+ }
+ // Configure retryable error criteria.
+ errorFunc := rx.Retry.errorFunc()
+
+ // Configure per-chunk retry deadline.
+ var retryDeadline time.Duration
+ if rx.ChunkRetryDeadline != 0 {
+ retryDeadline = rx.ChunkRetryDeadline
+ } else {
+ retryDeadline = defaultRetryDeadline
+ }
+
+ // Send all chunks.
+ for {
+ var pause time.Duration
+
+ // Each chunk gets its own initialized-at-zero backoff and invocation ID.
+ bo := rx.Retry.backoff()
+ quitAfterTimer := time.NewTimer(retryDeadline)
+ rx.attempts = 1
+ rx.invocationID = uuid.New().String()
+
+ // Retry loop for a single chunk.
+ for {
+ pauseTimer := time.NewTimer(pause)
+ select {
+ case <-ctx.Done():
+ quitAfterTimer.Stop()
+ pauseTimer.Stop()
+ if err == nil {
+ err = ctx.Err()
+ }
+ return prepareReturn(resp, err)
+ case <-pauseTimer.C:
+ quitAfterTimer.Stop()
+ case <-quitAfterTimer.C:
+ pauseTimer.Stop()
+ return prepareReturn(resp, err)
+ }
+ pauseTimer.Stop()
+
+ // 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():
+ quitAfterTimer.Stop()
+ if err == nil {
+ err = ctx.Err()
+ }
+ return prepareReturn(resp, err)
+ case <-quitAfterTimer.C:
+ return prepareReturn(resp, err)
+ default:
+ quitAfterTimer.Stop()
+ }
+
+ resp, err = rx.transferChunk(ctx)
+
+ var status int
+ if resp != nil {
+ status = resp.StatusCode
+ }
+
+ // Check if we should retry the request.
+ if !errorFunc(status, err) {
+ break
+ }
+
+ rx.attempts++
+ pause = bo.Pause()
+ if resp != nil && resp.Body != nil {
+ resp.Body.Close()
+ }
+ }
+
+ // If the chunk was uploaded successfully, but there's still
+ // more to go, upload the next chunk without any delay.
+ if statusResumeIncomplete(resp) {
+ resp.Body.Close()
+ continue
+ }
+
+ return prepareReturn(resp, err)
+ }
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/retry.go b/vendor/google.golang.org/api/internal/gensupport/retry.go
new file mode 100644
index 0000000..20b57d9
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/retry.go
@@ -0,0 +1,121 @@
+// Copyright 2021 Google LLC.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gensupport
+
+import (
+ "errors"
+ "io"
+ "net"
+ "strings"
+ "time"
+
+ "github.com/googleapis/gax-go/v2"
+ "google.golang.org/api/googleapi"
+)
+
+// 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 (
+ // Default per-chunk deadline for resumable uploads.
+ defaultRetryDeadline = 32 * time.Second
+ // Default backoff timer.
+ backoff = func() Backoff {
+ return &gax.Backoff{Initial: 100 * time.Millisecond}
+ }
+ // syscallRetryable is a platform-specific hook, specified in retryable_linux.go
+ syscallRetryable func(error) bool = func(err error) bool { return false }
+)
+
+const (
+ // 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
+ statusTooManyRequests = 429
+
+ // statusRequestTimeout is returned by the storage API if the
+ // upload connection was broken. The request should be retried.
+ statusRequestTimeout = 408
+)
+
+// shouldRetry indicates whether an error is retryable for the purposes of this
+// package, unless a ShouldRetry func is specified by the RetryConfig instead.
+// It follows guidance from
+// https://cloud.google.com/storage/docs/exponential-backoff .
+func shouldRetry(status int, err error) bool {
+ if 500 <= status && status <= 599 {
+ return true
+ }
+ if status == statusTooManyRequests || status == statusRequestTimeout {
+ return true
+ }
+ if err == io.ErrUnexpectedEOF {
+ return true
+ }
+ // Transient network errors should be retried.
+ if syscallRetryable(err) {
+ return true
+ }
+ if err, ok := err.(interface{ Temporary() bool }); ok {
+ if err.Temporary() {
+ return true
+ }
+ }
+ var opErr *net.OpError
+ if errors.As(err, &opErr) {
+ if strings.Contains(opErr.Error(), "use of closed network connection") {
+ // TODO: check against net.ErrClosed (go 1.16+) instead of string
+ return true
+ }
+ }
+
+ // If Go 1.13 error unwrapping is available, use this to examine wrapped
+ // errors.
+ if err, ok := err.(interface{ Unwrap() error }); ok {
+ return shouldRetry(status, err.Unwrap())
+ }
+ return false
+}
+
+// RetryConfig allows configuration of backoff timing and retryable errors.
+type RetryConfig struct {
+ Backoff *gax.Backoff
+ ShouldRetry func(err error) bool
+}
+
+// Get a new backoff object based on the configured values.
+func (r *RetryConfig) backoff() Backoff {
+ if r == nil || r.Backoff == nil {
+ return backoff()
+ }
+ return &gax.Backoff{
+ Initial: r.Backoff.Initial,
+ Max: r.Backoff.Max,
+ Multiplier: r.Backoff.Multiplier,
+ }
+}
+
+// This is kind of hacky; it is necessary because ShouldRetry expects to
+// handle HTTP errors via googleapi.Error, but the error has not yet been
+// wrapped with a googleapi.Error at this layer, and the ErrorFunc type
+// in the manual layer does not pass in a status explicitly as it does
+// here. So, we must wrap error status codes in a googleapi.Error so that
+// ShouldRetry can parse this correctly.
+func (r *RetryConfig) errorFunc() func(status int, err error) bool {
+ if r == nil || r.ShouldRetry == nil {
+ return shouldRetry
+ }
+ return func(status int, err error) bool {
+ if status >= 400 {
+ return r.ShouldRetry(&googleapi.Error{Code: status})
+ }
+ return r.ShouldRetry(err)
+ }
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/retryable_linux.go b/vendor/google.golang.org/api/internal/gensupport/retryable_linux.go
new file mode 100644
index 0000000..a916c3d
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/retryable_linux.go
@@ -0,0 +1,16 @@
+// Copyright 2020 Google LLC.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux
+// +build linux
+
+package gensupport
+
+import "syscall"
+
+func init() {
+ // Initialize syscallRetryable to return true on transient socket-level
+ // errors. These errors are specific to Linux.
+ syscallRetryable = func(err error) bool { return err == syscall.ECONNRESET || err == syscall.ECONNREFUSED }
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/send.go b/vendor/google.golang.org/api/internal/gensupport/send.go
new file mode 100644
index 0000000..85c7bcb
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/send.go
@@ -0,0 +1,180 @@
+// 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 (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/google/uuid"
+ "github.com/googleapis/gax-go/v2"
+)
+
+// Use this error type to return an error which allows introspection of both
+// the context error and the error from the service.
+type wrappedCallErr struct {
+ ctxErr error
+ wrappedErr error
+}
+
+func (e wrappedCallErr) Error() string {
+ return fmt.Sprintf("retry failed with %v; last error: %v", e.ctxErr, e.wrappedErr)
+}
+
+func (e wrappedCallErr) Unwrap() error {
+ return e.wrappedErr
+}
+
+// Is allows errors.Is to match the error from the call as well as context
+// sentinel errors.
+func (e wrappedCallErr) Is(target error) bool {
+ return errors.Is(e.ctxErr, target) || errors.Is(e.wrappedErr, target)
+}
+
+// SendRequest sends a single HTTP request using the given client.
+// If ctx is non-nil, it calls all hooks, then sends the request with
+// req.WithContext, then calls any functions returned by the hooks in
+// reverse order.
+func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
+ // Disallow Accept-Encoding because it interferes with the automatic gzip handling
+ // done by the default http.Transport. See https://github.com/google/google-api-go-client/issues/219.
+ if _, ok := req.Header["Accept-Encoding"]; ok {
+ return nil, errors.New("google api: custom Accept-Encoding headers not allowed")
+ }
+ if ctx == nil {
+ return client.Do(req)
+ }
+ return send(ctx, client, req)
+}
+
+func send(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
+ if client == nil {
+ client = http.DefaultClient
+ }
+ resp, err := client.Do(req.WithContext(ctx))
+ // If we got an error, and the context has been canceled,
+ // the context's error is probably more useful.
+ if err != nil {
+ select {
+ case <-ctx.Done():
+ err = ctx.Err()
+ default:
+ }
+ }
+ return resp, err
+}
+
+// SendRequestWithRetry sends a single HTTP request using the given client,
+// with retries if a retryable error is returned.
+// If ctx is non-nil, it calls all hooks, then sends the request with
+// req.WithContext, then calls any functions returned by the hooks in
+// reverse order.
+func SendRequestWithRetry(ctx context.Context, client *http.Client, req *http.Request, retry *RetryConfig) (*http.Response, error) {
+ // Disallow Accept-Encoding because it interferes with the automatic gzip handling
+ // done by the default http.Transport. See https://github.com/google/google-api-go-client/issues/219.
+ if _, ok := req.Header["Accept-Encoding"]; ok {
+ return nil, errors.New("google api: custom Accept-Encoding headers not allowed")
+ }
+ if ctx == nil {
+ return client.Do(req)
+ }
+ return sendAndRetry(ctx, client, req, retry)
+}
+
+func sendAndRetry(ctx context.Context, client *http.Client, req *http.Request, retry *RetryConfig) (*http.Response, error) {
+ if client == nil {
+ client = http.DefaultClient
+ }
+
+ var resp *http.Response
+ var err error
+ attempts := 1
+ invocationID := uuid.New().String()
+ baseXGoogHeader := req.Header.Get("X-Goog-Api-Client")
+
+ // Loop to retry the request, up to the context deadline.
+ var pause time.Duration
+ var bo Backoff
+ if retry != nil && retry.Backoff != nil {
+ bo = &gax.Backoff{
+ Initial: retry.Backoff.Initial,
+ Max: retry.Backoff.Max,
+ Multiplier: retry.Backoff.Multiplier,
+ }
+ } else {
+ bo = backoff()
+ }
+
+ var errorFunc = retry.errorFunc()
+
+ for {
+ t := time.NewTimer(pause)
+ select {
+ case <-ctx.Done():
+ t.Stop()
+ // If we got an error and the context has been canceled, return an error acknowledging
+ // both the context cancelation and the service error.
+ if err != nil {
+ return resp, wrappedCallErr{ctx.Err(), err}
+ }
+ return resp, ctx.Err()
+ case <-t.C:
+ }
+
+ if ctx.Err() != nil {
+ // Check for context cancellation once more. If more than one case in a
+ // select is 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.
+ if err != nil {
+ return resp, wrappedCallErr{ctx.Err(), err}
+ }
+ return resp, ctx.Err()
+ }
+ invocationHeader := fmt.Sprintf("gccl-invocation-id/%s gccl-attempt-count/%d", invocationID, attempts)
+ xGoogHeader := strings.Join([]string{invocationHeader, baseXGoogHeader}, " ")
+ req.Header.Set("X-Goog-Api-Client", xGoogHeader)
+
+ resp, err = client.Do(req.WithContext(ctx))
+
+ var status int
+ if resp != nil {
+ status = resp.StatusCode
+ }
+
+ // Check if we can retry the request. A retry can only be done if the error
+ // is retryable and the request body can be re-created using GetBody (this
+ // will not be possible if the body was unbuffered).
+ if req.GetBody == nil || !errorFunc(status, err) {
+ break
+ }
+ attempts++
+ var errBody error
+ req.Body, errBody = req.GetBody()
+ if errBody != nil {
+ break
+ }
+
+ pause = bo.Pause()
+ if resp != nil && resp.Body != nil {
+ resp.Body.Close()
+ }
+ }
+ return resp, err
+}
+
+// DecodeResponse decodes the body of res into target. If there is no body,
+// target is unchanged.
+func DecodeResponse(target interface{}, res *http.Response) error {
+ if res.StatusCode == http.StatusNoContent {
+ return nil
+ }
+ return json.NewDecoder(res.Body).Decode(target)
+}
diff --git a/vendor/google.golang.org/api/internal/gensupport/version.go b/vendor/google.golang.org/api/internal/gensupport/version.go
new file mode 100644
index 0000000..23f6aa2
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/gensupport/version.go
@@ -0,0 +1,53 @@
+// Copyright 2020 Google LLC. 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 (
+ "runtime"
+ "strings"
+ "unicode"
+)
+
+// GoVersion returns the Go runtime version. The returned string
+// has no whitespace.
+func GoVersion() string {
+ return goVersion
+}
+
+var goVersion = goVer(runtime.Version())
+
+const develPrefix = "devel +"
+
+func goVer(s string) string {
+ if strings.HasPrefix(s, develPrefix) {
+ s = s[len(develPrefix):]
+ if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
+ s = s[:p]
+ }
+ return s
+ }
+
+ if strings.HasPrefix(s, "go1") {
+ s = s[2:]
+ var prerelease string
+ if p := strings.IndexFunc(s, notSemverRune); p >= 0 {
+ s, prerelease = s[:p], s[p:]
+ }
+ if strings.HasSuffix(s, ".") {
+ s += "0"
+ } else if strings.Count(s, ".") < 2 {
+ s += ".0"
+ }
+ if prerelease != "" {
+ s += "-" + prerelease
+ }
+ return s
+ }
+ return ""
+}
+
+func notSemverRune(r rune) bool {
+ return !strings.ContainsRune("0123456789.", r)
+}
diff --git a/vendor/google.golang.org/api/internal/impersonate/impersonate.go b/vendor/google.golang.org/api/internal/impersonate/impersonate.go
new file mode 100644
index 0000000..b465bbc
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/impersonate/impersonate.go
@@ -0,0 +1,128 @@
+// Copyright 2020 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 impersonate is used to impersonate Google Credentials.
+package impersonate
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "time"
+
+ "golang.org/x/oauth2"
+)
+
+// Config for generating impersonated credentials.
+type Config struct {
+ // Target is the service account to impersonate. Required.
+ Target string
+ // Scopes the impersonated credential should have. Required.
+ Scopes []string
+ // Delegates are the service accounts in a delegation chain. Each service
+ // account must be granted roles/iam.serviceAccountTokenCreator on the next
+ // service account in the chain. Optional.
+ Delegates []string
+}
+
+// TokenSource returns an impersonated TokenSource configured with the provided
+// config using ts as the base credential provider for making requests.
+func TokenSource(ctx context.Context, ts oauth2.TokenSource, config *Config) (oauth2.TokenSource, error) {
+ if len(config.Scopes) == 0 {
+ return nil, fmt.Errorf("impersonate: scopes must be provided")
+ }
+ its := impersonatedTokenSource{
+ ctx: ctx,
+ ts: ts,
+ name: formatIAMServiceAccountName(config.Target),
+ // Default to the longest acceptable value of one hour as the token will
+ // be refreshed automatically.
+ lifetime: "3600s",
+ }
+
+ its.delegates = make([]string, len(config.Delegates))
+ for i, v := range config.Delegates {
+ its.delegates[i] = formatIAMServiceAccountName(v)
+ }
+ its.scopes = make([]string, len(config.Scopes))
+ copy(its.scopes, config.Scopes)
+
+ return oauth2.ReuseTokenSource(nil, its), nil
+}
+
+func formatIAMServiceAccountName(name string) string {
+ return fmt.Sprintf("projects/-/serviceAccounts/%s", name)
+}
+
+type generateAccessTokenReq struct {
+ Delegates []string `json:"delegates,omitempty"`
+ Lifetime string `json:"lifetime,omitempty"`
+ Scope []string `json:"scope,omitempty"`
+}
+
+type generateAccessTokenResp struct {
+ AccessToken string `json:"accessToken"`
+ ExpireTime string `json:"expireTime"`
+}
+
+type impersonatedTokenSource struct {
+ ctx context.Context
+ ts oauth2.TokenSource
+
+ name string
+ lifetime string
+ scopes []string
+ delegates []string
+}
+
+// Token returns an impersonated Token.
+func (i impersonatedTokenSource) Token() (*oauth2.Token, error) {
+ hc := oauth2.NewClient(i.ctx, i.ts)
+ reqBody := generateAccessTokenReq{
+ Delegates: i.delegates,
+ Lifetime: i.lifetime,
+ Scope: i.scopes,
+ }
+ b, err := json.Marshal(reqBody)
+ if err != nil {
+ return nil, fmt.Errorf("impersonate: unable to marshal request: %v", err)
+ }
+ url := fmt.Sprintf("https://iamcredentials.googleapis.com/v1/%s:generateAccessToken", i.name)
+ req, err := http.NewRequest("POST", url, bytes.NewReader(b))
+ if err != nil {
+ return nil, fmt.Errorf("impersonate: unable to create request: %v", err)
+ }
+ req = req.WithContext(i.ctx)
+ req.Header.Set("Content-Type", "application/json")
+
+ resp, err := hc.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("impersonate: unable to generate access token: %v", err)
+ }
+ defer resp.Body.Close()
+ body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
+ if err != nil {
+ return nil, fmt.Errorf("impersonate: unable to read body: %v", err)
+ }
+ if c := resp.StatusCode; c < 200 || c > 299 {
+ return nil, fmt.Errorf("impersonate: status code %d: %s", c, body)
+ }
+
+ var accessTokenResp generateAccessTokenResp
+ if err := json.Unmarshal(body, &accessTokenResp); err != nil {
+ return nil, fmt.Errorf("impersonate: unable to parse response: %v", err)
+ }
+ expiry, err := time.Parse(time.RFC3339, accessTokenResp.ExpireTime)
+ if err != nil {
+ return nil, fmt.Errorf("impersonate: unable to parse expiry: %v", err)
+ }
+ return &oauth2.Token{
+ AccessToken: accessTokenResp.AccessToken,
+ Expiry: expiry,
+ }, nil
+}
diff --git a/vendor/google.golang.org/api/internal/settings.go b/vendor/google.golang.org/api/internal/settings.go
new file mode 100644
index 0000000..76efdb2
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/settings.go
@@ -0,0 +1,142 @@
+// Copyright 2017 Google LLC.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package internal supports the options and transport packages.
+package internal
+
+import (
+ "crypto/tls"
+ "errors"
+ "net/http"
+
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/google"
+ "google.golang.org/api/internal/impersonate"
+ "google.golang.org/grpc"
+)
+
+// DialSettings holds information needed to establish a connection with a
+// Google API service.
+type DialSettings struct {
+ Endpoint string
+ DefaultEndpoint string
+ DefaultMTLSEndpoint string
+ Scopes []string
+ DefaultScopes []string
+ EnableJwtWithScope bool
+ TokenSource oauth2.TokenSource
+ Credentials *google.Credentials
+ CredentialsFile string // if set, Token Source is ignored.
+ CredentialsJSON []byte
+ InternalCredentials *google.Credentials
+ UserAgent string
+ APIKey string
+ Audiences []string
+ DefaultAudience string
+ HTTPClient *http.Client
+ GRPCDialOpts []grpc.DialOption
+ GRPCConn *grpc.ClientConn
+ GRPCConnPool ConnPool
+ GRPCConnPoolSize int
+ NoAuth bool
+ TelemetryDisabled bool
+ ClientCertSource func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
+ CustomClaims map[string]interface{}
+ SkipValidation bool
+ ImpersonationConfig *impersonate.Config
+ EnableDirectPath bool
+ AllowNonDefaultServiceAccount bool
+
+ // Google API system parameters. For more information please read:
+ // https://cloud.google.com/apis/docs/system-parameters
+ QuotaProject string
+ RequestReason string
+}
+
+// GetScopes returns the user-provided scopes, if set, or else falls back to the
+// default scopes.
+func (ds *DialSettings) GetScopes() []string {
+ if len(ds.Scopes) > 0 {
+ return ds.Scopes
+ }
+ return ds.DefaultScopes
+}
+
+// GetAudience returns the user-provided audience, if set, or else falls back to the default audience.
+func (ds *DialSettings) GetAudience() string {
+ if ds.HasCustomAudience() {
+ return ds.Audiences[0]
+ }
+ return ds.DefaultAudience
+}
+
+// HasCustomAudience returns true if a custom audience is provided by users.
+func (ds *DialSettings) HasCustomAudience() bool {
+ return len(ds.Audiences) > 0
+}
+
+// Validate reports an error if ds is invalid.
+func (ds *DialSettings) Validate() error {
+ if ds.SkipValidation {
+ return nil
+ }
+ hasCreds := ds.APIKey != "" || ds.TokenSource != nil || ds.CredentialsFile != "" || ds.Credentials != nil
+ if ds.NoAuth && hasCreds {
+ return errors.New("options.WithoutAuthentication is incompatible with any option that provides credentials")
+ }
+ // Credentials should not appear with other options.
+ // We currently allow TokenSource and CredentialsFile to coexist.
+ // TODO(jba): make TokenSource & CredentialsFile an error (breaking change).
+ nCreds := 0
+ if ds.Credentials != nil {
+ nCreds++
+ }
+ if ds.CredentialsJSON != nil {
+ nCreds++
+ }
+ if ds.CredentialsFile != "" {
+ nCreds++
+ }
+ if ds.APIKey != "" {
+ nCreds++
+ }
+ if ds.TokenSource != nil {
+ nCreds++
+ }
+ if len(ds.Scopes) > 0 && len(ds.Audiences) > 0 {
+ return errors.New("WithScopes is incompatible with WithAudience")
+ }
+ // Accept only one form of credentials, except we allow TokenSource and CredentialsFile for backwards compatibility.
+ if nCreds > 1 && !(nCreds == 2 && ds.TokenSource != nil && ds.CredentialsFile != "") {
+ return errors.New("multiple credential options provided")
+ }
+ if ds.GRPCConn != nil && ds.GRPCConnPool != nil {
+ return errors.New("WithGRPCConn is incompatible with WithConnPool")
+ }
+ if ds.HTTPClient != nil && ds.GRPCConnPool != nil {
+ return errors.New("WithHTTPClient is incompatible with WithConnPool")
+ }
+ if ds.HTTPClient != nil && ds.GRPCConn != nil {
+ return errors.New("WithHTTPClient is incompatible with WithGRPCConn")
+ }
+ if ds.HTTPClient != nil && ds.GRPCDialOpts != nil {
+ return errors.New("WithHTTPClient is incompatible with gRPC dial options")
+ }
+ if ds.HTTPClient != nil && ds.QuotaProject != "" {
+ return errors.New("WithHTTPClient is incompatible with QuotaProject")
+ }
+ if ds.HTTPClient != nil && ds.RequestReason != "" {
+ return errors.New("WithHTTPClient is incompatible with RequestReason")
+ }
+ if ds.HTTPClient != nil && ds.ClientCertSource != nil {
+ return errors.New("WithHTTPClient is incompatible with WithClientCertSource")
+ }
+ if ds.ClientCertSource != nil && (ds.GRPCConn != nil || ds.GRPCConnPool != nil || ds.GRPCConnPoolSize != 0 || ds.GRPCDialOpts != nil) {
+ return errors.New("WithClientCertSource is currently only supported for HTTP. gRPC settings are incompatible")
+ }
+ if ds.ImpersonationConfig != nil && len(ds.ImpersonationConfig.Scopes) == 0 && len(ds.Scopes) == 0 {
+ return errors.New("WithImpersonatedCredentials requires scopes being provided")
+ }
+ return nil
+}
diff --git a/vendor/google.golang.org/api/internal/third_party/uritemplates/LICENSE b/vendor/google.golang.org/api/internal/third_party/uritemplates/LICENSE
new file mode 100644
index 0000000..7109c6e
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/third_party/uritemplates/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2013 Joshua Tacoma. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/google.golang.org/api/internal/third_party/uritemplates/METADATA b/vendor/google.golang.org/api/internal/third_party/uritemplates/METADATA
new file mode 100644
index 0000000..c7f86fc
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/third_party/uritemplates/METADATA
@@ -0,0 +1,14 @@
+name: "uritemplates"
+description:
+ "Package uritemplates is a level 4 implementation of RFC 6570 (URI "
+ "Template, http://tools.ietf.org/html/rfc6570)."
+
+third_party {
+ url {
+ type: GIT
+ value: "https://github.com/jtacoma/uritemplates"
+ }
+ version: "0.1"
+ last_upgrade_date { year: 2014 month: 8 day: 18 }
+ license_type: NOTICE
+}
diff --git a/vendor/google.golang.org/api/internal/third_party/uritemplates/uritemplates.go b/vendor/google.golang.org/api/internal/third_party/uritemplates/uritemplates.go
new file mode 100644
index 0000000..8c27d19
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/third_party/uritemplates/uritemplates.go
@@ -0,0 +1,248 @@
+// Copyright 2013 Joshua Tacoma. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package uritemplates is a level 3 implementation of RFC 6570 (URI
+// Template, http://tools.ietf.org/html/rfc6570).
+// uritemplates does not support composite values (in Go: slices or maps)
+// and so does not qualify as a level 4 implementation.
+package uritemplates
+
+import (
+ "bytes"
+ "errors"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var (
+ unreserved = regexp.MustCompile("[^A-Za-z0-9\\-._~]")
+ reserved = regexp.MustCompile("[^A-Za-z0-9\\-._~:/?#[\\]@!$&'()*+,;=]")
+ validname = regexp.MustCompile("^([A-Za-z0-9_\\.]|%[0-9A-Fa-f][0-9A-Fa-f])+$")
+ hex = []byte("0123456789ABCDEF")
+)
+
+func pctEncode(src []byte) []byte {
+ dst := make([]byte, len(src)*3)
+ for i, b := range src {
+ buf := dst[i*3 : i*3+3]
+ buf[0] = 0x25
+ buf[1] = hex[b/16]
+ buf[2] = hex[b%16]
+ }
+ return dst
+}
+
+// pairWriter is a convenience struct which allows escaped and unescaped
+// versions of the template to be written in parallel.
+type pairWriter struct {
+ escaped, unescaped bytes.Buffer
+}
+
+// Write writes the provided string directly without any escaping.
+func (w *pairWriter) Write(s string) {
+ w.escaped.WriteString(s)
+ w.unescaped.WriteString(s)
+}
+
+// Escape writes the provided string, escaping the string for the
+// escaped output.
+func (w *pairWriter) Escape(s string, allowReserved bool) {
+ w.unescaped.WriteString(s)
+ if allowReserved {
+ w.escaped.Write(reserved.ReplaceAllFunc([]byte(s), pctEncode))
+ } else {
+ w.escaped.Write(unreserved.ReplaceAllFunc([]byte(s), pctEncode))
+ }
+}
+
+// Escaped returns the escaped string.
+func (w *pairWriter) Escaped() string {
+ return w.escaped.String()
+}
+
+// Unescaped returns the unescaped string.
+func (w *pairWriter) Unescaped() string {
+ return w.unescaped.String()
+}
+
+// A uriTemplate is a parsed representation of a URI template.
+type uriTemplate struct {
+ raw string
+ parts []templatePart
+}
+
+// parse parses a URI template string into a uriTemplate object.
+func parse(rawTemplate string) (*uriTemplate, error) {
+ split := strings.Split(rawTemplate, "{")
+ parts := make([]templatePart, len(split)*2-1)
+ for i, s := range split {
+ if i == 0 {
+ if strings.Contains(s, "}") {
+ return nil, errors.New("unexpected }")
+ }
+ parts[i].raw = s
+ continue
+ }
+ subsplit := strings.Split(s, "}")
+ if len(subsplit) != 2 {
+ return nil, errors.New("malformed template")
+ }
+ expression := subsplit[0]
+ var err error
+ parts[i*2-1], err = parseExpression(expression)
+ if err != nil {
+ return nil, err
+ }
+ parts[i*2].raw = subsplit[1]
+ }
+ return &uriTemplate{
+ raw: rawTemplate,
+ parts: parts,
+ }, nil
+}
+
+type templatePart struct {
+ raw string
+ terms []templateTerm
+ first string
+ sep string
+ named bool
+ ifemp string
+ allowReserved bool
+}
+
+type templateTerm struct {
+ name string
+ explode bool
+ truncate int
+}
+
+func parseExpression(expression string) (result templatePart, err error) {
+ switch expression[0] {
+ case '+':
+ result.sep = ","
+ result.allowReserved = true
+ expression = expression[1:]
+ case '.':
+ result.first = "."
+ result.sep = "."
+ expression = expression[1:]
+ case '/':
+ result.first = "/"
+ result.sep = "/"
+ expression = expression[1:]
+ case ';':
+ result.first = ";"
+ result.sep = ";"
+ result.named = true
+ expression = expression[1:]
+ case '?':
+ result.first = "?"
+ result.sep = "&"
+ result.named = true
+ result.ifemp = "="
+ expression = expression[1:]
+ case '&':
+ result.first = "&"
+ result.sep = "&"
+ result.named = true
+ result.ifemp = "="
+ expression = expression[1:]
+ case '#':
+ result.first = "#"
+ result.sep = ","
+ result.allowReserved = true
+ expression = expression[1:]
+ default:
+ result.sep = ","
+ }
+ rawterms := strings.Split(expression, ",")
+ result.terms = make([]templateTerm, len(rawterms))
+ for i, raw := range rawterms {
+ result.terms[i], err = parseTerm(raw)
+ if err != nil {
+ break
+ }
+ }
+ return result, err
+}
+
+func parseTerm(term string) (result templateTerm, err error) {
+ // TODO(djd): Remove "*" suffix parsing once we check that no APIs have
+ // mistakenly used that attribute.
+ if strings.HasSuffix(term, "*") {
+ result.explode = true
+ term = term[:len(term)-1]
+ }
+ split := strings.Split(term, ":")
+ if len(split) == 1 {
+ result.name = term
+ } else if len(split) == 2 {
+ result.name = split[0]
+ var parsed int64
+ parsed, err = strconv.ParseInt(split[1], 10, 0)
+ result.truncate = int(parsed)
+ } else {
+ err = errors.New("multiple colons in same term")
+ }
+ if !validname.MatchString(result.name) {
+ err = errors.New("not a valid name: " + result.name)
+ }
+ if result.explode && result.truncate > 0 {
+ err = errors.New("both explode and prefix modifiers on same term")
+ }
+ return result, err
+}
+
+// Expand expands a URI template with a set of values to produce the
+// resultant URI. Two forms of the result are returned: one with all the
+// elements escaped, and one with the elements unescaped.
+func (t *uriTemplate) Expand(values map[string]string) (escaped, unescaped string) {
+ var w pairWriter
+ for _, p := range t.parts {
+ p.expand(&w, values)
+ }
+ return w.Escaped(), w.Unescaped()
+}
+
+func (tp *templatePart) expand(w *pairWriter, values map[string]string) {
+ if len(tp.raw) > 0 {
+ w.Write(tp.raw)
+ return
+ }
+ var first = true
+ for _, term := range tp.terms {
+ value, exists := values[term.name]
+ if !exists {
+ continue
+ }
+ if first {
+ w.Write(tp.first)
+ first = false
+ } else {
+ w.Write(tp.sep)
+ }
+ tp.expandString(w, term, value)
+ }
+}
+
+func (tp *templatePart) expandName(w *pairWriter, name string, empty bool) {
+ if tp.named {
+ w.Write(name)
+ if empty {
+ w.Write(tp.ifemp)
+ } else {
+ w.Write("=")
+ }
+ }
+}
+
+func (tp *templatePart) expandString(w *pairWriter, t templateTerm, s string) {
+ if len(s) > t.truncate && t.truncate > 0 {
+ s = s[:t.truncate]
+ }
+ tp.expandName(w, t.name, len(s) == 0)
+ w.Escape(s, tp.allowReserved)
+}
diff --git a/vendor/google.golang.org/api/internal/third_party/uritemplates/utils.go b/vendor/google.golang.org/api/internal/third_party/uritemplates/utils.go
new file mode 100644
index 0000000..2e70b81
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/third_party/uritemplates/utils.go
@@ -0,0 +1,17 @@
+// 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 uritemplates
+
+// Expand parses then expands a URI template with a set of values to produce
+// the resultant URI. Two forms of the result are returned: one with all the
+// elements escaped, and one with the elements unescaped.
+func Expand(path string, values map[string]string) (escaped, unescaped string, err error) {
+ template, err := parse(path)
+ if err != nil {
+ return "", "", err
+ }
+ escaped, unescaped = template.Expand(values)
+ return escaped, unescaped, nil
+}
diff --git a/vendor/google.golang.org/api/internal/version.go b/vendor/google.golang.org/api/internal/version.go
new file mode 100644
index 0000000..2d02a44
--- /dev/null
+++ b/vendor/google.golang.org/api/internal/version.go
@@ -0,0 +1,8 @@
+// Copyright 2022 Google LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+// Version is the current tagged release of the library.
+const Version = "0.109.0"