actionpack 3.2.22.5 → 4.0.0.beta1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +641 -418
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -288
- data/lib/abstract_controller.rb +1 -8
- data/lib/abstract_controller/asset_paths.rb +2 -2
- data/lib/abstract_controller/base.rb +39 -37
- data/lib/abstract_controller/callbacks.rb +101 -82
- data/lib/abstract_controller/collector.rb +7 -3
- data/lib/abstract_controller/helpers.rb +23 -11
- data/lib/abstract_controller/layouts.rb +68 -73
- data/lib/abstract_controller/logger.rb +1 -2
- data/lib/abstract_controller/rendering.rb +22 -13
- data/lib/abstract_controller/translation.rb +16 -1
- data/lib/abstract_controller/url_for.rb +6 -6
- data/lib/abstract_controller/view_paths.rb +1 -1
- data/lib/action_controller.rb +15 -6
- data/lib/action_controller/base.rb +46 -22
- data/lib/action_controller/caching.rb +46 -33
- data/lib/action_controller/caching/fragments.rb +23 -53
- data/lib/action_controller/deprecated.rb +5 -1
- data/lib/action_controller/deprecated/integration_test.rb +3 -0
- data/lib/action_controller/log_subscriber.rb +11 -8
- data/lib/action_controller/metal.rb +16 -30
- data/lib/action_controller/metal/conditional_get.rb +76 -32
- data/lib/action_controller/metal/data_streaming.rb +20 -26
- data/lib/action_controller/metal/exceptions.rb +19 -6
- data/lib/action_controller/metal/flash.rb +24 -9
- data/lib/action_controller/metal/force_ssl.rb +32 -9
- data/lib/action_controller/metal/head.rb +25 -4
- data/lib/action_controller/metal/helpers.rb +6 -9
- data/lib/action_controller/metal/hide_actions.rb +1 -2
- data/lib/action_controller/metal/http_authentication.rb +105 -87
- data/lib/action_controller/metal/implicit_render.rb +1 -1
- data/lib/action_controller/metal/instrumentation.rb +2 -1
- data/lib/action_controller/metal/live.rb +141 -0
- data/lib/action_controller/metal/mime_responds.rb +161 -47
- data/lib/action_controller/metal/params_wrapper.rb +112 -74
- data/lib/action_controller/metal/rack_delegation.rb +9 -3
- data/lib/action_controller/metal/redirecting.rb +15 -20
- data/lib/action_controller/metal/renderers.rb +11 -9
- data/lib/action_controller/metal/rendering.rb +8 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
- data/lib/action_controller/metal/responder.rb +20 -19
- data/lib/action_controller/metal/streaming.rb +12 -18
- data/lib/action_controller/metal/strong_parameters.rb +516 -0
- data/lib/action_controller/metal/testing.rb +13 -18
- data/lib/action_controller/metal/url_for.rb +27 -25
- data/lib/action_controller/model_naming.rb +12 -0
- data/lib/action_controller/railtie.rb +33 -17
- data/lib/action_controller/railties/helpers.rb +22 -0
- data/lib/action_controller/record_identifier.rb +18 -72
- data/lib/action_controller/test_case.rb +215 -123
- data/lib/action_controller/vendor/html-scanner.rb +4 -19
- data/lib/action_dispatch.rb +27 -19
- data/lib/action_dispatch/http/cache.rb +63 -11
- data/lib/action_dispatch/http/filter_parameters.rb +18 -8
- data/lib/action_dispatch/http/filter_redirect.rb +37 -0
- data/lib/action_dispatch/http/headers.rb +27 -19
- data/lib/action_dispatch/http/mime_negotiation.rb +25 -2
- data/lib/action_dispatch/http/mime_type.rb +145 -113
- data/lib/action_dispatch/http/mime_types.rb +1 -1
- data/lib/action_dispatch/http/parameter_filter.rb +44 -46
- data/lib/action_dispatch/http/parameters.rb +12 -5
- data/lib/action_dispatch/http/rack_cache.rb +2 -3
- data/lib/action_dispatch/http/request.rb +49 -18
- data/lib/action_dispatch/http/response.rb +129 -35
- data/lib/action_dispatch/http/upload.rb +60 -17
- data/lib/action_dispatch/http/url.rb +53 -31
- data/lib/action_dispatch/journey.rb +5 -0
- data/lib/action_dispatch/journey/backwards.rb +5 -0
- data/lib/action_dispatch/journey/formatter.rb +146 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
- data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
- data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
- data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
- data/lib/action_dispatch/journey/nodes/node.rb +124 -0
- data/lib/action_dispatch/journey/parser.rb +206 -0
- data/lib/action_dispatch/journey/parser.y +47 -0
- data/lib/action_dispatch/journey/parser_extras.rb +23 -0
- data/lib/action_dispatch/journey/path/pattern.rb +196 -0
- data/lib/action_dispatch/journey/route.rb +116 -0
- data/lib/action_dispatch/journey/router.rb +164 -0
- data/lib/action_dispatch/journey/router/strexp.rb +24 -0
- data/lib/action_dispatch/journey/router/utils.rb +54 -0
- data/lib/action_dispatch/journey/routes.rb +75 -0
- data/lib/action_dispatch/journey/scanner.rb +61 -0
- data/lib/action_dispatch/journey/visitors.rb +189 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/middleware/callbacks.rb +9 -4
- data/lib/action_dispatch/middleware/cookies.rb +168 -57
- data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
- data/lib/action_dispatch/middleware/exception_wrapper.rb +27 -3
- data/lib/action_dispatch/middleware/flash.rb +58 -58
- data/lib/action_dispatch/middleware/params_parser.rb +14 -29
- data/lib/action_dispatch/middleware/public_exceptions.rb +31 -14
- data/lib/action_dispatch/middleware/reloader.rb +6 -6
- data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
- data/lib/action_dispatch/middleware/request_id.rb +2 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
- data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +81 -7
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
- data/lib/action_dispatch/middleware/ssl.rb +70 -0
- data/lib/action_dispatch/middleware/stack.rb +6 -1
- data/lib/action_dispatch/middleware/static.rb +5 -24
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -5
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
- data/lib/action_dispatch/railtie.rb +16 -6
- data/lib/action_dispatch/request/session.rb +181 -0
- data/lib/action_dispatch/routing.rb +41 -40
- data/lib/action_dispatch/routing/inspector.rb +240 -0
- data/lib/action_dispatch/routing/mapper.rb +501 -273
- data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
- data/lib/action_dispatch/routing/redirection.rb +46 -29
- data/lib/action_dispatch/routing/route_set.rb +203 -164
- data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
- data/lib/action_dispatch/routing/url_for.rb +48 -33
- data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
- data/lib/action_dispatch/testing/assertions/response.rb +32 -40
- data/lib/action_dispatch/testing/assertions/routing.rb +40 -39
- data/lib/action_dispatch/testing/assertions/selector.rb +15 -20
- data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
- data/lib/action_dispatch/testing/integration.rb +41 -22
- data/lib/action_dispatch/testing/test_process.rb +9 -6
- data/lib/action_dispatch/testing/test_request.rb +7 -3
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +4 -4
- data/lib/action_view.rb +17 -8
- data/lib/action_view/base.rb +15 -34
- data/lib/action_view/buffers.rb +1 -1
- data/lib/action_view/context.rb +4 -4
- data/lib/action_view/dependency_tracker.rb +91 -0
- data/lib/action_view/digestor.rb +85 -0
- data/lib/action_view/flows.rb +1 -4
- data/lib/action_view/helpers.rb +2 -4
- data/lib/action_view/helpers/active_model_helper.rb +3 -4
- data/lib/action_view/helpers/asset_tag_helper.rb +211 -353
- data/lib/action_view/helpers/asset_url_helper.rb +354 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
- data/lib/action_view/helpers/cache_helper.rb +150 -18
- data/lib/action_view/helpers/capture_helper.rb +42 -29
- data/lib/action_view/helpers/csrf_helper.rb +0 -2
- data/lib/action_view/helpers/date_helper.rb +268 -247
- data/lib/action_view/helpers/debug_helper.rb +10 -11
- data/lib/action_view/helpers/form_helper.rb +904 -547
- data/lib/action_view/helpers/form_options_helper.rb +341 -166
- data/lib/action_view/helpers/form_tag_helper.rb +188 -88
- data/lib/action_view/helpers/javascript_helper.rb +23 -16
- data/lib/action_view/helpers/number_helper.rb +148 -354
- data/lib/action_view/helpers/output_safety_helper.rb +3 -3
- data/lib/action_view/helpers/record_tag_helper.rb +17 -22
- data/lib/action_view/helpers/rendering_helper.rb +2 -4
- data/lib/action_view/helpers/sanitize_helper.rb +3 -6
- data/lib/action_view/helpers/tag_helper.rb +43 -37
- data/lib/action_view/helpers/tags.rb +39 -0
- data/lib/action_view/helpers/tags/base.rb +148 -0
- data/lib/action_view/helpers/tags/check_box.rb +64 -0
- data/lib/action_view/helpers/tags/checkable.rb +16 -0
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
- data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
- data/lib/action_view/helpers/tags/collection_select.rb +28 -0
- data/lib/action_view/helpers/tags/color_field.rb +25 -0
- data/lib/action_view/helpers/tags/date_field.rb +13 -0
- data/lib/action_view/helpers/tags/date_select.rb +72 -0
- data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
- data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
- data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
- data/lib/action_view/helpers/tags/email_field.rb +8 -0
- data/lib/action_view/helpers/tags/file_field.rb +8 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
- data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
- data/lib/action_view/helpers/tags/label.rb +65 -0
- data/lib/action_view/helpers/tags/month_field.rb +13 -0
- data/lib/action_view/helpers/tags/number_field.rb +18 -0
- data/lib/action_view/helpers/tags/password_field.rb +12 -0
- data/lib/action_view/helpers/tags/radio_button.rb +31 -0
- data/lib/action_view/helpers/tags/range_field.rb +8 -0
- data/lib/action_view/helpers/tags/search_field.rb +24 -0
- data/lib/action_view/helpers/tags/select.rb +41 -0
- data/lib/action_view/helpers/tags/tel_field.rb +8 -0
- data/lib/action_view/helpers/tags/text_area.rb +18 -0
- data/lib/action_view/helpers/tags/text_field.rb +29 -0
- data/lib/action_view/helpers/tags/time_field.rb +13 -0
- data/lib/action_view/helpers/tags/time_select.rb +8 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
- data/lib/action_view/helpers/tags/url_field.rb +8 -0
- data/lib/action_view/helpers/tags/week_field.rb +13 -0
- data/lib/action_view/helpers/text_helper.rb +126 -113
- data/lib/action_view/helpers/translation_helper.rb +32 -16
- data/lib/action_view/helpers/url_helper.rb +200 -271
- data/lib/action_view/locale/en.yml +1 -105
- data/lib/action_view/log_subscriber.rb +6 -4
- data/lib/action_view/lookup_context.rb +15 -39
- data/lib/action_view/model_naming.rb +12 -0
- data/lib/action_view/path_set.rb +9 -39
- data/lib/action_view/railtie.rb +6 -22
- data/lib/action_view/record_identifier.rb +84 -0
- data/lib/action_view/renderer/abstract_renderer.rb +10 -19
- data/lib/action_view/renderer/partial_renderer.rb +144 -81
- data/lib/action_view/renderer/renderer.rb +2 -19
- data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
- data/lib/action_view/renderer/template_renderer.rb +14 -13
- data/lib/action_view/routing_url_for.rb +107 -0
- data/lib/action_view/template.rb +22 -21
- data/lib/action_view/template/error.rb +22 -12
- data/lib/action_view/template/handlers.rb +12 -9
- data/lib/action_view/template/handlers/builder.rb +1 -1
- data/lib/action_view/template/handlers/erb.rb +11 -16
- data/lib/action_view/template/handlers/raw.rb +11 -0
- data/lib/action_view/template/resolver.rb +111 -83
- data/lib/action_view/template/text.rb +12 -8
- data/lib/action_view/template/types.rb +57 -0
- data/lib/action_view/test_case.rb +66 -43
- data/lib/action_view/testing/resolvers.rb +3 -2
- data/lib/action_view/vendor/html-scanner.rb +20 -0
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +18 -7
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +1 -1
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
- metadata +135 -125
- data/lib/action_controller/caching/actions.rb +0 -185
- data/lib/action_controller/caching/pages.rb +0 -187
- data/lib/action_controller/caching/sweeping.rb +0 -97
- data/lib/action_controller/deprecated/performance_test.rb +0 -1
- data/lib/action_controller/metal/compatibility.rb +0 -65
- data/lib/action_controller/metal/session_management.rb +0 -14
- data/lib/action_controller/railties/paths.rb +0 -25
- data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
- data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
- data/lib/action_dispatch/middleware/head.rb +0 -18
- data/lib/action_dispatch/middleware/rescue.rb +0 -26
- data/lib/action_dispatch/testing/performance_test.rb +0 -10
- data/lib/action_view/asset_paths.rb +0 -142
- data/lib/action_view/helpers/asset_paths.rb +0 -7
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
- data/lib/sprockets/assets.rake +0 -99
- data/lib/sprockets/bootstrap.rb +0 -37
- data/lib/sprockets/compressors.rb +0 -83
- data/lib/sprockets/helpers.rb +0 -6
- data/lib/sprockets/helpers/isolated_helper.rb +0 -13
- data/lib/sprockets/helpers/rails_helper.rb +0 -182
- data/lib/sprockets/railtie.rb +0 -62
- data/lib/sprockets/static_compiler.rb +0 -56
@@ -0,0 +1,189 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActionDispatch
|
3
|
+
module Journey # :nodoc:
|
4
|
+
module Visitors # :nodoc:
|
5
|
+
class Visitor # :nodoc:
|
6
|
+
DISPATCH_CACHE = Hash.new { |h,k|
|
7
|
+
h[k] = "visit_#{k}"
|
8
|
+
}
|
9
|
+
|
10
|
+
def accept(node)
|
11
|
+
visit(node)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def visit node
|
17
|
+
send(DISPATCH_CACHE[node.type], node)
|
18
|
+
end
|
19
|
+
|
20
|
+
def binary(node)
|
21
|
+
visit(node.left)
|
22
|
+
visit(node.right)
|
23
|
+
end
|
24
|
+
def visit_CAT(n); binary(n); end
|
25
|
+
|
26
|
+
def nary(node)
|
27
|
+
node.children.each { |c| visit(c) }
|
28
|
+
end
|
29
|
+
def visit_OR(n); nary(n); end
|
30
|
+
|
31
|
+
def unary(node)
|
32
|
+
visit(node.left)
|
33
|
+
end
|
34
|
+
def visit_GROUP(n); unary(n); end
|
35
|
+
def visit_STAR(n); unary(n); end
|
36
|
+
|
37
|
+
def terminal(node); end
|
38
|
+
%w{ LITERAL SYMBOL SLASH DOT }.each do |t|
|
39
|
+
class_eval %{ def visit_#{t}(n); terminal(n); end }, __FILE__, __LINE__
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Loop through the requirements AST
|
44
|
+
class Each < Visitor # :nodoc:
|
45
|
+
attr_reader :block
|
46
|
+
|
47
|
+
def initialize(block)
|
48
|
+
@block = block
|
49
|
+
end
|
50
|
+
|
51
|
+
def visit(node)
|
52
|
+
super
|
53
|
+
block.call(node)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class String < Visitor # :nodoc:
|
58
|
+
private
|
59
|
+
|
60
|
+
def binary(node)
|
61
|
+
[visit(node.left), visit(node.right)].join
|
62
|
+
end
|
63
|
+
|
64
|
+
def nary(node)
|
65
|
+
node.children.map { |c| visit(c) }.join '|'
|
66
|
+
end
|
67
|
+
|
68
|
+
def terminal(node)
|
69
|
+
node.left
|
70
|
+
end
|
71
|
+
|
72
|
+
def visit_GROUP(node)
|
73
|
+
"(#{visit(node.left)})"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Used for formatting urls (url_for)
|
78
|
+
class Formatter < Visitor # :nodoc:
|
79
|
+
attr_reader :options, :consumed
|
80
|
+
|
81
|
+
def initialize(options)
|
82
|
+
@options = options
|
83
|
+
@consumed = {}
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def visit_GROUP(node)
|
89
|
+
if consumed == options
|
90
|
+
nil
|
91
|
+
else
|
92
|
+
route = visit(node.left)
|
93
|
+
route.include?("\0") ? nil : route
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def terminal(node)
|
98
|
+
node.left
|
99
|
+
end
|
100
|
+
|
101
|
+
def binary(node)
|
102
|
+
[visit(node.left), visit(node.right)].join
|
103
|
+
end
|
104
|
+
|
105
|
+
def nary(node)
|
106
|
+
node.children.map { |c| visit(c) }.join
|
107
|
+
end
|
108
|
+
|
109
|
+
def visit_SYMBOL(node)
|
110
|
+
key = node.to_sym
|
111
|
+
|
112
|
+
if value = options[key]
|
113
|
+
consumed[key] = value
|
114
|
+
Router::Utils.escape_path(value)
|
115
|
+
else
|
116
|
+
"\0"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class Dot < Visitor # :nodoc:
|
122
|
+
def initialize
|
123
|
+
@nodes = []
|
124
|
+
@edges = []
|
125
|
+
end
|
126
|
+
|
127
|
+
def accept(node)
|
128
|
+
super
|
129
|
+
<<-eodot
|
130
|
+
digraph parse_tree {
|
131
|
+
size="8,5"
|
132
|
+
node [shape = none];
|
133
|
+
edge [dir = none];
|
134
|
+
#{@nodes.join "\n"}
|
135
|
+
#{@edges.join("\n")}
|
136
|
+
}
|
137
|
+
eodot
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def binary(node)
|
143
|
+
node.children.each do |c|
|
144
|
+
@edges << "#{node.object_id} -> #{c.object_id};"
|
145
|
+
end
|
146
|
+
super
|
147
|
+
end
|
148
|
+
|
149
|
+
def nary(node)
|
150
|
+
node.children.each do |c|
|
151
|
+
@edges << "#{node.object_id} -> #{c.object_id};"
|
152
|
+
end
|
153
|
+
super
|
154
|
+
end
|
155
|
+
|
156
|
+
def unary(node)
|
157
|
+
@edges << "#{node.object_id} -> #{node.left.object_id};"
|
158
|
+
super
|
159
|
+
end
|
160
|
+
|
161
|
+
def visit_GROUP(node)
|
162
|
+
@nodes << "#{node.object_id} [label=\"()\"];"
|
163
|
+
super
|
164
|
+
end
|
165
|
+
|
166
|
+
def visit_CAT(node)
|
167
|
+
@nodes << "#{node.object_id} [label=\"○\"];"
|
168
|
+
super
|
169
|
+
end
|
170
|
+
|
171
|
+
def visit_STAR(node)
|
172
|
+
@nodes << "#{node.object_id} [label=\"*\"];"
|
173
|
+
super
|
174
|
+
end
|
175
|
+
|
176
|
+
def visit_OR(node)
|
177
|
+
@nodes << "#{node.object_id} [label=\"|\"];"
|
178
|
+
super
|
179
|
+
end
|
180
|
+
|
181
|
+
def terminal(node)
|
182
|
+
value = node.left
|
183
|
+
|
184
|
+
@nodes << "#{node.object_id} [label=\"#{value}\"];"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
body {
|
2
|
+
font-family: "Helvetica Neue", Helvetica, Arial, Sans-Serif;
|
3
|
+
margin: 0;
|
4
|
+
}
|
5
|
+
|
6
|
+
h1 {
|
7
|
+
font-size: 2.0em; font-weight: bold; text-align: center;
|
8
|
+
color: white; background-color: black;
|
9
|
+
padding: 5px 0;
|
10
|
+
margin: 0 0 20px;
|
11
|
+
}
|
12
|
+
|
13
|
+
h2 {
|
14
|
+
text-align: center;
|
15
|
+
display: none;
|
16
|
+
font-size: 0.5em;
|
17
|
+
}
|
18
|
+
|
19
|
+
div#chart-2 {
|
20
|
+
height: 350px;
|
21
|
+
}
|
22
|
+
|
23
|
+
.clearfix {display: inline-block; }
|
24
|
+
.input { overflow: show;}
|
25
|
+
.instruction { color: #666; padding: 0 30px 20px; font-size: 0.9em}
|
26
|
+
.instruction p { padding: 0 0 5px; }
|
27
|
+
.instruction li { padding: 0 10px 5px; }
|
28
|
+
|
29
|
+
.form { background: #EEE; padding: 20px 30px; border-radius: 5px; margin-left: auto; margin-right: auto; width: 500px; margin-bottom: 20px}
|
30
|
+
.form p, .form form { text-align: center }
|
31
|
+
.form form {padding: 0 10px 5px; }
|
32
|
+
.form .fun_routes { font-size: 0.9em;}
|
33
|
+
.form .fun_routes a { margin: 0 5px 0 0; }
|
34
|
+
|
@@ -0,0 +1,134 @@
|
|
1
|
+
function tokenize(input, callback) {
|
2
|
+
while(input.length > 0) {
|
3
|
+
callback(input.match(/^[\/\.\?]|[^\/\.\?]+/)[0]);
|
4
|
+
input = input.replace(/^[\/\.\?]|[^\/\.\?]+/, '');
|
5
|
+
}
|
6
|
+
}
|
7
|
+
|
8
|
+
var graph = d3.select("#chart-2 svg");
|
9
|
+
var svg_edges = {};
|
10
|
+
var svg_nodes = {};
|
11
|
+
|
12
|
+
graph.selectAll("g.edge").each(function() {
|
13
|
+
var node = d3.select(this);
|
14
|
+
var index = node.select("title").text().split("->");
|
15
|
+
var left = parseInt(index[0]);
|
16
|
+
var right = parseInt(index[1]);
|
17
|
+
|
18
|
+
if(!svg_edges[left]) { svg_edges[left] = {} }
|
19
|
+
svg_edges[left][right] = node;
|
20
|
+
});
|
21
|
+
|
22
|
+
graph.selectAll("g.node").each(function() {
|
23
|
+
var node = d3.select(this);
|
24
|
+
var index = parseInt(node.select("title").text());
|
25
|
+
svg_nodes[index] = node;
|
26
|
+
});
|
27
|
+
|
28
|
+
function reset_graph() {
|
29
|
+
for(var key in svg_edges) {
|
30
|
+
for(var mkey in svg_edges[key]) {
|
31
|
+
var node = svg_edges[key][mkey];
|
32
|
+
var path = node.select("path");
|
33
|
+
var arrow = node.select("polygon");
|
34
|
+
path.style("stroke", "black");
|
35
|
+
arrow.style("stroke", "black").style("fill", "black");
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
for(var key in svg_nodes) {
|
40
|
+
var node = svg_nodes[key];
|
41
|
+
node.select('ellipse').style("fill", "white");
|
42
|
+
node.select('polygon').style("fill", "white");
|
43
|
+
}
|
44
|
+
return false;
|
45
|
+
}
|
46
|
+
|
47
|
+
function highlight_edge(from, to) {
|
48
|
+
var node = svg_edges[from][to];
|
49
|
+
var path = node.select("path");
|
50
|
+
var arrow = node.select("polygon");
|
51
|
+
|
52
|
+
path
|
53
|
+
.transition().duration(500)
|
54
|
+
.style("stroke", "green");
|
55
|
+
|
56
|
+
arrow
|
57
|
+
.transition().duration(500)
|
58
|
+
.style("stroke", "green").style("fill", "green");
|
59
|
+
}
|
60
|
+
|
61
|
+
function highlight_state(index, color) {
|
62
|
+
if(!color) { color = "green"; }
|
63
|
+
|
64
|
+
svg_nodes[index].select('ellipse')
|
65
|
+
.style("fill", "white")
|
66
|
+
.transition().duration(500)
|
67
|
+
.style("fill", color);
|
68
|
+
}
|
69
|
+
|
70
|
+
function highlight_finish(index) {
|
71
|
+
svg_nodes[index].select('polygon')
|
72
|
+
.style("fill", "while")
|
73
|
+
.transition().duration(500)
|
74
|
+
.style("fill", "blue");
|
75
|
+
}
|
76
|
+
|
77
|
+
function match(input) {
|
78
|
+
reset_graph();
|
79
|
+
var table = tt();
|
80
|
+
var states = [0];
|
81
|
+
var regexp_states = table['regexp_states'];
|
82
|
+
var string_states = table['string_states'];
|
83
|
+
var accepting = table['accepting'];
|
84
|
+
|
85
|
+
highlight_state(0);
|
86
|
+
|
87
|
+
tokenize(input, function(token) {
|
88
|
+
var new_states = [];
|
89
|
+
for(var key in states) {
|
90
|
+
var state = states[key];
|
91
|
+
|
92
|
+
if(string_states[state] && string_states[state][token]) {
|
93
|
+
var new_state = string_states[state][token];
|
94
|
+
highlight_edge(state, new_state);
|
95
|
+
highlight_state(new_state);
|
96
|
+
new_states.push(new_state);
|
97
|
+
}
|
98
|
+
|
99
|
+
if(regexp_states[state]) {
|
100
|
+
for(var key in regexp_states[state]) {
|
101
|
+
var re = new RegExp("^" + key + "$");
|
102
|
+
if(re.test(token)) {
|
103
|
+
var new_state = regexp_states[state][key];
|
104
|
+
highlight_edge(state, new_state);
|
105
|
+
highlight_state(new_state);
|
106
|
+
new_states.push(new_state);
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
if(new_states.length == 0) {
|
113
|
+
return;
|
114
|
+
}
|
115
|
+
states = new_states;
|
116
|
+
});
|
117
|
+
|
118
|
+
for(var key in states) {
|
119
|
+
var state = states[key];
|
120
|
+
if(accepting[state]) {
|
121
|
+
for(var mkey in svg_edges[state]) {
|
122
|
+
if(!regexp_states[mkey] && !string_states[mkey]) {
|
123
|
+
highlight_edge(state, mkey);
|
124
|
+
highlight_finish(mkey);
|
125
|
+
}
|
126
|
+
}
|
127
|
+
} else {
|
128
|
+
highlight_state(state, "red");
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
return false;
|
133
|
+
}
|
134
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= title %></title>
|
5
|
+
<link rel="stylesheet" href="https://raw.github.com/gist/1706081/af944401f75ea20515a02ddb3fb43d23ecb8c662/reset.css" type="text/css">
|
6
|
+
<style>
|
7
|
+
<% stylesheets.each do |style| %>
|
8
|
+
<%= style %>
|
9
|
+
<% end %>
|
10
|
+
</style>
|
11
|
+
<script src="https://raw.github.com/gist/1706081/df464722a05c3c2bec450b7b5c8240d9c31fa52d/d3.min.js" type="text/javascript"></script>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
<div id="wrapper">
|
15
|
+
<h1>Routes FSM with NFA simulation</h1>
|
16
|
+
<div class="instruction form">
|
17
|
+
<p>
|
18
|
+
Type a route in to the box and click "simulate".
|
19
|
+
</p>
|
20
|
+
<form onsubmit="return match(this.route.value);">
|
21
|
+
<input type="text" size="30" name="route" value="/articles/new" />
|
22
|
+
<button>simulate</button>
|
23
|
+
<input type="reset" value="reset" onclick="return reset_graph();"/>
|
24
|
+
</form>
|
25
|
+
<p class="fun_routes">
|
26
|
+
Some fun routes to try:
|
27
|
+
<% fun_routes.each do |path| %>
|
28
|
+
<a href="#" onclick="document.forms[0].elements[0].value=this.text.replace(/^\s+|\s+$/g,''); return match(this.text.replace(/^\s+|\s+$/g,''));">
|
29
|
+
<%= path %>
|
30
|
+
</a>
|
31
|
+
<% end %>
|
32
|
+
</p>
|
33
|
+
</div>
|
34
|
+
<div class='chart' id='chart-2'>
|
35
|
+
<%= svg %>
|
36
|
+
</div>
|
37
|
+
<div class="instruction">
|
38
|
+
<p>
|
39
|
+
This is a FSM for a system that has the following routes:
|
40
|
+
</p>
|
41
|
+
<ul>
|
42
|
+
<% paths.each do |route| %>
|
43
|
+
<li><%= route %></li>
|
44
|
+
<% end %>
|
45
|
+
</ul>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
<% javascripts.each do |js| %>
|
49
|
+
<script><%= js %></script>
|
50
|
+
<% end %>
|
51
|
+
</body>
|
52
|
+
</html>
|
@@ -1,11 +1,10 @@
|
|
1
|
-
require 'active_support/core_ext/module/delegation'
|
2
1
|
|
3
2
|
module ActionDispatch
|
4
3
|
# Provide callbacks to be executed before and after the request dispatch.
|
5
4
|
class Callbacks
|
6
5
|
include ActiveSupport::Callbacks
|
7
6
|
|
8
|
-
define_callbacks :call
|
7
|
+
define_callbacks :call
|
9
8
|
|
10
9
|
class << self
|
11
10
|
delegate :to_prepare, :to_cleanup, :to => "ActionDispatch::Reloader"
|
@@ -24,9 +23,15 @@ module ActionDispatch
|
|
24
23
|
end
|
25
24
|
|
26
25
|
def call(env)
|
27
|
-
|
28
|
-
|
26
|
+
error = nil
|
27
|
+
result = run_callbacks :call do
|
28
|
+
begin
|
29
|
+
@app.call(env)
|
30
|
+
rescue => error
|
31
|
+
end
|
29
32
|
end
|
33
|
+
raise error if error
|
34
|
+
result
|
30
35
|
end
|
31
36
|
end
|
32
37
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
-
require 'active_support/core_ext/object/blank'
|
2
1
|
require 'active_support/core_ext/hash/keys'
|
3
2
|
require 'active_support/core_ext/module/attribute_accessors'
|
3
|
+
require 'active_support/key_generator'
|
4
|
+
require 'active_support/message_verifier'
|
4
5
|
|
5
6
|
module ActionDispatch
|
6
|
-
class Request
|
7
|
+
class Request < Rack::Request
|
7
8
|
def cookie_jar
|
8
9
|
env['action_dispatch.cookies'] ||= Cookies::CookieJar.build(self)
|
9
10
|
end
|
@@ -15,7 +16,7 @@ module ActionDispatch
|
|
15
16
|
# being written will be sent out with the response. Reading a cookie does not get
|
16
17
|
# the cookie object itself back, just the value it holds.
|
17
18
|
#
|
18
|
-
# Examples
|
19
|
+
# Examples of writing:
|
19
20
|
#
|
20
21
|
# # Sets a simple session cookie.
|
21
22
|
# # This cookie will be deleted when the user's browser is closed.
|
@@ -25,11 +26,11 @@ module ActionDispatch
|
|
25
26
|
# cookies[:lat_lon] = [47.68, -122.37]
|
26
27
|
#
|
27
28
|
# # Sets a cookie that expires in 1 hour.
|
28
|
-
# cookies[:login] = { :
|
29
|
+
# cookies[:login] = { value: "XJ-122", expires: 1.hour.from_now }
|
29
30
|
#
|
30
|
-
# # Sets a signed cookie, which prevents
|
31
|
-
# # The cookie is signed by your app's <tt>config.
|
32
|
-
# #
|
31
|
+
# # Sets a signed cookie, which prevents users from tampering with its value.
|
32
|
+
# # The cookie is signed by your app's <tt>config.secret_key_base</tt> value.
|
33
|
+
# # It can be read using the signed method <tt>cookies.signed[:key]</tt>
|
33
34
|
# cookies.signed[:user_id] = current_user.id
|
34
35
|
#
|
35
36
|
# # Sets a "permanent" cookie (which expires in 20 years from now).
|
@@ -38,11 +39,12 @@ module ActionDispatch
|
|
38
39
|
# # You can also chain these methods:
|
39
40
|
# cookies.permanent.signed[:login] = "XJ-122"
|
40
41
|
#
|
41
|
-
# Examples
|
42
|
+
# Examples of reading:
|
42
43
|
#
|
43
|
-
# cookies[:user_name]
|
44
|
-
# cookies.size
|
45
|
-
# cookies[:lat_lon]
|
44
|
+
# cookies[:user_name] # => "david"
|
45
|
+
# cookies.size # => 2
|
46
|
+
# cookies[:lat_lon] # => [47.68, -122.37]
|
47
|
+
# cookies.signed[:login] # => "XJ-122"
|
46
48
|
#
|
47
49
|
# Example for deleting:
|
48
50
|
#
|
@@ -51,12 +53,12 @@ module ActionDispatch
|
|
51
53
|
# Please note that if you specify a :domain when setting a cookie, you must also specify the domain when deleting the cookie:
|
52
54
|
#
|
53
55
|
# cookies[:key] = {
|
54
|
-
# :
|
55
|
-
# :
|
56
|
-
# :
|
56
|
+
# value: 'a yummy cookie',
|
57
|
+
# expires: 1.year.from_now,
|
58
|
+
# domain: 'domain.com'
|
57
59
|
# }
|
58
60
|
#
|
59
|
-
# cookies.delete(:key, :
|
61
|
+
# cookies.delete(:key, domain: 'domain.com')
|
60
62
|
#
|
61
63
|
# The option symbols for setting cookies are:
|
62
64
|
#
|
@@ -69,8 +71,8 @@ module ActionDispatch
|
|
69
71
|
# to <tt>:all</tt>. Make sure to specify the <tt>:domain</tt> option with
|
70
72
|
# <tt>:all</tt> again when deleting keys.
|
71
73
|
#
|
72
|
-
# :
|
73
|
-
# :
|
74
|
+
# domain: nil # Does not sets cookie domain. (default)
|
75
|
+
# domain: :all # Allow the cookie for the top most level
|
74
76
|
# domain and subdomains.
|
75
77
|
#
|
76
78
|
# * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object.
|
@@ -79,11 +81,18 @@ module ActionDispatch
|
|
79
81
|
# * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or
|
80
82
|
# only HTTP. Defaults to +false+.
|
81
83
|
class Cookies
|
82
|
-
HTTP_HEADER
|
84
|
+
HTTP_HEADER = "Set-Cookie".freeze
|
85
|
+
GENERATOR_KEY = "action_dispatch.key_generator".freeze
|
86
|
+
SIGNED_COOKIE_SALT = "action_dispatch.signed_cookie_salt".freeze
|
87
|
+
ENCRYPTED_COOKIE_SALT = "action_dispatch.encrypted_cookie_salt".freeze
|
88
|
+
ENCRYPTED_SIGNED_COOKIE_SALT = "action_dispatch.encrypted_signed_cookie_salt".freeze
|
83
89
|
TOKEN_KEY = "action_dispatch.secret_token".freeze
|
84
90
|
|
91
|
+
# Cookies can typically store 4096 bytes.
|
92
|
+
MAX_COOKIE_SIZE = 4096
|
93
|
+
|
85
94
|
# Raised when storing more than 4K of session data.
|
86
|
-
|
95
|
+
CookieOverflow = Class.new StandardError
|
87
96
|
|
88
97
|
class CookieJar #:nodoc:
|
89
98
|
include Enumerable
|
@@ -102,23 +111,33 @@ module ActionDispatch
|
|
102
111
|
# $& => example.local
|
103
112
|
DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
|
104
113
|
|
114
|
+
def self.options_for_env(env) #:nodoc:
|
115
|
+
{ signed_cookie_salt: env[SIGNED_COOKIE_SALT] || '',
|
116
|
+
encrypted_cookie_salt: env[ENCRYPTED_COOKIE_SALT] || '',
|
117
|
+
encrypted_signed_cookie_salt: env[ENCRYPTED_SIGNED_COOKIE_SALT] || '',
|
118
|
+
token_key: env[TOKEN_KEY] }
|
119
|
+
end
|
120
|
+
|
105
121
|
def self.build(request)
|
106
|
-
|
122
|
+
env = request.env
|
123
|
+
key_generator = env[GENERATOR_KEY]
|
124
|
+
options = options_for_env env
|
125
|
+
|
107
126
|
host = request.host
|
108
127
|
secure = request.ssl?
|
109
128
|
|
110
|
-
new(
|
129
|
+
new(key_generator, host, secure, options).tap do |hash|
|
111
130
|
hash.update(request.cookies)
|
112
131
|
end
|
113
132
|
end
|
114
133
|
|
115
|
-
def initialize(
|
116
|
-
@
|
134
|
+
def initialize(key_generator, host = nil, secure = false, options = {})
|
135
|
+
@key_generator = key_generator
|
117
136
|
@set_cookies = {}
|
118
137
|
@delete_cookies = {}
|
119
138
|
@host = host
|
120
139
|
@secure = secure
|
121
|
-
@
|
140
|
+
@options = options
|
122
141
|
@cookies = {}
|
123
142
|
end
|
124
143
|
|
@@ -131,6 +150,10 @@ module ActionDispatch
|
|
131
150
|
@cookies[name.to_s]
|
132
151
|
end
|
133
152
|
|
153
|
+
def fetch(name, *args, &block)
|
154
|
+
@cookies.fetch(name.to_s, *args, &block)
|
155
|
+
end
|
156
|
+
|
134
157
|
def key?(name)
|
135
158
|
@cookies.key?(name.to_s)
|
136
159
|
end
|
@@ -155,7 +178,7 @@ module ActionDispatch
|
|
155
178
|
end
|
156
179
|
elsif options[:domain].is_a? Array
|
157
180
|
# if host matches one of the supplied domains without a dot in front of it
|
158
|
-
options[:domain] = options[:domain].find {|domain| @host.include? domain
|
181
|
+
options[:domain] = options[:domain].find {|domain| @host.include? domain.sub(/^\./, '') }
|
159
182
|
end
|
160
183
|
end
|
161
184
|
|
@@ -185,8 +208,9 @@ module ActionDispatch
|
|
185
208
|
# and setting its expiration date into the past. Like <tt>[]=</tt>, you can pass in
|
186
209
|
# an options hash to delete cookies with extra data such as a <tt>:path</tt>.
|
187
210
|
def delete(key, options = {})
|
188
|
-
|
211
|
+
return unless @cookies.has_key? key.to_s
|
189
212
|
|
213
|
+
options.symbolize_keys!
|
190
214
|
handle_options(options)
|
191
215
|
|
192
216
|
value = @cookies.delete(key.to_s)
|
@@ -194,6 +218,15 @@ module ActionDispatch
|
|
194
218
|
value
|
195
219
|
end
|
196
220
|
|
221
|
+
# Whether the given cookie is to be deleted by this CookieJar.
|
222
|
+
# Like <tt>[]=</tt>, you can pass in an options hash to test if a
|
223
|
+
# deletion applies to a specific <tt>:path</tt>, <tt>:domain</tt> etc.
|
224
|
+
def deleted?(key, options = {})
|
225
|
+
options.symbolize_keys!
|
226
|
+
handle_options(options)
|
227
|
+
@delete_cookies[key.to_s] == options
|
228
|
+
end
|
229
|
+
|
197
230
|
# Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie
|
198
231
|
def clear(options = {})
|
199
232
|
@cookies.each_key{ |k| delete(k, options) }
|
@@ -211,7 +244,7 @@ module ActionDispatch
|
|
211
244
|
# cookies.permanent.signed[:remember_me] = current_user.id
|
212
245
|
# # => Set-Cookie: remember_me=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
|
213
246
|
def permanent
|
214
|
-
@permanent ||= PermanentCookieJar.new(self, @
|
247
|
+
@permanent ||= PermanentCookieJar.new(self, @key_generator, @options)
|
215
248
|
end
|
216
249
|
|
217
250
|
# Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from
|
@@ -219,7 +252,7 @@ module ActionDispatch
|
|
219
252
|
# cookie was tampered with by the user (or a 3rd party), an ActiveSupport::MessageVerifier::InvalidSignature exception will
|
220
253
|
# be raised.
|
221
254
|
#
|
222
|
-
# This jar requires that you set a suitable secret for the verification on your app's config.
|
255
|
+
# This jar requires that you set a suitable secret for the verification on your app's +config.secret_key_base+.
|
223
256
|
#
|
224
257
|
# Example:
|
225
258
|
#
|
@@ -228,7 +261,28 @@ module ActionDispatch
|
|
228
261
|
#
|
229
262
|
# cookies.signed[:discount] # => 45
|
230
263
|
def signed
|
231
|
-
@signed ||= SignedCookieJar.new(self, @
|
264
|
+
@signed ||= SignedCookieJar.new(self, @key_generator, @options)
|
265
|
+
end
|
266
|
+
|
267
|
+
# Only needed for supporting the +UpgradeSignatureToEncryptionCookieStore+, users and plugin authors should not use this
|
268
|
+
def signed_using_old_secret #:nodoc:
|
269
|
+
@signed_using_old_secret ||= SignedCookieJar.new(self, ActiveSupport::DummyKeyGenerator.new(@options[:token_key]), @options)
|
270
|
+
end
|
271
|
+
|
272
|
+
# Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read.
|
273
|
+
# If the cookie was tampered with by the user (or a 3rd party), an ActiveSupport::MessageVerifier::InvalidSignature exception
|
274
|
+
# will be raised.
|
275
|
+
#
|
276
|
+
# This jar requires that you set a suitable secret for the verification on your app's +config.secret_key_base+.
|
277
|
+
#
|
278
|
+
# Example:
|
279
|
+
#
|
280
|
+
# cookies.encrypted[:discount] = 45
|
281
|
+
# # => Set-Cookie: discount=ZS9ZZ1R4cG1pcUJ1bm80anhQang3dz09LS1mbDZDSU5scGdOT3ltQ2dTdlhSdWpRPT0%3D--ab54663c9f4e3bc340c790d6d2b71e92f5b60315; path=/
|
282
|
+
#
|
283
|
+
# cookies.encrypted[:discount] # => 45
|
284
|
+
def encrypted
|
285
|
+
@encrypted ||= EncryptedCookieJar.new(self, @key_generator, @options)
|
232
286
|
end
|
233
287
|
|
234
288
|
def write(headers)
|
@@ -251,9 +305,15 @@ module ActionDispatch
|
|
251
305
|
end
|
252
306
|
end
|
253
307
|
|
254
|
-
class PermanentCookieJar
|
255
|
-
def initialize(parent_jar,
|
256
|
-
@parent_jar
|
308
|
+
class PermanentCookieJar #:nodoc:
|
309
|
+
def initialize(parent_jar, key_generator, options = {})
|
310
|
+
@parent_jar = parent_jar
|
311
|
+
@key_generator = key_generator
|
312
|
+
@options = options
|
313
|
+
end
|
314
|
+
|
315
|
+
def [](key)
|
316
|
+
@parent_jar[name.to_s]
|
257
317
|
end
|
258
318
|
|
259
319
|
def []=(key, options)
|
@@ -267,22 +327,29 @@ module ActionDispatch
|
|
267
327
|
@parent_jar[key] = options
|
268
328
|
end
|
269
329
|
|
330
|
+
def permanent
|
331
|
+
@permanent ||= PermanentCookieJar.new(self, @key_generator, @options)
|
332
|
+
end
|
333
|
+
|
270
334
|
def signed
|
271
|
-
@signed ||= SignedCookieJar.new(self, @
|
335
|
+
@signed ||= SignedCookieJar.new(self, @key_generator, @options)
|
336
|
+
end
|
337
|
+
|
338
|
+
def encrypted
|
339
|
+
@encrypted ||= EncryptedCookieJar.new(self, @key_generator, @options)
|
272
340
|
end
|
273
341
|
|
274
342
|
def method_missing(method, *arguments, &block)
|
275
|
-
|
343
|
+
ActiveSupport::Deprecation.warn "#{method} is deprecated with no replacement. " +
|
344
|
+
"You probably want to try this method over the parent CookieJar."
|
276
345
|
end
|
277
346
|
end
|
278
347
|
|
279
|
-
class SignedCookieJar
|
280
|
-
|
281
|
-
SECRET_MIN_LENGTH = 30 # Characters
|
282
|
-
|
283
|
-
def initialize(parent_jar, secret)
|
284
|
-
ensure_secret_secure(secret)
|
348
|
+
class SignedCookieJar #:nodoc:
|
349
|
+
def initialize(parent_jar, key_generator, options = {})
|
285
350
|
@parent_jar = parent_jar
|
351
|
+
@options = options
|
352
|
+
secret = key_generator.generate_key(@options[:signed_cookie_salt])
|
286
353
|
@verifier = ActiveSupport::MessageVerifier.new(secret)
|
287
354
|
end
|
288
355
|
|
@@ -306,29 +373,74 @@ module ActionDispatch
|
|
306
373
|
@parent_jar[key] = options
|
307
374
|
end
|
308
375
|
|
376
|
+
def permanent
|
377
|
+
@permanent ||= PermanentCookieJar.new(self, @key_generator, @options)
|
378
|
+
end
|
379
|
+
|
380
|
+
def signed
|
381
|
+
@signed ||= SignedCookieJar.new(self, @key_generator, @options)
|
382
|
+
end
|
383
|
+
|
384
|
+
def encrypted
|
385
|
+
@encrypted ||= EncryptedCookieJar.new(self, @key_generator, @options)
|
386
|
+
end
|
387
|
+
|
309
388
|
def method_missing(method, *arguments, &block)
|
310
|
-
|
389
|
+
ActiveSupport::Deprecation.warn "#{method} is deprecated with no replacement. " +
|
390
|
+
"You probably want to try this method over the parent CookieJar."
|
311
391
|
end
|
392
|
+
end
|
393
|
+
|
394
|
+
class EncryptedCookieJar #:nodoc:
|
395
|
+
def initialize(parent_jar, key_generator, options = {})
|
396
|
+
if ActiveSupport::DummyKeyGenerator === key_generator
|
397
|
+
raise "Encrypted Cookies must be used in conjunction with config.secret_key_base." +
|
398
|
+
"Set config.secret_key_base in config/initializers/secret_token.rb"
|
399
|
+
end
|
312
400
|
|
313
|
-
|
401
|
+
@parent_jar = parent_jar
|
402
|
+
@options = options
|
403
|
+
secret = key_generator.generate_key(@options[:encrypted_cookie_salt])
|
404
|
+
sign_secret = key_generator.generate_key(@options[:encrypted_signed_cookie_salt])
|
405
|
+
@encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
|
406
|
+
end
|
314
407
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
if secret.blank?
|
319
|
-
raise ArgumentError, "A secret is required to generate an " +
|
320
|
-
"integrity hash for cookie session data. Use " +
|
321
|
-
"config.secret_token = \"some secret phrase of at " +
|
322
|
-
"least #{SECRET_MIN_LENGTH} characters\"" +
|
323
|
-
"in config/initializers/secret_token.rb"
|
408
|
+
def [](key)
|
409
|
+
if encrypted_message = @parent_jar[key]
|
410
|
+
@encryptor.decrypt_and_verify(encrypted_message)
|
324
411
|
end
|
412
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature,
|
413
|
+
ActiveSupport::MessageEncryptor::InvalidMessage
|
414
|
+
nil
|
415
|
+
end
|
325
416
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
417
|
+
def []=(key, options)
|
418
|
+
if options.is_a?(Hash)
|
419
|
+
options.symbolize_keys!
|
420
|
+
else
|
421
|
+
options = { :value => options }
|
331
422
|
end
|
423
|
+
options[:value] = @encryptor.encrypt_and_sign(options[:value])
|
424
|
+
|
425
|
+
raise CookieOverflow if options[:value].size > MAX_COOKIE_SIZE
|
426
|
+
@parent_jar[key] = options
|
427
|
+
end
|
428
|
+
|
429
|
+
def permanent
|
430
|
+
@permanent ||= PermanentCookieJar.new(self, @key_generator, @options)
|
431
|
+
end
|
432
|
+
|
433
|
+
def signed
|
434
|
+
@signed ||= SignedCookieJar.new(self, @key_generator, @options)
|
435
|
+
end
|
436
|
+
|
437
|
+
def encrypted
|
438
|
+
@encrypted ||= EncryptedCookieJar.new(self, @key_generator, @options)
|
439
|
+
end
|
440
|
+
|
441
|
+
def method_missing(method, *arguments, &block)
|
442
|
+
ActiveSupport::Deprecation.warn "#{method} is deprecated with no replacement. " +
|
443
|
+
"You probably want to try this method over the parent CookieJar."
|
332
444
|
end
|
333
445
|
end
|
334
446
|
|
@@ -337,7 +449,6 @@ module ActionDispatch
|
|
337
449
|
end
|
338
450
|
|
339
451
|
def call(env)
|
340
|
-
cookie_jar = nil
|
341
452
|
status, headers, body = @app.call(env)
|
342
453
|
|
343
454
|
if cookie_jar = env['action_dispatch.cookies']
|