Jpmobileのtrans_sid(2)

Rails2.2上では


dispatch_cgiでCGIオブジェクトをつくるときに


actionpack/lib/action_controller/dispatcher.rb

    def dispatch_cgi(cgi, session_options)
      if cgi ||= self.class.failsafe_response(@output, '400 Bad Request') { CGI.new }
        @request = CgiRequest.new(cgi, session_options)
        @response = CgiResponse.new(cgi)
        dispatch
      end
    rescue Exception => exception
      failsafe_rescue exception
    end


CGIのinitializeで呼ばれるCGI::QueryExtensionのinitialize_queryを上書きして
CGIオブジェクトのインスタンス変数@paramsを{}にしてしまう


actionpack/lib/action_controller/cgi_ext/query_extension.rb

require 'cgi'

class CGI #:nodoc:
  module QueryExtension
    # Remove the old initialize_query method before redefining it.
    remove_method :initialize_query

    # Neuter CGI parameter parsing.
    def initialize_query
      # Fix some strange request environments.
      env_table['REQUEST_METHOD'] ||= 'GET'

      # POST assumes missing Content-Type is application/x-www-form-urlencoded.
      if env_table['CONTENT_TYPE'].blank? && env_table['REQUEST_METHOD'] == 'POST'
        env_table['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
      end

      @cookies = CGI::Cookie::parse(env_table['HTTP_COOKIE'] || env_table['COOKIE'])
      @params = {}
    end
  end
end


このため、パラメータにセッションキーがあってもCgi::Sessionの初期化時にsession_idにするとしているところに
ひっかからない。

cgi/session.rb

    def initialize(request, option={})
      @new_session = false
      session_key = option['session_key'] || '_session_id'
      session_id = option['session_id']
      unless session_id
        if option['new_session']
          session_id = create_new_id
        end
      end
      unless session_id
        if request.key?(session_key) #ここで書き込んだパラメータがsession_idになる
          session_id = request[session_key]
          session_id = session_id.read if session_id.respond_to?(:read)
        end
        unless session_id
          session_id, = request.cookies[session_key]
        end
        unless session_id
          unless option.fetch('new_session', true)
            raise ArgumentError, "session_key `%s' should be supplied"%session_key
          end
          session_id = create_new_id
        end
      end
      @session_id = session_id

Jpmobileのtrans_sidでは、Cgi::Sessionの初期化の直前にCGIパラメータにセッションキーと値を書き込んで、
クエリストリング・POSTデータからsession_idが作られるようにしているわけですか・・

jpmobile/lib/jpmobile/trans_sid.rb

  class << self
    def trans_sid(mode=:mobile)
      include Jpmobile::TransSid
      self.trans_sid_mode = mode
      unless mode == :none
        # CSRF対策への対策
        session :cookie_only => false
        # url/postからsession_keyを取得できるようhookを追加する
        unless ::CGI::Session.private_method_defined?(:initialize_without_session_key_fixation)
          ::CGI::Session.class_eval do
            alias_method :initialize_without_session_key_fixation, :initialize
            def initialize(cgi, options = {})
              key = options['session_key']
              if cgi.cookies[key].empty?
                session_id = (CGI.parse(cgi.env_table['RAW_POST_DATA'])[key] rescue nil) ||
                  (CGI.parse(ENV['QUERY_STRING'] || cgi.query_string)[key] rescue nil)
                cgi.params[key] = session_id unless session_id.blank?  #ここでパラメータに書き込み
              end
              initialize_without_session_key_fixation(cgi, options)
            end
          end
        end
      end
    end