Web アプリケーションの話題。
自分はもっぱら、ASP.NET による Web アプリケーションを書くのが主な仕事になるのだが、さて。
If-modified-since 要求ヘッダにちゃんと反応させる
とある事情があって、半固定的なコンテンツをレスポンスに返す HTTP ハンドラを自前で書くことになった。
で、ブラウザのキャッシュを有効活用してもらうよう、If-modified-since 要求ヘッダ値に書かれた日時情報をちゃんと見るように実装。
すなわち、ブラウザがキャッシュに覚えているコンテンツのタイムスタンプがじゅうぶん新しければ、HTTP 304 Not Modified だけを返すようにしていた。
"じゅうぶん新しいかどうか" の日時計算にあたっては、If-modified-since 要求ヘッダ値を DateTime.Parse() に読ませて、.NET Framework の DateTime 型に変換して比較・計算する実装としていた。
さて、通常、If-modified-since 要求ヘッダ値には次のような文字列が格納されているはずである。
Wed, 28 Sep 2011 14:42:36 GMT
.NET の DateTime 型は、Parse 静的メソッドによってこの文字列を正しく DateTime 型の値に解析して返してくれるわけだ。
解析できない日付文字列が!
ところが、実際に試してみたところ、どういうわけか、この DateTime.Parse を呼び出しているところで下記の例外が発生してしまう現象に遭遇。
FormatException - 文字列は有効な DateTime として認識されませんでした。インデックス 0 から始まる位置に不明な単語があります。
いったいどんな If-modified-since 要求ヘッダ値がきたのか、確認してみると、次のとおり。
Mi, 28 Sep 2011 14:42:36 GMT
ん?
曜日の文字列のところが "Wed" ( 水曜日:Wednesday ) ではなく、"Mi" になっている。
"Mi" っていったいなんだ?
"Mi" はドイツ語での水曜日の略称表記
ネットで検索してみたところ、これはドイツ語における曜日名の略称表記らしい(ドイツ語に限らないかもしれないが)。
英語表記なら、"Sun","Mon","Tue","Wed","Thu","Fri","Sat" となるが、これがドイツ語だと "So","Mo","Di","Mi","Do","Fr","Sa" となるそうな。
ちなみに、月の略称表記も英語とドイツ語とで異なるのだが、9月に関してはたまたま、両者とも "Sep" で同じであった。
RFC 読んでないので、このような非英語圏の表記で if-modified-since 要求ヘッダを送ってもよいことになっているのかどうかは知らない。
とにかく現実に、このような if-modified-since 要求ヘッダ値を送ってよこすユーザーエージェントが実在するということだ(非常に希ではあったのだが)。
なお、対策としては、DateTime.Parse についてどの言語のカレンダに基づいて解析するか、カルチャ指定のオプションがあるはずなので、それを駆使することも可能かと思われる。
しかし、そもそもどのカルチャで解析すべきかの判断・判定処理が事前に必要になる。
希なケースであるし、そこまでこだわる必要がなかったので、単純に DateTime.TryPase して、解析できなければ愚直にコンテンツを返すことで決着させた。