3

I have generated a pre-signed url from S3 using the following .Net code (in a service that has the appropriate IAM role/permission for the bucket)

            var key = GenerateKey(jobId, batchId);
            var linkExpiresAt = _dateTimeService.Now().AddMinutes(_expiryTime);

            var request = new GetPreSignedUrlRequest
            {
                BucketName = _bucketName,
                Key = key,
                Verb = HttpVerb.PUT,
                ContentType = "application/json",
                Expires = linkExpiresAt,
                ServerSideEncryptionMethod = ServerSideEncryptionMethod.None
            };

            var url = _s3Client.GetPreSignedURL(request);

I can use this url in Postman to do a PUT with content 'JSON', but when I try to use it from code, I get 403

            var content = new StringContent(mooStr, Encoding.ASCII, "application/json");
            var fileStreamResponse = await httpClient.PutAsync(
                url,
                content);

Is there anything that stands out as wrong with the .Net attempt to PUT to the url?

Pete Roberts
  • 118
  • 7

2 Answers2

2

If anyone comes across the same issue, I found the solution.

When I ran Fiddler, I captured the successful request from Postman and the failing request from .Net code. The only difference I could spot was that the successful one had this header (I'd changed to text/plain since my first post, but the problem remained):-

Content-Type: text/plain

and the failing one from .Net had:-

Content-Type: text/plain; charset=utf-8

A bit of a search around StackOverflow found me these posts

How to remove charset=utf8 from Content-Type header generated by HttpClient.PostAsJsonAsync()?

How do I not exclude charset in Content-Type when using HttpClient?

I edited the captured request in Fiddler and removed the charset and it worked. Altering my original code to the following worked (note - setting text/plain on the StringContent didn't work):-

            var content = new StringContent(mooStr);
            content.Headers.ContentType = MediaTypeHeaderValue.Parse("text/plain");

            var fileStreamResponse = await httpClient.PutAsync(
                Url,
                content); 
Pete Roberts
  • 118
  • 7
0

Following code worked for me (for posting a file of type IFormFile):

public async Task<bool> UploadObject(string preSignedUrl)
{
    try
    {
        using (var client = new HttpClient())
        {
            StreamContent streamContent = new StreamContent(file.OpenReadStream());
            var result = await client.PutAsync(preSignedUrl, streamContent);
            if (result.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception();
            }
         }

          return true;
     }
     catch (Exception e)
     {
         .... 
     }

     return false;
}

Create the preSignedUrl with the IAmazonS3 package.

Wouter
  • 1,293
  • 2
  • 16
  • 34