actionpack 4.0.1 → 4.2.11.1
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 +5 -5
- data/CHANGELOG.md +402 -1173
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -7
- data/lib/abstract_controller/base.rb +39 -7
- data/lib/abstract_controller/callbacks.rb +32 -53
- data/lib/abstract_controller/collector.rb +11 -1
- data/lib/abstract_controller/helpers.rb +26 -16
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
- data/lib/abstract_controller/rendering.rb +57 -127
- data/lib/abstract_controller/url_for.rb +1 -1
- data/lib/abstract_controller.rb +1 -2
- data/lib/action_controller/base.rb +19 -10
- data/lib/action_controller/caching/fragments.rb +7 -1
- data/lib/action_controller/caching.rb +2 -12
- data/lib/action_controller/log_subscriber.rb +29 -20
- data/lib/action_controller/metal/conditional_get.rb +37 -12
- data/lib/action_controller/metal/data_streaming.rb +1 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
- data/lib/action_controller/metal/exceptions.rb +1 -1
- data/lib/action_controller/metal/flash.rb +17 -0
- data/lib/action_controller/metal/force_ssl.rb +2 -2
- data/lib/action_controller/metal/head.rb +8 -6
- data/lib/action_controller/metal/helpers.rb +6 -2
- data/lib/action_controller/metal/http_authentication.rb +45 -23
- data/lib/action_controller/metal/instrumentation.rb +9 -6
- data/lib/action_controller/metal/live.rb +173 -20
- data/lib/action_controller/metal/mime_responds.rb +127 -232
- data/lib/action_controller/metal/params_wrapper.rb +16 -9
- data/lib/action_controller/metal/rack_delegation.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +34 -26
- data/lib/action_controller/metal/renderers.rb +39 -12
- data/lib/action_controller/metal/rendering.rb +41 -14
- data/lib/action_controller/metal/request_forgery_protection.rb +147 -19
- data/lib/action_controller/metal/streaming.rb +19 -21
- data/lib/action_controller/metal/strong_parameters.rb +166 -22
- data/lib/action_controller/metal/testing.rb +0 -1
- data/lib/action_controller/metal/url_for.rb +11 -12
- data/lib/action_controller/metal.rb +14 -8
- data/lib/action_controller/model_naming.rb +1 -1
- data/lib/action_controller/railtie.rb +5 -1
- data/lib/action_controller/test_case.rb +160 -94
- data/lib/action_controller.rb +2 -18
- data/lib/action_dispatch/http/cache.rb +5 -4
- data/lib/action_dispatch/http/filter_parameters.rb +2 -2
- data/lib/action_dispatch/http/filter_redirect.rb +5 -4
- data/lib/action_dispatch/http/headers.rb +46 -10
- data/lib/action_dispatch/http/mime_negotiation.rb +31 -4
- data/lib/action_dispatch/http/mime_type.rb +25 -26
- data/lib/action_dispatch/http/mime_types.rb +1 -0
- data/lib/action_dispatch/http/parameter_filter.rb +1 -1
- data/lib/action_dispatch/http/parameters.rb +25 -41
- data/lib/action_dispatch/http/request.rb +49 -32
- data/lib/action_dispatch/http/response.rb +127 -25
- data/lib/action_dispatch/http/upload.rb +9 -21
- data/lib/action_dispatch/http/url.rb +97 -70
- data/lib/action_dispatch/journey/formatter.rb +35 -19
- data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -33
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
- data/lib/action_dispatch/journey/nodes/node.rb +4 -0
- data/lib/action_dispatch/journey/parser.rb +51 -59
- data/lib/action_dispatch/journey/parser.y +12 -10
- data/lib/action_dispatch/journey/path/pattern.rb +16 -19
- data/lib/action_dispatch/journey/route.rb +8 -19
- data/lib/action_dispatch/journey/router/strexp.rb +9 -6
- data/lib/action_dispatch/journey/router/utils.rb +54 -18
- data/lib/action_dispatch/journey/router.rb +53 -75
- data/lib/action_dispatch/journey/routes.rb +4 -0
- data/lib/action_dispatch/journey/scanner.rb +5 -5
- data/lib/action_dispatch/journey/visitors.rb +81 -60
- data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
- data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
- data/lib/action_dispatch/middleware/callbacks.rb +7 -7
- data/lib/action_dispatch/middleware/cookies.rb +119 -43
- data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -13
- data/lib/action_dispatch/middleware/exception_wrapper.rb +60 -20
- data/lib/action_dispatch/middleware/flash.rb +37 -24
- data/lib/action_dispatch/middleware/params_parser.rb +2 -2
- data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
- data/lib/action_dispatch/middleware/reloader.rb +11 -2
- data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +8 -7
- data/lib/action_dispatch/middleware/show_exceptions.rb +6 -2
- data/lib/action_dispatch/middleware/ssl.rb +10 -7
- data/lib/action_dispatch/middleware/static.rb +79 -23
- data/lib/action_dispatch/middleware/templates/rescues/{_request_and_response.erb → _request_and_response.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/{routing_error.erb → routing_error.html.erb} +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/{unknown_action.erb → unknown_action.html.erb} +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
- data/lib/action_dispatch/railtie.rb +5 -2
- data/lib/action_dispatch/request/session.rb +12 -0
- data/lib/action_dispatch/request/utils.rb +35 -0
- data/lib/action_dispatch/routing/endpoint.rb +10 -0
- data/lib/action_dispatch/routing/inspector.rb +11 -17
- data/lib/action_dispatch/routing/mapper.rb +519 -312
- data/lib/action_dispatch/routing/polymorphic_routes.rb +204 -79
- data/lib/action_dispatch/routing/redirection.rb +51 -26
- data/lib/action_dispatch/routing/route_set.rb +331 -206
- data/lib/action_dispatch/routing/routes_proxy.rb +5 -4
- data/lib/action_dispatch/routing/url_for.rb +19 -5
- data/lib/action_dispatch/routing.rb +9 -6
- data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
- data/lib/action_dispatch/testing/assertions/response.rb +9 -15
- data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
- data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
- data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
- data/lib/action_dispatch/testing/assertions.rb +11 -7
- data/lib/action_dispatch/testing/integration.rb +31 -29
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +1 -5
- data/lib/action_dispatch.rb +5 -8
- data/lib/action_pack/gem_version.rb +15 -0
- data/lib/action_pack/version.rb +4 -7
- data/lib/action_pack.rb +1 -1
- metadata +77 -159
- data/lib/abstract_controller/layouts.rb +0 -423
- data/lib/abstract_controller/view_paths.rb +0 -96
- data/lib/action_controller/deprecated/integration_test.rb +0 -5
- data/lib/action_controller/deprecated.rb +0 -7
- data/lib/action_controller/metal/responder.rb +0 -287
- data/lib/action_controller/record_identifier.rb +0 -31
- data/lib/action_controller/vendor/html-scanner.rb +0 -5
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -24
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -7
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -43
- data/lib/action_view/base.rb +0 -201
- data/lib/action_view/buffers.rb +0 -49
- data/lib/action_view/context.rb +0 -36
- data/lib/action_view/dependency_tracker.rb +0 -93
- data/lib/action_view/digestor.rb +0 -113
- data/lib/action_view/flows.rb +0 -76
- data/lib/action_view/helpers/active_model_helper.rb +0 -49
- data/lib/action_view/helpers/asset_tag_helper.rb +0 -320
- data/lib/action_view/helpers/asset_url_helper.rb +0 -355
- data/lib/action_view/helpers/atom_feed_helper.rb +0 -203
- data/lib/action_view/helpers/cache_helper.rb +0 -196
- data/lib/action_view/helpers/capture_helper.rb +0 -216
- data/lib/action_view/helpers/controller_helper.rb +0 -25
- data/lib/action_view/helpers/csrf_helper.rb +0 -30
- data/lib/action_view/helpers/date_helper.rb +0 -1083
- data/lib/action_view/helpers/debug_helper.rb +0 -39
- data/lib/action_view/helpers/form_helper.rb +0 -1880
- data/lib/action_view/helpers/form_options_helper.rb +0 -838
- data/lib/action_view/helpers/form_tag_helper.rb +0 -785
- data/lib/action_view/helpers/javascript_helper.rb +0 -117
- data/lib/action_view/helpers/number_helper.rb +0 -441
- data/lib/action_view/helpers/output_safety_helper.rb +0 -38
- data/lib/action_view/helpers/record_tag_helper.rb +0 -106
- data/lib/action_view/helpers/rendering_helper.rb +0 -90
- data/lib/action_view/helpers/sanitize_helper.rb +0 -256
- data/lib/action_view/helpers/tag_helper.rb +0 -173
- data/lib/action_view/helpers/tags/base.rb +0 -148
- data/lib/action_view/helpers/tags/check_box.rb +0 -64
- data/lib/action_view/helpers/tags/checkable.rb +0 -16
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -44
- data/lib/action_view/helpers/tags/collection_helpers.rb +0 -84
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -36
- data/lib/action_view/helpers/tags/collection_select.rb +0 -28
- data/lib/action_view/helpers/tags/color_field.rb +0 -25
- data/lib/action_view/helpers/tags/date_field.rb +0 -13
- data/lib/action_view/helpers/tags/date_select.rb +0 -72
- data/lib/action_view/helpers/tags/datetime_field.rb +0 -22
- data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -19
- data/lib/action_view/helpers/tags/datetime_select.rb +0 -8
- data/lib/action_view/helpers/tags/email_field.rb +0 -8
- data/lib/action_view/helpers/tags/file_field.rb +0 -8
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +0 -29
- data/lib/action_view/helpers/tags/hidden_field.rb +0 -8
- data/lib/action_view/helpers/tags/label.rb +0 -66
- data/lib/action_view/helpers/tags/month_field.rb +0 -13
- data/lib/action_view/helpers/tags/number_field.rb +0 -18
- data/lib/action_view/helpers/tags/password_field.rb +0 -12
- data/lib/action_view/helpers/tags/radio_button.rb +0 -31
- data/lib/action_view/helpers/tags/range_field.rb +0 -8
- data/lib/action_view/helpers/tags/search_field.rb +0 -24
- data/lib/action_view/helpers/tags/select.rb +0 -40
- data/lib/action_view/helpers/tags/tel_field.rb +0 -8
- data/lib/action_view/helpers/tags/text_area.rb +0 -18
- data/lib/action_view/helpers/tags/text_field.rb +0 -29
- data/lib/action_view/helpers/tags/time_field.rb +0 -13
- data/lib/action_view/helpers/tags/time_select.rb +0 -8
- data/lib/action_view/helpers/tags/time_zone_select.rb +0 -20
- data/lib/action_view/helpers/tags/url_field.rb +0 -8
- data/lib/action_view/helpers/tags/week_field.rb +0 -13
- data/lib/action_view/helpers/tags.rb +0 -39
- data/lib/action_view/helpers/text_helper.rb +0 -443
- data/lib/action_view/helpers/translation_helper.rb +0 -107
- data/lib/action_view/helpers/url_helper.rb +0 -635
- data/lib/action_view/helpers.rb +0 -58
- data/lib/action_view/locale/en.yml +0 -56
- data/lib/action_view/log_subscriber.rb +0 -30
- data/lib/action_view/lookup_context.rb +0 -241
- data/lib/action_view/model_naming.rb +0 -12
- data/lib/action_view/path_set.rb +0 -77
- data/lib/action_view/railtie.rb +0 -43
- data/lib/action_view/record_identifier.rb +0 -84
- data/lib/action_view/renderer/abstract_renderer.rb +0 -47
- data/lib/action_view/renderer/partial_renderer.rb +0 -492
- data/lib/action_view/renderer/renderer.rb +0 -50
- data/lib/action_view/renderer/streaming_template_renderer.rb +0 -103
- data/lib/action_view/renderer/template_renderer.rb +0 -96
- data/lib/action_view/routing_url_for.rb +0 -107
- data/lib/action_view/tasks/dependencies.rake +0 -17
- data/lib/action_view/template/error.rb +0 -138
- data/lib/action_view/template/handlers/builder.rb +0 -26
- data/lib/action_view/template/handlers/erb.rb +0 -146
- data/lib/action_view/template/handlers/raw.rb +0 -11
- data/lib/action_view/template/handlers.rb +0 -53
- data/lib/action_view/template/resolver.rb +0 -326
- data/lib/action_view/template/text.rb +0 -34
- data/lib/action_view/template/types.rb +0 -57
- data/lib/action_view/template.rb +0 -339
- data/lib/action_view/test_case.rb +0 -270
- data/lib/action_view/testing/resolvers.rb +0 -50
- data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
- data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
- data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
- data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
- data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
- data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
- data/lib/action_view/vendor/html-scanner.rb +0 -20
- data/lib/action_view.rb +0 -93
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/hash/keys'
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
class Request < Rack::Request
|
3
5
|
# Access the contents of the flash. Use <tt>flash["notice"]</tt> to
|
@@ -8,7 +10,7 @@ module ActionDispatch
|
|
8
10
|
end
|
9
11
|
end
|
10
12
|
|
11
|
-
# The flash provides a way to pass temporary
|
13
|
+
# The flash provides a way to pass temporary primitive-types (String, Array, Hash) between actions. Anything you place in the flash will be exposed
|
12
14
|
# to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create
|
13
15
|
# action that sets <tt>flash[:notice] = "Post successfully created"</tt> before redirecting to a display action that can
|
14
16
|
# then expose the flash to its template. Actually, that exposure is automatically done.
|
@@ -35,8 +37,11 @@ module ActionDispatch
|
|
35
37
|
# flash.alert = "You must be logged in"
|
36
38
|
# flash.notice = "Post successfully created"
|
37
39
|
#
|
38
|
-
# This example
|
39
|
-
#
|
40
|
+
# This example places a string in the flash. And of course, you can put as many as you like at a time too. If you want to pass
|
41
|
+
# non-primitive types, you will have to handle that in your application. Example: To show messages with links, you will have to
|
42
|
+
# use sanitize helper.
|
43
|
+
#
|
44
|
+
# Just remember: They'll be gone by the time the next action has been performed.
|
40
45
|
#
|
41
46
|
# See docs on the FlashHash class for more details about the flash.
|
42
47
|
class Flash
|
@@ -50,13 +55,14 @@ module ActionDispatch
|
|
50
55
|
end
|
51
56
|
|
52
57
|
def []=(k, v)
|
58
|
+
k = k.to_s
|
53
59
|
@flash[k] = v
|
54
60
|
@flash.discard(k)
|
55
61
|
v
|
56
62
|
end
|
57
63
|
|
58
64
|
def [](k)
|
59
|
-
@flash[k]
|
65
|
+
@flash[k.to_s]
|
60
66
|
end
|
61
67
|
|
62
68
|
# Convenience accessor for <tt>flash.now[:alert]=</tt>.
|
@@ -73,7 +79,7 @@ module ActionDispatch
|
|
73
79
|
class FlashHash
|
74
80
|
include Enumerable
|
75
81
|
|
76
|
-
def self.from_session_value(value)
|
82
|
+
def self.from_session_value(value) #:nodoc:
|
77
83
|
flash = case value
|
78
84
|
when FlashHash # Rails 3.1, 3.2
|
79
85
|
new(value.instance_variable_get(:@flashes), value.instance_variable_get(:@used))
|
@@ -85,15 +91,18 @@ module ActionDispatch
|
|
85
91
|
|
86
92
|
flash.tap(&:sweep)
|
87
93
|
end
|
88
|
-
|
89
|
-
|
94
|
+
|
95
|
+
# Builds a hash containing the discarded values and the hashes
|
96
|
+
# representing the flashes.
|
97
|
+
# If there are no values in @flashes, returns nil.
|
98
|
+
def to_session_value #:nodoc:
|
90
99
|
return nil if empty?
|
91
100
|
{'discard' => @discard.to_a, 'flashes' => @flashes}
|
92
101
|
end
|
93
102
|
|
94
103
|
def initialize(flashes = {}, discard = []) #:nodoc:
|
95
|
-
@discard = Set.new(discard)
|
96
|
-
@flashes = flashes
|
104
|
+
@discard = Set.new(stringify_array(discard))
|
105
|
+
@flashes = flashes.stringify_keys
|
97
106
|
@now = nil
|
98
107
|
end
|
99
108
|
|
@@ -106,17 +115,18 @@ module ActionDispatch
|
|
106
115
|
end
|
107
116
|
|
108
117
|
def []=(k, v)
|
118
|
+
k = k.to_s
|
109
119
|
@discard.delete k
|
110
120
|
@flashes[k] = v
|
111
121
|
end
|
112
122
|
|
113
123
|
def [](k)
|
114
|
-
@flashes[k]
|
124
|
+
@flashes[k.to_s]
|
115
125
|
end
|
116
126
|
|
117
127
|
def update(h) #:nodoc:
|
118
|
-
@discard.subtract h.keys
|
119
|
-
@flashes.update h
|
128
|
+
@discard.subtract stringify_array(h.keys)
|
129
|
+
@flashes.update h.stringify_keys
|
120
130
|
self
|
121
131
|
end
|
122
132
|
|
@@ -125,10 +135,11 @@ module ActionDispatch
|
|
125
135
|
end
|
126
136
|
|
127
137
|
def key?(name)
|
128
|
-
@flashes.key? name
|
138
|
+
@flashes.key? name.to_s
|
129
139
|
end
|
130
140
|
|
131
141
|
def delete(key)
|
142
|
+
key = key.to_s
|
132
143
|
@discard.delete key
|
133
144
|
@flashes.delete key
|
134
145
|
self
|
@@ -155,7 +166,7 @@ module ActionDispatch
|
|
155
166
|
|
156
167
|
def replace(h) #:nodoc:
|
157
168
|
@discard.clear
|
158
|
-
@flashes.replace h
|
169
|
+
@flashes.replace h.stringify_keys
|
159
170
|
self
|
160
171
|
end
|
161
172
|
|
@@ -186,6 +197,7 @@ module ActionDispatch
|
|
186
197
|
# flash.keep # keeps the entire flash
|
187
198
|
# flash.keep(:notice) # keeps only the "notice" entry, the rest of the flash is discarded
|
188
199
|
def keep(k = nil)
|
200
|
+
k = k.to_s if k
|
189
201
|
@discard.subtract Array(k || keys)
|
190
202
|
k ? self[k] : self
|
191
203
|
end
|
@@ -195,6 +207,7 @@ module ActionDispatch
|
|
195
207
|
# flash.discard # discard the entire flash at the end of the current action
|
196
208
|
# flash.discard(:warning) # discard only the "warning" entry at the end of the current action
|
197
209
|
def discard(k = nil)
|
210
|
+
k = k.to_s if k
|
198
211
|
@discard.merge Array(k || keys)
|
199
212
|
k ? self[k] : self
|
200
213
|
end
|
@@ -231,6 +244,12 @@ module ActionDispatch
|
|
231
244
|
def now_is_loaded?
|
232
245
|
@now
|
233
246
|
end
|
247
|
+
|
248
|
+
def stringify_array(array)
|
249
|
+
array.map do |item|
|
250
|
+
item.kind_of?(Symbol) ? item.to_s : item
|
251
|
+
end
|
252
|
+
end
|
234
253
|
end
|
235
254
|
|
236
255
|
def initialize(app)
|
@@ -243,19 +262,13 @@ module ActionDispatch
|
|
243
262
|
session = Request::Session.find(env) || {}
|
244
263
|
flash_hash = env[KEY]
|
245
264
|
|
246
|
-
if flash_hash
|
247
|
-
|
248
|
-
|
249
|
-
new_hash = flash_hash.dup
|
250
|
-
else
|
251
|
-
new_hash = flash_hash
|
252
|
-
end
|
253
|
-
|
254
|
-
env[KEY] = new_hash
|
265
|
+
if flash_hash && (flash_hash.present? || session.key?('flash'))
|
266
|
+
session["flash"] = flash_hash.to_session_value
|
267
|
+
env[KEY] = flash_hash.dup
|
255
268
|
end
|
256
269
|
|
257
270
|
if (!session.respond_to?(:loaded?) || session.loaded?) && # (reset_session uses {}, which doesn't implement #loaded?)
|
258
|
-
|
271
|
+
session.key?('flash') && session['flash'].nil?
|
259
272
|
session.delete('flash')
|
260
273
|
end
|
261
274
|
end
|
@@ -43,11 +43,11 @@ module ActionDispatch
|
|
43
43
|
when :json
|
44
44
|
data = ActiveSupport::JSON.decode(request.raw_post)
|
45
45
|
data = {:_json => data} unless data.is_a?(Hash)
|
46
|
-
|
46
|
+
Request::Utils.deep_munge(data).with_indifferent_access
|
47
47
|
else
|
48
48
|
false
|
49
49
|
end
|
50
|
-
rescue
|
50
|
+
rescue => e # JSON or Ruby code block errors
|
51
51
|
logger(env).debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
|
52
52
|
|
53
53
|
raise ParseError.new(e.message, e)
|
@@ -1,4 +1,14 @@
|
|
1
1
|
module ActionDispatch
|
2
|
+
# When called, this middleware renders an error page. By default if an HTML
|
3
|
+
# response is expected it will render static error pages from the `/public`
|
4
|
+
# directory. For example when this middleware receives a 500 response it will
|
5
|
+
# render the template found in `/public/500.html`.
|
6
|
+
# If an internationalized locale is set, this middleware will attempt to render
|
7
|
+
# the template in `/public/500.<locale>.html`. If an internationalized template
|
8
|
+
# is not found it will fall back on `/public/500.html`.
|
9
|
+
#
|
10
|
+
# When a request with a content type other than HTML is made, this middleware
|
11
|
+
# will attempt to convert error information into the appropriate response type.
|
2
12
|
class PublicExceptions
|
3
13
|
attr_accessor :public_path
|
4
14
|
|
@@ -32,9 +42,8 @@ module ActionDispatch
|
|
32
42
|
end
|
33
43
|
|
34
44
|
def render_html(status)
|
35
|
-
|
36
|
-
path = "#{public_path}/#{status}
|
37
|
-
path = "#{public_path}/#{status}.html" unless path && (found = File.exist?(path))
|
45
|
+
path = "#{public_path}/#{status}.#{I18n.locale}.html"
|
46
|
+
path = "#{public_path}/#{status}.html" unless (found = File.exist?(path))
|
38
47
|
|
39
48
|
if found || File.exist?(path)
|
40
49
|
render_format(status, 'text/html', File.read(path))
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/deprecation/reporting'
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
# ActionDispatch::Reloader provides prepare and cleanup callbacks,
|
3
5
|
# intended to assist with code reloading during development.
|
@@ -25,19 +27,26 @@ module ActionDispatch
|
|
25
27
|
#
|
26
28
|
class Reloader
|
27
29
|
include ActiveSupport::Callbacks
|
30
|
+
include ActiveSupport::Deprecation::Reporting
|
28
31
|
|
29
|
-
define_callbacks :prepare
|
30
|
-
define_callbacks :cleanup
|
32
|
+
define_callbacks :prepare
|
33
|
+
define_callbacks :cleanup
|
31
34
|
|
32
35
|
# Add a prepare callback. Prepare callbacks are run before each request, prior
|
33
36
|
# to ActionDispatch::Callback's before callbacks.
|
34
37
|
def self.to_prepare(*args, &block)
|
38
|
+
unless block_given?
|
39
|
+
warn "to_prepare without a block is deprecated. Please use a block"
|
40
|
+
end
|
35
41
|
set_callback(:prepare, *args, &block)
|
36
42
|
end
|
37
43
|
|
38
44
|
# Add a cleanup callback. Cleanup callbacks are run after each request is
|
39
45
|
# complete (after #close is called on the response body).
|
40
46
|
def self.to_cleanup(*args, &block)
|
47
|
+
unless block_given?
|
48
|
+
warn "to_cleanup without a block is deprecated. Please use a block"
|
49
|
+
end
|
41
50
|
set_callback(:cleanup, *args, &block)
|
42
51
|
end
|
43
52
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
# This middleware calculates the IP address of the remote client that is
|
3
5
|
# making the request. It does this by checking various headers that could
|
@@ -11,7 +13,7 @@ module ActionDispatch
|
|
11
13
|
# Some Rack servers concatenate repeated headers, like {HTTP RFC 2616}[http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2]
|
12
14
|
# requires. Some Rack servers simply drop preceding headers, and only report
|
13
15
|
# the value that was {given in the last header}[http://andre.arko.net/2011/12/26/repeated-headers-and-ruby-web-servers].
|
14
|
-
# If you are behind multiple proxy servers (like
|
16
|
+
# If you are behind multiple proxy servers (like NGINX to HAProxy to Unicorn)
|
15
17
|
# then you should test your Rack server to make sure your data is good.
|
16
18
|
#
|
17
19
|
# IF YOU DON'T USE A PROXY, THIS MAKES YOU VULNERABLE TO IP SPOOFING.
|
@@ -28,14 +30,14 @@ module ActionDispatch
|
|
28
30
|
# guaranteed by the IP specification to be private addresses. Those will
|
29
31
|
# not be the ultimate client IP in production, and so are discarded. See
|
30
32
|
# http://en.wikipedia.org/wiki/Private_network for details.
|
31
|
-
TRUSTED_PROXIES =
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
}
|
33
|
+
TRUSTED_PROXIES = [
|
34
|
+
"127.0.0.1", # localhost IPv4
|
35
|
+
"::1", # localhost IPv6
|
36
|
+
"fc00::/7", # private IPv6 range fc00::/7
|
37
|
+
"10.0.0.0/8", # private IPv4 range 10.x.x.x
|
38
|
+
"172.16.0.0/12", # private IPv4 range 172.16.0.0 .. 172.31.255.255
|
39
|
+
"192.168.0.0/16", # private IPv4 range 192.168.x.x
|
40
|
+
].map { |proxy| IPAddr.new(proxy) }
|
39
41
|
|
40
42
|
attr_reader :check_ip, :proxies
|
41
43
|
|
@@ -47,24 +49,24 @@ module ActionDispatch
|
|
47
49
|
# clients (like WAP devices), or behind proxies that set headers in an
|
48
50
|
# incorrect or confusing way (like AWS ELB).
|
49
51
|
#
|
50
|
-
# The +
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
52
|
+
# The +custom_proxies+ argument can take an Array of string, IPAddr, or
|
53
|
+
# Regexp objects which will be used instead of +TRUSTED_PROXIES+. If a
|
54
|
+
# single string, IPAddr, or Regexp object is provided, it will be used in
|
55
|
+
# addition to +TRUSTED_PROXIES+. Any proxy setup will put the value you
|
56
|
+
# want in the middle (or at the beginning) of the X-Forwarded-For list,
|
57
|
+
# with your proxy servers after it. If your proxies aren't removed, pass
|
58
|
+
# them in via the +custom_proxies+ parameter. That way, the middleware will
|
59
|
+
# ignore those IP addresses, and return the one that you want.
|
57
60
|
def initialize(app, check_ip_spoofing = true, custom_proxies = nil)
|
58
61
|
@app = app
|
59
62
|
@check_ip = check_ip_spoofing
|
60
|
-
@proxies =
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
63
|
+
@proxies = if custom_proxies.blank?
|
64
|
+
TRUSTED_PROXIES
|
65
|
+
elsif custom_proxies.respond_to?(:any?)
|
66
|
+
custom_proxies
|
67
|
+
else
|
68
|
+
Array(custom_proxies) + TRUSTED_PROXIES
|
69
|
+
end
|
68
70
|
end
|
69
71
|
|
70
72
|
# Since the IP address may not be needed, we store the object here
|
@@ -80,32 +82,6 @@ module ActionDispatch
|
|
80
82
|
# into an actual IP address. If the ActionDispatch::Request#remote_ip method
|
81
83
|
# is called, this class will calculate the value and then memoize it.
|
82
84
|
class GetIp
|
83
|
-
|
84
|
-
# This constant contains a regular expression that validates every known
|
85
|
-
# form of IP v4 and v6 address, with or without abbreviations, adapted
|
86
|
-
# from {this gist}[https://gist.github.com/gazay/1289635].
|
87
|
-
VALID_IP = %r{
|
88
|
-
(^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9]{1,2})){3}$) | # ip v4
|
89
|
-
(^(
|
90
|
-
(([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}) | # ip v6 not abbreviated
|
91
|
-
(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4}) | # ip v6 with double colon in the end
|
92
|
-
(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4}) | # - ip addresses v6
|
93
|
-
(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4}) | # - with
|
94
|
-
(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4}) | # - double colon
|
95
|
-
(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4}) | # - in the middle
|
96
|
-
(([0-9A-Fa-f]{1,4}:){6} ((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3} (\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
|
97
|
-
(([0-9A-Fa-f]{1,4}:){1,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
|
98
|
-
(([0-9A-Fa-f]{1,4}:){1}:([0-9A-Fa-f]{1,4}:){0,4}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
|
99
|
-
(([0-9A-Fa-f]{1,4}:){0,2}:([0-9A-Fa-f]{1,4}:){0,3}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
|
100
|
-
(([0-9A-Fa-f]{1,4}:){0,3}:([0-9A-Fa-f]{1,4}:){0,2}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
|
101
|
-
(([0-9A-Fa-f]{1,4}:){0,4}:([0-9A-Fa-f]{1,4}:){1}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
|
102
|
-
(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d) |(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)) | # ip v6 with compatible to v4
|
103
|
-
([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4}) | # ip v6 with compatible to v4
|
104
|
-
(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4}) | # ip v6 with double colon at the beginning
|
105
|
-
(([0-9A-Fa-f]{1,4}:){1,7}:) # ip v6 without ending
|
106
|
-
)$)
|
107
|
-
}x
|
108
|
-
|
109
85
|
def initialize(env, middleware)
|
110
86
|
@env = env
|
111
87
|
@check_ip = middleware.check_ip
|
@@ -118,7 +94,7 @@ module ActionDispatch
|
|
118
94
|
#
|
119
95
|
# REMOTE_ADDR will be correct if the request is made directly against the
|
120
96
|
# Ruby process, on e.g. Heroku. When the request is proxied by another
|
121
|
-
# server like HAProxy or
|
97
|
+
# server like HAProxy or NGINX, the IP address that made the original
|
122
98
|
# request will be put in an X-Forwarded-For header. If there are multiple
|
123
99
|
# proxies, that header may contain a list of IPs. Other proxy services
|
124
100
|
# set the Client-Ip header instead, so we check that too.
|
@@ -173,12 +149,22 @@ module ActionDispatch
|
|
173
149
|
def ips_from(header)
|
174
150
|
# Split the comma-separated list into an array of strings
|
175
151
|
ips = @env[header] ? @env[header].strip.split(/[,\s]+/) : []
|
176
|
-
|
177
|
-
|
152
|
+
ips.select do |ip|
|
153
|
+
begin
|
154
|
+
# Only return IPs that are valid according to the IPAddr#new method
|
155
|
+
range = IPAddr.new(ip).to_range
|
156
|
+
# we want to make sure nobody is sneaking a netmask in
|
157
|
+
range.begin == range.end
|
158
|
+
rescue ArgumentError
|
159
|
+
nil
|
160
|
+
end
|
161
|
+
end
|
178
162
|
end
|
179
163
|
|
180
164
|
def filter_proxies(ips)
|
181
|
-
ips.reject
|
165
|
+
ips.reject do |ip|
|
166
|
+
@proxies.any? { |proxy| proxy === ip }
|
167
|
+
end
|
182
168
|
end
|
183
169
|
|
184
170
|
end
|
@@ -5,7 +5,7 @@ module ActionDispatch
|
|
5
5
|
# Makes a unique request id available to the action_dispatch.request_id env variable (which is then accessible through
|
6
6
|
# ActionDispatch::Request#uuid) and sends the same id to the client via the X-Request-Id header.
|
7
7
|
#
|
8
|
-
# The unique request id is either based
|
8
|
+
# The unique request id is either based on the X-Request-Id header in the request, which would typically be generated
|
9
9
|
# by a firewall, load balancer, or the web server, or, if this header is not available, a random uuid. If the
|
10
10
|
# header is accepted from the outside world, we sanitize it to a max of 255 chars and alphanumeric and dashes only.
|
11
11
|
#
|
@@ -16,9 +16,9 @@ module ActionDispatch
|
|
16
16
|
|
17
17
|
# Get a session from the cache.
|
18
18
|
def get_session(env, sid)
|
19
|
-
sid
|
20
|
-
|
21
|
-
|
19
|
+
unless sid and session = @cache.read(cache_key(sid))
|
20
|
+
sid, session = generate_sid, {}
|
21
|
+
end
|
22
22
|
[sid, session]
|
23
23
|
end
|
24
24
|
|
@@ -15,8 +15,8 @@ module ActionDispatch
|
|
15
15
|
# best possible option given your application's configuration.
|
16
16
|
#
|
17
17
|
# If you only have secret_token set, your cookies will be signed, but
|
18
|
-
# not encrypted. This means a user cannot alter
|
19
|
-
# knowing your app's secret key, but can easily read
|
18
|
+
# not encrypted. This means a user cannot alter their +user_id+ without
|
19
|
+
# knowing your app's secret key, but can easily read their +user_id+. This
|
20
20
|
# was the default for Rails 3 apps.
|
21
21
|
#
|
22
22
|
# If you have secret_key_base set, your cookies will be encrypted. This
|
@@ -29,11 +29,12 @@ module ActionDispatch
|
|
29
29
|
#
|
30
30
|
# Configure your session store in config/initializers/session_store.rb:
|
31
31
|
#
|
32
|
-
#
|
32
|
+
# Rails.application.config.session_store :cookie_store, key: '_your_app_session'
|
33
33
|
#
|
34
|
-
# Configure your secret key in config/
|
34
|
+
# Configure your secret key in config/secrets.yml:
|
35
35
|
#
|
36
|
-
#
|
36
|
+
# development:
|
37
|
+
# secret_key_base: 'secret key'
|
37
38
|
#
|
38
39
|
# To generate a secret key for an existing application, run `rake secret`.
|
39
40
|
#
|
@@ -48,9 +49,9 @@ module ActionDispatch
|
|
48
49
|
# reasonably sure that your upgrade is otherwise complete. Additionally,
|
49
50
|
# you should take care to make sure you are not relying on the ability to
|
50
51
|
# decode signed cookies generated by your app in external applications or
|
51
|
-
#
|
52
|
+
# JavaScript before upgrading.
|
52
53
|
#
|
53
|
-
# Note that changing
|
54
|
+
# Note that changing the secret key will invalidate all existing sessions!
|
54
55
|
class CookieStore < Rack::Session::Abstract::ID
|
55
56
|
include Compatibility
|
56
57
|
include StaleSessionCheck
|
@@ -29,8 +29,11 @@ module ActionDispatch
|
|
29
29
|
def call(env)
|
30
30
|
@app.call(env)
|
31
31
|
rescue Exception => exception
|
32
|
-
|
33
|
-
|
32
|
+
if env['action_dispatch.show_exceptions'] == false
|
33
|
+
raise exception
|
34
|
+
else
|
35
|
+
render_exception(env, exception)
|
36
|
+
end
|
34
37
|
end
|
35
38
|
|
36
39
|
private
|
@@ -39,6 +42,7 @@ module ActionDispatch
|
|
39
42
|
wrapper = ExceptionWrapper.new(env, exception)
|
40
43
|
status = wrapper.status_code
|
41
44
|
env["action_dispatch.exception"] = wrapper.exception
|
45
|
+
env["action_dispatch.original_path"] = env["PATH_INFO"]
|
42
46
|
env["PATH_INFO"] = "/#{status}"
|
43
47
|
response = @exceptions_app.call(env)
|
44
48
|
response[1]['X-Cascade'] == 'pass' ? pass_response(status) : response
|
@@ -22,7 +22,7 @@ module ActionDispatch
|
|
22
22
|
|
23
23
|
if request.ssl?
|
24
24
|
status, headers, body = @app.call(env)
|
25
|
-
headers
|
25
|
+
headers.reverse_merge!(hsts_headers)
|
26
26
|
flag_cookies_as_secure!(headers)
|
27
27
|
[status, headers, body]
|
28
28
|
else
|
@@ -32,11 +32,14 @@ module ActionDispatch
|
|
32
32
|
|
33
33
|
private
|
34
34
|
def redirect_to_https(request)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
host = @host || request.host
|
36
|
+
port = @port || request.port
|
37
|
+
|
38
|
+
location = "https://#{host}"
|
39
|
+
location << ":#{port}" if port != 80
|
40
|
+
location << request.fullpath
|
41
|
+
|
42
|
+
headers = { 'Content-Type' => 'text/html', 'Location' => location }
|
40
43
|
|
41
44
|
[301, headers, []]
|
42
45
|
end
|
@@ -57,7 +60,7 @@ module ActionDispatch
|
|
57
60
|
cookies = cookies.split("\n")
|
58
61
|
|
59
62
|
headers['Set-Cookie'] = cookies.map { |cookie|
|
60
|
-
if cookie !~ /;\s
|
63
|
+
if cookie !~ /;\s*secure\s*(;|$)/i
|
61
64
|
"#{cookie}; secure"
|
62
65
|
else
|
63
66
|
cookie
|
@@ -2,49 +2,105 @@ require 'rack/utils'
|
|
2
2
|
require 'active_support/core_ext/uri'
|
3
3
|
|
4
4
|
module ActionDispatch
|
5
|
+
# This middleware returns a file's contents from disk in the body response.
|
6
|
+
# When initialized it can accept an optional 'Cache-Control' header which
|
7
|
+
# will be set when a response containing a file's contents is delivered.
|
8
|
+
#
|
9
|
+
# This middleware will render the file specified in `env["PATH_INFO"]`
|
10
|
+
# where the base path is in the +root+ directory. For example if the +root+
|
11
|
+
# is set to `public/` then a request with `env["PATH_INFO"]` of
|
12
|
+
# `assets/application.js` will return a response with contents of a file
|
13
|
+
# located at `public/assets/application.js` if the file exists. If the file
|
14
|
+
# does not exist a 404 "File not Found" response will be returned.
|
5
15
|
class FileHandler
|
6
16
|
def initialize(root, cache_control)
|
7
17
|
@root = root.chomp('/')
|
8
18
|
@compiled_root = /^#{Regexp.escape(root)}/
|
9
|
-
headers
|
10
|
-
@file_server
|
19
|
+
headers = cache_control && { 'Cache-Control' => cache_control }
|
20
|
+
@file_server = ::Rack::File.new(@root, headers)
|
11
21
|
end
|
12
22
|
|
13
23
|
def match?(path)
|
14
|
-
path = path
|
24
|
+
path = URI.parser.unescape(path)
|
25
|
+
return false unless valid_path?(path)
|
15
26
|
|
16
|
-
|
17
|
-
|
27
|
+
paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"].map { |v|
|
28
|
+
Rack::Utils.clean_path_info v
|
29
|
+
}
|
18
30
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
31
|
+
if match = paths.detect { |p|
|
32
|
+
path = File.join(@root, p.force_encoding('UTF-8'))
|
33
|
+
begin
|
34
|
+
File.file?(path) && File.readable?(path)
|
35
|
+
rescue SystemCallError
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
}
|
40
|
+
return ::Rack::Utils.escape(match)
|
24
41
|
end
|
25
42
|
end
|
26
43
|
|
27
44
|
def call(env)
|
28
|
-
|
29
|
-
|
45
|
+
path = env['PATH_INFO']
|
46
|
+
gzip_path = gzip_file_path(path)
|
30
47
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
48
|
+
if gzip_path && gzip_encoding_accepted?(env)
|
49
|
+
env['PATH_INFO'] = gzip_path
|
50
|
+
status, headers, body = @file_server.call(env)
|
51
|
+
if status == 304
|
52
|
+
return [status, headers, body]
|
53
|
+
end
|
54
|
+
headers['Content-Encoding'] = 'gzip'
|
55
|
+
headers['Content-Type'] = content_type(path)
|
56
|
+
else
|
57
|
+
status, headers, body = @file_server.call(env)
|
35
58
|
end
|
36
|
-
end
|
37
59
|
|
38
|
-
|
39
|
-
URI.parser.unescape(path)
|
40
|
-
end
|
60
|
+
headers['Vary'] = 'Accept-Encoding' if gzip_path
|
41
61
|
|
42
|
-
|
43
|
-
|
44
|
-
|
62
|
+
return [status, headers, body]
|
63
|
+
ensure
|
64
|
+
env['PATH_INFO'] = path
|
45
65
|
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def ext
|
69
|
+
::ActionController::Base.default_static_extension
|
70
|
+
end
|
71
|
+
|
72
|
+
def content_type(path)
|
73
|
+
::Rack::Mime.mime_type(::File.extname(path), 'text/plain')
|
74
|
+
end
|
75
|
+
|
76
|
+
def gzip_encoding_accepted?(env)
|
77
|
+
env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/i
|
78
|
+
end
|
79
|
+
|
80
|
+
def gzip_file_path(path)
|
81
|
+
can_gzip_mime = content_type(path) =~ /\A(?:text\/|application\/javascript)/
|
82
|
+
gzip_path = "#{path}.gz"
|
83
|
+
if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape(gzip_path)))
|
84
|
+
gzip_path
|
85
|
+
else
|
86
|
+
false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def valid_path?(path)
|
91
|
+
path.valid_encoding? && !path.include?("\0")
|
92
|
+
end
|
46
93
|
end
|
47
94
|
|
95
|
+
# This middleware will attempt to return the contents of a file's body from
|
96
|
+
# disk in the response. If a file is not found on disk, the request will be
|
97
|
+
# delegated to the application stack. This middleware is commonly initialized
|
98
|
+
# to serve assets from a server's `public/` directory.
|
99
|
+
#
|
100
|
+
# This middleware verifies the path to ensure that only files
|
101
|
+
# living in the root directory can be rendered. A request cannot
|
102
|
+
# produce a directory traversal using this middleware. Only 'GET' and 'HEAD'
|
103
|
+
# requests will result in a file being returned.
|
48
104
|
class Static
|
49
105
|
def initialize(app, path, cache_control=nil)
|
50
106
|
@app = app
|
File without changes
|