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