RailsとCookieではまったこと

( Rails )

今回Railsで起きた問題、ちと自分の中で迷ったの纏めておく。

PHPで運用していたものをRuby(Rails)にのせ変えようとしたときに置きました。
以前、前の仕様でCookieでカンマ区切りにして保存していた情報があったのですが
それを気にしないでRailsを導入していたら初期表示でサーバエラーになるという
問題が発生しました。

保存していたもの

document.cookie = "HOGE=1,,1,1"

どうもRack側で発生していることに気づきましてCookieの文字列を解析している箇所で「;」「,」の
二つでハッシュ化していることが原因だとわかりました。

      # According to RFC 2109:
      #   If multiple cookies satisfy the criteria above, they are ordered in
      #   the Cookie header such that those with more specific Path attributes
      #   precede those with less specific.  Ordering with respect to other
      #   attributes (e.g., Domain) is unspecified.
      Utils.parse_query(string, ';,').each { |k,v| hash[k] = Array === v ? v.first : v }
      @env["rack.request.cookie_string"] = string
      hash

Rackが悪いのでは?と思っていてけどRFCまわりをよくよく調査してみるとNAME,VALUEにセミコロン、コンマ、空白文字を
除いた文字列を指定すべきで、いれるときはエンコードすべき。あと、サーバは将来の互換性のためにカンマも受け入れるべきです。
てきなことが記述されていたので間違っていないことは確認しました。

とはいっても、サーバエラーにしてクッキー削除してから閲覧してねという訳にもいかないので一時凌ぎとして

コロンで解析しないようにしました。

修正したこと

# environment.rb

module Rack
  class Request
    def cookies
      hash   = @env["rack.request.cookie_hash"] ||= {}
      string = @env["HTTP_COOKIE"]

      return hash if string == @env["rack.request.cookie_string"]
      hash.clear

      Utils.parse_query(string, ';').each { |k,v| hash[k] = Array === v ? v.first : v}

      @env["rack.request.cookie_string"] = string

      hash
    rescue => error
      error.message.replace "cannot parse Cookie header: #{error.message}"
      raise
    end
  end
end

Reference

  • http://www.ietf.org/rfc/rfc2109.txt