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.

Files changed (265) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +641 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller.rb +1 -8
  6. data/lib/abstract_controller/asset_paths.rb +2 -2
  7. data/lib/abstract_controller/base.rb +39 -37
  8. data/lib/abstract_controller/callbacks.rb +101 -82
  9. data/lib/abstract_controller/collector.rb +7 -3
  10. data/lib/abstract_controller/helpers.rb +23 -11
  11. data/lib/abstract_controller/layouts.rb +68 -73
  12. data/lib/abstract_controller/logger.rb +1 -2
  13. data/lib/abstract_controller/rendering.rb +22 -13
  14. data/lib/abstract_controller/translation.rb +16 -1
  15. data/lib/abstract_controller/url_for.rb +6 -6
  16. data/lib/abstract_controller/view_paths.rb +1 -1
  17. data/lib/action_controller.rb +15 -6
  18. data/lib/action_controller/base.rb +46 -22
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/caching/fragments.rb +23 -53
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  23. data/lib/action_controller/log_subscriber.rb +11 -8
  24. data/lib/action_controller/metal.rb +16 -30
  25. data/lib/action_controller/metal/conditional_get.rb +76 -32
  26. data/lib/action_controller/metal/data_streaming.rb +20 -26
  27. data/lib/action_controller/metal/exceptions.rb +19 -6
  28. data/lib/action_controller/metal/flash.rb +24 -9
  29. data/lib/action_controller/metal/force_ssl.rb +32 -9
  30. data/lib/action_controller/metal/head.rb +25 -4
  31. data/lib/action_controller/metal/helpers.rb +6 -9
  32. data/lib/action_controller/metal/hide_actions.rb +1 -2
  33. data/lib/action_controller/metal/http_authentication.rb +105 -87
  34. data/lib/action_controller/metal/implicit_render.rb +1 -1
  35. data/lib/action_controller/metal/instrumentation.rb +2 -1
  36. data/lib/action_controller/metal/live.rb +141 -0
  37. data/lib/action_controller/metal/mime_responds.rb +161 -47
  38. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  39. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  40. data/lib/action_controller/metal/redirecting.rb +15 -20
  41. data/lib/action_controller/metal/renderers.rb +11 -9
  42. data/lib/action_controller/metal/rendering.rb +8 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  44. data/lib/action_controller/metal/responder.rb +20 -19
  45. data/lib/action_controller/metal/streaming.rb +12 -18
  46. data/lib/action_controller/metal/strong_parameters.rb +516 -0
  47. data/lib/action_controller/metal/testing.rb +13 -18
  48. data/lib/action_controller/metal/url_for.rb +27 -25
  49. data/lib/action_controller/model_naming.rb +12 -0
  50. data/lib/action_controller/railtie.rb +33 -17
  51. data/lib/action_controller/railties/helpers.rb +22 -0
  52. data/lib/action_controller/record_identifier.rb +18 -72
  53. data/lib/action_controller/test_case.rb +215 -123
  54. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  55. data/lib/action_dispatch.rb +27 -19
  56. data/lib/action_dispatch/http/cache.rb +63 -11
  57. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  59. data/lib/action_dispatch/http/headers.rb +27 -19
  60. data/lib/action_dispatch/http/mime_negotiation.rb +25 -2
  61. data/lib/action_dispatch/http/mime_type.rb +145 -113
  62. data/lib/action_dispatch/http/mime_types.rb +1 -1
  63. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  64. data/lib/action_dispatch/http/parameters.rb +12 -5
  65. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  66. data/lib/action_dispatch/http/request.rb +49 -18
  67. data/lib/action_dispatch/http/response.rb +129 -35
  68. data/lib/action_dispatch/http/upload.rb +60 -17
  69. data/lib/action_dispatch/http/url.rb +53 -31
  70. data/lib/action_dispatch/journey.rb +5 -0
  71. data/lib/action_dispatch/journey/backwards.rb +5 -0
  72. data/lib/action_dispatch/journey/formatter.rb +146 -0
  73. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  74. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  75. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  76. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  77. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  78. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  79. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  80. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  81. data/lib/action_dispatch/journey/parser.rb +206 -0
  82. data/lib/action_dispatch/journey/parser.y +47 -0
  83. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  84. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  85. data/lib/action_dispatch/journey/route.rb +116 -0
  86. data/lib/action_dispatch/journey/router.rb +164 -0
  87. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  88. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  89. data/lib/action_dispatch/journey/routes.rb +75 -0
  90. data/lib/action_dispatch/journey/scanner.rb +61 -0
  91. data/lib/action_dispatch/journey/visitors.rb +189 -0
  92. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  93. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  94. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  95. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  96. data/lib/action_dispatch/middleware/cookies.rb +168 -57
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  98. data/lib/action_dispatch/middleware/exception_wrapper.rb +27 -3
  99. data/lib/action_dispatch/middleware/flash.rb +58 -58
  100. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +31 -14
  102. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  103. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  104. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +81 -7
  108. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  109. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  110. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  111. data/lib/action_dispatch/middleware/stack.rb +6 -1
  112. data/lib/action_dispatch/middleware/static.rb +5 -24
  113. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  114. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
  116. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  117. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  124. data/lib/action_dispatch/railtie.rb +16 -6
  125. data/lib/action_dispatch/request/session.rb +181 -0
  126. data/lib/action_dispatch/routing.rb +41 -40
  127. data/lib/action_dispatch/routing/inspector.rb +240 -0
  128. data/lib/action_dispatch/routing/mapper.rb +501 -273
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  130. data/lib/action_dispatch/routing/redirection.rb +46 -29
  131. data/lib/action_dispatch/routing/route_set.rb +203 -164
  132. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  133. data/lib/action_dispatch/routing/url_for.rb +48 -33
  134. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  135. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  136. data/lib/action_dispatch/testing/assertions/routing.rb +40 -39
  137. data/lib/action_dispatch/testing/assertions/selector.rb +15 -20
  138. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  139. data/lib/action_dispatch/testing/integration.rb +41 -22
  140. data/lib/action_dispatch/testing/test_process.rb +9 -6
  141. data/lib/action_dispatch/testing/test_request.rb +7 -3
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_pack/version.rb +4 -4
  144. data/lib/action_view.rb +17 -8
  145. data/lib/action_view/base.rb +15 -34
  146. data/lib/action_view/buffers.rb +1 -1
  147. data/lib/action_view/context.rb +4 -4
  148. data/lib/action_view/dependency_tracker.rb +91 -0
  149. data/lib/action_view/digestor.rb +85 -0
  150. data/lib/action_view/flows.rb +1 -4
  151. data/lib/action_view/helpers.rb +2 -4
  152. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  153. data/lib/action_view/helpers/asset_tag_helper.rb +211 -353
  154. data/lib/action_view/helpers/asset_url_helper.rb +354 -0
  155. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  156. data/lib/action_view/helpers/cache_helper.rb +150 -18
  157. data/lib/action_view/helpers/capture_helper.rb +42 -29
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  159. data/lib/action_view/helpers/date_helper.rb +268 -247
  160. data/lib/action_view/helpers/debug_helper.rb +10 -11
  161. data/lib/action_view/helpers/form_helper.rb +904 -547
  162. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  163. data/lib/action_view/helpers/form_tag_helper.rb +188 -88
  164. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  165. data/lib/action_view/helpers/number_helper.rb +148 -354
  166. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  167. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  168. data/lib/action_view/helpers/rendering_helper.rb +2 -4
  169. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  170. data/lib/action_view/helpers/tag_helper.rb +43 -37
  171. data/lib/action_view/helpers/tags.rb +39 -0
  172. data/lib/action_view/helpers/tags/base.rb +148 -0
  173. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  174. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  175. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  176. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  177. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  178. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  179. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  180. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  181. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  182. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  183. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  184. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  185. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  186. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  187. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  188. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  189. data/lib/action_view/helpers/tags/label.rb +65 -0
  190. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  191. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  192. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  193. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  194. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  195. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  196. data/lib/action_view/helpers/tags/select.rb +41 -0
  197. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  198. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  199. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  200. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  201. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  202. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  203. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  204. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  205. data/lib/action_view/helpers/text_helper.rb +126 -113
  206. data/lib/action_view/helpers/translation_helper.rb +32 -16
  207. data/lib/action_view/helpers/url_helper.rb +200 -271
  208. data/lib/action_view/locale/en.yml +1 -105
  209. data/lib/action_view/log_subscriber.rb +6 -4
  210. data/lib/action_view/lookup_context.rb +15 -39
  211. data/lib/action_view/model_naming.rb +12 -0
  212. data/lib/action_view/path_set.rb +9 -39
  213. data/lib/action_view/railtie.rb +6 -22
  214. data/lib/action_view/record_identifier.rb +84 -0
  215. data/lib/action_view/renderer/abstract_renderer.rb +10 -19
  216. data/lib/action_view/renderer/partial_renderer.rb +144 -81
  217. data/lib/action_view/renderer/renderer.rb +2 -19
  218. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  219. data/lib/action_view/renderer/template_renderer.rb +14 -13
  220. data/lib/action_view/routing_url_for.rb +107 -0
  221. data/lib/action_view/template.rb +22 -21
  222. data/lib/action_view/template/error.rb +22 -12
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/handlers/builder.rb +1 -1
  225. data/lib/action_view/template/handlers/erb.rb +11 -16
  226. data/lib/action_view/template/handlers/raw.rb +11 -0
  227. data/lib/action_view/template/resolver.rb +111 -83
  228. data/lib/action_view/template/text.rb +12 -8
  229. data/lib/action_view/template/types.rb +57 -0
  230. data/lib/action_view/test_case.rb +66 -43
  231. data/lib/action_view/testing/resolvers.rb +3 -2
  232. data/lib/action_view/vendor/html-scanner.rb +20 -0
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  235. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +18 -7
  236. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +1 -1
  237. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  238. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  239. metadata +135 -125
  240. data/lib/action_controller/caching/actions.rb +0 -185
  241. data/lib/action_controller/caching/pages.rb +0 -187
  242. data/lib/action_controller/caching/sweeping.rb +0 -97
  243. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  244. data/lib/action_controller/metal/compatibility.rb +0 -65
  245. data/lib/action_controller/metal/session_management.rb +0 -14
  246. data/lib/action_controller/railties/paths.rb +0 -25
  247. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  248. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  249. data/lib/action_dispatch/middleware/head.rb +0 -18
  250. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  251. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  252. data/lib/action_view/asset_paths.rb +0 -142
  253. data/lib/action_view/helpers/asset_paths.rb +0 -7
  254. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  255. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  256. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  257. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  258. data/lib/sprockets/assets.rake +0 -99
  259. data/lib/sprockets/bootstrap.rb +0 -37
  260. data/lib/sprockets/compressors.rb +0 -83
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  263. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  264. data/lib/sprockets/railtie.rb +0 -62
  265. 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, :rescuable => true
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
- run_callbacks :call do
28
- @app.call(env)
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 for writing:
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] = { :value => "XJ-122", :expires => 1.hour.from_now }
29
+ # cookies[:login] = { value: "XJ-122", expires: 1.hour.from_now }
29
30
  #
30
- # # Sets a signed cookie, which prevents a user from tampering with its value.
31
- # # The cookie is signed by your app's <tt>config.secret_token</tt> value.
32
- # # Rails generates this value by default when you create a new Rails app.
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 for reading:
42
+ # Examples of reading:
42
43
  #
43
- # cookies[:user_name] # => "david"
44
- # cookies.size # => 2
45
- # cookies[:lat_lon] # => [47.68, -122.37]
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
- # :value => 'a yummy cookie',
55
- # :expires => 1.year.from_now,
56
- # :domain => 'domain.com'
56
+ # value: 'a yummy cookie',
57
+ # expires: 1.year.from_now,
58
+ # domain: 'domain.com'
57
59
  # }
58
60
  #
59
- # cookies.delete(:key, :domain => 'domain.com')
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
- # :domain => nil # Does not sets cookie domain. (default)
73
- # :domain => :all # Allow the cookie for the top most level
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 = "Set-Cookie".freeze
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
- class CookieOverflow < StandardError; end
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
- secret = request.env[TOKEN_KEY]
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(secret, host, secure).tap do |hash|
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(secret = nil, host = nil, secure = false)
116
- @secret = secret
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
- @closed = false
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[/^\.?(.*)$/, 1] }
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
- options.symbolize_keys!
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, @secret)
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.secret_token.
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, @secret)
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 < CookieJar #:nodoc:
255
- def initialize(parent_jar, secret)
256
- @parent_jar, @secret = parent_jar, secret
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, @secret)
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
- @parent_jar.send(method, *arguments, &block)
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 < CookieJar #:nodoc:
280
- MAX_COOKIE_SIZE = 4096 # Cookies can typically store 4096 bytes.
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
- @parent_jar.send(method, *arguments, &block)
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
- protected
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
- # To prevent users from using something insecure like "Password" we make sure that the
316
- # secret they've provided is at least 30 characters in length.
317
- def ensure_secret_secure(secret)
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
- if secret.length < SECRET_MIN_LENGTH
327
- raise ArgumentError, "Secret should be something secure, " +
328
- "like \"#{SecureRandom.hex(16)}\". The value you " +
329
- "provided, \"#{secret}\", is shorter than the minimum length " +
330
- "of #{SECRET_MIN_LENGTH} characters"
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']