actionpack 2.2.3 → 2.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +433 -375
- data/MIT-LICENSE +1 -1
- data/README +21 -75
- data/Rakefile +1 -1
- data/lib/action_controller.rb +80 -43
- data/lib/action_controller/assertions/model_assertions.rb +1 -0
- data/lib/action_controller/assertions/response_assertions.rb +43 -16
- data/lib/action_controller/assertions/routing_assertions.rb +1 -1
- data/lib/action_controller/assertions/selector_assertions.rb +17 -12
- data/lib/action_controller/assertions/tag_assertions.rb +1 -4
- data/lib/action_controller/base.rb +153 -82
- data/lib/action_controller/benchmarking.rb +9 -9
- data/lib/action_controller/caching.rb +9 -11
- data/lib/action_controller/caching/actions.rb +11 -18
- data/lib/action_controller/caching/fragments.rb +28 -20
- data/lib/action_controller/caching/pages.rb +13 -15
- data/lib/action_controller/caching/sweeping.rb +2 -2
- data/lib/action_controller/cgi_ext.rb +0 -1
- data/lib/action_controller/cgi_ext/cookie.rb +2 -0
- data/lib/action_controller/cgi_process.rb +54 -162
- data/lib/action_controller/cookies.rb +13 -25
- data/lib/action_controller/dispatcher.rb +43 -122
- data/lib/action_controller/failsafe.rb +52 -0
- data/lib/action_controller/flash.rb +38 -47
- data/lib/action_controller/helpers.rb +13 -9
- data/lib/action_controller/http_authentication.rb +203 -23
- data/lib/action_controller/integration.rb +126 -70
- data/lib/action_controller/layout.rb +36 -39
- data/lib/action_controller/middleware_stack.rb +119 -0
- data/lib/action_controller/middlewares.rb +13 -0
- data/lib/action_controller/mime_responds.rb +19 -4
- data/lib/action_controller/mime_type.rb +8 -0
- data/lib/action_controller/params_parser.rb +71 -0
- data/lib/action_controller/performance_test.rb +0 -1
- data/lib/action_controller/polymorphic_routes.rb +36 -30
- data/lib/action_controller/reloader.rb +14 -0
- data/lib/action_controller/request.rb +107 -499
- data/lib/action_controller/request_forgery_protection.rb +7 -39
- data/lib/action_controller/rescue.rb +55 -35
- data/lib/action_controller/resources.rb +34 -31
- data/lib/action_controller/response.rb +99 -57
- data/lib/action_controller/rewindable_input.rb +28 -0
- data/lib/action_controller/routing.rb +7 -7
- data/lib/action_controller/routing/builder.rb +4 -1
- data/lib/action_controller/routing/optimisations.rb +1 -1
- data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
- data/lib/action_controller/routing/route.rb +15 -5
- data/lib/action_controller/routing/route_set.rb +82 -35
- data/lib/action_controller/routing/segments.rb +35 -0
- data/lib/action_controller/session/abstract_store.rb +181 -0
- data/lib/action_controller/session/cookie_store.rb +197 -175
- data/lib/action_controller/session/mem_cache_store.rb +36 -83
- data/lib/action_controller/session_management.rb +26 -134
- data/lib/action_controller/streaming.rb +24 -7
- data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
- data/lib/action_controller/templates/rescues/template_error.erb +2 -2
- data/lib/action_controller/test_case.rb +87 -30
- data/lib/action_controller/test_process.rb +145 -104
- data/lib/action_controller/uploaded_file.rb +44 -0
- data/lib/action_controller/url_rewriter.rb +3 -6
- data/lib/action_controller/vendor/html-scanner.rb +16 -0
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
- data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
- data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
- data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
- data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
- data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
- data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
- data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
- data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
- data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
- data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
- data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
- data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
- data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
- data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
- data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
- data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
- data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
- data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
- data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
- data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
- data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
- data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
- data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
- data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
- data/lib/action_controller/verification.rb +1 -1
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +22 -17
- data/lib/action_view/base.rb +53 -79
- data/lib/action_view/erb/util.rb +38 -0
- data/lib/action_view/helpers.rb +24 -5
- data/lib/action_view/helpers/active_record_helper.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
- data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
- data/lib/action_view/helpers/benchmark_helper.rb +26 -5
- data/lib/action_view/helpers/date_helper.rb +82 -7
- data/lib/action_view/helpers/form_helper.rb +295 -64
- data/lib/action_view/helpers/form_options_helper.rb +160 -18
- data/lib/action_view/helpers/form_tag_helper.rb +2 -2
- data/lib/action_view/helpers/number_helper.rb +31 -18
- data/lib/action_view/helpers/prototype_helper.rb +2 -12
- data/lib/action_view/helpers/sanitize_helper.rb +0 -10
- data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
- data/lib/action_view/helpers/tag_helper.rb +3 -4
- data/lib/action_view/helpers/text_helper.rb +99 -122
- data/lib/action_view/helpers/translation_helper.rb +19 -1
- data/lib/action_view/helpers/url_helper.rb +25 -2
- data/lib/action_view/inline_template.rb +1 -1
- data/lib/action_view/locale/en.yml +19 -1
- data/lib/action_view/partials.rb +46 -9
- data/lib/action_view/paths.rb +28 -84
- data/lib/action_view/reloadable_template.rb +117 -0
- data/lib/action_view/renderable.rb +28 -35
- data/lib/action_view/renderable_partial.rb +3 -4
- data/lib/action_view/template.rb +172 -31
- data/lib/action_view/template_error.rb +8 -9
- data/lib/action_view/template_handler.rb +1 -1
- data/lib/action_view/template_handlers.rb +9 -6
- data/lib/action_view/template_handlers/erb.rb +2 -39
- data/lib/action_view/template_handlers/rjs.rb +1 -0
- data/lib/action_view/test_case.rb +27 -1
- data/test/abstract_unit.rb +23 -17
- data/test/active_record_unit.rb +5 -4
- data/test/activerecord/active_record_store_test.rb +139 -106
- data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
- data/test/controller/action_pack_assertions_test.rb +25 -23
- data/test/controller/addresses_render_test.rb +3 -6
- data/test/controller/assert_select_test.rb +83 -70
- data/test/controller/base_test.rb +11 -13
- data/test/controller/benchmark_test.rb +3 -3
- data/test/controller/caching_test.rb +34 -24
- data/test/controller/capture_test.rb +3 -6
- data/test/controller/content_type_test.rb +3 -6
- data/test/controller/cookie_test.rb +31 -66
- data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
- data/test/controller/dispatcher_test.rb +23 -28
- data/test/controller/fake_models.rb +8 -0
- data/test/controller/filters_test.rb +6 -2
- data/test/controller/flash_test.rb +2 -6
- data/test/controller/helper_test.rb +15 -1
- data/test/controller/html-scanner/document_test.rb +1 -1
- data/test/controller/html-scanner/sanitizer_test.rb +1 -1
- data/test/controller/http_basic_authentication_test.rb +88 -0
- data/test/controller/http_digest_authentication_test.rb +178 -0
- data/test/controller/integration_test.rb +56 -52
- data/test/controller/layout_test.rb +46 -44
- data/test/controller/middleware_stack_test.rb +90 -0
- data/test/controller/mime_responds_test.rb +7 -11
- data/test/controller/mime_type_test.rb +9 -0
- data/test/controller/polymorphic_routes_test.rb +235 -151
- data/test/controller/rack_test.rb +52 -81
- data/test/controller/redirect_test.rb +6 -14
- data/test/controller/render_test.rb +273 -60
- data/test/controller/request/json_params_parsing_test.rb +45 -0
- data/test/controller/request/multipart_params_parsing_test.rb +223 -0
- data/test/controller/request/query_string_parsing_test.rb +120 -0
- data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
- data/test/controller/request/xml_params_parsing_test.rb +88 -0
- data/test/controller/request_forgery_protection_test.rb +17 -98
- data/test/controller/request_test.rb +45 -530
- data/test/controller/rescue_test.rb +45 -22
- data/test/controller/resources_test.rb +112 -37
- data/test/controller/routing_test.rb +1442 -1384
- data/test/controller/selector_test.rb +3 -3
- data/test/controller/send_file_test.rb +30 -3
- data/test/controller/session/cookie_store_test.rb +169 -240
- data/test/controller/session/mem_cache_store_test.rb +94 -148
- data/test/controller/session/test_session_test.rb +58 -0
- data/test/controller/test_test.rb +32 -13
- data/test/controller/url_rewriter_test.rb +54 -4
- data/test/controller/verification_test.rb +1 -1
- data/test/controller/view_paths_test.rb +15 -15
- data/test/controller/webservice_test.rb +178 -147
- data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
- data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
- data/test/fixtures/layouts/default_html.html.erb +1 -0
- data/test/fixtures/layouts/xhr.html.erb +2 -0
- data/test/fixtures/multipart/empty +10 -0
- data/test/fixtures/multipart/hello.txt +1 -0
- data/test/fixtures/multipart/none +9 -0
- data/test/fixtures/public/500.da.html +1 -0
- data/test/fixtures/quiz/questions/_question.html.erb +1 -0
- data/test/fixtures/replies.yml +1 -1
- data/test/fixtures/test/_one.html.erb +1 -0
- data/test/fixtures/test/_two.html.erb +1 -0
- data/test/fixtures/test/dont_pick_me +1 -0
- data/test/fixtures/test/hello.builder +1 -1
- data/test/fixtures/test/hello_world.da.html.erb +1 -0
- data/test/fixtures/test/hello_world.erb~ +1 -0
- data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
- data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
- data/test/fixtures/test/malformed/malformed.erb~ +1 -0
- data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
- data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
- data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
- data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
- data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
- data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
- data/test/fixtures/test/utf8.html.erb +2 -0
- data/test/template/active_record_helper_i18n_test.rb +31 -33
- data/test/template/active_record_helper_test.rb +34 -0
- data/test/template/asset_tag_helper_test.rb +52 -14
- data/test/template/atom_feed_helper_test.rb +3 -5
- data/test/template/benchmark_helper_test.rb +50 -24
- data/test/template/compiled_templates_test.rb +177 -33
- data/test/template/date_helper_i18n_test.rb +88 -81
- data/test/template/date_helper_test.rb +427 -43
- data/test/template/form_helper_test.rb +243 -44
- data/test/template/form_options_helper_test.rb +631 -565
- data/test/template/form_tag_helper_test.rb +9 -2
- data/test/template/javascript_helper_test.rb +0 -5
- data/test/template/number_helper_i18n_test.rb +60 -48
- data/test/template/number_helper_test.rb +1 -0
- data/test/template/render_test.rb +117 -35
- data/test/template/test_test.rb +4 -6
- data/test/template/text_helper_test.rb +129 -50
- data/test/template/translation_helper_test.rb +23 -19
- data/test/template/url_helper_test.rb +35 -2
- data/test/view/test_case_test.rb +8 -0
- metadata +197 -23
- data/lib/action_controller/assertions.rb +0 -69
- data/lib/action_controller/caching/sql_cache.rb +0 -18
- data/lib/action_controller/cgi_ext/session.rb +0 -53
- data/lib/action_controller/components.rb +0 -169
- data/lib/action_controller/rack_process.rb +0 -297
- data/lib/action_controller/request_profiler.rb +0 -169
- data/lib/action_controller/session/active_record_store.rb +0 -340
- data/lib/action_controller/session/drb_server.rb +0 -32
- data/lib/action_controller/session/drb_store.rb +0 -35
- data/test/controller/cgi_test.rb +0 -269
- data/test/controller/components_test.rb +0 -156
- data/test/controller/http_authentication_test.rb +0 -54
- data/test/controller/integration_upload_test.rb +0 -43
- data/test/controller/session_fixation_test.rb +0 -89
- data/test/controller/session_management_test.rb +0 -178
- data/test/fixtures/test/hello_world.js +0 -1
@@ -1,199 +1,221 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
1
|
+
module ActionController
|
2
|
+
module Session
|
3
|
+
# This cookie-based session store is the Rails default. Sessions typically
|
4
|
+
# contain at most a user_id and flash message; both fit within the 4K cookie
|
5
|
+
# size limit. Cookie-based sessions are dramatically faster than the
|
6
|
+
# alternatives.
|
7
|
+
#
|
8
|
+
# If you have more than 4K of session data or don't want your data to be
|
9
|
+
# visible to the user, pick another session store.
|
10
|
+
#
|
11
|
+
# CookieOverflow is raised if you attempt to store more than 4K of data.
|
12
|
+
#
|
13
|
+
# A message digest is included with the cookie to ensure data integrity:
|
14
|
+
# a user cannot alter his +user_id+ without knowing the secret key
|
15
|
+
# included in the hash. New apps are generated with a pregenerated secret
|
16
|
+
# in config/environment.rb. Set your own for old apps you're upgrading.
|
17
|
+
#
|
18
|
+
# Session options:
|
19
|
+
#
|
20
|
+
# * <tt>:secret</tt>: An application-wide key string or block returning a
|
21
|
+
# string called per generated digest. The block is called with the
|
22
|
+
# CGI::Session instance as an argument. It's important that the secret
|
23
|
+
# is not vulnerable to a dictionary attack. Therefore, you should choose
|
24
|
+
# a secret consisting of random numbers and letters and more than 30
|
25
|
+
# characters. Examples:
|
26
|
+
#
|
27
|
+
# :secret => '449fe2e7daee471bffae2fd8dc02313d'
|
28
|
+
# :secret => Proc.new { User.current_user.secret_key }
|
29
|
+
#
|
30
|
+
# * <tt>:digest</tt>: The message digest algorithm used to verify session
|
31
|
+
# integrity defaults to 'SHA1' but may be any digest provided by OpenSSL,
|
32
|
+
# such as 'MD5', 'RIPEMD160', 'SHA256', etc.
|
33
|
+
#
|
34
|
+
# To generate a secret key for an existing application, run
|
35
|
+
# "rake secret" and set the key in config/environment.rb.
|
36
|
+
#
|
37
|
+
# Note that changing digest or secret invalidates all existing sessions!
|
38
|
+
class CookieStore
|
39
|
+
# Cookies can typically store 4096 bytes.
|
40
|
+
MAX = 4096
|
41
|
+
SECRET_MIN_LENGTH = 30 # characters
|
42
|
+
|
43
|
+
DEFAULT_OPTIONS = {
|
44
|
+
:key => '_session_id',
|
45
|
+
:domain => nil,
|
46
|
+
:path => "/",
|
47
|
+
:expire_after => nil,
|
48
|
+
:httponly => true
|
49
|
+
}.freeze
|
50
|
+
|
51
|
+
ENV_SESSION_KEY = "rack.session".freeze
|
52
|
+
ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze
|
53
|
+
HTTP_SET_COOKIE = "Set-Cookie".freeze
|
54
|
+
|
55
|
+
# Raised when storing more than 4K of session data.
|
56
|
+
class CookieOverflow < StandardError; end
|
57
|
+
|
58
|
+
def initialize(app, options = {})
|
59
|
+
# Process legacy CGI options
|
60
|
+
options = options.symbolize_keys
|
61
|
+
if options.has_key?(:session_path)
|
62
|
+
options[:path] = options.delete(:session_path)
|
63
|
+
end
|
64
|
+
if options.has_key?(:session_key)
|
65
|
+
options[:key] = options.delete(:session_key)
|
66
|
+
end
|
67
|
+
if options.has_key?(:session_http_only)
|
68
|
+
options[:httponly] = options.delete(:session_http_only)
|
69
|
+
end
|
57
70
|
|
58
|
-
|
59
|
-
ensure_secret_secure(options['secret'])
|
60
|
-
|
61
|
-
# Keep the session and its secret on hand so we can read and write cookies.
|
62
|
-
@session, @secret = session, options['secret']
|
63
|
-
|
64
|
-
# Message digest defaults to SHA1.
|
65
|
-
@digest = options['digest'] || 'SHA1'
|
66
|
-
|
67
|
-
# Default cookie options derived from session settings.
|
68
|
-
@cookie_options = {
|
69
|
-
'name' => options['session_key'],
|
70
|
-
'path' => options['session_path'],
|
71
|
-
'domain' => options['session_domain'],
|
72
|
-
'expires' => options['session_expires'],
|
73
|
-
'secure' => options['session_secure'],
|
74
|
-
'http_only' => options['session_http_only']
|
75
|
-
}
|
76
|
-
|
77
|
-
# Set no_hidden and no_cookies since the session id is unused and we
|
78
|
-
# set our own data cookie.
|
79
|
-
options['no_hidden'] = true
|
80
|
-
options['no_cookies'] = true
|
81
|
-
end
|
71
|
+
@app = app
|
82
72
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
# There's no way we can do this check if they've provided a proc for the
|
87
|
-
# secret.
|
88
|
-
return true if secret.is_a?(Proc)
|
73
|
+
# The session_key option is required.
|
74
|
+
ensure_session_key(options[:key])
|
75
|
+
@key = options.delete(:key).freeze
|
89
76
|
|
90
|
-
|
91
|
-
|
92
|
-
|
77
|
+
# The secret option is required.
|
78
|
+
ensure_secret_secure(options[:secret])
|
79
|
+
@secret = options.delete(:secret).freeze
|
93
80
|
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
end
|
81
|
+
@digest = options.delete(:digest) || 'SHA1'
|
82
|
+
@verifier = verifier_for(@secret, @digest)
|
98
83
|
|
99
|
-
|
100
|
-
def restore
|
101
|
-
@original = read_cookie
|
102
|
-
@data = unmarshal(@original) || {}
|
103
|
-
end
|
84
|
+
@default_options = DEFAULT_OPTIONS.merge(options).freeze
|
104
85
|
|
105
|
-
|
106
|
-
|
86
|
+
freeze
|
87
|
+
end
|
107
88
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
updated = marshal(@data)
|
112
|
-
raise CookieOverflow if updated.size > MAX
|
113
|
-
write_cookie('value' => updated) unless updated == @original
|
114
|
-
end
|
115
|
-
end
|
89
|
+
def call(env)
|
90
|
+
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
|
91
|
+
env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
|
116
92
|
|
117
|
-
|
118
|
-
def delete
|
119
|
-
@data = nil
|
120
|
-
clear_old_cookie_value
|
121
|
-
write_cookie('value' => nil, 'expires' => 1.year.ago)
|
122
|
-
end
|
93
|
+
status, headers, body = @app.call(env)
|
123
94
|
|
124
|
-
|
125
|
-
|
126
|
-
key = @secret.respond_to?(:call) ? @secret.call(@session) : @secret
|
127
|
-
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(@digest), key, data)
|
128
|
-
end
|
95
|
+
session_data = env[ENV_SESSION_KEY]
|
96
|
+
options = env[ENV_SESSION_OPTIONS_KEY]
|
129
97
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
data = ActiveSupport::Base64.encode64s(Marshal.dump(session))
|
134
|
-
"#{data}--#{generate_digest(data)}"
|
135
|
-
end
|
98
|
+
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
|
99
|
+
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
|
100
|
+
session_data = marshal(session_data.to_hash)
|
136
101
|
|
137
|
-
|
138
|
-
def unmarshal(cookie)
|
139
|
-
if cookie
|
140
|
-
data, digest = cookie.split('--')
|
102
|
+
raise CookieOverflow if session_data.size > MAX
|
141
103
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
104
|
+
cookie = Hash.new
|
105
|
+
cookie[:value] = session_data
|
106
|
+
unless options[:expire_after].nil?
|
107
|
+
cookie[:expires] = Time.now + options[:expire_after]
|
108
|
+
end
|
109
|
+
|
110
|
+
cookie = build_cookie(@key, cookie.merge(options))
|
111
|
+
unless headers[HTTP_SET_COOKIE].blank?
|
112
|
+
headers[HTTP_SET_COOKIE] << "\n#{cookie}"
|
113
|
+
else
|
114
|
+
headers[HTTP_SET_COOKIE] = cookie
|
115
|
+
end
|
146
116
|
end
|
147
117
|
|
148
|
-
|
118
|
+
[status, headers, body]
|
149
119
|
end
|
150
|
-
end
|
151
120
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
121
|
+
private
|
122
|
+
# Should be in Rack::Utils soon
|
123
|
+
def build_cookie(key, value)
|
124
|
+
case value
|
125
|
+
when Hash
|
126
|
+
domain = "; domain=" + value[:domain] if value[:domain]
|
127
|
+
path = "; path=" + value[:path] if value[:path]
|
128
|
+
# According to RFC 2109, we need dashes here.
|
129
|
+
# N.B.: cgi.rb uses spaces...
|
130
|
+
expires = "; expires=" + value[:expires].clone.gmtime.
|
131
|
+
strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
|
132
|
+
secure = "; secure" if value[:secure]
|
133
|
+
httponly = "; HttpOnly" if value[:httponly]
|
134
|
+
value = value[:value]
|
135
|
+
end
|
136
|
+
value = [value] unless Array === value
|
137
|
+
cookie = Rack::Utils.escape(key) + "=" +
|
138
|
+
value.map { |v| Rack::Utils.escape(v) }.join("&") +
|
139
|
+
"#{domain}#{path}#{expires}#{secure}#{httponly}"
|
140
|
+
end
|
156
141
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
142
|
+
def load_session(env)
|
143
|
+
request = Rack::Request.new(env)
|
144
|
+
session_data = request.cookies[@key]
|
145
|
+
data = unmarshal(session_data) || persistent_session_id!({})
|
146
|
+
[data[:session_id], data]
|
147
|
+
end
|
162
148
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
149
|
+
# Marshal a session hash into safe cookie data. Include an integrity hash.
|
150
|
+
def marshal(session)
|
151
|
+
@verifier.generate(persistent_session_id!(session))
|
152
|
+
end
|
153
|
+
|
154
|
+
# Unmarshal cookie data to a hash and verify its integrity.
|
155
|
+
def unmarshal(cookie)
|
156
|
+
persistent_session_id!(@verifier.verify(cookie)) if cookie
|
157
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
158
|
+
nil
|
159
|
+
end
|
160
|
+
|
161
|
+
def ensure_session_key(key)
|
162
|
+
if key.blank?
|
163
|
+
raise ArgumentError, 'A key is required to write a ' +
|
164
|
+
'cookie containing the session data. Use ' +
|
165
|
+
'config.action_controller.session = { :key => ' +
|
166
|
+
'"_myapp_session", :secret => "some secret phrase" } in ' +
|
167
|
+
'config/environment.rb'
|
178
168
|
end
|
179
|
-
result == 0
|
180
|
-
else
|
181
|
-
false
|
182
169
|
end
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
170
|
+
|
171
|
+
# To prevent users from using something insecure like "Password" we make sure that the
|
172
|
+
# secret they've provided is at least 30 characters in length.
|
173
|
+
def ensure_secret_secure(secret)
|
174
|
+
# There's no way we can do this check if they've provided a proc for the
|
175
|
+
# secret.
|
176
|
+
return true if secret.is_a?(Proc)
|
177
|
+
|
178
|
+
if secret.blank?
|
179
|
+
raise ArgumentError, "A secret is required to generate an " +
|
180
|
+
"integrity hash for cookie session data. Use " +
|
181
|
+
"config.action_controller.session = { :key => " +
|
182
|
+
"\"_myapp_session\", :secret => \"some secret phrase of at " +
|
183
|
+
"least #{SECRET_MIN_LENGTH} characters\" } " +
|
184
|
+
"in config/environment.rb"
|
185
|
+
end
|
186
|
+
|
187
|
+
if secret.length < SECRET_MIN_LENGTH
|
188
|
+
raise ArgumentError, "Secret should be something secure, " +
|
189
|
+
"like \"#{ActiveSupport::SecureRandom.hex(16)}\". The value you " +
|
190
|
+
"provided, \"#{secret}\", is shorter than the minimum length " +
|
191
|
+
"of #{SECRET_MIN_LENGTH} characters"
|
191
192
|
end
|
192
|
-
result == 0
|
193
|
-
else
|
194
|
-
false
|
195
193
|
end
|
196
|
-
end
|
197
|
-
end
|
198
194
|
|
195
|
+
def verifier_for(secret, digest)
|
196
|
+
key = secret.respond_to?(:call) ? secret.call : secret
|
197
|
+
ActiveSupport::MessageVerifier.new(key, digest)
|
198
|
+
end
|
199
|
+
|
200
|
+
def generate_sid
|
201
|
+
ActiveSupport::SecureRandom.hex(16)
|
202
|
+
end
|
203
|
+
|
204
|
+
def persistent_session_id!(data)
|
205
|
+
(data ||= {}).merge!(inject_persistent_session_id(data))
|
206
|
+
end
|
207
|
+
|
208
|
+
def inject_persistent_session_id(data)
|
209
|
+
requires_session_id?(data) ? { :session_id => generate_sid } : {}
|
210
|
+
end
|
211
|
+
|
212
|
+
def requires_session_id?(data)
|
213
|
+
if data
|
214
|
+
data.respond_to?(:key?) && !data.key?(:session_id)
|
215
|
+
else
|
216
|
+
true
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
199
221
|
end
|
@@ -1,95 +1,48 @@
|
|
1
|
-
# cgi/session/memcached.rb - persistent storage of marshalled session data
|
2
|
-
#
|
3
|
-
# == Overview
|
4
|
-
#
|
5
|
-
# This file provides the CGI::Session::MemCache class, which builds
|
6
|
-
# persistence of storage data on top of the MemCache library. See
|
7
|
-
# cgi/session.rb for more details on session storage managers.
|
8
|
-
#
|
9
|
-
|
10
1
|
begin
|
11
|
-
require 'cgi/session'
|
12
2
|
require_library_or_gem 'memcache'
|
13
3
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# in a memcached cache.
|
21
|
-
class MemCacheStore
|
22
|
-
def check_id(id) #:nodoc:#
|
23
|
-
/[^0-9a-zA-Z]+/ =~ id.to_s ? false : true
|
24
|
-
end
|
4
|
+
module ActionController
|
5
|
+
module Session
|
6
|
+
class MemCacheStore < AbstractStore
|
7
|
+
def initialize(app, options = {})
|
8
|
+
# Support old :expires option
|
9
|
+
options[:expire_after] ||= options[:expires]
|
25
10
|
|
26
|
-
|
27
|
-
#
|
28
|
-
# This constructor is used internally by CGI::Session. The
|
29
|
-
# user does not generally need to call it directly.
|
30
|
-
#
|
31
|
-
# +session+ is the session for which this instance is being
|
32
|
-
# created. The session id must only contain alphanumeric
|
33
|
-
# characters; automatically generated session ids observe
|
34
|
-
# this requirement.
|
35
|
-
#
|
36
|
-
# +options+ is a hash of options for the initializer. The
|
37
|
-
# following options are recognized:
|
38
|
-
#
|
39
|
-
# cache:: an instance of a MemCache client to use as the
|
40
|
-
# session cache.
|
41
|
-
#
|
42
|
-
# expires:: an expiry time value to use for session entries in
|
43
|
-
# the session cache. +expires+ is interpreted in seconds
|
44
|
-
# relative to the current time if it�s less than 60*60*24*30
|
45
|
-
# (30 days), or as an absolute Unix time (e.g., Time#to_i) if
|
46
|
-
# greater. If +expires+ is +0+, or not passed on +options+,
|
47
|
-
# the entry will never expire.
|
48
|
-
#
|
49
|
-
# This session's memcache entry will be created if it does
|
50
|
-
# not exist, or retrieved if it does.
|
51
|
-
def initialize(session, options = {})
|
52
|
-
id = session.session_id
|
53
|
-
unless check_id(id)
|
54
|
-
raise ArgumentError, "session_id '%s' is invalid" % id
|
55
|
-
end
|
56
|
-
@cache = options['cache'] || MemCache.new('localhost')
|
57
|
-
@expires = options['expires'] || 0
|
58
|
-
@session_key = "session:#{id}"
|
59
|
-
@session_data = {}
|
60
|
-
# Add this key to the store if haven't done so yet
|
61
|
-
unless @cache.get(@session_key)
|
62
|
-
@cache.add(@session_key, @session_data, @expires)
|
63
|
-
end
|
64
|
-
end
|
11
|
+
super
|
65
12
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
@session_data = @cache[@session_key] || {}
|
71
|
-
end
|
13
|
+
@default_options = {
|
14
|
+
:namespace => 'rack:session',
|
15
|
+
:memcache_server => 'localhost:11211'
|
16
|
+
}.merge(@default_options)
|
72
17
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
# Update and close the session's memcache entry.
|
79
|
-
def close
|
80
|
-
update
|
81
|
-
end
|
18
|
+
@pool = options[:cache] || MemCache.new(@default_options[:memcache_server], @default_options)
|
19
|
+
unless @pool.servers.any? { |s| s.alive? }
|
20
|
+
raise "#{self} unable to find server during initialization."
|
21
|
+
end
|
22
|
+
@mutex = Mutex.new
|
82
23
|
|
83
|
-
|
84
|
-
def delete
|
85
|
-
@cache.delete(@session_key)
|
86
|
-
@session_data = {}
|
87
|
-
end
|
88
|
-
|
89
|
-
def data
|
90
|
-
@session_data
|
24
|
+
super
|
91
25
|
end
|
92
26
|
|
27
|
+
private
|
28
|
+
def get_session(env, sid)
|
29
|
+
sid ||= generate_sid
|
30
|
+
begin
|
31
|
+
session = @pool.get(sid) || {}
|
32
|
+
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
33
|
+
session = {}
|
34
|
+
end
|
35
|
+
[sid, session]
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_session(env, sid, session_data)
|
39
|
+
options = env['rack.session.options']
|
40
|
+
expiry = options[:expire_after] || 0
|
41
|
+
@pool.set(sid, session_data, expiry)
|
42
|
+
return true
|
43
|
+
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
44
|
+
return false
|
45
|
+
end
|
93
46
|
end
|
94
47
|
end
|
95
48
|
end
|