125

For some reason files in my S3 bucket are being forced as downloads instead of displaying in-line so if I copy an image link and paste it into address bar and then navigate to it, it will promote my browser to download it. Instead I actually have to click on open image to go to the url.

Any ways to change the way files are served from S3

Cl'
  • 1,535
  • 2
  • 10
  • 17
  • When you copy image link, it directly points to the image URL. Browser simply understands to execute the URL provided. – Sunil Gulabani Jan 04 '13 at 05:11
  • @SunilGulabani But I seen sites using amazon s3 that allow you to access the file directly without having to force download the file. For example image hosting sites allow for direct image access. I am referring to direct file-path here is an example this is a file hosted in my S3 bucket: https://droplet-files.s3.amazonaws.com/7c32280bbcb1d3e67ac799ce9c71212f.JPG – Cl' Jan 04 '13 at 05:18
  • 1
    I think your content type provided will be wrong while uploading the image. It needs to be image/jpeg. Check for Content-Type: http://en.wikipedia.org/wiki/Internet_media_type – Sunil Gulabani Jan 04 '13 at 05:30
  • 1
    @SunilGulabani I don't send any data to S3 on regards on MINE type. I just simply: $s3->putObjectFile($tmp, $bucket , $actual_image_name, S3::ACL_PUBLIC_READ) and whola – Cl' Jan 04 '13 at 05:33
  • 1
    Use $s3->create_object($bucket, $file_name, array( 'contentType' => 'image/jpeg', 'acl' => AmazonS3::ACL_PUBLIC )); – Sunil Gulabani Jan 04 '13 at 05:56
  • You can get rid of this by making your image public. Click on the bucket in your console then click on image which you have uploaded and click action on the top then make public option in that drop down – thomas chacko Aug 19 '15 at 06:19

16 Answers16

91

You need to define the content type, see below:

$client->putObject(array(
        'Bucket'     => 'buckname',
        'Key'        => $destination,
        'SourceFile' => $source,
        'ContentType' =>'image/jpeg', //<-- this is what you need!
        'ACL'          => 'public-read'//<-- this makes it public so people can see it
    ));
Neo
  • 11,078
  • 2
  • 68
  • 79
  • 5
    Thanks for 'ContentType' =>'image/jpeg', //<-- this is what you need! – Alvin Chettiar Jun 10 '18 at 07:08
  • 4
    'ContentType' =>'image/jpeg', sill downloads the url instead of diplay in browser – insivika Sep 19 '20 at 19:29
  • 4
    @insivika try open in an incognito browser. I had the same problema, it worked for me when i opened in anonymous mode. – marcelobrgomes Jan 15 '21 at 16:51
  • Indeed works in a new browser or incognito. – Omar Dulaimi Jan 15 '22 at 17:00
  • I really hate that S3 decides how the data gets presented. I have an app that on some pages there is a download link (so I want the file to download). On other pages I want to view the file in a modal. This can't be done with the way S3 works unless you upload 2 files. 1 with the ContentType and one without. Why can't the developer decide what happens with the file? – Battousai Mar 08 '22 at 23:12
  • why does it work with incognito window and doesn't work with normal one? have set my file's content type to `text/plain`, but it doesn't open in a normal window. – mangusta Feb 21 '23 at 01:46
  • Converting the file format works too. – Trishant Pahwa Jun 10 '23 at 20:00
54

You need to change the Content-Type. From the S3 console, right click on the object and select Properties then it's under Metadata. You can also do it programmatically: http://docs.amazonwebservices.com/AWSSDKforPHP/latest/index.html#m=AmazonS3/change_content_type

gregbeaty
  • 679
  • 4
  • 4
  • 2
    I see, I was using $s3->putObjectFile($tmp, $bucket , $actual_image_name, S3::ACL_PUBLIC_READ) before, but for some reason I recall doing the same that I want to achieved with use of bucket policy – Cl' Jan 04 '13 at 05:38
  • 2
    @Cl' you can also [set content-type in `putObject()` method](http://undesigned.org.za/2007/10/22/amazon-s3-php-class/documentation#putObject) (as `putObjectFile()` is legacy now). – mathielo Sep 01 '14 at 14:56
18

You need to specify Content Disposition as well for inline instead attachment .

$client->putObject(array(
    'Bucket'     => 'buckname',
    'Key'        => $destination,
    'SourceFile' => $source,
    'ContentType' =>'image/jpeg', //<-- this is what you need!
    'ContentDisposition' => 'inline; filename=filename.jpg', //<-- and this !
    'ACL'          => 'public-read'//<-- this makes it public so people can see it
));
Alin Razvan
  • 1,451
  • 13
  • 18
  • 3
    This worked for me. For those looking to get this code working with any type of file be sure to use 'ContentType' => mime_content_type($file) – Cary Jun 26 '19 at 15:17
17

if you are using python, you can set ContentType as follows

s3 = boto3.client('s3')

mimetype = 'image/jpeg' # you can programmatically get mimetype using the `mimetypes` module
s3.upload_file(
    Filename=local_path,
    Bucket=bucket,
    Key=remote_path,
    ExtraArgs={
        "ContentType": mimetype
    }
)

You can also achieve the same in aws cli. Note *.jpeg Check s3 documentation

aws s3 cp \
      --exclude "*" \
      --include "*.jpeg" \
      --content-type="image/jpeg"  \
      --metadata-directive="REPLACE" \
      --recursive \
      --dryrun \
       s3://<bucket>/<path>/ \
       s3://<bucket>/<path>/

Alternatively if you'd want to do modify one object at a time you might want to use s3api copy-object

aws s3api copy-object \
    --content-type="image/jpeg" \
    --metadata-directive="REPLACE" \
    --copy-source "<bucket>/<key>" \
    --bucket "<bucket>" \
    --key "<key>" \
    --acl public-read
Anthony Awuley
  • 3,455
  • 30
  • 20
6

You can change the content type from the AWS S3 Console too.

enter image description here

Then you will get to see the side pop up, use that to change it manually.

enter image description here

Nerdy Sid
  • 332
  • 5
  • 14
4

You can try this one, this works for me.

const params = {
          Bucket: 'bucket-name',
          Body: file,
          ACL: 'public-read',
          ContentType: contentType,
          ContentEncoding: 'base64',
          ContentDisposition: 'attachment',
        };
Pushprajsinh Chudasama
  • 7,772
  • 4
  • 20
  • 43
3

You can try this one, ContentType is compulsory for open in a browser if you have already opened any URL on the browser then try in incognito.

var params = {
            Bucket: config.BUCKET_NAME,
            Key: fileName,
            ContentEncoding: 'base64',
            ContentDisposition: 'inline',
            ContentType: 'image/jpeg',
            Body: buf
        };
Ankit Kumar Rajpoot
  • 5,188
  • 2
  • 38
  • 32
3

I found out that if we pass an empty value to ContentType it will open the file instead of downloading.

This is actually nice when uploading files of all kind of extensions.

$s3->putObject(
[
    'Bucket' => ..,
    'Key' => ..,
    'Body' => ..,
    'ContentType' => '', <---
    'ACL' => 'public-read',
]);
Linesofcode
  • 5,327
  • 13
  • 62
  • 116
  • 1
    I was facing same in python , added " bucket.put_object(Key=key,Body=strdata,ACL='public-read',ContentType='text/html'), and it worked. – PankajKushwaha Apr 16 '21 at 20:29
2

I had the same problem today. The problem was the Content-type property, when I was saving the file in s3. I am using Spring Boot, and content data in s3 was saving application/octet-stream in the value properties instead of image/jpeg, for example. Therefore, when I opened the file link, the browser downloaded the file.

The solution for this problem is to change the Content-type before saving the file in s3 !

Mario Varchmin
  • 3,704
  • 4
  • 18
  • 33
1

In case someone who is using Java SDK is finding a solution for this, you need to set content type to ObjectMetaData.

ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType("image/png");

s3client.putObject(new PutObjectRequest
    (bucketName, fileName + ".png", inputStream, 
     objectMetadata).withCannedAcl(CannedAccessControlList.PublicRead));
vigamage
  • 1,975
  • 7
  • 48
  • 74
1

What really worked for me was to set the ContentType params to image/png before saving the S3 file.

Clau
  • 86
  • 1
  • 2
0

If you open it in incognito it will work other than that it will not work for some reason.

kd12345
  • 689
  • 10
  • 29
0

Use these two properties to force browsers to inline the file from s3:

'ResponseContentType' & 'ResponseContentDisposition'

You can use them in the getCommand when generating a signed URL

$cmd = $s3Client->getCommand('GetObject', [
        'Bucket' => $bucket_name,
        'Key' => $filename,
        'ResponseContentType' =>  get_mime_type($filename),
        'ResponseContentDisposition' => 'inline; filename='.$user_filename
    ]);
   

get_mime_type is just my custom function to return mime type using the file name

This is what I used when I faced the same problem, I have millions of files in my s3 bucket and I couldn't change the mime type individually in console

Mike T.
  • 35
  • 1
  • 5
0

After 2 days of fighting, this is the code I want.
Here is the code for anyone who uses "generate_presigned_post" in python

s3 = boto3.client('s3',
                  aws_access_key_id="<aws_access_key_id>",
                  aws_secret_access_key="<aws_secret_access_key>",
                  config=Config(
                      region_name="<region_name>",
                      signature_version="<signature_version>"
                  ))

key = 'bbb.png'

creds = s3.generate_presigned_post(
    Bucket="<Bucket>",
    Key=key,
    Fields={"Content-Type": "image/png"},
    Conditions=[{"Content-Type": "image/png"}],
    ExpiresIn=3600)
T H
  • 423
  • 4
  • 7
0

Though this is pretty old question but when i was googling a similar issue then I landed here so for them who lands here, just wanted to clarify that why files are being downloaded instead of displaying it - Because when you don't set the Content-Type explicitly, then by default S3 set the Content-Type to application/octet-stream

enter image description here

Avnish Tiwary
  • 2,188
  • 22
  • 27
-1

Below code worked for me but pdf not open in browser only jpeg or png file open in the browser.

$result = $s3->putObject(
            array(
                'Bucket'                =>  $bucketName,
                'Key'                   =>  $keyName,
                'SourceFile'            =>  $file,
                'StorageClass'          =>  'REDUCED_REDUNDANCY',
                'ContentEncoding'       =>  'base64',
                'ContentDisposition'    =>  'inline',
                'ContentType'           =>  'image/jpeg', //<-- this is what you need!
                'ACL'                   =>  'public-read'//<-- this makes it public so people can see it
            )
        );