3

I need to retrieve images from S3. I can't make the folder public and I cant use presigned URL's so all I am left with is GetObject();. Now the image that I'll get back has to be set as a source for an Iframe. To do that I am using a HttpWebHandler. The issue is that if i retrieve a html page it is working fine. But when I try to get an image back, all i get is junk data. Here is my code:

 public void ProcessRequest(HttpContext context)
        {

            NameValueCollection appConfig = ConfigurationManager.AppSettings;
            _accessKeyId = appConfig["AWSAccessKey"];
            _secretAccessKeyId = appConfig["AWSSecretKey"];
            S3 = new AmazonS3Client(_accessKeyId, _secretAccessKeyId);
            string responseBody = "";
            var request = new GetObjectRequest()
            .WithBucketName(bucketName).WithKey("020/images/intro.jpg");
            var responseHeaders = new ResponseHeaderOverrides
                                      {
                                          ContentType = "image/jpeg"
                                      };

            request.ResponseHeaderOverrides = responseHeaders;
            using (var response = S3.GetObject(request))
            {
                using (var responseStream = response.ResponseStream)
                {
                    using (var reader =
                        new StreamReader(responseStream))
                    {
                        responseBody = reader.ReadToEnd();
                    }
                }

            }
            context.Response.Write(responseBody);
            context.Response.Flush();
            context.Response.End();
        }
}
Abhi.Net
  • 634
  • 3
  • 11
  • 34

1 Answers1

3

There are a couple of problems here:

  1. You are setting the Content-Type on the response coming back from amazon, but not on the response from your application
  2. You are using a StreamReader to read the content of the stream as text and then writing it back as text

Try this instead:

using (var response = S3.GetObject(request))
{
    using (var responseStream = response.ResponseStream)
    {
        context.Response.ContentType = "image/jpeg";

        var buffer = new byte[8000];
        int bytesRead = -1;
        while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
        {
            context.Response.OutputStream.Write(buffer, 0, bytesRead);
        }
    }
}

context.Response.End();
Jason
  • 339
  • 2
  • 6
  • Thank you Jason, I've one more related issue. The above code that you see is a part of a program where I am trying to retrieve HTML files from S3. The HTML files has objects related to it(CSS, javascript, Images). Now I have a web handler to get that gets the stream and sets it as a source. the problem is that I don't know the content type of incoming stream. Your code would work great If I was only working with Images but I also have to stream other types. Is there a way to determine the content type for incoming stream? Thanks again for your help much appreciated! – Abhi.Net May 22 '12 at 07:17
  • You have two options: you could set the content-type when you're storing content in S3 and use that the content-type value on the way back out or you could guess the type based on the extension of the file. There is code here (http://stackoverflow.com/questions/58510/using-net-how-can-you-find-the-mime-type-of-a-file-based-on-the-file-signature) that has some example methods for sniffing the mime type. Using the file extension may be good enough for your needs, so using a static dictionary or the Windows registry may be an acceptable solution. – Jason Jun 01 '12 at 03:17