AWS CLIでS3オブジェクトのContentTypeを設定する

aws_logo
aws が提供するコマンドラインツールの aws cli を使って、S3オブジェクトのContentTypeを設定する方法をメモ。

aws s3 cp の場合

default

aws s3 cp コマンドを使うと、デフォルトでは ContentType が guess される。

$ aws s3 cp song.mp3 s3://02a8/song.mp3
upload: ./song.mp3 to s3://02a8/song.mp3
$ aws s3api head-object --bucket 02a8 --key song.mp3
{
    "LastModified": "Tue, 13 May 2014 15:19:57 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "audio/mpeg",
    "ContentLength": "0"
}

guess の仕様は Python 標準ライブラリー の mimetypes.guess_type に準拠。

guess 例

$ python
Python 2.7.3 (default, Aug  1 2012, 05:14:39)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import mimetypes
>>> mimetypes.guess_type('foo.mp3')
('audio/mpeg', None)
>>> mimetypes.guess_type('foo.json')
('application/json', None)

ContentType の guess をやめる

--no-guess-mime-type をつけて cp する。

$ aws s3 cp --no-guess-mime-type song.mp3 s3://02a8/noguess.mp3
upload: ./song.mp3 to s3://02a8/noguess.mp3
$ aws s3api head-object --bucket 02a8 --key noguess.mp3
{
    "LastModified": "Tue, 13 May 2014 15:21:32 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "binary/octet-stream",
    "ContentLength": "0"
}

ContentType を明示的に指定

--content-type で明示的に指定して cp する。

$ aws s3 cp --content-type text/plain song.mp3 s3://02a8/text_plain.mp3
upload: ./song.mp3 to s3://02a8/text_plain.mp3
$ aws s3api head-object --bucket 02a8 --key text_plain.mp3
{
    "LastModified": "Tue, 13 May 2014 15:22:32 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "text/plain",
    "ContentLength": "0"
}

別バケットからコピーした時の挙動

コピー元がローカルのファイルシステムではなく、S3 オブジェクト(すでに Content-Type を持っている)だったらどうなるのか?

$ aws s3 cp --no-guess-mime-type s3://02a8/text_plain.mp3 s3://02a8/cp_noguess.mp3
copy: s3://02a8/text_plain.mp3 to s3://02a8/cp_noguess.mp3
$ aws s3api head-object --bucket 02a8 --key cp_noguess.mp3
{
    "LastModified": "Tue, 13 May 2014 15:54:04 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "text/plain",
    "ContentLength": "0"
}
$ aws s3 cp --content-type text/html s3://02a8/text_plain.mp3 s3://02a8/cp_text_html.mp3
copy: s3://02a8/text_plain.mp3 to s3://02a8/cp_text_html.mp3
$ aws s3api head-object --bucket 02a8 --key cp_text_html.mp3
{
    "LastModified": "Tue, 13 May 2014 15:54:14 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "text/plain",
    "ContentLength": "0"
}

--no-guess-mime-type オプションをつけようと --content-type オプションをつけようと、コピー元の ContentType が引き継がれる。

aws s3 sync の場合

動きは aws s3 cpの時と同じ。

  • sync 元がローカルのファイルシステムの場合、デフォルトで ContentType は guess され、--no-guess-mime-type--content-type で guess を上書きできる。
  • sync 元が S3 オブジェクトの場合(バケット間コピーとか)、コピー元の ContentType がそのまま引き継がれる。

上で 02a8 バケットに作成したオブジェクトを 02a9 バケットに aws s3 sync してみると

$ aws s3 sync s3://02a8 s3://02a9
copy: s3://02a8/copied_song.mp3 to s3://02a9/copied_song.mp3
copy: s3://02a8/song.mp3 to s3://02a9/song.mp3
copy: s3://02a8/cp_noguess.mp3 to s3://02a9/cp_noguess.mp3
copy: s3://02a8/text_plain.mp3 to s3://02a9/text_plain.mp3
copy: s3://02a8/copied_noguess.mp3 to s3://02a9/copied_noguess.mp3
copy: s3://02a8/cp_text_html.mp3 to s3://02a9/cp_text_html.mp3
copy: s3://02a8/noguess.mp3 to s3://02a9/noguess.mp3

$ aws s3api head-object --bucket 02a9 --key song.mp3
{
    "LastModified": "Tue, 13 May 2014 15:55:30 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "audio/mpeg",
    "ContentLength": "0"
}
$ aws s3api head-object --bucket 02a9 --key text_plain.mp3
{
    "LastModified": "Tue, 13 May 2014 15:55:30 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "text/plain",
    "ContentLength": "0"
}

というように、コピー元の ContentType がそのまま引き継がれている。

aws s3api put-object の場合

次に aws s3 cp コマンドのローレベル API である aws s3api put-object を触ってみる。
ローカルのファイルシステムにあるオブジェクトをコピーするためにつかう。
S3 の Put Object API の aws cli 対応版

デフォルト

$ aws s3api put-object --bucket 02a8 --key song.mp3 --body song.mp3
{
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\""
}
$ aws s3api head-object --bucket 02a8 --key song.mp3
{
    "LastModified": "Tue, 13 May 2014 16:02:17 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "binary/octet-stream",
    "ContentLength": "0"
}

デフォルトでは ContentType は guess されない。

ContentType を指定

--content-type をつけて ContentType を指定する。

$ aws s3api put-object --body song.mp3 --bucket 02a8 --key audio_mpeg.mp3 --content-type audio/mpeg
{
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\""
}
$ aws s3api head-object --bucket 02a8 --key audio_mpeg.mp3
{
    "LastModified": "Tue, 13 May 2014 16:03:35 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "audio/mpeg",
    "ContentLength": "0"
}

copy-object の場合

次に aws s3 cp コマンドのもう一つのローレベル API である aws s3api copy-object を触ってみる。

S3 にあるオブジェクトをコピーするためにつかう。
S3 の Put Object – Copy API の aws cli 対応版

<pre>$ aws s3api head-object --bucket 02a8 --key audio_mpeg.mp3
{
    "LastModified": "Tue, 13 May 2014 16:23:13 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "audio/mpeg",
    "ContentLength": "0"
}
$ aws s3api copy-object --copy-source 02a8/audio_mpeg.mp3 --bucket 02a8 --key copied_audio_mpeg.mp3
{
    "CopyObjectResult": {
        "LastModified": "2014-05-13T16:36:57.000Z",
        "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\""
    }
}
$ aws s3api head-object --bucket 02a8 --key copied_audio_mpeg.mp3
{
    "LastModified": "Tue, 13 May 2014 16:36:57 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "audio/mpeg",
    "ContentLength": "0"
}

デフォルトでは、コピー元の ContentType が引き継がれる。

ContentType を指定

--content-type をつけて ContentType を指定してみる。

$ aws s3api copy-object --copy-source 02a8/song.mp3 --bucket 02a8 --key copied_text_html.mp3 --content-type text/html
{
    "CopyObjectResult": {
        "LastModified": "2014-05-13T16:06:01.000Z",
        "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\""
    }
}
$ aws s3api head-object --bucket 02a8 --key copied_text_html.mp3                                                 {
    "LastModified": "Tue, 13 May 2014 16:06:01 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "binary/octet-stream",
    "ContentLength": "0"
}

なぜか ContentType が “text/html” に変わっていない。

原因は、コピー元が S3 オブジェクトの場合、 --metadata-directive を REPLACE にしないとコピー元のメタデータが引き継がれるため。(デフォルトのモードは COPY でメタデータが引き継がれる)
詳細は PUT Object – Copy API x-amz-metadata-directive ディレクティブの説明を参照

--metadata-directive REPLACE をつけて ContentType を指定してみる。

$ aws s3api copy-object --copy-source 02a8/song.mp3 --bucket 02a8 --key copied_metadata_replace.mp3 --content-type text/html  --metadata-directive REPLACE
{
    "CopyObjectResult": {
        "LastModified": "2014-05-13T16:07:14.000Z",
        "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\""
    }
}
$ aws s3api head-object --bucket 02a8 --key copied_metadata_replace.mp3                                          {
    "LastModified": "Tue, 13 May 2014 16:07:14 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "text/html",
    "ContentLength": "0"
}

期待どおり ContentType が変わった。

S3 オブジェクトの ContentType だけを更新する

最終目標にやりたかったのがこれ。

初期データの投入方法がまずくて、ContentType を付け直したいときにどうすればよいのか?
残念なことに AWS S3 の RestAPI にはそんな都合のよい API は存在しない。

自分自身にコピーして、ContentType を上書きすれば OK

“ContentType”: “binary/octet-stream” な s3://02a8/song.mp3 の ContentType を “audio/mpeg” に変えてみる。

$ aws s3api head-object --bucket 02a8 --key song.mp3
{
    "LastModified": "Tue, 13 May 2014 16:02:17 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "binary/octet-stream",
    "ContentLength": "0"
}
$ aws s3api copy-object --bucket 02a8 --copy-source 02a8/song.mp3 --key song.mp3 --content-type audio/mpeg --metadata-directive REPLACE
{
    "CopyObjectResult": {
        "LastModified": "2014-05-13T16:08:54.000Z",
        "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\""
    }
}
$ aws s3api head-object --bucket 02a8 --key song.mp3                                                             {
    "LastModified": "Tue, 13 May 2014 16:08:54 GMT",
    "AcceptRanges": "bytes",
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "audio/mpeg",
    "ContentLength": "0"
}

ということで無事更新出来た。
めでたし、めでたし。

Advertisements
Tagged with: , ,
Posted in aws
One comment on “AWS CLIでS3オブジェクトのContentTypeを設定する

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
  • RT @__apf__: How to write a research paper: a guide for software engineers & practitioners. docs.google.com/presentation/d… /cc @inwyrd 6 months ago
  • RT @HayatoChiba: 昔、自然と対話しながら数学に打ち込んだら何かを悟れるのではと思いたち、専門書1つだけ持ってパワースポットで名高い奈良の山奥に1週間籠ったことがある。しかし泊まった民宿にドカベンが全巻揃っていたため、水島新司と対話しただけで1週間過ぎた。 それ… 6 months ago
  • RT @googlecloud: Ever wonder what underwater fiber optic internet cables look like? Look no further than this deep dive w/ @NatAndLo: https… 6 months ago
  • @ijin UTC+01:00 な時間帯で生活しています、、、 1 year ago
  • RT @mattcutts: Google's world-class Site Reliability Engineering team wrote a new book: amazon.com/Site-Reliabili… It's about managing produc… 1 year ago
%d bloggers like this: