チャットに画像の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末尾に画像の拡張子が付いていなくても画像が返ってくるサービスもある。そういうのが埋め込めない。

問題

いくつか問題というか解決策がある。どれが正しいのかは知らない。
  1. GETでアクセスしただけでログアウトしてしまうサービスが悪い
  2. imgタグを描画する前に、本当にURLがimageなのか調べるべき。でもJavaScriptだけではcontent-type調べられない。
  3. ブラウザはサーバーに期待するmime-typeを付けてリクエストする。imgタグからリクエストするなら X-Mime-Condition: image/* とか
3が一番いいけど、2が現実的かな。


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というオンメモリキャッシュを使った。