1// Code generated by smithy-go-codegen DO NOT EDIT.
2
3package s3
4
5import (
6	"context"
7	"errors"
8	"fmt"
9	awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
10	"github.com/aws/aws-sdk-go-v2/aws/signer/v4"
11	s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations"
12	"github.com/aws/aws-sdk-go-v2/service/s3/types"
13	"github.com/aws/smithy-go/middleware"
14	smithytime "github.com/aws/smithy-go/time"
15	smithyhttp "github.com/aws/smithy-go/transport/http"
16	smithywaiter "github.com/aws/smithy-go/waiter"
17	"time"
18)
19
20// This action is useful to determine if a bucket exists and you have permission to
21// access it. The action returns a 200 OK if the bucket exists and you have
22// permission to access it. If the bucket does not exist or you do not have
23// permission to access it, the HEAD request returns a generic 404 Not Found or 403
24// Forbidden code. A message body is not included, so you cannot determine the
25// exception beyond these error codes. To use this operation, you must have
26// permissions to perform the s3:ListBucket action. The bucket owner has this
27// permission by default and can grant this permission to others. For more
28// information about permissions, see Permissions Related to Bucket Subresource
29// Operations
30// (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources)
31// and Managing Access Permissions to Your Amazon S3 Resources
32// (https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html).
33// To use this API against an access point, you must provide the alias of the
34// access point in place of the bucket name or specify the access point ARN. When
35// using the access point ARN, you must direct requests to the access point
36// hostname. The access point hostname takes the form
37// AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using the
38// Amazon Web Services SDKs, you provide the ARN in place of the bucket name. For
39// more information see, Using access points
40// (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html).
41func (c *Client) HeadBucket(ctx context.Context, params *HeadBucketInput, optFns ...func(*Options)) (*HeadBucketOutput, error) {
42	if params == nil {
43		params = &HeadBucketInput{}
44	}
45
46	result, metadata, err := c.invokeOperation(ctx, "HeadBucket", params, optFns, c.addOperationHeadBucketMiddlewares)
47	if err != nil {
48		return nil, err
49	}
50
51	out := result.(*HeadBucketOutput)
52	out.ResultMetadata = metadata
53	return out, nil
54}
55
56type HeadBucketInput struct {
57
58	// The bucket name. When using this action with an access point, you must direct
59	// requests to the access point hostname. The access point hostname takes the form
60	// AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this
61	// action with an access point through the Amazon Web Services SDKs, you provide
62	// the access point ARN in place of the bucket name. For more information about
63	// access point ARNs, see Using access points
64	// (https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html)
65	// in the Amazon S3 User Guide. When using this action with Amazon S3 on Outposts,
66	// you must direct requests to the S3 on Outposts hostname. The S3 on Outposts
67	// hostname takes the form
68	// AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When using
69	// this action using S3 on Outposts through the Amazon Web Services SDKs, you
70	// provide the Outposts bucket ARN in place of the bucket name. For more
71	// information about S3 on Outposts ARNs, see Using S3 on Outposts
72	// (https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html) in the
73	// Amazon S3 User Guide.
74	//
75	// This member is required.
76	Bucket *string
77
78	// The account ID of the expected bucket owner. If the bucket is owned by a
79	// different account, the request will fail with an HTTP 403 (Access Denied) error.
80	ExpectedBucketOwner *string
81
82	noSmithyDocumentSerde
83}
84
85type HeadBucketOutput struct {
86	// Metadata pertaining to the operation's result.
87	ResultMetadata middleware.Metadata
88
89	noSmithyDocumentSerde
90}
91
92func (c *Client) addOperationHeadBucketMiddlewares(stack *middleware.Stack, options Options) (err error) {
93	err = stack.Serialize.Add(&awsRestxml_serializeOpHeadBucket{}, middleware.After)
94	if err != nil {
95		return err
96	}
97	err = stack.Deserialize.Add(&awsRestxml_deserializeOpHeadBucket{}, middleware.After)
98	if err != nil {
99		return err
100	}
101	if err = addSetLoggerMiddleware(stack, options); err != nil {
102		return err
103	}
104	if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil {
105		return err
106	}
107	if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil {
108		return err
109	}
110	if err = addResolveEndpointMiddleware(stack, options); err != nil {
111		return err
112	}
113	if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil {
114		return err
115	}
116	if err = addRetryMiddlewares(stack, options); err != nil {
117		return err
118	}
119	if err = addHTTPSignerV4Middleware(stack, options); err != nil {
120		return err
121	}
122	if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil {
123		return err
124	}
125	if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil {
126		return err
127	}
128	if err = addClientUserAgent(stack); err != nil {
129		return err
130	}
131	if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil {
132		return err
133	}
134	if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil {
135		return err
136	}
137	if err = swapWithCustomHTTPSignerMiddleware(stack, options); err != nil {
138		return err
139	}
140	if err = addOpHeadBucketValidationMiddleware(stack); err != nil {
141		return err
142	}
143	if err = stack.Initialize.Add(newServiceMetadataMiddleware_opHeadBucket(options.Region), middleware.Before); err != nil {
144		return err
145	}
146	if err = addMetadataRetrieverMiddleware(stack); err != nil {
147		return err
148	}
149	if err = addHeadBucketUpdateEndpoint(stack, options); err != nil {
150		return err
151	}
152	if err = addResponseErrorMiddleware(stack); err != nil {
153		return err
154	}
155	if err = v4.AddContentSHA256HeaderMiddleware(stack); err != nil {
156		return err
157	}
158	if err = disableAcceptEncodingGzip(stack); err != nil {
159		return err
160	}
161	if err = addRequestResponseLogging(stack, options); err != nil {
162		return err
163	}
164	return nil
165}
166
167// HeadBucketAPIClient is a client that implements the HeadBucket operation.
168type HeadBucketAPIClient interface {
169	HeadBucket(context.Context, *HeadBucketInput, ...func(*Options)) (*HeadBucketOutput, error)
170}
171
172var _ HeadBucketAPIClient = (*Client)(nil)
173
174// BucketExistsWaiterOptions are waiter options for BucketExistsWaiter
175type BucketExistsWaiterOptions struct {
176
177	// Set of options to modify how an operation is invoked. These apply to all
178	// operations invoked for this client. Use functional options on operation call to
179	// modify this list for per operation behavior.
180	APIOptions []func(*middleware.Stack) error
181
182	// MinDelay is the minimum amount of time to delay between retries. If unset,
183	// BucketExistsWaiter will use default minimum delay of 5 seconds. Note that
184	// MinDelay must resolve to a value lesser than or equal to the MaxDelay.
185	MinDelay time.Duration
186
187	// MaxDelay is the maximum amount of time to delay between retries. If unset or set
188	// to zero, BucketExistsWaiter will use default max delay of 120 seconds. Note that
189	// MaxDelay must resolve to value greater than or equal to the MinDelay.
190	MaxDelay time.Duration
191
192	// LogWaitAttempts is used to enable logging for waiter retry attempts
193	LogWaitAttempts bool
194
195	// Retryable is function that can be used to override the service defined
196	// waiter-behavior based on operation output, or returned error. This function is
197	// used by the waiter to decide if a state is retryable or a terminal state. By
198	// default service-modeled logic will populate this option. This option can thus be
199	// used to define a custom waiter state with fall-back to service-modeled waiter
200	// state mutators.The function returns an error in case of a failure state. In case
201	// of retry state, this function returns a bool value of true and nil error, while
202	// in case of success it returns a bool value of false and nil error.
203	Retryable func(context.Context, *HeadBucketInput, *HeadBucketOutput, error) (bool, error)
204}
205
206// BucketExistsWaiter defines the waiters for BucketExists
207type BucketExistsWaiter struct {
208	client HeadBucketAPIClient
209
210	options BucketExistsWaiterOptions
211}
212
213// NewBucketExistsWaiter constructs a BucketExistsWaiter.
214func NewBucketExistsWaiter(client HeadBucketAPIClient, optFns ...func(*BucketExistsWaiterOptions)) *BucketExistsWaiter {
215	options := BucketExistsWaiterOptions{}
216	options.MinDelay = 5 * time.Second
217	options.MaxDelay = 120 * time.Second
218	options.Retryable = bucketExistsStateRetryable
219
220	for _, fn := range optFns {
221		fn(&options)
222	}
223	return &BucketExistsWaiter{
224		client:  client,
225		options: options,
226	}
227}
228
229// Wait calls the waiter function for BucketExists waiter. The maxWaitDur is the
230// maximum wait duration the waiter will wait. The maxWaitDur is required and must
231// be greater than zero.
232func (w *BucketExistsWaiter) Wait(ctx context.Context, params *HeadBucketInput, maxWaitDur time.Duration, optFns ...func(*BucketExistsWaiterOptions)) error {
233	if maxWaitDur <= 0 {
234		return fmt.Errorf("maximum wait time for waiter must be greater than zero")
235	}
236
237	options := w.options
238	for _, fn := range optFns {
239		fn(&options)
240	}
241
242	if options.MaxDelay <= 0 {
243		options.MaxDelay = 120 * time.Second
244	}
245
246	if options.MinDelay > options.MaxDelay {
247		return fmt.Errorf("minimum waiter delay %v must be lesser than or equal to maximum waiter delay of %v.", options.MinDelay, options.MaxDelay)
248	}
249
250	ctx, cancelFn := context.WithTimeout(ctx, maxWaitDur)
251	defer cancelFn()
252
253	logger := smithywaiter.Logger{}
254	remainingTime := maxWaitDur
255
256	var attempt int64
257	for {
258
259		attempt++
260		apiOptions := options.APIOptions
261		start := time.Now()
262
263		if options.LogWaitAttempts {
264			logger.Attempt = attempt
265			apiOptions = append([]func(*middleware.Stack) error{}, options.APIOptions...)
266			apiOptions = append(apiOptions, logger.AddLogger)
267		}
268
269		out, err := w.client.HeadBucket(ctx, params, func(o *Options) {
270			o.APIOptions = append(o.APIOptions, apiOptions...)
271		})
272
273		retryable, err := options.Retryable(ctx, params, out, err)
274		if err != nil {
275			return err
276		}
277		if !retryable {
278			return nil
279		}
280
281		remainingTime -= time.Since(start)
282		if remainingTime < options.MinDelay || remainingTime <= 0 {
283			break
284		}
285
286		// compute exponential backoff between waiter retries
287		delay, err := smithywaiter.ComputeDelay(
288			attempt, options.MinDelay, options.MaxDelay, remainingTime,
289		)
290		if err != nil {
291			return fmt.Errorf("error computing waiter delay, %w", err)
292		}
293
294		remainingTime -= delay
295		// sleep for the delay amount before invoking a request
296		if err := smithytime.SleepWithContext(ctx, delay); err != nil {
297			return fmt.Errorf("request cancelled while waiting, %w", err)
298		}
299	}
300	return fmt.Errorf("exceeded max wait time for BucketExists waiter")
301}
302
303func bucketExistsStateRetryable(ctx context.Context, input *HeadBucketInput, output *HeadBucketOutput, err error) (bool, error) {
304
305	if err == nil {
306		return false, nil
307	}
308
309	if err != nil {
310		var errorType *types.NotFound
311		if errors.As(err, &errorType) {
312			return true, nil
313		}
314	}
315
316	return true, nil
317}
318
319// BucketNotExistsWaiterOptions are waiter options for BucketNotExistsWaiter
320type BucketNotExistsWaiterOptions struct {
321
322	// Set of options to modify how an operation is invoked. These apply to all
323	// operations invoked for this client. Use functional options on operation call to
324	// modify this list for per operation behavior.
325	APIOptions []func(*middleware.Stack) error
326
327	// MinDelay is the minimum amount of time to delay between retries. If unset,
328	// BucketNotExistsWaiter will use default minimum delay of 5 seconds. Note that
329	// MinDelay must resolve to a value lesser than or equal to the MaxDelay.
330	MinDelay time.Duration
331
332	// MaxDelay is the maximum amount of time to delay between retries. If unset or set
333	// to zero, BucketNotExistsWaiter will use default max delay of 120 seconds. Note
334	// that MaxDelay must resolve to value greater than or equal to the MinDelay.
335	MaxDelay time.Duration
336
337	// LogWaitAttempts is used to enable logging for waiter retry attempts
338	LogWaitAttempts bool
339
340	// Retryable is function that can be used to override the service defined
341	// waiter-behavior based on operation output, or returned error. This function is
342	// used by the waiter to decide if a state is retryable or a terminal state. By
343	// default service-modeled logic will populate this option. This option can thus be
344	// used to define a custom waiter state with fall-back to service-modeled waiter
345	// state mutators.The function returns an error in case of a failure state. In case
346	// of retry state, this function returns a bool value of true and nil error, while
347	// in case of success it returns a bool value of false and nil error.
348	Retryable func(context.Context, *HeadBucketInput, *HeadBucketOutput, error) (bool, error)
349}
350
351// BucketNotExistsWaiter defines the waiters for BucketNotExists
352type BucketNotExistsWaiter struct {
353	client HeadBucketAPIClient
354
355	options BucketNotExistsWaiterOptions
356}
357
358// NewBucketNotExistsWaiter constructs a BucketNotExistsWaiter.
359func NewBucketNotExistsWaiter(client HeadBucketAPIClient, optFns ...func(*BucketNotExistsWaiterOptions)) *BucketNotExistsWaiter {
360	options := BucketNotExistsWaiterOptions{}
361	options.MinDelay = 5 * time.Second
362	options.MaxDelay = 120 * time.Second
363	options.Retryable = bucketNotExistsStateRetryable
364
365	for _, fn := range optFns {
366		fn(&options)
367	}
368	return &BucketNotExistsWaiter{
369		client:  client,
370		options: options,
371	}
372}
373
374// Wait calls the waiter function for BucketNotExists waiter. The maxWaitDur is the
375// maximum wait duration the waiter will wait. The maxWaitDur is required and must
376// be greater than zero.
377func (w *BucketNotExistsWaiter) Wait(ctx context.Context, params *HeadBucketInput, maxWaitDur time.Duration, optFns ...func(*BucketNotExistsWaiterOptions)) error {
378	if maxWaitDur <= 0 {
379		return fmt.Errorf("maximum wait time for waiter must be greater than zero")
380	}
381
382	options := w.options
383	for _, fn := range optFns {
384		fn(&options)
385	}
386
387	if options.MaxDelay <= 0 {
388		options.MaxDelay = 120 * time.Second
389	}
390
391	if options.MinDelay > options.MaxDelay {
392		return fmt.Errorf("minimum waiter delay %v must be lesser than or equal to maximum waiter delay of %v.", options.MinDelay, options.MaxDelay)
393	}
394
395	ctx, cancelFn := context.WithTimeout(ctx, maxWaitDur)
396	defer cancelFn()
397
398	logger := smithywaiter.Logger{}
399	remainingTime := maxWaitDur
400
401	var attempt int64
402	for {
403
404		attempt++
405		apiOptions := options.APIOptions
406		start := time.Now()
407
408		if options.LogWaitAttempts {
409			logger.Attempt = attempt
410			apiOptions = append([]func(*middleware.Stack) error{}, options.APIOptions...)
411			apiOptions = append(apiOptions, logger.AddLogger)
412		}
413
414		out, err := w.client.HeadBucket(ctx, params, func(o *Options) {
415			o.APIOptions = append(o.APIOptions, apiOptions...)
416		})
417
418		retryable, err := options.Retryable(ctx, params, out, err)
419		if err != nil {
420			return err
421		}
422		if !retryable {
423			return nil
424		}
425
426		remainingTime -= time.Since(start)
427		if remainingTime < options.MinDelay || remainingTime <= 0 {
428			break
429		}
430
431		// compute exponential backoff between waiter retries
432		delay, err := smithywaiter.ComputeDelay(
433			attempt, options.MinDelay, options.MaxDelay, remainingTime,
434		)
435		if err != nil {
436			return fmt.Errorf("error computing waiter delay, %w", err)
437		}
438
439		remainingTime -= delay
440		// sleep for the delay amount before invoking a request
441		if err := smithytime.SleepWithContext(ctx, delay); err != nil {
442			return fmt.Errorf("request cancelled while waiting, %w", err)
443		}
444	}
445	return fmt.Errorf("exceeded max wait time for BucketNotExists waiter")
446}
447
448func bucketNotExistsStateRetryable(ctx context.Context, input *HeadBucketInput, output *HeadBucketOutput, err error) (bool, error) {
449
450	if err != nil {
451		var errorType *types.NotFound
452		if errors.As(err, &errorType) {
453			return false, nil
454		}
455	}
456
457	return true, nil
458}
459
460func newServiceMetadataMiddleware_opHeadBucket(region string) *awsmiddleware.RegisterServiceMetadata {
461	return &awsmiddleware.RegisterServiceMetadata{
462		Region:        region,
463		ServiceID:     ServiceID,
464		SigningName:   "s3",
465		OperationName: "HeadBucket",
466	}
467}
468
469// getHeadBucketBucketMember returns a pointer to string denoting a provided bucket
470// member valueand a boolean indicating if the input has a modeled bucket name,
471func getHeadBucketBucketMember(input interface{}) (*string, bool) {
472	in := input.(*HeadBucketInput)
473	if in.Bucket == nil {
474		return nil, false
475	}
476	return in.Bucket, true
477}
478func addHeadBucketUpdateEndpoint(stack *middleware.Stack, options Options) error {
479	return s3cust.UpdateEndpoint(stack, s3cust.UpdateEndpointOptions{
480		Accessor: s3cust.UpdateEndpointParameterAccessor{
481			GetBucketFromInput: getHeadBucketBucketMember,
482		},
483		UsePathStyle:                   options.UsePathStyle,
484		UseAccelerate:                  options.UseAccelerate,
485		SupportsAccelerate:             true,
486		TargetS3ObjectLambda:           false,
487		EndpointResolver:               options.EndpointResolver,
488		EndpointResolverOptions:        options.EndpointOptions,
489		UseDualstack:                   options.UseDualstack,
490		UseARNRegion:                   options.UseARNRegion,
491		DisableMultiRegionAccessPoints: options.DisableMultiRegionAccessPoints,
492	})
493}
494