Go で net/http/cookiejar をフォークしたライブラリを使わずに Cookie を永続的に保存したかった
できなかった。
動機
既存の CookieJar を保存できそうなライブラリが、標準ライブラリをフォークしたライブラリしかない 現在の標準ライブラリより遅れるだろうから、問題を発生させるかもしれないために使いたくない
それを抜きにしてもインターフェースがよくないものばかりに見えた
直接ファイルに保存するのは柔軟性に欠けていて、嫌
データベースに保存するとは考えなかったんですか?
また、既にプライベートなリポジトリで試して、ある程度動くことがわかっていた
ただし後述する問題があったのを知らなかったので動いているように見えていた部分もある
実装
既存の Jar をラップして、SetCookies で URL を sync.Map に保存して、Cookies にその URL を全部投げてユニークにするというアプローチを取った
実際には URL というか、Cookie を取ってくるときに考慮しなければいけない箇所のみを結合した文字列なわけだが
schema://host/path のみ
もちろん http.Cookie を保存してもよいが、それをするとただのプロキシできる http.CookieJar の実装なわけで、下位の CookieJar にある程度の処理を丸投げできるメリットが消えてしまうのでナシ
もしそれをするなら http.CookieJar を自前で実装するということになる
効率が悪いということは忘れる
保存時にしか影響がないので、大して問題にならないと考えた
コピーは大量に発生している
結果
6時間くらい検証してたが、あえなくアーカイブ
ただし人の目には触れてほしいなぁと思ったので、アーカイブして otofune 配下に置くことにした
Cookie を永続化するにあたって必要な情報が取れなかったため
Cookies(*url.URL) メソッドからしか http.Cookie が取得できないことが問題だった
このメソッド、標準ライブラリである net/http/CookieJar は Name と Value しか埋まってない http.Cookie しかくれないんだよね
HTTPOnly, Expires (or Max-Age), Path や Domain が追加で必要
このうち、Expires を除くとなんとか取得はできる
Path は URL を保存する際に工夫すれば、URL へ保持できる
Path が指定されていれば保存する URL に上書き
Path がなければ Cookie はその親ディレクトリに適用されるため、そのように保存してやる
HTTPOnly も同じで、最短のものを選ぶと自動でスキーマも最短になるはずである
ただ http:// で取ってみないとダメなので、偶然 https:// のみで HTTPOnly じゃない Cookie を扱っていると破滅する
Path のように保存時に加工すればよいと思う
一度でも出現すれば OK なので
Domain はサブドメインをつけた URL も加えて検証すれば、判明する
同じ Name と Value を持つ、サブドメインにも反映される Cookie はもっとも短いドメインの持ちもので、Domain が指定されているという扱いをすればいいわけ
ただし同じ Name と Value でサブドメインに登録されていたらおかしくなってしまう
これは回避しようがないが、現実には発生しにくいだろうと判断して無視した
で、問題はこいつなんだが、Expires や Max-Age が取れない
終わった。
現実時間で取れるか取れないかしかわからないので、どうしようもない
Expires が取れないと、persistent cookie か session cookie かの判別がつかないので、どうしようもない
但し書きの点も怪しいが、期限が全く取れないなら実用じゃないよね、ということでアーカイブに