1// Copyright 2014 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 storage
16
17import (
18	"context"
19	"fmt"
20	"net/http"
21	"reflect"
22	"time"
23
24	"cloud.google.com/go/internal/optional"
25	"cloud.google.com/go/internal/trace"
26	"google.golang.org/api/googleapi"
27	"google.golang.org/api/iterator"
28	raw "google.golang.org/api/storage/v1"
29)
30
31// BucketHandle provides operations on a Google Cloud Storage bucket.
32// Use Client.Bucket to get a handle.
33type BucketHandle struct {
34	c                *Client
35	name             string
36	acl              ACLHandle
37	defaultObjectACL ACLHandle
38	conds            *BucketConditions
39	userProject      string // project for Requester Pays buckets
40}
41
42// Bucket returns a BucketHandle, which provides operations on the named bucket.
43// This call does not perform any network operations.
44//
45// The supplied name must contain only lowercase letters, numbers, dashes,
46// underscores, and dots. The full specification for valid bucket names can be
47// found at:
48//   https://cloud.google.com/storage/docs/bucket-naming
49func (c *Client) Bucket(name string) *BucketHandle {
50	return &BucketHandle{
51		c:    c,
52		name: name,
53		acl: ACLHandle{
54			c:      c,
55			bucket: name,
56		},
57		defaultObjectACL: ACLHandle{
58			c:         c,
59			bucket:    name,
60			isDefault: true,
61		},
62	}
63}
64
65// Create creates the Bucket in the project.
66// If attrs is nil the API defaults will be used.
67func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *BucketAttrs) (err error) {
68	ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create")
69	defer func() { trace.EndSpan(ctx, err) }()
70
71	var bkt *raw.Bucket
72	if attrs != nil {
73		bkt = attrs.toRawBucket()
74	} else {
75		bkt = &raw.Bucket{}
76	}
77	bkt.Name = b.name
78	// If there is lifecycle information but no location, explicitly set
79	// the location. This is a GCS quirk/bug.
80	if bkt.Location == "" && bkt.Lifecycle != nil {
81		bkt.Location = "US"
82	}
83	req := b.c.raw.Buckets.Insert(projectID, bkt)
84	setClientHeader(req.Header())
85	if attrs != nil && attrs.PredefinedACL != "" {
86		req.PredefinedAcl(attrs.PredefinedACL)
87	}
88	if attrs != nil && attrs.PredefinedDefaultObjectACL != "" {
89		req.PredefinedDefaultObjectAcl(attrs.PredefinedDefaultObjectACL)
90	}
91	return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err })
92}
93
94// Delete deletes the Bucket.
95func (b *BucketHandle) Delete(ctx context.Context) (err error) {
96	ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Delete")
97	defer func() { trace.EndSpan(ctx, err) }()
98
99	req, err := b.newDeleteCall()
100	if err != nil {
101		return err
102	}
103	return runWithRetry(ctx, func() error { return req.Context(ctx).Do() })
104}
105
106func (b *BucketHandle) newDeleteCall() (*raw.BucketsDeleteCall, error) {
107	req := b.c.raw.Buckets.Delete(b.name)
108	setClientHeader(req.Header())
109	if err := applyBucketConds("BucketHandle.Delete", b.conds, req); err != nil {
110		return nil, err
111	}
112	if b.userProject != "" {
113		req.UserProject(b.userProject)
114	}
115	return req, nil
116}
117
118// ACL returns an ACLHandle, which provides access to the bucket's access control list.
119// This controls who can list, create or overwrite the objects in a bucket.
120// This call does not perform any network operations.
121func (b *BucketHandle) ACL() *ACLHandle {
122	return &b.acl
123}
124
125// DefaultObjectACL returns an ACLHandle, which provides access to the bucket's default object ACLs.
126// These ACLs are applied to newly created objects in this bucket that do not have a defined ACL.
127// This call does not perform any network operations.
128func (b *BucketHandle) DefaultObjectACL() *ACLHandle {
129	return &b.defaultObjectACL
130}
131
132// Object returns an ObjectHandle, which provides operations on the named object.
133// This call does not perform any network operations such as fetching the object or verifying its existence.
134// Use methods on ObjectHandle to perform network operations.
135//
136// name must consist entirely of valid UTF-8-encoded runes. The full specification
137// for valid object names can be found at:
138//   https://cloud.google.com/storage/docs/naming-objects
139func (b *BucketHandle) Object(name string) *ObjectHandle {
140	return &ObjectHandle{
141		c:      b.c,
142		bucket: b.name,
143		object: name,
144		acl: ACLHandle{
145			c:           b.c,
146			bucket:      b.name,
147			object:      name,
148			userProject: b.userProject,
149		},
150		gen:         -1,
151		userProject: b.userProject,
152	}
153}
154
155// Attrs returns the metadata for the bucket.
156func (b *BucketHandle) Attrs(ctx context.Context) (attrs *BucketAttrs, err error) {
157	ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Attrs")
158	defer func() { trace.EndSpan(ctx, err) }()
159
160	req, err := b.newGetCall()
161	if err != nil {
162		return nil, err
163	}
164	var resp *raw.Bucket
165	err = runWithRetry(ctx, func() error {
166		resp, err = req.Context(ctx).Do()
167		return err
168	})
169	if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
170		return nil, ErrBucketNotExist
171	}
172	if err != nil {
173		return nil, err
174	}
175	return newBucket(resp)
176}
177
178func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) {
179	req := b.c.raw.Buckets.Get(b.name).Projection("full")
180	setClientHeader(req.Header())
181	if err := applyBucketConds("BucketHandle.Attrs", b.conds, req); err != nil {
182		return nil, err
183	}
184	if b.userProject != "" {
185		req.UserProject(b.userProject)
186	}
187	return req, nil
188}
189
190// Update updates a bucket's attributes.
191func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) (attrs *BucketAttrs, err error) {
192	ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create")
193	defer func() { trace.EndSpan(ctx, err) }()
194
195	req, err := b.newPatchCall(&uattrs)
196	if err != nil {
197		return nil, err
198	}
199	if uattrs.PredefinedACL != "" {
200		req.PredefinedAcl(uattrs.PredefinedACL)
201	}
202	if uattrs.PredefinedDefaultObjectACL != "" {
203		req.PredefinedDefaultObjectAcl(uattrs.PredefinedDefaultObjectACL)
204	}
205	// TODO(jba): retry iff metagen is set?
206	rb, err := req.Context(ctx).Do()
207	if err != nil {
208		return nil, err
209	}
210	return newBucket(rb)
211}
212
213func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) {
214	rb := uattrs.toRawBucket()
215	req := b.c.raw.Buckets.Patch(b.name, rb).Projection("full")
216	setClientHeader(req.Header())
217	if err := applyBucketConds("BucketHandle.Update", b.conds, req); err != nil {
218		return nil, err
219	}
220	if b.userProject != "" {
221		req.UserProject(b.userProject)
222	}
223	return req, nil
224}
225
226// BucketAttrs represents the metadata for a Google Cloud Storage bucket.
227// Read-only fields are ignored by BucketHandle.Create.
228type BucketAttrs struct {
229	// Name is the name of the bucket.
230	// This field is read-only.
231	Name string
232
233	// ACL is the list of access control rules on the bucket.
234	ACL []ACLRule
235
236	// BucketPolicyOnly is an alias for UniformBucketLevelAccess. Use of
237	// UniformBucketLevelAccess is recommended above the use of this field.
238	// Setting BucketPolicyOnly.Enabled OR UniformBucketLevelAccess.Enabled to
239	// true, will enable UniformBucketLevelAccess.
240	BucketPolicyOnly BucketPolicyOnly
241
242	// UniformBucketLevelAccess configures access checks to use only bucket-level IAM
243	// policies and ignore any ACL rules for the bucket.
244	// See https://cloud.google.com/storage/docs/uniform-bucket-level-access
245	// for more information.
246	UniformBucketLevelAccess UniformBucketLevelAccess
247
248	// PublicAccessPrevention is the setting for the bucket's
249	// PublicAccessPrevention policy, which can be used to prevent public access
250	// of data in the bucket. See
251	// https://cloud.google.com/storage/docs/public-access-prevention for more
252	// information.
253	PublicAccessPrevention PublicAccessPrevention
254
255	// DefaultObjectACL is the list of access controls to
256	// apply to new objects when no object ACL is provided.
257	DefaultObjectACL []ACLRule
258
259	// DefaultEventBasedHold is the default value for event-based hold on
260	// newly created objects in this bucket. It defaults to false.
261	DefaultEventBasedHold bool
262
263	// If not empty, applies a predefined set of access controls. It should be set
264	// only when creating a bucket.
265	// It is always empty for BucketAttrs returned from the service.
266	// See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert
267	// for valid values.
268	PredefinedACL string
269
270	// If not empty, applies a predefined set of default object access controls.
271	// It should be set only when creating a bucket.
272	// It is always empty for BucketAttrs returned from the service.
273	// See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert
274	// for valid values.
275	PredefinedDefaultObjectACL string
276
277	// Location is the location of the bucket. It defaults to "US".
278	Location string
279
280	// MetaGeneration is the metadata generation of the bucket.
281	// This field is read-only.
282	MetaGeneration int64
283
284	// StorageClass is the default storage class of the bucket. This defines
285	// how objects in the bucket are stored and determines the SLA
286	// and the cost of storage. Typical values are "STANDARD", "NEARLINE",
287	// "COLDLINE" and "ARCHIVE". Defaults to "STANDARD".
288	// See https://cloud.google.com/storage/docs/storage-classes for all
289	// valid values.
290	StorageClass string
291
292	// Created is the creation time of the bucket.
293	// This field is read-only.
294	Created time.Time
295
296	// VersioningEnabled reports whether this bucket has versioning enabled.
297	VersioningEnabled bool
298
299	// Labels are the bucket's labels.
300	Labels map[string]string
301
302	// RequesterPays reports whether the bucket is a Requester Pays bucket.
303	// Clients performing operations on Requester Pays buckets must provide
304	// a user project (see BucketHandle.UserProject), which will be billed
305	// for the operations.
306	RequesterPays bool
307
308	// Lifecycle is the lifecycle configuration for objects in the bucket.
309	Lifecycle Lifecycle
310
311	// Retention policy enforces a minimum retention time for all objects
312	// contained in the bucket. A RetentionPolicy of nil implies the bucket
313	// has no minimum data retention.
314	//
315	// This feature is in private alpha release. It is not currently available to
316	// most customers. It might be changed in backwards-incompatible ways and is not
317	// subject to any SLA or deprecation policy.
318	RetentionPolicy *RetentionPolicy
319
320	// The bucket's Cross-Origin Resource Sharing (CORS) configuration.
321	CORS []CORS
322
323	// The encryption configuration used by default for newly inserted objects.
324	Encryption *BucketEncryption
325
326	// The logging configuration.
327	Logging *BucketLogging
328
329	// The website configuration.
330	Website *BucketWebsite
331
332	// Etag is the HTTP/1.1 Entity tag for the bucket.
333	// This field is read-only.
334	Etag string
335
336	// LocationType describes how data is stored and replicated.
337	// Typical values are "multi-region", "region" and "dual-region".
338	// This field is read-only.
339	LocationType string
340}
341
342// BucketPolicyOnly is an alias for UniformBucketLevelAccess.
343// Use of UniformBucketLevelAccess is preferred above BucketPolicyOnly.
344type BucketPolicyOnly struct {
345	// Enabled specifies whether access checks use only bucket-level IAM
346	// policies. Enabled may be disabled until the locked time.
347	Enabled bool
348	// LockedTime specifies the deadline for changing Enabled from true to
349	// false.
350	LockedTime time.Time
351}
352
353// UniformBucketLevelAccess configures access checks to use only bucket-level IAM
354// policies.
355type UniformBucketLevelAccess struct {
356	// Enabled specifies whether access checks use only bucket-level IAM
357	// policies. Enabled may be disabled until the locked time.
358	Enabled bool
359	// LockedTime specifies the deadline for changing Enabled from true to
360	// false.
361	LockedTime time.Time
362}
363
364// PublicAccessPrevention configures the Public Access Prevention feature, which
365// can be used to disallow public access to any data in a bucket. See
366// https://cloud.google.com/storage/docs/public-access-prevention for more
367// information.
368type PublicAccessPrevention int
369
370const (
371	// PublicAccessPreventionUnknown is a zero value, used only if this field is
372	// not set in a call to GCS.
373	PublicAccessPreventionUnknown PublicAccessPrevention = iota
374
375	// PublicAccessPreventionUnspecified corresponds to a value of "unspecified"
376	// and is the default for buckets.
377	PublicAccessPreventionUnspecified
378
379	// PublicAccessPreventionEnforced corresponds to a value of "enforced". This
380	// enforces Public Access Prevention on the bucket.
381	PublicAccessPreventionEnforced
382
383	publicAccessPreventionUnknown     string = ""
384	publicAccessPreventionUnspecified        = "unspecified"
385	publicAccessPreventionEnforced           = "enforced"
386)
387
388func (p PublicAccessPrevention) String() string {
389	switch p {
390	case PublicAccessPreventionUnspecified:
391		return publicAccessPreventionUnspecified
392	case PublicAccessPreventionEnforced:
393		return publicAccessPreventionEnforced
394	default:
395		return publicAccessPreventionUnknown
396	}
397}
398
399// Lifecycle is the lifecycle configuration for objects in the bucket.
400type Lifecycle struct {
401	Rules []LifecycleRule
402}
403
404// RetentionPolicy enforces a minimum retention time for all objects
405// contained in the bucket.
406//
407// Any attempt to overwrite or delete objects younger than the retention
408// period will result in an error. An unlocked retention policy can be
409// modified or removed from the bucket via the Update method. A
410// locked retention policy cannot be removed or shortened in duration
411// for the lifetime of the bucket.
412//
413// This feature is in private alpha release. It is not currently available to
414// most customers. It might be changed in backwards-incompatible ways and is not
415// subject to any SLA or deprecation policy.
416type RetentionPolicy struct {
417	// RetentionPeriod specifies the duration that objects need to be
418	// retained. Retention duration must be greater than zero and less than
419	// 100 years. Note that enforcement of retention periods less than a day
420	// is not guaranteed. Such periods should only be used for testing
421	// purposes.
422	RetentionPeriod time.Duration
423
424	// EffectiveTime is the time from which the policy was enforced and
425	// effective. This field is read-only.
426	EffectiveTime time.Time
427
428	// IsLocked describes whether the bucket is locked. Once locked, an
429	// object retention policy cannot be modified.
430	// This field is read-only.
431	IsLocked bool
432}
433
434const (
435	// RFC3339 timestamp with only the date segment, used for CreatedBefore,
436	// CustomTimeBefore, and NoncurrentTimeBefore in LifecycleRule.
437	rfc3339Date = "2006-01-02"
438
439	// DeleteAction is a lifecycle action that deletes a live and/or archived
440	// objects. Takes precedence over SetStorageClass actions.
441	DeleteAction = "Delete"
442
443	// SetStorageClassAction changes the storage class of live and/or archived
444	// objects.
445	SetStorageClassAction = "SetStorageClass"
446)
447
448// LifecycleRule is a lifecycle configuration rule.
449//
450// When all the configured conditions are met by an object in the bucket, the
451// configured action will automatically be taken on that object.
452type LifecycleRule struct {
453	// Action is the action to take when all of the associated conditions are
454	// met.
455	Action LifecycleAction
456
457	// Condition is the set of conditions that must be met for the associated
458	// action to be taken.
459	Condition LifecycleCondition
460}
461
462// LifecycleAction is a lifecycle configuration action.
463type LifecycleAction struct {
464	// Type is the type of action to take on matching objects.
465	//
466	// Acceptable values are "Delete" to delete matching objects and
467	// "SetStorageClass" to set the storage class defined in StorageClass on
468	// matching objects.
469	Type string
470
471	// StorageClass is the storage class to set on matching objects if the Action
472	// is "SetStorageClass".
473	StorageClass string
474}
475
476// Liveness specifies whether the object is live or not.
477type Liveness int
478
479const (
480	// LiveAndArchived includes both live and archived objects.
481	LiveAndArchived Liveness = iota
482	// Live specifies that the object is still live.
483	Live
484	// Archived specifies that the object is archived.
485	Archived
486)
487
488// LifecycleCondition is a set of conditions used to match objects and take an
489// action automatically.
490//
491// All configured conditions must be met for the associated action to be taken.
492type LifecycleCondition struct {
493	// AgeInDays is the age of the object in days.
494	AgeInDays int64
495
496	// CreatedBefore is the time the object was created.
497	//
498	// This condition is satisfied when an object is created before midnight of
499	// the specified date in UTC.
500	CreatedBefore time.Time
501
502	// CustomTimeBefore is the CustomTime metadata field of the object. This
503	// condition is satisfied when an object's CustomTime timestamp is before
504	// midnight of the specified date in UTC.
505	//
506	// This condition can only be satisfied if CustomTime has been set.
507	CustomTimeBefore time.Time
508
509	// DaysSinceCustomTime is the days elapsed since the CustomTime date of the
510	// object. This condition can only be satisfied if CustomTime has been set.
511	DaysSinceCustomTime int64
512
513	// DaysSinceNoncurrentTime is the days elapsed since the noncurrent timestamp
514	// of the object. This condition is relevant only for versioned objects.
515	DaysSinceNoncurrentTime int64
516
517	// Liveness specifies the object's liveness. Relevant only for versioned objects
518	Liveness Liveness
519
520	// MatchesStorageClasses is the condition matching the object's storage
521	// class.
522	//
523	// Values include "STANDARD", "NEARLINE", "COLDLINE" and "ARCHIVE".
524	MatchesStorageClasses []string
525
526	// NoncurrentTimeBefore is the noncurrent timestamp of the object. This
527	// condition is satisfied when an object's noncurrent timestamp is before
528	// midnight of the specified date in UTC.
529	//
530	// This condition is relevant only for versioned objects.
531	NoncurrentTimeBefore time.Time
532
533	// NumNewerVersions is the condition matching objects with a number of newer versions.
534	//
535	// If the value is N, this condition is satisfied when there are at least N
536	// versions (including the live version) newer than this version of the
537	// object.
538	NumNewerVersions int64
539}
540
541// BucketLogging holds the bucket's logging configuration, which defines the
542// destination bucket and optional name prefix for the current bucket's
543// logs.
544type BucketLogging struct {
545	// The destination bucket where the current bucket's logs
546	// should be placed.
547	LogBucket string
548
549	// A prefix for log object names.
550	LogObjectPrefix string
551}
552
553// BucketWebsite holds the bucket's website configuration, controlling how the
554// service behaves when accessing bucket contents as a web site. See
555// https://cloud.google.com/storage/docs/static-website for more information.
556type BucketWebsite struct {
557	// If the requested object path is missing, the service will ensure the path has
558	// a trailing '/', append this suffix, and attempt to retrieve the resulting
559	// object. This allows the creation of index.html objects to represent directory
560	// pages.
561	MainPageSuffix string
562
563	// If the requested object path is missing, and any mainPageSuffix object is
564	// missing, if applicable, the service will return the named object from this
565	// bucket as the content for a 404 Not Found result.
566	NotFoundPage string
567}
568
569func newBucket(b *raw.Bucket) (*BucketAttrs, error) {
570	if b == nil {
571		return nil, nil
572	}
573	rp, err := toRetentionPolicy(b.RetentionPolicy)
574	if err != nil {
575		return nil, err
576	}
577	return &BucketAttrs{
578		Name:                     b.Name,
579		Location:                 b.Location,
580		MetaGeneration:           b.Metageneration,
581		DefaultEventBasedHold:    b.DefaultEventBasedHold,
582		StorageClass:             b.StorageClass,
583		Created:                  convertTime(b.TimeCreated),
584		VersioningEnabled:        b.Versioning != nil && b.Versioning.Enabled,
585		ACL:                      toBucketACLRules(b.Acl),
586		DefaultObjectACL:         toObjectACLRules(b.DefaultObjectAcl),
587		Labels:                   b.Labels,
588		RequesterPays:            b.Billing != nil && b.Billing.RequesterPays,
589		Lifecycle:                toLifecycle(b.Lifecycle),
590		RetentionPolicy:          rp,
591		CORS:                     toCORS(b.Cors),
592		Encryption:               toBucketEncryption(b.Encryption),
593		Logging:                  toBucketLogging(b.Logging),
594		Website:                  toBucketWebsite(b.Website),
595		BucketPolicyOnly:         toBucketPolicyOnly(b.IamConfiguration),
596		UniformBucketLevelAccess: toUniformBucketLevelAccess(b.IamConfiguration),
597		PublicAccessPrevention:   toPublicAccessPrevention(b.IamConfiguration),
598		Etag:                     b.Etag,
599		LocationType:             b.LocationType,
600	}, nil
601}
602
603// toRawBucket copies the editable attribute from b to the raw library's Bucket type.
604func (b *BucketAttrs) toRawBucket() *raw.Bucket {
605	// Copy label map.
606	var labels map[string]string
607	if len(b.Labels) > 0 {
608		labels = make(map[string]string, len(b.Labels))
609		for k, v := range b.Labels {
610			labels[k] = v
611		}
612	}
613	// Ignore VersioningEnabled if it is false. This is OK because
614	// we only call this method when creating a bucket, and by default
615	// new buckets have versioning off.
616	var v *raw.BucketVersioning
617	if b.VersioningEnabled {
618		v = &raw.BucketVersioning{Enabled: true}
619	}
620	var bb *raw.BucketBilling
621	if b.RequesterPays {
622		bb = &raw.BucketBilling{RequesterPays: true}
623	}
624	var bktIAM *raw.BucketIamConfiguration
625	if b.UniformBucketLevelAccess.Enabled || b.BucketPolicyOnly.Enabled || b.PublicAccessPrevention != PublicAccessPreventionUnknown {
626		bktIAM = &raw.BucketIamConfiguration{}
627		if b.UniformBucketLevelAccess.Enabled || b.BucketPolicyOnly.Enabled {
628			bktIAM.UniformBucketLevelAccess = &raw.BucketIamConfigurationUniformBucketLevelAccess{
629				Enabled: true,
630			}
631		}
632		if b.PublicAccessPrevention != PublicAccessPreventionUnknown {
633			bktIAM.PublicAccessPrevention = b.PublicAccessPrevention.String()
634		}
635	}
636	return &raw.Bucket{
637		Name:             b.Name,
638		Location:         b.Location,
639		StorageClass:     b.StorageClass,
640		Acl:              toRawBucketACL(b.ACL),
641		DefaultObjectAcl: toRawObjectACL(b.DefaultObjectACL),
642		Versioning:       v,
643		Labels:           labels,
644		Billing:          bb,
645		Lifecycle:        toRawLifecycle(b.Lifecycle),
646		RetentionPolicy:  b.RetentionPolicy.toRawRetentionPolicy(),
647		Cors:             toRawCORS(b.CORS),
648		Encryption:       b.Encryption.toRawBucketEncryption(),
649		Logging:          b.Logging.toRawBucketLogging(),
650		Website:          b.Website.toRawBucketWebsite(),
651		IamConfiguration: bktIAM,
652	}
653}
654
655// CORS is the bucket's Cross-Origin Resource Sharing (CORS) configuration.
656type CORS struct {
657	// MaxAge is the value to return in the Access-Control-Max-Age
658	// header used in preflight responses.
659	MaxAge time.Duration
660
661	// Methods is the list of HTTP methods on which to include CORS response
662	// headers, (GET, OPTIONS, POST, etc) Note: "*" is permitted in the list
663	// of methods, and means "any method".
664	Methods []string
665
666	// Origins is the list of Origins eligible to receive CORS response
667	// headers. Note: "*" is permitted in the list of origins, and means
668	// "any Origin".
669	Origins []string
670
671	// ResponseHeaders is the list of HTTP headers other than the simple
672	// response headers to give permission for the user-agent to share
673	// across domains.
674	ResponseHeaders []string
675}
676
677// BucketEncryption is a bucket's encryption configuration.
678type BucketEncryption struct {
679	// A Cloud KMS key name, in the form
680	// projects/P/locations/L/keyRings/R/cryptoKeys/K, that will be used to encrypt
681	// objects inserted into this bucket, if no encryption method is specified.
682	// The key's location must be the same as the bucket's.
683	DefaultKMSKeyName string
684}
685
686// BucketAttrsToUpdate define the attributes to update during an Update call.
687type BucketAttrsToUpdate struct {
688	// If set, updates whether the bucket uses versioning.
689	VersioningEnabled optional.Bool
690
691	// If set, updates whether the bucket is a Requester Pays bucket.
692	RequesterPays optional.Bool
693
694	// DefaultEventBasedHold is the default value for event-based hold on
695	// newly created objects in this bucket.
696	DefaultEventBasedHold optional.Bool
697
698	// BucketPolicyOnly is an alias for UniformBucketLevelAccess. Use of
699	// UniformBucketLevelAccess is recommended above the use of this field.
700	// Setting BucketPolicyOnly.Enabled OR UniformBucketLevelAccess.Enabled to
701	// true, will enable UniformBucketLevelAccess. If both BucketPolicyOnly and
702	// UniformBucketLevelAccess are set, the value of UniformBucketLevelAccess
703	// will take precedence.
704	BucketPolicyOnly *BucketPolicyOnly
705
706	// UniformBucketLevelAccess configures access checks to use only bucket-level IAM
707	// policies and ignore any ACL rules for the bucket.
708	// See https://cloud.google.com/storage/docs/uniform-bucket-level-access
709	// for more information.
710	UniformBucketLevelAccess *UniformBucketLevelAccess
711
712	// PublicAccessPrevention is the setting for the bucket's
713	// PublicAccessPrevention policy, which can be used to prevent public access
714	// of data in the bucket. See
715	// https://cloud.google.com/storage/docs/public-access-prevention for more
716	// information.
717	PublicAccessPrevention PublicAccessPrevention
718
719	// StorageClass is the default storage class of the bucket. This defines
720	// how objects in the bucket are stored and determines the SLA
721	// and the cost of storage. Typical values are "STANDARD", "NEARLINE",
722	// "COLDLINE" and "ARCHIVE". Defaults to "STANDARD".
723	// See https://cloud.google.com/storage/docs/storage-classes for all
724	// valid values.
725	StorageClass string
726
727	// If set, updates the retention policy of the bucket. Using
728	// RetentionPolicy.RetentionPeriod = 0 will delete the existing policy.
729	//
730	// This feature is in private alpha release. It is not currently available to
731	// most customers. It might be changed in backwards-incompatible ways and is not
732	// subject to any SLA or deprecation policy.
733	RetentionPolicy *RetentionPolicy
734
735	// If set, replaces the CORS configuration with a new configuration.
736	// An empty (rather than nil) slice causes all CORS policies to be removed.
737	CORS []CORS
738
739	// If set, replaces the encryption configuration of the bucket. Using
740	// BucketEncryption.DefaultKMSKeyName = "" will delete the existing
741	// configuration.
742	Encryption *BucketEncryption
743
744	// If set, replaces the lifecycle configuration of the bucket.
745	Lifecycle *Lifecycle
746
747	// If set, replaces the logging configuration of the bucket.
748	Logging *BucketLogging
749
750	// If set, replaces the website configuration of the bucket.
751	Website *BucketWebsite
752
753	// If not empty, applies a predefined set of access controls.
754	// See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch.
755	PredefinedACL string
756
757	// If not empty, applies a predefined set of default object access controls.
758	// See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch.
759	PredefinedDefaultObjectACL string
760
761	setLabels    map[string]string
762	deleteLabels map[string]bool
763}
764
765// SetLabel causes a label to be added or modified when ua is used
766// in a call to Bucket.Update.
767func (ua *BucketAttrsToUpdate) SetLabel(name, value string) {
768	if ua.setLabels == nil {
769		ua.setLabels = map[string]string{}
770	}
771	ua.setLabels[name] = value
772}
773
774// DeleteLabel causes a label to be deleted when ua is used in a
775// call to Bucket.Update.
776func (ua *BucketAttrsToUpdate) DeleteLabel(name string) {
777	if ua.deleteLabels == nil {
778		ua.deleteLabels = map[string]bool{}
779	}
780	ua.deleteLabels[name] = true
781}
782
783func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
784	rb := &raw.Bucket{}
785	if ua.CORS != nil {
786		rb.Cors = toRawCORS(ua.CORS)
787		rb.ForceSendFields = append(rb.ForceSendFields, "Cors")
788	}
789	if ua.DefaultEventBasedHold != nil {
790		rb.DefaultEventBasedHold = optional.ToBool(ua.DefaultEventBasedHold)
791		rb.ForceSendFields = append(rb.ForceSendFields, "DefaultEventBasedHold")
792	}
793	if ua.RetentionPolicy != nil {
794		if ua.RetentionPolicy.RetentionPeriod == 0 {
795			rb.NullFields = append(rb.NullFields, "RetentionPolicy")
796			rb.RetentionPolicy = nil
797		} else {
798			rb.RetentionPolicy = ua.RetentionPolicy.toRawRetentionPolicy()
799		}
800	}
801	if ua.VersioningEnabled != nil {
802		rb.Versioning = &raw.BucketVersioning{
803			Enabled:         optional.ToBool(ua.VersioningEnabled),
804			ForceSendFields: []string{"Enabled"},
805		}
806	}
807	if ua.RequesterPays != nil {
808		rb.Billing = &raw.BucketBilling{
809			RequesterPays:   optional.ToBool(ua.RequesterPays),
810			ForceSendFields: []string{"RequesterPays"},
811		}
812	}
813	if ua.BucketPolicyOnly != nil {
814		rb.IamConfiguration = &raw.BucketIamConfiguration{
815			UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{
816				Enabled:         ua.BucketPolicyOnly.Enabled,
817				ForceSendFields: []string{"Enabled"},
818			},
819		}
820	}
821	if ua.UniformBucketLevelAccess != nil {
822		rb.IamConfiguration = &raw.BucketIamConfiguration{
823			UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{
824				Enabled:         ua.UniformBucketLevelAccess.Enabled,
825				ForceSendFields: []string{"Enabled"},
826			},
827		}
828	}
829	if ua.PublicAccessPrevention != PublicAccessPreventionUnknown {
830		if rb.IamConfiguration == nil {
831			rb.IamConfiguration = &raw.BucketIamConfiguration{}
832		}
833		rb.IamConfiguration.PublicAccessPrevention = ua.PublicAccessPrevention.String()
834	}
835	if ua.Encryption != nil {
836		if ua.Encryption.DefaultKMSKeyName == "" {
837			rb.NullFields = append(rb.NullFields, "Encryption")
838			rb.Encryption = nil
839		} else {
840			rb.Encryption = ua.Encryption.toRawBucketEncryption()
841		}
842	}
843	if ua.Lifecycle != nil {
844		rb.Lifecycle = toRawLifecycle(*ua.Lifecycle)
845		rb.ForceSendFields = append(rb.ForceSendFields, "Lifecycle")
846	}
847	if ua.Logging != nil {
848		if *ua.Logging == (BucketLogging{}) {
849			rb.NullFields = append(rb.NullFields, "Logging")
850			rb.Logging = nil
851		} else {
852			rb.Logging = ua.Logging.toRawBucketLogging()
853		}
854	}
855	if ua.Website != nil {
856		if *ua.Website == (BucketWebsite{}) {
857			rb.NullFields = append(rb.NullFields, "Website")
858			rb.Website = nil
859		} else {
860			rb.Website = ua.Website.toRawBucketWebsite()
861		}
862	}
863	if ua.PredefinedACL != "" {
864		// Clear ACL or the call will fail.
865		rb.Acl = nil
866		rb.ForceSendFields = append(rb.ForceSendFields, "Acl")
867	}
868	if ua.PredefinedDefaultObjectACL != "" {
869		// Clear ACLs or the call will fail.
870		rb.DefaultObjectAcl = nil
871		rb.ForceSendFields = append(rb.ForceSendFields, "DefaultObjectAcl")
872	}
873	rb.StorageClass = ua.StorageClass
874	if ua.setLabels != nil || ua.deleteLabels != nil {
875		rb.Labels = map[string]string{}
876		for k, v := range ua.setLabels {
877			rb.Labels[k] = v
878		}
879		if len(rb.Labels) == 0 && len(ua.deleteLabels) > 0 {
880			rb.ForceSendFields = append(rb.ForceSendFields, "Labels")
881		}
882		for l := range ua.deleteLabels {
883			rb.NullFields = append(rb.NullFields, "Labels."+l)
884		}
885	}
886	return rb
887}
888
889// If returns a new BucketHandle that applies a set of preconditions.
890// Preconditions already set on the BucketHandle are ignored.
891// Operations on the new handle will return an error if the preconditions are not
892// satisfied. The only valid preconditions for buckets are MetagenerationMatch
893// and MetagenerationNotMatch.
894func (b *BucketHandle) If(conds BucketConditions) *BucketHandle {
895	b2 := *b
896	b2.conds = &conds
897	return &b2
898}
899
900// BucketConditions constrain bucket methods to act on specific metagenerations.
901//
902// The zero value is an empty set of constraints.
903type BucketConditions struct {
904	// MetagenerationMatch specifies that the bucket must have the given
905	// metageneration for the operation to occur.
906	// If MetagenerationMatch is zero, it has no effect.
907	MetagenerationMatch int64
908
909	// MetagenerationNotMatch specifies that the bucket must not have the given
910	// metageneration for the operation to occur.
911	// If MetagenerationNotMatch is zero, it has no effect.
912	MetagenerationNotMatch int64
913}
914
915func (c *BucketConditions) validate(method string) error {
916	if *c == (BucketConditions{}) {
917		return fmt.Errorf("storage: %s: empty conditions", method)
918	}
919	if c.MetagenerationMatch != 0 && c.MetagenerationNotMatch != 0 {
920		return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method)
921	}
922	return nil
923}
924
925// UserProject returns a new BucketHandle that passes the project ID as the user
926// project for all subsequent calls. Calls with a user project will be billed to that
927// project rather than to the bucket's owning project.
928//
929// A user project is required for all operations on Requester Pays buckets.
930func (b *BucketHandle) UserProject(projectID string) *BucketHandle {
931	b2 := *b
932	b2.userProject = projectID
933	b2.acl.userProject = projectID
934	b2.defaultObjectACL.userProject = projectID
935	return &b2
936}
937
938// LockRetentionPolicy locks a bucket's retention policy until a previously-configured
939// RetentionPeriod past the EffectiveTime. Note that if RetentionPeriod is set to less
940// than a day, the retention policy is treated as a development configuration and locking
941// will have no effect. The BucketHandle must have a metageneration condition that
942// matches the bucket's metageneration. See BucketHandle.If.
943//
944// This feature is in private alpha release. It is not currently available to
945// most customers. It might be changed in backwards-incompatible ways and is not
946// subject to any SLA or deprecation policy.
947func (b *BucketHandle) LockRetentionPolicy(ctx context.Context) error {
948	var metageneration int64
949	if b.conds != nil {
950		metageneration = b.conds.MetagenerationMatch
951	}
952	req := b.c.raw.Buckets.LockRetentionPolicy(b.name, metageneration)
953	return runWithRetry(ctx, func() error {
954		_, err := req.Context(ctx).Do()
955		return err
956	})
957}
958
959// applyBucketConds modifies the provided call using the conditions in conds.
960// call is something that quacks like a *raw.WhateverCall.
961func applyBucketConds(method string, conds *BucketConditions, call interface{}) error {
962	if conds == nil {
963		return nil
964	}
965	if err := conds.validate(method); err != nil {
966		return err
967	}
968	cval := reflect.ValueOf(call)
969	switch {
970	case conds.MetagenerationMatch != 0:
971		if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) {
972			return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method)
973		}
974	case conds.MetagenerationNotMatch != 0:
975		if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) {
976			return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method)
977		}
978	}
979	return nil
980}
981
982func (rp *RetentionPolicy) toRawRetentionPolicy() *raw.BucketRetentionPolicy {
983	if rp == nil {
984		return nil
985	}
986	return &raw.BucketRetentionPolicy{
987		RetentionPeriod: int64(rp.RetentionPeriod / time.Second),
988	}
989}
990
991func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) {
992	if rp == nil {
993		return nil, nil
994	}
995	t, err := time.Parse(time.RFC3339, rp.EffectiveTime)
996	if err != nil {
997		return nil, err
998	}
999	return &RetentionPolicy{
1000		RetentionPeriod: time.Duration(rp.RetentionPeriod) * time.Second,
1001		EffectiveTime:   t,
1002		IsLocked:        rp.IsLocked,
1003	}, nil
1004}
1005
1006func toRawCORS(c []CORS) []*raw.BucketCors {
1007	var out []*raw.BucketCors
1008	for _, v := range c {
1009		out = append(out, &raw.BucketCors{
1010			MaxAgeSeconds:  int64(v.MaxAge / time.Second),
1011			Method:         v.Methods,
1012			Origin:         v.Origins,
1013			ResponseHeader: v.ResponseHeaders,
1014		})
1015	}
1016	return out
1017}
1018
1019func toCORS(rc []*raw.BucketCors) []CORS {
1020	var out []CORS
1021	for _, v := range rc {
1022		out = append(out, CORS{
1023			MaxAge:          time.Duration(v.MaxAgeSeconds) * time.Second,
1024			Methods:         v.Method,
1025			Origins:         v.Origin,
1026			ResponseHeaders: v.ResponseHeader,
1027		})
1028	}
1029	return out
1030}
1031
1032func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle {
1033	var rl raw.BucketLifecycle
1034	if len(l.Rules) == 0 {
1035		rl.ForceSendFields = []string{"Rule"}
1036	}
1037	for _, r := range l.Rules {
1038		rr := &raw.BucketLifecycleRule{
1039			Action: &raw.BucketLifecycleRuleAction{
1040				Type:         r.Action.Type,
1041				StorageClass: r.Action.StorageClass,
1042			},
1043			Condition: &raw.BucketLifecycleRuleCondition{
1044				Age:                     r.Condition.AgeInDays,
1045				DaysSinceCustomTime:     r.Condition.DaysSinceCustomTime,
1046				DaysSinceNoncurrentTime: r.Condition.DaysSinceNoncurrentTime,
1047				MatchesStorageClass:     r.Condition.MatchesStorageClasses,
1048				NumNewerVersions:        r.Condition.NumNewerVersions,
1049			},
1050		}
1051
1052		switch r.Condition.Liveness {
1053		case LiveAndArchived:
1054			rr.Condition.IsLive = nil
1055		case Live:
1056			rr.Condition.IsLive = googleapi.Bool(true)
1057		case Archived:
1058			rr.Condition.IsLive = googleapi.Bool(false)
1059		}
1060
1061		if !r.Condition.CreatedBefore.IsZero() {
1062			rr.Condition.CreatedBefore = r.Condition.CreatedBefore.Format(rfc3339Date)
1063		}
1064		if !r.Condition.CustomTimeBefore.IsZero() {
1065			rr.Condition.CustomTimeBefore = r.Condition.CustomTimeBefore.Format(rfc3339Date)
1066		}
1067		if !r.Condition.NoncurrentTimeBefore.IsZero() {
1068			rr.Condition.NoncurrentTimeBefore = r.Condition.NoncurrentTimeBefore.Format(rfc3339Date)
1069		}
1070		rl.Rule = append(rl.Rule, rr)
1071	}
1072	return &rl
1073}
1074
1075func toLifecycle(rl *raw.BucketLifecycle) Lifecycle {
1076	var l Lifecycle
1077	if rl == nil {
1078		return l
1079	}
1080	for _, rr := range rl.Rule {
1081		r := LifecycleRule{
1082			Action: LifecycleAction{
1083				Type:         rr.Action.Type,
1084				StorageClass: rr.Action.StorageClass,
1085			},
1086			Condition: LifecycleCondition{
1087				AgeInDays:               rr.Condition.Age,
1088				DaysSinceCustomTime:     rr.Condition.DaysSinceCustomTime,
1089				DaysSinceNoncurrentTime: rr.Condition.DaysSinceNoncurrentTime,
1090				MatchesStorageClasses:   rr.Condition.MatchesStorageClass,
1091				NumNewerVersions:        rr.Condition.NumNewerVersions,
1092			},
1093		}
1094
1095		if rr.Condition.IsLive == nil {
1096			r.Condition.Liveness = LiveAndArchived
1097		} else if *rr.Condition.IsLive {
1098			r.Condition.Liveness = Live
1099		} else {
1100			r.Condition.Liveness = Archived
1101		}
1102
1103		if rr.Condition.CreatedBefore != "" {
1104			r.Condition.CreatedBefore, _ = time.Parse(rfc3339Date, rr.Condition.CreatedBefore)
1105		}
1106		if rr.Condition.CustomTimeBefore != "" {
1107			r.Condition.CustomTimeBefore, _ = time.Parse(rfc3339Date, rr.Condition.CustomTimeBefore)
1108		}
1109		if rr.Condition.NoncurrentTimeBefore != "" {
1110			r.Condition.NoncurrentTimeBefore, _ = time.Parse(rfc3339Date, rr.Condition.NoncurrentTimeBefore)
1111		}
1112		l.Rules = append(l.Rules, r)
1113	}
1114	return l
1115}
1116
1117func (e *BucketEncryption) toRawBucketEncryption() *raw.BucketEncryption {
1118	if e == nil {
1119		return nil
1120	}
1121	return &raw.BucketEncryption{
1122		DefaultKmsKeyName: e.DefaultKMSKeyName,
1123	}
1124}
1125
1126func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption {
1127	if e == nil {
1128		return nil
1129	}
1130	return &BucketEncryption{DefaultKMSKeyName: e.DefaultKmsKeyName}
1131}
1132
1133func (b *BucketLogging) toRawBucketLogging() *raw.BucketLogging {
1134	if b == nil {
1135		return nil
1136	}
1137	return &raw.BucketLogging{
1138		LogBucket:       b.LogBucket,
1139		LogObjectPrefix: b.LogObjectPrefix,
1140	}
1141}
1142
1143func toBucketLogging(b *raw.BucketLogging) *BucketLogging {
1144	if b == nil {
1145		return nil
1146	}
1147	return &BucketLogging{
1148		LogBucket:       b.LogBucket,
1149		LogObjectPrefix: b.LogObjectPrefix,
1150	}
1151}
1152
1153func (w *BucketWebsite) toRawBucketWebsite() *raw.BucketWebsite {
1154	if w == nil {
1155		return nil
1156	}
1157	return &raw.BucketWebsite{
1158		MainPageSuffix: w.MainPageSuffix,
1159		NotFoundPage:   w.NotFoundPage,
1160	}
1161}
1162
1163func toBucketWebsite(w *raw.BucketWebsite) *BucketWebsite {
1164	if w == nil {
1165		return nil
1166	}
1167	return &BucketWebsite{
1168		MainPageSuffix: w.MainPageSuffix,
1169		NotFoundPage:   w.NotFoundPage,
1170	}
1171}
1172
1173func toBucketPolicyOnly(b *raw.BucketIamConfiguration) BucketPolicyOnly {
1174	if b == nil || b.BucketPolicyOnly == nil || !b.BucketPolicyOnly.Enabled {
1175		return BucketPolicyOnly{}
1176	}
1177	lt, err := time.Parse(time.RFC3339, b.BucketPolicyOnly.LockedTime)
1178	if err != nil {
1179		return BucketPolicyOnly{
1180			Enabled: true,
1181		}
1182	}
1183	return BucketPolicyOnly{
1184		Enabled:    true,
1185		LockedTime: lt,
1186	}
1187}
1188
1189func toUniformBucketLevelAccess(b *raw.BucketIamConfiguration) UniformBucketLevelAccess {
1190	if b == nil || b.UniformBucketLevelAccess == nil || !b.UniformBucketLevelAccess.Enabled {
1191		return UniformBucketLevelAccess{}
1192	}
1193	lt, err := time.Parse(time.RFC3339, b.UniformBucketLevelAccess.LockedTime)
1194	if err != nil {
1195		return UniformBucketLevelAccess{
1196			Enabled: true,
1197		}
1198	}
1199	return UniformBucketLevelAccess{
1200		Enabled:    true,
1201		LockedTime: lt,
1202	}
1203}
1204
1205func toPublicAccessPrevention(b *raw.BucketIamConfiguration) PublicAccessPrevention {
1206	if b == nil {
1207		return PublicAccessPreventionUnknown
1208	}
1209	switch b.PublicAccessPrevention {
1210	case publicAccessPreventionUnspecified:
1211		return PublicAccessPreventionUnspecified
1212	case publicAccessPreventionEnforced:
1213		return PublicAccessPreventionEnforced
1214	default:
1215		return PublicAccessPreventionUnknown
1216	}
1217}
1218
1219// Objects returns an iterator over the objects in the bucket that match the
1220// Query q. If q is nil, no filtering is done. Objects will be iterated over
1221// lexicographically by name.
1222//
1223// Note: The returned iterator is not safe for concurrent operations without explicit synchronization.
1224func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator {
1225	it := &ObjectIterator{
1226		ctx:    ctx,
1227		bucket: b,
1228	}
1229	it.pageInfo, it.nextFunc = iterator.NewPageInfo(
1230		it.fetch,
1231		func() int { return len(it.items) },
1232		func() interface{} { b := it.items; it.items = nil; return b })
1233	if q != nil {
1234		it.query = *q
1235	}
1236	return it
1237}
1238
1239// An ObjectIterator is an iterator over ObjectAttrs.
1240//
1241// Note: This iterator is not safe for concurrent operations without explicit synchronization.
1242type ObjectIterator struct {
1243	ctx      context.Context
1244	bucket   *BucketHandle
1245	query    Query
1246	pageInfo *iterator.PageInfo
1247	nextFunc func() error
1248	items    []*ObjectAttrs
1249}
1250
1251// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
1252//
1253// Note: This method is not safe for concurrent operations without explicit synchronization.
1254func (it *ObjectIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
1255
1256// Next returns the next result. Its second return value is iterator.Done if
1257// there are no more results. Once Next returns iterator.Done, all subsequent
1258// calls will return iterator.Done.
1259//
1260// In addition, if Next returns an error other than iterator.Done, all
1261// subsequent calls will return the same error. To continue iteration, a new
1262// `ObjectIterator` must be created. Since objects are ordered lexicographically
1263// by name, `Query.StartOffset` can be used to create a new iterator which will
1264// start at the desired place. See
1265// https://pkg.go.dev/cloud.google.com/go/storage?tab=doc#hdr-Listing_objects.
1266//
1267// If Query.Delimiter is non-empty, some of the ObjectAttrs returned by Next will
1268// have a non-empty Prefix field, and a zero value for all other fields. These
1269// represent prefixes.
1270//
1271// Note: This method is not safe for concurrent operations without explicit synchronization.
1272func (it *ObjectIterator) Next() (*ObjectAttrs, error) {
1273	if err := it.nextFunc(); err != nil {
1274		return nil, err
1275	}
1276	item := it.items[0]
1277	it.items = it.items[1:]
1278	return item, nil
1279}
1280
1281func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) {
1282	req := it.bucket.c.raw.Objects.List(it.bucket.name)
1283	setClientHeader(req.Header())
1284	projection := it.query.Projection
1285	if projection == ProjectionDefault {
1286		projection = ProjectionFull
1287	}
1288	req.Projection(projection.String())
1289	req.Delimiter(it.query.Delimiter)
1290	req.Prefix(it.query.Prefix)
1291	req.StartOffset(it.query.StartOffset)
1292	req.EndOffset(it.query.EndOffset)
1293	req.Versions(it.query.Versions)
1294	if len(it.query.fieldSelection) > 0 {
1295		req.Fields("nextPageToken", googleapi.Field(it.query.fieldSelection))
1296	}
1297	req.PageToken(pageToken)
1298	if it.bucket.userProject != "" {
1299		req.UserProject(it.bucket.userProject)
1300	}
1301	if pageSize > 0 {
1302		req.MaxResults(int64(pageSize))
1303	}
1304	var resp *raw.Objects
1305	var err error
1306	err = runWithRetry(it.ctx, func() error {
1307		resp, err = req.Context(it.ctx).Do()
1308		return err
1309	})
1310	if err != nil {
1311		if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
1312			err = ErrBucketNotExist
1313		}
1314		return "", err
1315	}
1316	for _, item := range resp.Items {
1317		it.items = append(it.items, newObject(item))
1318	}
1319	for _, prefix := range resp.Prefixes {
1320		it.items = append(it.items, &ObjectAttrs{Prefix: prefix})
1321	}
1322	return resp.NextPageToken, nil
1323}
1324
1325// Buckets returns an iterator over the buckets in the project. You may
1326// optionally set the iterator's Prefix field to restrict the list to buckets
1327// whose names begin with the prefix. By default, all buckets in the project
1328// are returned.
1329//
1330// Note: The returned iterator is not safe for concurrent operations without explicit synchronization.
1331func (c *Client) Buckets(ctx context.Context, projectID string) *BucketIterator {
1332	it := &BucketIterator{
1333		ctx:       ctx,
1334		client:    c,
1335		projectID: projectID,
1336	}
1337	it.pageInfo, it.nextFunc = iterator.NewPageInfo(
1338		it.fetch,
1339		func() int { return len(it.buckets) },
1340		func() interface{} { b := it.buckets; it.buckets = nil; return b })
1341
1342	return it
1343}
1344
1345// A BucketIterator is an iterator over BucketAttrs.
1346//
1347// Note: This iterator is not safe for concurrent operations without explicit synchronization.
1348type BucketIterator struct {
1349	// Prefix restricts the iterator to buckets whose names begin with it.
1350	Prefix string
1351
1352	ctx       context.Context
1353	client    *Client
1354	projectID string
1355	buckets   []*BucketAttrs
1356	pageInfo  *iterator.PageInfo
1357	nextFunc  func() error
1358}
1359
1360// Next returns the next result. Its second return value is iterator.Done if
1361// there are no more results. Once Next returns iterator.Done, all subsequent
1362// calls will return iterator.Done.
1363//
1364// Note: This method is not safe for concurrent operations without explicit synchronization.
1365func (it *BucketIterator) Next() (*BucketAttrs, error) {
1366	if err := it.nextFunc(); err != nil {
1367		return nil, err
1368	}
1369	b := it.buckets[0]
1370	it.buckets = it.buckets[1:]
1371	return b, nil
1372}
1373
1374// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
1375//
1376// Note: This method is not safe for concurrent operations without explicit synchronization.
1377func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
1378
1379func (it *BucketIterator) fetch(pageSize int, pageToken string) (token string, err error) {
1380	req := it.client.raw.Buckets.List(it.projectID)
1381	setClientHeader(req.Header())
1382	req.Projection("full")
1383	req.Prefix(it.Prefix)
1384	req.PageToken(pageToken)
1385	if pageSize > 0 {
1386		req.MaxResults(int64(pageSize))
1387	}
1388	var resp *raw.Buckets
1389	err = runWithRetry(it.ctx, func() error {
1390		resp, err = req.Context(it.ctx).Do()
1391		return err
1392	})
1393	if err != nil {
1394		return "", err
1395	}
1396	for _, item := range resp.Items {
1397		b, err := newBucket(item)
1398		if err != nil {
1399			return "", err
1400		}
1401		it.buckets = append(it.buckets, b)
1402	}
1403	return resp.NextPageToken, nil
1404}
1405