actionpack 3.0.20 → 3.1.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 (161) hide show
  1. data/CHANGELOG +88 -142
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +5 -6
  4. data/lib/abstract_controller.rb +1 -0
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +24 -19
  7. data/lib/abstract_controller/callbacks.rb +19 -19
  8. data/lib/abstract_controller/helpers.rb +11 -13
  9. data/lib/abstract_controller/layouts.rb +4 -5
  10. data/lib/abstract_controller/railties/routes_helpers.rb +18 -0
  11. data/lib/abstract_controller/rendering.rb +34 -31
  12. data/lib/abstract_controller/url_for.rb +27 -0
  13. data/lib/abstract_controller/view_paths.rb +31 -6
  14. data/lib/action_controller.rb +5 -3
  15. data/lib/action_controller/base.rb +15 -16
  16. data/lib/action_controller/caching.rb +2 -2
  17. data/lib/action_controller/caching/actions.rb +11 -12
  18. data/lib/action_controller/caching/fragments.rb +41 -19
  19. data/lib/action_controller/caching/pages.rb +3 -9
  20. data/lib/action_controller/caching/sweeping.rb +0 -1
  21. data/lib/action_controller/deprecated.rb +1 -1
  22. data/lib/action_controller/log_subscriber.rb +1 -1
  23. data/lib/action_controller/metal.rb +78 -20
  24. data/lib/action_controller/metal/compatibility.rb +0 -9
  25. data/lib/action_controller/metal/conditional_get.rb +9 -9
  26. data/lib/action_controller/metal/data_streaming.rb +145 -0
  27. data/lib/action_controller/metal/force_ssl.rb +35 -0
  28. data/lib/action_controller/metal/head.rb +1 -1
  29. data/lib/action_controller/metal/helpers.rb +37 -44
  30. data/lib/action_controller/metal/hide_actions.rb +2 -3
  31. data/lib/action_controller/metal/http_authentication.rb +41 -38
  32. data/lib/action_controller/metal/implicit_render.rb +13 -13
  33. data/lib/action_controller/metal/instrumentation.rb +2 -2
  34. data/lib/action_controller/metal/mime_responds.rb +25 -19
  35. data/lib/action_controller/metal/params_wrapper.rb +224 -0
  36. data/lib/action_controller/metal/redirecting.rb +6 -2
  37. data/lib/action_controller/metal/renderers.rb +50 -36
  38. data/lib/action_controller/metal/rendering.rb +34 -25
  39. data/lib/action_controller/metal/request_forgery_protection.rb +18 -36
  40. data/lib/action_controller/metal/responder.rb +47 -12
  41. data/lib/action_controller/metal/streaming.rb +244 -138
  42. data/lib/action_controller/metal/testing.rb +0 -9
  43. data/lib/action_controller/metal/url_for.rb +12 -14
  44. data/lib/action_controller/railtie.rb +19 -37
  45. data/lib/action_controller/railties/paths.rb +24 -0
  46. data/lib/action_controller/record_identifier.rb +4 -10
  47. data/lib/action_controller/test_case.rb +36 -19
  48. data/lib/action_controller/vendor/html-scanner/html/node.rb +5 -5
  49. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +3 -3
  50. data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -0
  51. data/lib/action_dispatch.rb +4 -1
  52. data/lib/action_dispatch/http/cache.rb +5 -32
  53. data/lib/action_dispatch/http/filter_parameters.rb +3 -1
  54. data/lib/action_dispatch/http/mime_negotiation.rb +22 -3
  55. data/lib/action_dispatch/http/mime_type.rb +45 -5
  56. data/lib/action_dispatch/http/rack_cache.rb +58 -0
  57. data/lib/action_dispatch/http/request.rb +27 -41
  58. data/lib/action_dispatch/http/response.rb +56 -54
  59. data/lib/action_dispatch/http/upload.rb +1 -11
  60. data/lib/action_dispatch/http/url.rb +102 -42
  61. data/lib/action_dispatch/middleware/callbacks.rb +8 -25
  62. data/lib/action_dispatch/middleware/closed_error.rb +7 -0
  63. data/lib/action_dispatch/middleware/cookies.rb +37 -15
  64. data/lib/action_dispatch/middleware/flash.rb +80 -11
  65. data/lib/action_dispatch/middleware/params_parser.rb +2 -2
  66. data/lib/action_dispatch/middleware/reloader.rb +76 -0
  67. data/lib/action_dispatch/middleware/session/abstract_store.rb +56 -226
  68. data/lib/action_dispatch/middleware/session/cookie_store.rb +20 -44
  69. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -46
  70. data/lib/action_dispatch/middleware/show_exceptions.rb +15 -2
  71. data/lib/action_dispatch/middleware/stack.rb +50 -17
  72. data/lib/action_dispatch/middleware/static.rb +41 -29
  73. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +3 -3
  74. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
  75. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +3 -3
  76. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -2
  77. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +2 -6
  78. data/lib/action_dispatch/railtie.rb +8 -0
  79. data/lib/action_dispatch/routing.rb +13 -1
  80. data/lib/action_dispatch/routing/mapper.rb +345 -227
  81. data/lib/action_dispatch/routing/polymorphic_routes.rb +33 -13
  82. data/lib/action_dispatch/routing/redirection.rb +110 -0
  83. data/lib/action_dispatch/routing/route.rb +15 -13
  84. data/lib/action_dispatch/routing/route_set.rb +116 -90
  85. data/lib/action_dispatch/routing/routes_proxy.rb +35 -0
  86. data/lib/action_dispatch/routing/url_for.rb +25 -1
  87. data/lib/action_dispatch/testing/assertions/response.rb +8 -10
  88. data/lib/action_dispatch/testing/assertions/routing.rb +15 -15
  89. data/lib/action_dispatch/testing/assertions/selector.rb +13 -220
  90. data/lib/action_dispatch/testing/integration.rb +37 -28
  91. data/lib/action_dispatch/testing/performance_test.rb +1 -3
  92. data/lib/action_dispatch/testing/test_process.rb +1 -1
  93. data/lib/action_dispatch/testing/test_request.rb +9 -3
  94. data/lib/action_dispatch/testing/test_response.rb +4 -111
  95. data/lib/action_pack.rb +1 -1
  96. data/lib/action_pack/version.rb +3 -3
  97. data/lib/action_view.rb +39 -24
  98. data/lib/action_view/base.rb +61 -86
  99. data/lib/action_view/buffers.rb +43 -0
  100. data/lib/action_view/context.rb +21 -24
  101. data/lib/action_view/flows.rb +79 -0
  102. data/lib/action_view/helpers.rb +8 -6
  103. data/lib/action_view/helpers/active_model_helper.rb +0 -23
  104. data/lib/action_view/helpers/asset_paths.rb +79 -0
  105. data/lib/action_view/helpers/asset_tag_helper.rb +30 -500
  106. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +147 -0
  107. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +101 -0
  108. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +200 -0
  109. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +152 -0
  110. data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
  111. data/lib/action_view/helpers/cache_helper.rb +11 -19
  112. data/lib/action_view/helpers/capture_helper.rb +19 -8
  113. data/lib/action_view/helpers/controller_helper.rb +21 -0
  114. data/lib/action_view/helpers/csrf_helper.rb +22 -4
  115. data/lib/action_view/helpers/date_helper.rb +36 -22
  116. data/lib/action_view/helpers/form_helper.rb +199 -113
  117. data/lib/action_view/helpers/form_options_helper.rb +10 -11
  118. data/lib/action_view/helpers/form_tag_helper.rb +94 -22
  119. data/lib/action_view/helpers/javascript_helper.rb +24 -107
  120. data/lib/action_view/helpers/number_helper.rb +36 -33
  121. data/lib/action_view/helpers/output_safety_helper.rb +38 -0
  122. data/lib/action_view/helpers/record_tag_helper.rb +6 -6
  123. data/lib/action_view/helpers/rendering_helper.rb +90 -0
  124. data/lib/action_view/helpers/sanitize_helper.rb +2 -2
  125. data/lib/action_view/helpers/sprockets_helper.rb +69 -0
  126. data/lib/action_view/helpers/tag_helper.rb +34 -12
  127. data/lib/action_view/helpers/text_helper.rb +30 -145
  128. data/lib/action_view/helpers/translation_helper.rb +10 -17
  129. data/lib/action_view/helpers/url_helper.rb +70 -67
  130. data/lib/action_view/locale/en.yml +1 -1
  131. data/lib/action_view/lookup_context.rb +36 -14
  132. data/lib/action_view/{paths.rb → path_set.rb} +9 -8
  133. data/lib/action_view/railtie.rb +12 -4
  134. data/lib/action_view/renderer/abstract_renderer.rb +36 -0
  135. data/lib/action_view/{render/partials.rb → renderer/partial_renderer.rb} +147 -146
  136. data/lib/action_view/renderer/renderer.rb +54 -0
  137. data/lib/action_view/renderer/streaming_template_renderer.rb +106 -0
  138. data/lib/action_view/renderer/template_renderer.rb +74 -0
  139. data/lib/action_view/template.rb +91 -54
  140. data/lib/action_view/template/error.rb +11 -8
  141. data/lib/action_view/template/handler.rb +9 -1
  142. data/lib/action_view/template/handlers.rb +9 -9
  143. data/lib/action_view/template/handlers/builder.rb +4 -4
  144. data/lib/action_view/template/handlers/erb.rb +21 -41
  145. data/lib/action_view/template/resolver.rb +171 -57
  146. data/lib/action_view/template/text.rb +0 -4
  147. data/lib/action_view/test_case.rb +32 -16
  148. data/lib/action_view/testing/resolvers.rb +16 -10
  149. data/lib/sprockets/railtie.rb +100 -0
  150. metadata +162 -140
  151. checksums.yaml +0 -7
  152. data/lib/action_controller/deprecated/base.rb +0 -143
  153. data/lib/action_controller/deprecated/dispatcher.rb +0 -28
  154. data/lib/action_controller/deprecated/url_writer.rb +0 -14
  155. data/lib/action_dispatch/routing/deprecated_mapper.rb +0 -525
  156. data/lib/action_view/helpers/prototype_helper.rb +0 -851
  157. data/lib/action_view/helpers/raw_output_helper.rb +0 -18
  158. data/lib/action_view/helpers/scriptaculous_helper.rb +0 -263
  159. data/lib/action_view/render/layouts.rb +0 -83
  160. data/lib/action_view/render/rendering.rb +0 -67
  161. data/lib/action_view/template/handlers/rjs.rb +0 -17
@@ -39,10 +39,11 @@ module ActionDispatch
39
39
  end
40
40
 
41
41
  module Response
42
- attr_reader :cache_control
42
+ attr_reader :cache_control, :etag
43
+ alias :etag? :etag
43
44
 
44
45
  def initialize(*)
45
- status, header, body = super
46
+ super
46
47
 
47
48
  @cache_control = {}
48
49
  @etag = self["ETag"]
@@ -50,8 +51,7 @@ module ActionDispatch
50
51
  if cache_control = self["Cache-Control"]
51
52
  cache_control.split(/,\s*/).each do |segment|
52
53
  first, last = segment.split("=")
53
- last ||= true
54
- @cache_control[first.to_sym] = last
54
+ @cache_control[first.to_sym] = last || true
55
55
  end
56
56
  end
57
57
  end
@@ -70,14 +70,6 @@ module ActionDispatch
70
70
  headers['Last-Modified'] = utc_time.httpdate
71
71
  end
72
72
 
73
- def etag
74
- @etag
75
- end
76
-
77
- def etag?
78
- @etag
79
- end
80
-
81
73
  def etag=(etag)
82
74
  key = ActiveSupport::Cache.expand_cache_key(etag)
83
75
  @etag = self["ETag"] = %("#{Digest::MD5.hexdigest(key)}")
@@ -88,28 +80,9 @@ module ActionDispatch
88
80
  def handle_conditional_get!
89
81
  if etag? || last_modified? || !@cache_control.empty?
90
82
  set_conditional_cache_control!
91
- elsif nonempty_ok_response?
92
- self.etag = body
93
-
94
- if request && request.etag_matches?(etag)
95
- self.status = 304
96
- self.body = []
97
- end
98
-
99
- set_conditional_cache_control!
100
- else
101
- headers["Cache-Control"] = "no-cache"
102
83
  end
103
84
  end
104
85
 
105
- def nonempty_ok_response?
106
- @status == 200 && string_body?
107
- end
108
-
109
- def string_body?
110
- !@blank && @body.respond_to?(:all?) && @body.all? { |part| part.is_a?(String) }
111
- end
112
-
113
86
  DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
114
87
 
115
88
  def set_conditional_cache_control!
@@ -119,7 +92,7 @@ module ActionDispatch
119
92
 
120
93
  if control.empty?
121
94
  headers["Cache-Control"] = DEFAULT_CACHE_CONTROL
122
- elsif @cache_control[:no_cache]
95
+ elsif control[:no_cache]
123
96
  headers["Cache-Control"] = "no-cache"
124
97
  else
125
98
  extras = control[:extras]
@@ -26,6 +26,8 @@ module ActionDispatch
26
26
  module FilterParameters
27
27
  extend ActiveSupport::Concern
28
28
 
29
+ @@parameter_filter_for = {}
30
+
29
31
  # Return a hash of parameters with all sensitive data replaced.
30
32
  def filtered_parameters
31
33
  @filtered_parameters ||= parameter_filter.filter(parameters)
@@ -52,7 +54,7 @@ module ActionDispatch
52
54
  end
53
55
 
54
56
  def parameter_filter_for(filters)
55
- ParameterFilter.new(filters)
57
+ @@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
56
58
  end
57
59
 
58
60
  KV_RE = '[^&;=]+'
@@ -1,6 +1,13 @@
1
1
  module ActionDispatch
2
2
  module Http
3
3
  module MimeNegotiation
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ mattr_accessor :ignore_accept_header
8
+ self.ignore_accept_header = false
9
+ end
10
+
4
11
  # The MIME type of the HTTP request, such as Mime::XML.
5
12
  #
6
13
  # For backward compatibility, the post \format is extracted from the
@@ -43,13 +50,13 @@ module ActionDispatch
43
50
  end
44
51
 
45
52
  def formats
46
- accept = @env['HTTP_ACCEPT']
47
-
48
53
  @env["action_dispatch.request.formats"] ||=
49
54
  if parameters[:format]
50
55
  Array(Mime[parameters[:format]])
51
- elsif xhr? || (accept && accept !~ /,\s*\*\/\*/)
56
+ elsif use_accept_header && valid_accept_header
52
57
  accepts
58
+ elsif xhr?
59
+ [Mime::JS]
53
60
  else
54
61
  [Mime::HTML]
55
62
  end
@@ -85,6 +92,18 @@ module ActionDispatch
85
92
 
86
93
  order.include?(Mime::ALL) ? formats.first : nil
87
94
  end
95
+
96
+ protected
97
+
98
+ BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
99
+
100
+ def valid_accept_header
101
+ xhr? || (accept && accept !~ BROWSER_LIKE_ACCEPTS)
102
+ end
103
+
104
+ def use_accept_header
105
+ !self.class.ignore_accept_header
106
+ end
88
107
  end
89
108
  end
90
109
  end
@@ -80,6 +80,9 @@ module Mime
80
80
  end
81
81
 
82
82
  class << self
83
+
84
+ TRAILING_STAR_REGEXP = /(text|application)\/\*/
85
+
83
86
  def lookup(string)
84
87
  LOOKUP[string]
85
88
  end
@@ -105,15 +108,28 @@ module Mime
105
108
 
106
109
  def parse(accept_header)
107
110
  if accept_header !~ /,/
108
- [Mime::Type.lookup(accept_header)]
111
+ if accept_header =~ TRAILING_STAR_REGEXP
112
+ parse_data_with_trailing_star($1)
113
+ else
114
+ [Mime::Type.lookup(accept_header)]
115
+ end
109
116
  else
110
117
  # keep track of creation order to keep the subsequent sort stable
111
- list = []
112
- accept_header.split(/,/).each_with_index do |header, index|
118
+ list, index = [], 0
119
+ accept_header.split(/,/).each do |header|
113
120
  params, q = header.split(/;\s*q=/)
114
- if params
121
+ if params.present?
115
122
  params.strip!
116
- list << AcceptItem.new(index, params, q) unless params.empty?
123
+
124
+ if params =~ TRAILING_STAR_REGEXP
125
+ parse_data_with_trailing_star($1).each do |m|
126
+ list << AcceptItem.new(index, m.to_s, q)
127
+ index += 1
128
+ end
129
+ else
130
+ list << AcceptItem.new(index, params, q)
131
+ index += 1
132
+ end
117
133
  end
118
134
  end
119
135
  list.sort!
@@ -160,6 +176,30 @@ module Mime
160
176
  list
161
177
  end
162
178
  end
179
+
180
+ # input: 'text'
181
+ # returned value: [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT]
182
+ #
183
+ # input: 'application'
184
+ # returned value: [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM]
185
+ def parse_data_with_trailing_star(input)
186
+ Mime::SET.select { |m| m =~ input }
187
+ end
188
+
189
+ # This method is opposite of register method.
190
+ #
191
+ # Usage:
192
+ #
193
+ # Mime::Type.unregister(:mobile)
194
+ def unregister(symbol)
195
+ symbol = symbol.to_s.upcase
196
+ mime = Mime.const_get(symbol)
197
+ Mime.instance_eval { remove_const(symbol) }
198
+
199
+ SET.delete_if { |v| v.eql?(mime) }
200
+ LOOKUP.delete_if { |k,v| v.eql?(mime) }
201
+ EXTENSION_LOOKUP.delete_if { |k,v| v.eql?(mime) }
202
+ end
163
203
  end
164
204
 
165
205
  def initialize(string, symbol = nil, synonyms = [])
@@ -0,0 +1,58 @@
1
+ require "rack/cache"
2
+ require "rack/cache/context"
3
+ require "active_support/cache"
4
+
5
+ module ActionDispatch
6
+ class RailsMetaStore < Rack::Cache::MetaStore
7
+ def self.resolve(uri)
8
+ new
9
+ end
10
+
11
+ # TODO: Finally deal with the RAILS_CACHE global
12
+ def initialize(store = RAILS_CACHE)
13
+ @store = store
14
+ end
15
+
16
+ def read(key)
17
+ @store.read(key) || []
18
+ end
19
+
20
+ def write(key, value)
21
+ @store.write(key, value)
22
+ end
23
+
24
+ ::Rack::Cache::MetaStore::RAILS = self
25
+ end
26
+
27
+ class RailsEntityStore < Rack::Cache::EntityStore
28
+ def self.resolve(uri)
29
+ new
30
+ end
31
+
32
+ def initialize(store = RAILS_CACHE)
33
+ @store = store
34
+ end
35
+
36
+ def exist?(key)
37
+ @store.exist?(key)
38
+ end
39
+
40
+ def open(key)
41
+ @store.read(key)
42
+ end
43
+
44
+ def read(key)
45
+ body = open(key)
46
+ body.join if body
47
+ end
48
+
49
+ def write(body)
50
+ buf = []
51
+ key, size = slurp(body) { |part| buf << part }
52
+ @store.write(key, buf)
53
+ [key, size]
54
+ end
55
+
56
+ ::Rack::Cache::EntityStore::RAILS = self
57
+ end
58
+ end
@@ -17,16 +17,17 @@ module ActionDispatch
17
17
  include ActionDispatch::Http::Upload
18
18
  include ActionDispatch::Http::URL
19
19
 
20
- LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze
21
-
22
- %w[ AUTH_TYPE GATEWAY_INTERFACE
20
+ LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze
21
+ ENV_METHODS = %w[ AUTH_TYPE GATEWAY_INTERFACE
23
22
  PATH_TRANSLATED REMOTE_HOST
24
23
  REMOTE_IDENT REMOTE_USER REMOTE_ADDR
25
24
  SERVER_NAME SERVER_PROTOCOL
26
25
 
27
26
  HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
28
27
  HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
29
- HTTP_NEGOTIATE HTTP_PRAGMA ].each do |env|
28
+ HTTP_NEGOTIATE HTTP_PRAGMA ].freeze
29
+
30
+ ENV_METHODS.each do |env|
30
31
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
31
32
  def #{env.sub(/^HTTP_/n, '').downcase}
32
33
  @env["#{env}"]
@@ -72,11 +73,7 @@ module ActionDispatch
72
73
  # the application should use), this \method returns the overridden
73
74
  # value, not the original.
74
75
  def request_method
75
- @request_method ||= begin
76
- method = env["REQUEST_METHOD"]
77
- HTTP_METHOD_LOOKUP[method] || raise(ActionController::UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
78
- method
79
- end
76
+ @request_method ||= check_method(env["REQUEST_METHOD"])
80
77
  end
81
78
 
82
79
  # Returns a symbol form of the #request_method
@@ -88,11 +85,7 @@ module ActionDispatch
88
85
  # even if it was overridden by middleware. See #request_method for
89
86
  # more information.
90
87
  def method
91
- @method ||= begin
92
- method = env["rack.methodoverride.original_method"] || env['REQUEST_METHOD']
93
- HTTP_METHOD_LOOKUP[method] || raise(ActionController::UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
94
- method
95
- end
88
+ @method ||= check_method(env["rack.methodoverride.original_method"] || env['REQUEST_METHOD'])
96
89
  end
97
90
 
98
91
  # Returns a symbol form of the #method
@@ -155,11 +148,11 @@ module ActionDispatch
155
148
  super.to_i
156
149
  end
157
150
 
158
- # Returns true if the request's "X-Requested-With" header contains
159
- # "XMLHttpRequest". (The Prototype Javascript library sends this header with
160
- # every Ajax request.)
151
+ # Returns true if the "X-Requested-With" header contains "XMLHttpRequest"
152
+ # (case-insensitive). All major JavaScript libraries send this header with
153
+ # every Ajax request.
161
154
  def xml_http_request?
162
- !(@env['HTTP_X_REQUESTED_WITH'] !~ /XMLHttpRequest/i)
155
+ @env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/i
163
156
  end
164
157
  alias :xhr? :xml_http_request?
165
158
 
@@ -168,8 +161,16 @@ module ActionDispatch
168
161
  end
169
162
 
170
163
  # Which IP addresses are "trusted proxies" that can be stripped from
171
- # the right-hand-side of X-Forwarded-For
172
- TRUSTED_PROXIES = /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
164
+ # the right-hand-side of X-Forwarded-For.
165
+ #
166
+ # http://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces.
167
+ TRUSTED_PROXIES = %r{
168
+ ^127\.0\.0\.1$ | # localhost
169
+ ^(10 | # private IP 10.x.x.x
170
+ 172\.(1[6-9]|2[0-9]|3[0-1]) | # private IP in the range 172.16.0.0 .. 172.31.255.255
171
+ 192\.168 # private IP 192.168.x.x
172
+ )\.
173
+ }x
173
174
 
174
175
  # Determines originating IP address. REMOTE_ADDR is the standard
175
176
  # but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or
@@ -233,13 +234,13 @@ module ActionDispatch
233
234
 
234
235
  # Override Rack's GET method to support indifferent access
235
236
  def GET
236
- @env["action_dispatch.request.query_parameters"] ||= normalize_parameters(super)
237
+ @env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {})
237
238
  end
238
239
  alias :query_parameters :GET
239
240
 
240
241
  # Override Rack's POST method to support indifferent access
241
242
  def POST
242
- @env["action_dispatch.request.request_parameters"] ||= normalize_parameters(super)
243
+ @env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {})
243
244
  end
244
245
  alias :request_parameters :POST
245
246
 
@@ -258,26 +259,11 @@ module ActionDispatch
258
259
  LOCALHOST.any? { |local_ip| local_ip === remote_addr && local_ip === remote_ip }
259
260
  end
260
261
 
261
- # Remove nils from the params hash
262
- def deep_munge(hash)
263
- hash.each do |k, v|
264
- case v
265
- when Array
266
- v.grep(Hash) { |x| deep_munge(x) }
267
- v.compact!
268
- hash[k] = nil if v.empty?
269
- when Hash
270
- deep_munge(v)
271
- end
272
- end
273
-
274
- hash
275
- end
276
-
277
- protected
262
+ private
278
263
 
279
- def parse_query(qs)
280
- deep_munge(super)
264
+ def check_method(name)
265
+ HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
266
+ name
281
267
  end
282
268
  end
283
269
  end
@@ -32,24 +32,35 @@ module ActionDispatch # :nodoc:
32
32
  # puts @response.body
33
33
  # end
34
34
  # end
35
- class Response < Rack::Response
36
- attr_accessor :request, :blank
35
+ class Response
36
+ attr_accessor :request, :header, :status
37
+ attr_writer :sending_file
37
38
 
38
- attr_writer :header, :sending_file
39
39
  alias_method :headers=, :header=
40
+ alias_method :headers, :header
41
+
42
+ delegate :[], :[]=, :to => :@header
43
+ delegate :each, :to => :@body
44
+
45
+ # Sets the HTTP response's content MIME type. For example, in the controller
46
+ # you could write this:
47
+ #
48
+ # response.content_type = "text/plain"
49
+ #
50
+ # If a character set has been defined for this response (see charset=) then
51
+ # the character set information will also be included in the content type
52
+ # information.
53
+ attr_accessor :charset, :content_type
54
+
55
+ CONTENT_TYPE = "Content-Type"
56
+
57
+ cattr_accessor(:default_charset) { "utf-8" }
40
58
 
41
59
  module Setup
42
60
  def initialize(status = 200, header = {}, body = [])
43
- @writer = lambda { |x| @body << x }
44
- @block = nil
45
- @length = 0
46
-
47
- @status, @header = status, header
48
- self.body = body
61
+ self.body, self.header, self.status = body, header, status
49
62
 
50
- @cookie = []
51
63
  @sending_file = false
52
-
53
64
  @blank = false
54
65
 
55
66
  if content_type = self["Content-Type"]
@@ -62,6 +73,7 @@ module ActionDispatch # :nodoc:
62
73
  end
63
74
  end
64
75
 
76
+ include Rack::Response::Helpers
65
77
  include Setup
66
78
  include ActionDispatch::Http::Cache::Response
67
79
 
@@ -106,13 +118,29 @@ module ActionDispatch # :nodoc:
106
118
 
107
119
  def body=(body)
108
120
  @blank = true if body == EMPTY
109
- @body = body.respond_to?(:to_str) ? [body] : body
121
+
122
+ # Explicitly check for strings. This is *wrong* theoretically
123
+ # but if we don't check this, the performance on string bodies
124
+ # is bad on Ruby 1.8 (because strings responds to each then).
125
+ @body = if body.respond_to?(:to_str) || !body.respond_to?(:each)
126
+ [body]
127
+ else
128
+ body
129
+ end
110
130
  end
111
131
 
112
132
  def body_parts
113
133
  @body
114
134
  end
115
135
 
136
+ def set_cookie(key, value)
137
+ ::Rack::Utils.set_cookie_header!(header, key, value)
138
+ end
139
+
140
+ def delete_cookie(key, value={})
141
+ ::Rack::Utils.delete_cookie_header!(header, key, value)
142
+ end
143
+
116
144
  def location
117
145
  headers['Location']
118
146
  end
@@ -122,47 +150,21 @@ module ActionDispatch # :nodoc:
122
150
  headers['Location'] = url
123
151
  end
124
152
 
125
- # Sets the HTTP response's content MIME type. For example, in the controller
126
- # you could write this:
127
- #
128
- # response.content_type = "text/plain"
129
- #
130
- # If a character set has been defined for this response (see charset=) then
131
- # the character set information will also be included in the content type
132
- # information.
133
- attr_accessor :charset, :content_type
134
-
135
- CONTENT_TYPE = "Content-Type"
136
-
137
- cattr_accessor(:default_charset) { "utf-8" }
138
-
139
153
  def to_a
140
154
  assign_default_content_type_and_charset!
141
155
  handle_conditional_get!
142
- self["Set-Cookie"] = self["Set-Cookie"].join("\n") if self["Set-Cookie"].respond_to?(:join)
143
- self["ETag"] = @_etag if @_etag
144
- super
145
- end
146
156
 
147
- alias prepare! to_a
157
+ @header["Set-Cookie"] = @header["Set-Cookie"].join("\n") if @header["Set-Cookie"].respond_to?(:join)
148
158
 
149
- def each(&callback)
150
- if @body.respond_to?(:call)
151
- @writer = lambda { |x| callback.call(x) }
152
- @body.call(self, self)
159
+ if [204, 304].include?(@status)
160
+ @header.delete "Content-Type"
161
+ [@status, @header, []]
153
162
  else
154
- @body.each { |part| callback.call(part.to_s) }
163
+ [@status, @header, self]
155
164
  end
156
-
157
- @writer = callback
158
- @block.call(self) if @block
159
- end
160
-
161
- def write(str)
162
- str = str.to_s
163
- @writer.call str
164
- str
165
165
  end
166
+ alias prepare! to_a
167
+ alias to_ary to_a # For implicit splat on 1.9.2
166
168
 
167
169
  # Returns the response cookies, converted to a Hash of (name => value) pairs
168
170
  #
@@ -181,18 +183,18 @@ module ActionDispatch # :nodoc:
181
183
  cookies
182
184
  end
183
185
 
184
- private
185
- def assign_default_content_type_and_charset!
186
- return if headers[CONTENT_TYPE].present?
186
+ private
187
187
 
188
- @content_type ||= Mime::HTML
189
- @charset ||= self.class.default_charset
188
+ def assign_default_content_type_and_charset!
189
+ return if headers[CONTENT_TYPE].present?
190
190
 
191
- type = @content_type.to_s.dup
192
- type << "; charset=#{@charset}" unless @sending_file
191
+ @content_type ||= Mime::HTML
192
+ @charset ||= self.class.default_charset
193
193
 
194
- headers[CONTENT_TYPE] = type
195
- end
194
+ type = @content_type.to_s.dup
195
+ type << "; charset=#{@charset}" unless @sending_file
196
196
 
197
+ headers[CONTENT_TYPE] = type
198
+ end
197
199
  end
198
200
  end