Boto3: Content-type when uploading files using boto3

Created on 15 Mar 2016  Â·  10Comments  Â·  Source: boto/boto3

Not certain if this is an issue or user error...

I have:

bucket = s3.Bucket()
bucket.upload_file(,,ExtraArgs={'....'})

This works, but I fuind that the uploaded file always has:

Content-Type: binary/octet-stream

Irrespective of the file type of the original local file. Is there any way to preserve the content type of the original local file?

closing-soon question

Most helpful comment

Yeah that should be too small for multipart uploads to kick in if you are using the default threshold of 8MB. This is what I tried and it works for me (the content type ends up being text/x-python):

import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('mybucketfoo')
bucket.upload_file(
    'foo.py', 'mykey', ExtraArgs={'ContentType': 'text/x-python'})

my_object = bucket.Object('mykey')
print(my_object.content_type)  

Could you provide a code snippet of what you are providing to ExtraArgs? If you do not provide anything for ContentType to ExtraArgs, the end content type will always be binary/octet-stream.

All 10 comments

Where are you seeing the content-type set like that?

I was using firebug to check the file headers.
The below works as expected - not sure it is the best way of doing what I need, but it certainly works:

mime_type = mime.guess_type(file)
f = open(directory+file, 'r')
data=f.read()
f.close()

bucket.put_object(
Body=data,
Key=file,
ACL='public-read',
StorageClass='REDUCED_REDUNDANCY',
ContentType=mime_type[0])

What version of boto3 are you using? I just stepped through with both put_object and upload_file and everything seems to be working correctly.

Also, are you uploading a file large enough to do a multipart upload? content-type is only set on the InitiateMulitpartUpload, all subsequent UploadPart requests will lack the header.

Hi,

The files were all of the order of ~100kB, so I suspect too small for
multiplart uploads.
Perhaps there is some S3 setting that can overwrite the content-type header
of uploaded files unless is is explicitly set in the upload request?

If that were the case it would explain why you haven't seen it, since it
would be an artifact of how my S3 bucket is set up....

I'll take a look in the morning...

Cheers!

On Mon, Mar 21, 2016 at 10:59 PM, Jordon Phillips [email protected]
wrote:

Also, are you uploading a file large enough to do a multipart upload?
content-type is only set on the InitiateMulitpartUpload, all subsequent
UploadPart requests will lack the header.

—
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/boto/boto3/issues/548#issuecomment-199525646

Yeah that should be too small for multipart uploads to kick in if you are using the default threshold of 8MB. This is what I tried and it works for me (the content type ends up being text/x-python):

import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('mybucketfoo')
bucket.upload_file(
    'foo.py', 'mykey', ExtraArgs={'ContentType': 'text/x-python'})

my_object = bucket.Object('mykey')
print(my_object.content_type)  

Could you provide a code snippet of what you are providing to ExtraArgs? If you do not provide anything for ContentType to ExtraArgs, the end content type will always be binary/octet-stream.

Ok - that's interesting. I'm not sure what I /was/ passing any more, but
you are correct, the above does seem to work. So I can now do either:

mime_type = mime.guess_type(file)
f = open(file, 'r')
data=f.read()
f.close()
bucket.put_object(Body=data, Key=file, ACL='public-read',
StorageClass='REDUCED_REDUNDANCY', ContentType=mime_type[0])

Or

mime_type = mime.guess_type(file)
bucket.upload_file(file, file, ExtraArgs={'ContentType': mime_type[0],
'ACL':'public-read', 'StorageClass':'REDUCED_REDUNDANCY'})

In both cases I have to query the mime type, but in the latter I don't have
to read the file into a variable first, which doesn't seem all that
efficient - so I imagine the second example (as you used) is a better
solution!

On Wed, Mar 23, 2016 at 5:23 PM, Kyle Knapp [email protected]
wrote:

Yeah that should be too small for multipart uploads to kick in if you are
using the default threshold of 8MB. This is what I tried and it works for
me (the content type ends up being text/x-python):

import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('mybucketfoo')
bucket.upload_file(
'foo.py', 'mykey', ExtraArgs={'ContentType': 'text/x-python'})

my_object = bucket.Object('mykey')print(my_object.content_type)

Could you provide a code snippet of what you are providing to ExtraArgs?
If you do not provide anything for ContentType to ExtraArgs, the end
content type will always be binary/octet-stream.

—
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/boto/boto3/issues/548#issuecomment-200450364

Awesome. Glad to hear that it is now working. Closing.

Apologies if this is the wrong place, but is there a way to have boto3 respect the default MIME type of a file, instead of this behavior:

If you do not provide anything for ContentType to ExtraArgs, the end content type will always be binary/octet-stream.

For anyone else who stumbles upon this issue and wants to automatically set ContentType, Python has a built-in module (mimetypes) that can be used to guess the mimetype. Here is a sample snippet:

import mimetypes 

mimetype, _ = mimetypes.guess_type(local_path)
if mimetype is None:
    raise Exception("Failed to guess mimetype")

s3.upload_file(
    Filename=local_path,
    Bucket=bucket,
    Key=remote_path,
    ExtraArgs={
        "ContentType": mimetype
    }
)
Was this page helpful?
0 / 5 - 0 ratings