チャットに画像のURLが貼られた時に、安全にimgタグを埋め込みたいという議論があったので書いておく。
一番単純な実装だと、
var s = "はろー http://shokai.org.ex/example.jpg てすとてすと";のようにすると
s.replace(/(https?:\/\/.+)\.(jpe?g|gif|png)/g, "<img src=\"$1.$2\">$1.$2</img>");
"はろー <img src="http://shokai.org.ex/example.jpg">http://shokai.org.ex/example.jpg</img> てすとてすと"
になるのだが、よく考えると http://tumblr.com/logout#.png みたいなのを貼られるとimgタグが描画された瞬間にログアウトしてしまう。
正規表現がショボいのも悪いけど、最近はURL末尾に画像の拡張子が付いていなくても画像が返ってくるサービスもある。そういうのが埋め込めない。
問題
いくつか問題というか解決策がある。どれが正しいのかは知らない。- GETでアクセスしただけでログアウトしてしまうサービスが悪い
- imgタグを描画する前に、本当にURLがimageなのか調べるべき。でもJavaScriptだけではcontent-type調べられない。
- ブラウザはサーバーに期待するmime-typeを付けてリクエストする。imgタグからリクエストするなら X-Mime-Condition: image/* とか
api.geta6.net
2について、geta6が2つ作ってくれた。http://api.geta6.com/imagent
URL先のページや画像をPhantomJS+xvfbでキャプチャして画像で返してくれるAPIで、これを使うとなんでもimgタグに埋め込んで大丈夫になる。
画像だったら画像がそのまま返ってくるし、webページも画像になって返ってくる。
resizeやcropもできる。
http://api.geta6.com/headers
URLを渡すとmime-typeがJSONPで取得できるので、JavaScriptで判別してimg/embed/audio/iframe/aなど適当なタグで埋め込む。
content-type.herokuapp.com
Node.jsの勉強がてら、簡単なのを作ってみた。
http://content-type.herokuapp.com/
http://content-type.herokuapp.com/type/image/IMAGE_URL のようにすると、typeがimageでなければ埋め込まれない。
<img src="http://content-type.herokuapp.com/type/image/http://twiticon.herokuapp.com/shokai/bigger">
画像じゃない時はエラー画像が表示される。
<img src="http://content-type.herokuapp.com/type/image/http://tumblr.com/logout#.png">
あと、 http://content-type.herokuapp.com/type/http://twiticon.herokuapp.com/shokai でmime-typeが取得できるのでこれを使って適当にタグを埋め込むJSライブラリを作ると便利かもしれない。
Herokuのmemcache
上のをNodeで作ってて誤算だったのは、HerokuのNode.jsではMemcacheが使えなかったことだった。HerokuのMemcacheはSASLという認証が必要なんだけど、SASLをサポートしているNode.jsのmemcacheライブラリがmemjsしかない。でもmemjsもSASL通らなかった。
しょうがないのでmemory-cacheというオンメモリキャッシュを使った。