aws / aws-sdk-net

The official AWS SDK for .NET. For more information on the AWS SDK for .NET, see our web site:
http://aws.amazon.com/sdkfornet/
Apache License 2.0
2.05k stars 853 forks source link

S3 Client not Exposing HeadBucket #3178

Open dscpinheiro opened 7 months ago

dscpinheiro commented 7 months ago

Discussed in https://github.com/aws/aws-sdk-net/discussions/3175

Originally posted by **omamoo** February 7, 2024 Hello all, I'm writing a code that uploading content to S3 bucket that resides at different account, i.e. I have a cross account scenario of uploading content to S3. While writing the code I used `GetBucketLocation` API call to determine the bucket location, however on cross account scenario the `GetBucketLocation` fails since I'm not the bucket owner, in addition, I saw on AWS documentation that their recommendation is to use `HeadBucket` API call, however the SDK does not expose this API call and defined this call as `internal`. Here is a snapshot from the SDK code: ``` internal virtual Task HeadBucketAsync(HeadBucketRequest request, System.Threading.CancellationToken cancellationToken = default(CancellationToken)) { var options = new InvokeOptions(); options.RequestMarshaller = HeadBucketRequestMarshaller.Instance; options.ResponseUnmarshaller = HeadBucketResponseUnmarshaller.Instance; return InvokeAsync(request, options, cancellationToken); } ``` Can we make this public for use?
b-dongen commented 2 weeks ago

In case anyone is inpatient like me, I've created this extension method using reflection to access the HeadBucketAsync() method.

`static class AmazonS3ClientExtension {

pragma warning disable S3011 // Reflection should not be used to increase accessibility of classes, methods, or fields

static readonly MethodInfo _headBucketAsyncMethod = typeof(AmazonS3Client)
    .GetMethod("HeadBucketAsync", BindingFlags.Instance | BindingFlags.NonPublic)!;
static readonly FieldInfo _httpClientResponseDataHeaderField = typeof(HttpClientResponseData)
    .GetField("_headers", BindingFlags.NonPublic | BindingFlags.Instance)!;

pragma warning restore S3011 // Reflection should not be used to increase accessibility of classes, methods, or fields

static public Task<HeadBucketResponse> HeadBucketAsync(this AmazonS3Client client, HeadBucketRequest request, CancellationToken cancellationToken = default)
    => (Task<HeadBucketResponse>)_headBucketAsyncMethod.Invoke(client, [request, cancellationToken])!;

// Use reflection to get the region from the response-headers
static public string? GetRegionFromResponseHeader(this AmazonServiceException ex)
{
    var responseEx = ex.InnerException as HttpErrorResponseException;
    var responseData = responseEx?.Response as HttpClientResponseData;
    var headers = _httpClientResponseDataHeaderField.GetValue(responseData) as Dictionary<string, string>;
    string? region = headers?.GetValueOrDefault("x-amz-bucket-region");

    return region;
}

}`