halorgium-actionpack 3.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. data/CHANGELOG +5179 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +409 -0
  4. data/lib/abstract_controller.rb +16 -0
  5. data/lib/abstract_controller/base.rb +158 -0
  6. data/lib/abstract_controller/callbacks.rb +113 -0
  7. data/lib/abstract_controller/exceptions.rb +12 -0
  8. data/lib/abstract_controller/helpers.rb +151 -0
  9. data/lib/abstract_controller/layouts.rb +250 -0
  10. data/lib/abstract_controller/localized_cache.rb +49 -0
  11. data/lib/abstract_controller/logger.rb +61 -0
  12. data/lib/abstract_controller/rendering_controller.rb +188 -0
  13. data/lib/action_controller.rb +72 -0
  14. data/lib/action_controller/base.rb +168 -0
  15. data/lib/action_controller/caching.rb +80 -0
  16. data/lib/action_controller/caching/actions.rb +163 -0
  17. data/lib/action_controller/caching/fragments.rb +116 -0
  18. data/lib/action_controller/caching/pages.rb +154 -0
  19. data/lib/action_controller/caching/sweeping.rb +97 -0
  20. data/lib/action_controller/deprecated.rb +4 -0
  21. data/lib/action_controller/deprecated/integration_test.rb +2 -0
  22. data/lib/action_controller/deprecated/performance_test.rb +1 -0
  23. data/lib/action_controller/dispatch/dispatcher.rb +57 -0
  24. data/lib/action_controller/metal.rb +129 -0
  25. data/lib/action_controller/metal/benchmarking.rb +73 -0
  26. data/lib/action_controller/metal/compatibility.rb +145 -0
  27. data/lib/action_controller/metal/conditional_get.rb +86 -0
  28. data/lib/action_controller/metal/configuration.rb +28 -0
  29. data/lib/action_controller/metal/cookies.rb +105 -0
  30. data/lib/action_controller/metal/exceptions.rb +55 -0
  31. data/lib/action_controller/metal/filter_parameter_logging.rb +77 -0
  32. data/lib/action_controller/metal/flash.rb +162 -0
  33. data/lib/action_controller/metal/head.rb +27 -0
  34. data/lib/action_controller/metal/helpers.rb +115 -0
  35. data/lib/action_controller/metal/hide_actions.rb +47 -0
  36. data/lib/action_controller/metal/http_authentication.rb +312 -0
  37. data/lib/action_controller/metal/layouts.rb +171 -0
  38. data/lib/action_controller/metal/mime_responds.rb +317 -0
  39. data/lib/action_controller/metal/rack_convenience.rb +27 -0
  40. data/lib/action_controller/metal/redirector.rb +22 -0
  41. data/lib/action_controller/metal/render_options.rb +103 -0
  42. data/lib/action_controller/metal/rendering_controller.rb +57 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +108 -0
  44. data/lib/action_controller/metal/rescuable.rb +13 -0
  45. data/lib/action_controller/metal/responder.rb +200 -0
  46. data/lib/action_controller/metal/session.rb +15 -0
  47. data/lib/action_controller/metal/session_management.rb +45 -0
  48. data/lib/action_controller/metal/streaming.rb +188 -0
  49. data/lib/action_controller/metal/testing.rb +39 -0
  50. data/lib/action_controller/metal/url_for.rb +41 -0
  51. data/lib/action_controller/metal/verification.rb +130 -0
  52. data/lib/action_controller/middleware.rb +38 -0
  53. data/lib/action_controller/notifications.rb +10 -0
  54. data/lib/action_controller/polymorphic_routes.rb +183 -0
  55. data/lib/action_controller/record_identifier.rb +91 -0
  56. data/lib/action_controller/testing/process.rb +111 -0
  57. data/lib/action_controller/testing/test_case.rb +345 -0
  58. data/lib/action_controller/translation.rb +13 -0
  59. data/lib/action_controller/url_rewriter.rb +204 -0
  60. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  61. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  62. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  63. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +176 -0
  64. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  65. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  66. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  67. data/lib/action_dispatch.rb +70 -0
  68. data/lib/action_dispatch/http/headers.rb +33 -0
  69. data/lib/action_dispatch/http/mime_type.rb +231 -0
  70. data/lib/action_dispatch/http/mime_types.rb +23 -0
  71. data/lib/action_dispatch/http/request.rb +539 -0
  72. data/lib/action_dispatch/http/response.rb +290 -0
  73. data/lib/action_dispatch/http/status_codes.rb +42 -0
  74. data/lib/action_dispatch/http/utils.rb +20 -0
  75. data/lib/action_dispatch/middleware/callbacks.rb +50 -0
  76. data/lib/action_dispatch/middleware/params_parser.rb +79 -0
  77. data/lib/action_dispatch/middleware/rescue.rb +26 -0
  78. data/lib/action_dispatch/middleware/session/abstract_store.rb +208 -0
  79. data/lib/action_dispatch/middleware/session/cookie_store.rb +235 -0
  80. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +47 -0
  81. data/lib/action_dispatch/middleware/show_exceptions.rb +143 -0
  82. data/lib/action_dispatch/middleware/stack.rb +116 -0
  83. data/lib/action_dispatch/middleware/static.rb +44 -0
  84. data/lib/action_dispatch/middleware/string_coercion.rb +29 -0
  85. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +24 -0
  86. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +26 -0
  87. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +10 -0
  88. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +29 -0
  89. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +2 -0
  90. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +10 -0
  91. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +21 -0
  92. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +2 -0
  93. data/lib/action_dispatch/routing.rb +381 -0
  94. data/lib/action_dispatch/routing/deprecated_mapper.rb +878 -0
  95. data/lib/action_dispatch/routing/mapper.rb +327 -0
  96. data/lib/action_dispatch/routing/route.rb +49 -0
  97. data/lib/action_dispatch/routing/route_set.rb +497 -0
  98. data/lib/action_dispatch/testing/assertions.rb +8 -0
  99. data/lib/action_dispatch/testing/assertions/dom.rb +35 -0
  100. data/lib/action_dispatch/testing/assertions/model.rb +19 -0
  101. data/lib/action_dispatch/testing/assertions/response.rb +145 -0
  102. data/lib/action_dispatch/testing/assertions/routing.rb +144 -0
  103. data/lib/action_dispatch/testing/assertions/selector.rb +639 -0
  104. data/lib/action_dispatch/testing/assertions/tag.rb +123 -0
  105. data/lib/action_dispatch/testing/integration.rb +504 -0
  106. data/lib/action_dispatch/testing/performance_test.rb +15 -0
  107. data/lib/action_dispatch/testing/test_request.rb +83 -0
  108. data/lib/action_dispatch/testing/test_response.rb +131 -0
  109. data/lib/action_pack.rb +24 -0
  110. data/lib/action_pack/version.rb +9 -0
  111. data/lib/action_view.rb +58 -0
  112. data/lib/action_view/base.rb +308 -0
  113. data/lib/action_view/context.rb +44 -0
  114. data/lib/action_view/erb/util.rb +48 -0
  115. data/lib/action_view/helpers.rb +62 -0
  116. data/lib/action_view/helpers/active_model_helper.rb +306 -0
  117. data/lib/action_view/helpers/ajax_helper.rb +68 -0
  118. data/lib/action_view/helpers/asset_tag_helper.rb +830 -0
  119. data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
  120. data/lib/action_view/helpers/cache_helper.rb +39 -0
  121. data/lib/action_view/helpers/capture_helper.rb +168 -0
  122. data/lib/action_view/helpers/date_helper.rb +988 -0
  123. data/lib/action_view/helpers/debug_helper.rb +38 -0
  124. data/lib/action_view/helpers/form_helper.rb +1102 -0
  125. data/lib/action_view/helpers/form_options_helper.rb +600 -0
  126. data/lib/action_view/helpers/form_tag_helper.rb +495 -0
  127. data/lib/action_view/helpers/javascript_helper.rb +208 -0
  128. data/lib/action_view/helpers/number_helper.rb +311 -0
  129. data/lib/action_view/helpers/prototype_helper.rb +1309 -0
  130. data/lib/action_view/helpers/raw_output_helper.rb +9 -0
  131. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  132. data/lib/action_view/helpers/record_tag_helper.rb +58 -0
  133. data/lib/action_view/helpers/sanitize_helper.rb +259 -0
  134. data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
  135. data/lib/action_view/helpers/tag_helper.rb +151 -0
  136. data/lib/action_view/helpers/text_helper.rb +594 -0
  137. data/lib/action_view/helpers/translation_helper.rb +39 -0
  138. data/lib/action_view/helpers/url_helper.rb +639 -0
  139. data/lib/action_view/locale/en.yml +117 -0
  140. data/lib/action_view/paths.rb +80 -0
  141. data/lib/action_view/render/partials.rb +342 -0
  142. data/lib/action_view/render/rendering.rb +134 -0
  143. data/lib/action_view/safe_buffer.rb +28 -0
  144. data/lib/action_view/template/error.rb +101 -0
  145. data/lib/action_view/template/handler.rb +36 -0
  146. data/lib/action_view/template/handlers.rb +52 -0
  147. data/lib/action_view/template/handlers/builder.rb +17 -0
  148. data/lib/action_view/template/handlers/erb.rb +53 -0
  149. data/lib/action_view/template/handlers/rjs.rb +18 -0
  150. data/lib/action_view/template/resolver.rb +165 -0
  151. data/lib/action_view/template/template.rb +131 -0
  152. data/lib/action_view/template/text.rb +38 -0
  153. data/lib/action_view/test_case.rb +163 -0
  154. metadata +236 -0
@@ -0,0 +1,26 @@
1
+ module ActionDispatch
2
+ class Rescue
3
+ def initialize(app, rescuers = {}, &block)
4
+ @app, @rescuers = app, {}
5
+ rescuers.each { |exception, rescuer| rescue_from(exception, rescuer) }
6
+ instance_eval(&block) if block_given?
7
+ end
8
+
9
+ def call(env)
10
+ @app.call(env)
11
+ rescue Exception => exception
12
+ if rescuer = @rescuers[exception.class.name]
13
+ env['action_dispatch.rescue.exception'] = exception
14
+ rescuer.call(env)
15
+ else
16
+ raise exception
17
+ end
18
+ end
19
+
20
+ protected
21
+ def rescue_from(exception, rescuer)
22
+ exception = exception.class.name if exception.is_a?(Exception)
23
+ @rescuers[exception.to_s] = rescuer
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,208 @@
1
+ require 'rack/utils'
2
+
3
+ module ActionDispatch
4
+ module Session
5
+ class SessionRestoreError < StandardError #:nodoc:
6
+ end
7
+
8
+ class AbstractStore
9
+ ENV_SESSION_KEY = 'rack.session'.freeze
10
+ ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze
11
+
12
+ HTTP_COOKIE = 'HTTP_COOKIE'.freeze
13
+ SET_COOKIE = 'Set-Cookie'.freeze
14
+
15
+ class SessionHash < Hash
16
+ def initialize(by, env)
17
+ super()
18
+ @by = by
19
+ @env = env
20
+ @loaded = false
21
+ end
22
+
23
+ def session_id
24
+ ActiveSupport::Deprecation.warn(
25
+ "ActionDispatch::Session::AbstractStore::SessionHash#session_id " +
26
+ "has been deprecated. Please use request.session_options[:id] instead.", caller)
27
+ @env[ENV_SESSION_OPTIONS_KEY][:id]
28
+ end
29
+
30
+ def [](key)
31
+ load! unless @loaded
32
+ super(key.to_s)
33
+ end
34
+
35
+ def []=(key, value)
36
+ load! unless @loaded
37
+ super(key.to_s, value)
38
+ end
39
+
40
+ def to_hash
41
+ h = {}.replace(self)
42
+ h.delete_if { |k,v| v.nil? }
43
+ h
44
+ end
45
+
46
+ def update(hash = nil)
47
+ if hash.nil?
48
+ ActiveSupport::Deprecation.warn('use replace instead', caller)
49
+ replace({})
50
+ else
51
+ load! unless @loaded
52
+ super(hash.stringify_keys)
53
+ end
54
+ end
55
+
56
+ def delete(key = nil)
57
+ if key.nil?
58
+ ActiveSupport::Deprecation.warn('use clear instead', caller)
59
+ clear
60
+ else
61
+ load! unless @loaded
62
+ super(key.to_s)
63
+ end
64
+ end
65
+
66
+ def data
67
+ ActiveSupport::Deprecation.warn(
68
+ "ActionDispatch::Session::AbstractStore::SessionHash#data " +
69
+ "has been deprecated. Please use #to_hash instead.", caller)
70
+ to_hash
71
+ end
72
+
73
+ def close
74
+ ActiveSupport::Deprecation.warn('sessions should no longer be closed', caller)
75
+ end
76
+
77
+ def inspect
78
+ load! unless @loaded
79
+ super
80
+ end
81
+
82
+ private
83
+ def loaded?
84
+ @loaded
85
+ end
86
+
87
+ def load!
88
+ stale_session_check! do
89
+ id, session = @by.send(:load_session, @env)
90
+ (@env[ENV_SESSION_OPTIONS_KEY] ||= {})[:id] = id
91
+ replace(session.stringify_keys)
92
+ @loaded = true
93
+ end
94
+ end
95
+
96
+ def stale_session_check!
97
+ yield
98
+ rescue ArgumentError => argument_error
99
+ if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
100
+ begin
101
+ # Note that the regexp does not allow $1 to end with a ':'
102
+ $1.constantize
103
+ rescue LoadError, NameError => const_error
104
+ raise ActionDispatch::SessionRestoreError, "Session contains objects whose class definition isn't available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: #{const_error.message} [#{const_error.class}])\n"
105
+ end
106
+
107
+ retry
108
+ else
109
+ raise
110
+ end
111
+ end
112
+ end
113
+
114
+ DEFAULT_OPTIONS = {
115
+ :key => '_session_id',
116
+ :path => '/',
117
+ :domain => nil,
118
+ :expire_after => nil,
119
+ :secure => false,
120
+ :httponly => true,
121
+ :cookie_only => true
122
+ }
123
+
124
+ def initialize(app, options = {})
125
+ # Process legacy CGI options
126
+ options = options.symbolize_keys
127
+ if options.has_key?(:session_path)
128
+ options[:path] = options.delete(:session_path)
129
+ end
130
+ if options.has_key?(:session_key)
131
+ options[:key] = options.delete(:session_key)
132
+ end
133
+ if options.has_key?(:session_http_only)
134
+ options[:httponly] = options.delete(:session_http_only)
135
+ end
136
+
137
+ @app = app
138
+ @default_options = DEFAULT_OPTIONS.merge(options)
139
+ @key = @default_options[:key]
140
+ @cookie_only = @default_options[:cookie_only]
141
+ end
142
+
143
+ def call(env)
144
+ session = SessionHash.new(self, env)
145
+
146
+ env[ENV_SESSION_KEY] = session
147
+ env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
148
+
149
+ response = @app.call(env)
150
+
151
+ session_data = env[ENV_SESSION_KEY]
152
+ options = env[ENV_SESSION_OPTIONS_KEY]
153
+
154
+ if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
155
+ session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
156
+
157
+ sid = options[:id] || generate_sid
158
+
159
+ unless set_session(env, sid, session_data.to_hash)
160
+ return response
161
+ end
162
+
163
+ cookie = Rack::Utils.escape(@key) + '=' + Rack::Utils.escape(sid)
164
+ cookie << "; domain=#{options[:domain]}" if options[:domain]
165
+ cookie << "; path=#{options[:path]}" if options[:path]
166
+ if options[:expire_after]
167
+ expiry = Time.now + options[:expire_after]
168
+ cookie << "; expires=#{expiry.httpdate}"
169
+ end
170
+ cookie << "; Secure" if options[:secure]
171
+ cookie << "; HttpOnly" if options[:httponly]
172
+
173
+ headers = response[1]
174
+ unless headers[SET_COOKIE].blank?
175
+ headers[SET_COOKIE] << "\n#{cookie}"
176
+ else
177
+ headers[SET_COOKIE] = cookie
178
+ end
179
+ end
180
+
181
+ response
182
+ end
183
+
184
+ private
185
+ def generate_sid
186
+ ActiveSupport::SecureRandom.hex(16)
187
+ end
188
+
189
+ def load_session(env)
190
+ request = Rack::Request.new(env)
191
+ sid = request.cookies[@key]
192
+ unless @cookie_only
193
+ sid ||= request.params[@key]
194
+ end
195
+ sid, session = get_session(env, sid)
196
+ [sid, session]
197
+ end
198
+
199
+ def get_session(env, sid)
200
+ raise '#get_session needs to be implemented.'
201
+ end
202
+
203
+ def set_session(env, sid, session_data)
204
+ raise '#set_session needs to be implemented.'
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,235 @@
1
+ require "active_support/core_ext/hash/keys"
2
+
3
+ module ActionDispatch
4
+ module Session
5
+ # This cookie-based session store is the Rails default. Sessions typically
6
+ # contain at most a user_id and flash message; both fit within the 4K cookie
7
+ # size limit. Cookie-based sessions are dramatically faster than the
8
+ # alternatives.
9
+ #
10
+ # If you have more than 4K of session data or don't want your data to be
11
+ # visible to the user, pick another session store.
12
+ #
13
+ # CookieOverflow is raised if you attempt to store more than 4K of data.
14
+ #
15
+ # A message digest is included with the cookie to ensure data integrity:
16
+ # a user cannot alter his +user_id+ without knowing the secret key
17
+ # included in the hash. New apps are generated with a pregenerated secret
18
+ # in config/environment.rb. Set your own for old apps you're upgrading.
19
+ #
20
+ # Session options:
21
+ #
22
+ # * <tt>:secret</tt>: An application-wide key string or block returning a
23
+ # string called per generated digest. The block is called with the
24
+ # CGI::Session instance as an argument. It's important that the secret
25
+ # is not vulnerable to a dictionary attack. Therefore, you should choose
26
+ # a secret consisting of random numbers and letters and more than 30
27
+ # characters. Examples:
28
+ #
29
+ # :secret => '449fe2e7daee471bffae2fd8dc02313d'
30
+ # :secret => Proc.new { User.current_user.secret_key }
31
+ #
32
+ # * <tt>:digest</tt>: The message digest algorithm used to verify session
33
+ # integrity defaults to 'SHA1' but may be any digest provided by OpenSSL,
34
+ # such as 'MD5', 'RIPEMD160', 'SHA256', etc.
35
+ #
36
+ # To generate a secret key for an existing application, run
37
+ # "rake secret" and set the key in config/environment.rb.
38
+ #
39
+ # Note that changing digest or secret invalidates all existing sessions!
40
+ class CookieStore
41
+ # Cookies can typically store 4096 bytes.
42
+ MAX = 4096
43
+ SECRET_MIN_LENGTH = 30 # characters
44
+
45
+ DEFAULT_OPTIONS = {
46
+ :key => '_session_id',
47
+ :domain => nil,
48
+ :path => "/",
49
+ :expire_after => nil,
50
+ :httponly => true
51
+ }.freeze
52
+
53
+ class OptionsHash < Hash
54
+ def initialize(by, env, default_options)
55
+ @session_data = env[CookieStore::ENV_SESSION_KEY]
56
+ default_options.each { |key, value| self[key] = value }
57
+ end
58
+
59
+ def [](key)
60
+ key == :id ? @session_data[:session_id] : super(key)
61
+ end
62
+ end
63
+
64
+ ENV_SESSION_KEY = "rack.session".freeze
65
+ ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze
66
+ HTTP_SET_COOKIE = "Set-Cookie".freeze
67
+
68
+ # Raised when storing more than 4K of session data.
69
+ class CookieOverflow < StandardError; end
70
+
71
+ def initialize(app, options = {})
72
+ # Process legacy CGI options
73
+ options = options.symbolize_keys
74
+ if options.has_key?(:session_path)
75
+ options[:path] = options.delete(:session_path)
76
+ end
77
+ if options.has_key?(:session_key)
78
+ options[:key] = options.delete(:session_key)
79
+ end
80
+ if options.has_key?(:session_http_only)
81
+ options[:httponly] = options.delete(:session_http_only)
82
+ end
83
+
84
+ @app = app
85
+
86
+ # The session_key option is required.
87
+ ensure_session_key(options[:key])
88
+ @key = options.delete(:key).freeze
89
+
90
+ # The secret option is required.
91
+ ensure_secret_secure(options[:secret])
92
+ @secret = options.delete(:secret).freeze
93
+
94
+ @digest = options.delete(:digest) || 'SHA1'
95
+ @verifier = verifier_for(@secret, @digest)
96
+
97
+ @default_options = DEFAULT_OPTIONS.merge(options).freeze
98
+
99
+ freeze
100
+ end
101
+
102
+ def call(env)
103
+ env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
104
+ env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
105
+
106
+ status, headers, body = @app.call(env)
107
+
108
+ session_data = env[ENV_SESSION_KEY]
109
+ options = env[ENV_SESSION_OPTIONS_KEY]
110
+
111
+ if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
112
+ session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
113
+ session_data = marshal(session_data.to_hash)
114
+
115
+ raise CookieOverflow if session_data.size > MAX
116
+
117
+ cookie = Hash.new
118
+ cookie[:value] = session_data
119
+ unless options[:expire_after].nil?
120
+ cookie[:expires] = Time.now + options[:expire_after]
121
+ end
122
+
123
+ cookie = build_cookie(@key, cookie.merge(options))
124
+ unless headers[HTTP_SET_COOKIE].blank?
125
+ headers[HTTP_SET_COOKIE] << "\n#{cookie}"
126
+ else
127
+ headers[HTTP_SET_COOKIE] = cookie
128
+ end
129
+ end
130
+
131
+ [status, headers, body]
132
+ end
133
+
134
+ private
135
+ # Should be in Rack::Utils soon
136
+ def build_cookie(key, value)
137
+ case value
138
+ when Hash
139
+ domain = "; domain=" + value[:domain] if value[:domain]
140
+ path = "; path=" + value[:path] if value[:path]
141
+ # According to RFC 2109, we need dashes here.
142
+ # N.B.: cgi.rb uses spaces...
143
+ expires = "; expires=" + value[:expires].clone.gmtime.
144
+ strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
145
+ secure = "; secure" if value[:secure]
146
+ httponly = "; HttpOnly" if value[:httponly]
147
+ value = value[:value]
148
+ end
149
+ value = [value] unless Array === value
150
+ cookie = Rack::Utils.escape(key) + "=" +
151
+ value.map { |v| Rack::Utils.escape(v) }.join("&") +
152
+ "#{domain}#{path}#{expires}#{secure}#{httponly}"
153
+ end
154
+
155
+ def load_session(env)
156
+ request = Rack::Request.new(env)
157
+ session_data = request.cookies[@key]
158
+ data = unmarshal(session_data) || persistent_session_id!({})
159
+ data.stringify_keys!
160
+ [data["session_id"], data]
161
+ end
162
+
163
+ # Marshal a session hash into safe cookie data. Include an integrity hash.
164
+ def marshal(session)
165
+ @verifier.generate(persistent_session_id!(session))
166
+ end
167
+
168
+ # Unmarshal cookie data to a hash and verify its integrity.
169
+ def unmarshal(cookie)
170
+ persistent_session_id!(@verifier.verify(cookie)) if cookie
171
+ rescue ActiveSupport::MessageVerifier::InvalidSignature
172
+ nil
173
+ end
174
+
175
+ def ensure_session_key(key)
176
+ if key.blank?
177
+ raise ArgumentError, 'A key is required to write a ' +
178
+ 'cookie containing the session data. Use ' +
179
+ 'config.action_controller.session = { :key => ' +
180
+ '"_myapp_session", :secret => "some secret phrase" } in ' +
181
+ 'config/environment.rb'
182
+ end
183
+ end
184
+
185
+ # To prevent users from using something insecure like "Password" we make sure that the
186
+ # secret they've provided is at least 30 characters in length.
187
+ def ensure_secret_secure(secret)
188
+ # There's no way we can do this check if they've provided a proc for the
189
+ # secret.
190
+ return true if secret.is_a?(Proc)
191
+
192
+ if secret.blank?
193
+ raise ArgumentError, "A secret is required to generate an " +
194
+ "integrity hash for cookie session data. Use " +
195
+ "config.action_controller.session = { :key => " +
196
+ "\"_myapp_session\", :secret => \"some secret phrase of at " +
197
+ "least #{SECRET_MIN_LENGTH} characters\" } " +
198
+ "in config/environment.rb"
199
+ end
200
+
201
+ if secret.length < SECRET_MIN_LENGTH
202
+ raise ArgumentError, "Secret should be something secure, " +
203
+ "like \"#{ActiveSupport::SecureRandom.hex(16)}\". The value you " +
204
+ "provided, \"#{secret}\", is shorter than the minimum length " +
205
+ "of #{SECRET_MIN_LENGTH} characters"
206
+ end
207
+ end
208
+
209
+ def verifier_for(secret, digest)
210
+ key = secret.respond_to?(:call) ? secret.call : secret
211
+ ActiveSupport::MessageVerifier.new(key, digest)
212
+ end
213
+
214
+ def generate_sid
215
+ ActiveSupport::SecureRandom.hex(16)
216
+ end
217
+
218
+ def persistent_session_id!(data)
219
+ (data ||= {}).merge!(inject_persistent_session_id(data))
220
+ end
221
+
222
+ def inject_persistent_session_id(data)
223
+ requires_session_id?(data) ? { "session_id" => generate_sid } : {}
224
+ end
225
+
226
+ def requires_session_id?(data)
227
+ if data
228
+ data.respond_to?(:key?) && !data.key?("session_id")
229
+ else
230
+ true
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end