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