actionpack 4.2.0.beta1 → 4.2.0.beta2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6d649528dc6dcae47651b64c5dfe0e92989d3fb9
4
- data.tar.gz: 4cd8d6dd611b187e5005aa4ecbe4f766c574da5e
3
+ metadata.gz: d9093a36f426a1fe8cef497530b8ae253e1de975
4
+ data.tar.gz: c8704d3bc342e3eebab15189b9d5f996472c999a
5
5
  SHA512:
6
- metadata.gz: 7670d5691189a68b9a041ebd58916056febb4e71a8a2b4871edf78ba6b5cbdc18472f7e1026c76a8f6f179efdbe282ce801387887267e0d9f03cbad4193e134a
7
- data.tar.gz: 6f2c063b5f9f67661c316081daf87ee7300647d54a43c2179712f69765f79472e83fe3d4457944f4d064f9c4475d0cf5a8502cc1457aeeb433336eb2a71fe671
6
+ metadata.gz: 8d3f4fb1fb46549a3bf300d861f998239e812fa38aa906e8675a1362f51f51ffdd9e264888e1f122dc9fc955b43c0fdb944dc6b696a2bd781c18906c4909cefd
7
+ data.tar.gz: ba2666cc3a9f82160f9a2e092dfe9f952b3ac132f1ecdb68f57a70f692b169245e7085b120ba474954e1300ca693b072cc88058999780d17087b40add6e8afa7
@@ -1,3 +1,53 @@
1
+ * Deprecate implicit Array conversion for Response objects. It was added
2
+ (using `#to_ary`) so we could conveniently use implicit splatting:
3
+
4
+ status, headers, body = response
5
+
6
+ But it also means `response + response` works and `[response].flatten`
7
+ cascades down to the Rack body. Nonsense behavior. Instead, rely on
8
+ explicit conversion and splatting with `#to_a`:
9
+
10
+ status, header, body = *response
11
+
12
+ *Jeremy Kemper*
13
+
14
+ * Don't rescue `IPAddr::InvalidAddressError`.
15
+
16
+ `IPAddr::InvalidAddressError` does not exist in Ruby 1.9.3
17
+ and fails for JRuby in 1.9 mode.
18
+
19
+ *Peter Suschlik*
20
+
21
+ * Fix bug where the router would ignore any constraints added to redirect
22
+ routes.
23
+
24
+ Fixes #16605.
25
+
26
+ *Agis Anastasopoulos*
27
+
28
+ * Allow `config.action_dispatch.trusted_proxies` to accept an IPAddr object.
29
+
30
+ Example:
31
+
32
+ # config/environments/production.rb
33
+ config.action_dispatch.trusted_proxies = IPAddr.new('4.8.15.0/16')
34
+
35
+ *Sam Aarons*
36
+
37
+ * Avoid duplicating routes for HEAD requests.
38
+
39
+ Instead of duplicating the routes, we will first match the HEAD request to
40
+ HEAD routes. If no match is found, we will then map the HEAD request to
41
+ GET routes.
42
+
43
+ *Guo Xiang Tan*, *Andrew White*
44
+
45
+ * Requests that hit `ActionDispatch::Static` can now take advantage
46
+ of gzipped assets on disk. By default a gzip asset will be served if
47
+ the client supports gzip and a compressed file is on disk.
48
+
49
+ *Richard Schneeman*
50
+
1
51
  * `ActionController::Parameters` will stop inheriting from `Hash` and
2
52
  `HashWithIndifferentAccess` in the next major release. If you use any method
3
53
  that is not available on `ActionController::Parameters` you should consider
@@ -33,7 +83,7 @@
33
83
 
34
84
  *Prem Sichanugrist*
35
85
 
36
- * Deprecated TagAssertions.
86
+ * Deprecated `TagAssertions`.
37
87
 
38
88
  *Kasper Timm Hansen*
39
89
 
@@ -65,11 +115,11 @@
65
115
  If you render a different template, you can now pass the `:template`
66
116
  option to include its digest instead:
67
117
 
68
- fresh_when @post, template: 'widgets/show'
118
+ fresh_when @post, template: 'widgets/show'
69
119
 
70
120
  Pass `template: false` to skip the lookup. To turn this off entirely, set:
71
121
 
72
- config.action_controller.etag_with_template_digest = false
122
+ config.action_controller.etag_with_template_digest = false
73
123
 
74
124
  *Jeremy Kemper*
75
125
 
@@ -123,7 +173,7 @@
123
173
  *Godfrey Chan*
124
174
 
125
175
  * Prepend a JS comment to JSONP callbacks. Addresses CVE-2014-4671
126
- ("Rosetta Flash")
176
+ ("Rosetta Flash").
127
177
 
128
178
  *Greg Campbell*
129
179
 
@@ -34,14 +34,15 @@ module ActionController
34
34
  end
35
35
 
36
36
  def render_to_body(options)
37
- _handle_render_options(options) || super
37
+ _render_to_body_with_renderer(options) || super
38
38
  end
39
39
 
40
- def _handle_render_options(options)
40
+ def _render_to_body_with_renderer(options)
41
41
  _renderers.each do |name|
42
42
  if options.key?(name)
43
43
  _process_options(options)
44
- return send("_render_option_#{name}", options.delete(name), options)
44
+ method_name = Renderers._render_with_renderer_method_name(name)
45
+ return send(method_name, options.delete(name), options)
45
46
  end
46
47
  end
47
48
  nil
@@ -51,6 +52,10 @@ module ActionController
51
52
  # Default values are <tt>:json</tt>, <tt>:js</tt>, <tt>:xml</tt>.
52
53
  RENDERERS = Set.new
53
54
 
55
+ def self._render_with_renderer_method_name(key)
56
+ "_render_with_renderer_#{key}"
57
+ end
58
+
54
59
  # Adds a new renderer to call within controller actions.
55
60
  # A renderer is invoked by passing its name as an option to
56
61
  # <tt>AbstractController::Rendering#render</tt>. To create a renderer
@@ -84,7 +89,7 @@ module ActionController
84
89
  # <tt>ActionController::MimeResponds::ClassMethods.respond_to</tt> and
85
90
  # <tt>ActionController::MimeResponds#respond_with</tt>
86
91
  def self.add(key, &block)
87
- define_method("_render_option_#{key}", &block)
92
+ define_method(_render_with_renderer_method_name(key), &block)
88
93
  RENDERERS << key.to_sym
89
94
  end
90
95
 
@@ -95,8 +100,8 @@ module ActionController
95
100
  # ActionController::Renderers.remove(:csv)
96
101
  def self.remove(key)
97
102
  RENDERERS.delete(key.to_sym)
98
- method = "_render_option_#{key}"
99
- remove_method(method) if method_defined?(method)
103
+ method_name = _render_with_renderer_method_name(key)
104
+ remove_method(method_name) if method_defined?(method_name)
100
105
  end
101
106
 
102
107
  module All
@@ -112,7 +117,7 @@ module ActionController
112
117
  json = json.to_json(options) unless json.kind_of?(String)
113
118
 
114
119
  if options[:callback].present?
115
- if self.content_type.nil? || self.content_type == Mime::JSON
120
+ if content_type.nil? || content_type == Mime::JSON
116
121
  self.content_type = Mime::JS
117
122
  end
118
123
 
@@ -45,8 +45,8 @@ module Mime
45
45
  #
46
46
  # respond_to do |format|
47
47
  # format.html
48
- # format.ics { render text: post.to_ics, mime_type: Mime::Type["text/calendar"] }
49
- # format.xml { render xml: @people }
48
+ # format.ics { render text: @post.to_ics, mime_type: Mime::Type["text/calendar"] }
49
+ # format.xml { render xml: @post }
50
50
  # end
51
51
  # end
52
52
  # end
@@ -105,6 +105,12 @@ module ActionDispatch
105
105
  @request_method ||= check_method(env["REQUEST_METHOD"])
106
106
  end
107
107
 
108
+ def request_method=(request_method) #:nodoc:
109
+ if check_method(request_method)
110
+ @request_method = env["REQUEST_METHOD"] = request_method
111
+ end
112
+ end
113
+
108
114
  # Returns a symbol form of the #request_method
109
115
  def request_method_symbol
110
116
  HTTP_METHOD_LOOKUP[request_method]
@@ -292,7 +298,7 @@ module ActionDispatch
292
298
  # Override Rack's GET method to support indifferent access
293
299
  def GET
294
300
  @env["action_dispatch.request.query_parameters"] ||= Utils.deep_munge(normalize_encode_params(super || {}))
295
- rescue TypeError, Rack::Utils::InvalidParameterError => e
301
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
296
302
  raise ActionController::BadRequest.new(:query, e)
297
303
  end
298
304
  alias :query_parameters :GET
@@ -300,7 +306,7 @@ module ActionDispatch
300
306
  # Override Rack's POST method to support indifferent access
301
307
  def POST
302
308
  @env["action_dispatch.request.request_parameters"] ||= Utils.deep_munge(normalize_encode_params(super || {}))
303
- rescue TypeError, Rack::Utils::InvalidParameterError => e
309
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
304
310
  raise ActionController::BadRequest.new(:request, e)
305
311
  end
306
312
  alias :request_parameters :POST
@@ -1,4 +1,5 @@
1
1
  require 'active_support/core_ext/module/attribute_accessors'
2
+ require 'active_support/deprecation'
2
3
  require 'action_dispatch/http/filter_redirect'
3
4
  require 'monitor'
4
5
 
@@ -274,12 +275,22 @@ module ActionDispatch # :nodoc:
274
275
  end
275
276
 
276
277
  # Turns the Response into a Rack-compatible array of the status, headers,
277
- # and body.
278
+ # and body. Allows explict splatting:
279
+ #
280
+ # status, headers, body = *response
278
281
  def to_a
279
282
  rack_response @status, @header.to_hash
280
283
  end
281
284
  alias prepare! to_a
282
- alias to_ary to_a
285
+
286
+ # Be super clear that a response object is not an Array. Defining this
287
+ # would make implicit splatting work, but it also makes adding responses
288
+ # as arrays work, and "flattening" responses, cascading to the rack body!
289
+ # Not sensible behavior.
290
+ def to_ary
291
+ ActiveSupport::Deprecation.warn 'ActionDispatch::Response#to_ary no longer performs implicit conversion to an Array. Please use response.to_a instead, or a splat like `status, headers, body = *response`'
292
+ to_a
293
+ end
283
294
 
284
295
  # Returns the response cookies, converted to a Hash of (name => value) pairs
285
296
  #
@@ -369,6 +380,10 @@ module ActionDispatch # :nodoc:
369
380
  def to_path
370
381
  @response.stream.to_path
371
382
  end
383
+
384
+ def to_ary
385
+ nil
386
+ end
372
387
  end
373
388
 
374
389
  def rack_response(status, header)
@@ -101,11 +101,13 @@ module ActionDispatch
101
101
  r.path.match(req.path_info)
102
102
  }
103
103
 
104
- if req.env["REQUEST_METHOD"] === "HEAD"
105
- routes.concat get_routes_as_head(routes)
106
- end
104
+ routes =
105
+ if req.request_method == "HEAD"
106
+ match_head_routes(routes, req)
107
+ else
108
+ match_routes(routes, req)
109
+ end
107
110
 
108
- routes.select! { |r| r.matches?(req) }
109
111
  routes.sort_by!(&:precedence)
110
112
 
111
113
  routes.map! { |r|
@@ -118,19 +120,23 @@ module ActionDispatch
118
120
  }
119
121
  end
120
122
 
121
- def get_routes_as_head(routes)
122
- precedence = (routes.map(&:precedence).max || 0) + 1
123
- routes.select { |r|
124
- r.verb === "GET" && !(r.verb === "HEAD")
125
- }.map! { |r|
126
- Route.new(r.name,
127
- r.app,
128
- r.path,
129
- r.conditions.merge(request_method: "HEAD"),
130
- r.defaults).tap do |route|
131
- route.precedence = r.precedence + precedence
132
- end
133
- }
123
+ def match_head_routes(routes, req)
124
+ head_routes = match_routes(routes, req)
125
+
126
+ if head_routes.empty?
127
+ begin
128
+ req.request_method = "GET"
129
+ match_routes(routes, req)
130
+ ensure
131
+ req.request_method = "HEAD"
132
+ end
133
+ else
134
+ head_routes
135
+ end
136
+ end
137
+
138
+ def match_routes(routes, req)
139
+ routes.select { |r| r.matches?(req) }
134
140
  end
135
141
  end
136
142
  end
@@ -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
@@ -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 = %r{
32
- ^127\.0\.0\.1$ | # localhost IPv4
33
- ^::1$ | # localhost IPv6
34
- ^[fF][cCdD] | # private IPv6 range fc00::/7
35
- ^10\. | # private IPv4 range 10.x.x.x
36
- ^172\.(1[6-9]|2[0-9]|3[0-1])\.| # private IPv4 range 172.16.0.0 .. 172.31.255.255
37
- ^192\.168\. # private IPv4 range 192.168.x.x
38
- }x
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 +custom_proxies+ argument can take a regex, which will be used
51
- # instead of +TRUSTED_PROXIES+, or a string, which will be used in addition
52
- # to +TRUSTED_PROXIES+. Any proxy setup will put the value you want in the
53
- # middle (or at the beginning) of the X-Forwarded-For list, with your proxy
54
- # servers after it. If your proxies aren't removed, pass them in via the
55
- # +custom_proxies+ parameter. That way, the middleware will ignore those
56
- # IP addresses, and return the one that you want.
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 = case custom_proxies
61
- when Regexp
62
- custom_proxies
63
- when nil
64
- TRUSTED_PROXIES
65
- else
66
- Regexp.union(TRUSTED_PROXIES, custom_proxies)
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
@@ -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
- # Only return IPs that are valid according to the regex
177
- ips.select{ |ip| ip =~ VALID_IP }
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 { |ip| ip =~ @proxies }
165
+ ips.reject do |ip|
166
+ @proxies.any? { |proxy| proxy === ip }
167
+ end
182
168
  end
183
169
 
184
170
  end
@@ -16,43 +16,63 @@ module ActionDispatch
16
16
  def initialize(root, cache_control)
17
17
  @root = root.chomp('/')
18
18
  @compiled_root = /^#{Regexp.escape(root)}/
19
- headers = cache_control && { 'Cache-Control' => cache_control }
20
- @file_server = ::Rack::File.new(@root, headers)
19
+ headers = cache_control && { 'Cache-Control' => cache_control }
20
+ @file_server = ::Rack::File.new(@root, headers)
21
21
  end
22
22
 
23
23
  def match?(path)
24
- path = unescape_path(path)
24
+ path = URI.parser.unescape(path)
25
25
  return false unless path.valid_encoding?
26
26
 
27
- full_path = path.empty? ? @root : File.join(@root, escape_glob_chars(path))
28
- paths = "#{full_path}#{ext}"
27
+ paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"]
29
28
 
30
- matches = Dir[paths]
31
- match = matches.detect { |m| File.file?(m) }
32
- if match
33
- match.sub!(@compiled_root, '')
34
- ::Rack::Utils.escape(match)
29
+ if match = paths.detect {|p| File.file?(File.join(@root, p)) }
30
+ return ::Rack::Utils.escape(match)
35
31
  end
36
32
  end
37
33
 
38
34
  def call(env)
39
- @file_server.call(env)
40
- end
35
+ path = env['PATH_INFO']
36
+ gzip_path = gzip_file_path(path)
41
37
 
42
- def ext
43
- @ext ||= begin
44
- ext = ::ActionController::Base.default_static_extension
45
- "{,#{ext},/index#{ext}}"
38
+ if gzip_path && gzip_encoding_accepted?(env)
39
+ env['PATH_INFO'] = gzip_path
40
+ status, headers, body = @file_server.call(env)
41
+ headers['Content-Encoding'] = 'gzip'
42
+ headers['Content-Type'] = content_type(path)
43
+ else
44
+ status, headers, body = @file_server.call(env)
46
45
  end
47
- end
48
46
 
49
- def unescape_path(path)
50
- URI.parser.unescape(path)
51
- end
47
+ headers['Vary'] = 'Accept-Encoding' if gzip_path
52
48
 
53
- def escape_glob_chars(path)
54
- path.gsub(/[*?{}\[\]]/, "\\\\\\&")
49
+ return [status, headers, body]
50
+ ensure
51
+ env['PATH_INFO'] = path
55
52
  end
53
+
54
+ private
55
+ def ext
56
+ ::ActionController::Base.default_static_extension
57
+ end
58
+
59
+ def content_type(path)
60
+ ::Rack::Mime.mime_type(::File.extname(path), 'text/plain')
61
+ end
62
+
63
+ def gzip_encoding_accepted?(env)
64
+ env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/i
65
+ end
66
+
67
+ def gzip_file_path(path)
68
+ can_gzip_mime = content_type(path) =~ /\A(?:text\/|application\/javascript)/
69
+ gzip_path = "#{path}.gz"
70
+ if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape(gzip_path)))
71
+ gzip_path
72
+ else
73
+ false
74
+ end
75
+ end
56
76
  end
57
77
 
58
78
  # This middleware will attempt to return the contents of a file's body from
@@ -241,8 +241,6 @@ module ActionDispatch
241
241
  end
242
242
 
243
243
  def app(blocks)
244
- return to if Redirect === to
245
-
246
244
  if to.respond_to?(:call)
247
245
  Constraints.new(to, blocks, false)
248
246
  else
@@ -116,7 +116,6 @@ module ActionDispatch
116
116
  action,
117
117
  type,
118
118
  opts
119
-
120
119
  end
121
120
 
122
121
  # Returns the path component of a URL for the given record. It uses
@@ -159,8 +158,7 @@ module ActionDispatch
159
158
  end
160
159
 
161
160
  def polymorphic_path_for_action(action, record_or_hash, options)
162
- options = options.merge(:action => action, :routing_type => :path)
163
- polymorphic_path(record_or_hash, options)
161
+ polymorphic_path(record_or_hash, options.merge(:action => action))
164
162
  end
165
163
 
166
164
  class HelperMethodBuilder # :nodoc:
@@ -197,7 +195,8 @@ module ActionDispatch
197
195
 
198
196
  case record_or_hash_or_array
199
197
  when Array
200
- if record_or_hash_or_array.empty? || record_or_hash_or_array.include?(nil)
198
+ record_or_hash_or_array = record_or_hash_or_array.compact
199
+ if record_or_hash_or_array.empty?
201
200
  raise ArgumentError, "Nil location provided. Can't build URI."
202
201
  end
203
202
  if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy)
@@ -38,7 +38,7 @@ module ActionDispatch
38
38
  # # Test a custom route
39
39
  # assert_recognizes({controller: 'items', action: 'show', id: '1'}, 'view/item1')
40
40
  def assert_recognizes(expected_options, path, extras={}, msg=nil)
41
- request = recognized_request_for(path, extras)
41
+ request = recognized_request_for(path, extras, msg)
42
42
 
43
43
  expected_options = expected_options.clone
44
44
 
@@ -69,9 +69,9 @@ module ActionDispatch
69
69
  #
70
70
  # # Asserts that the generated route gives us our custom route
71
71
  # assert_generates "changesets/12", { controller: 'scm', action: 'show_diff', revision: "12" }
72
- def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
72
+ def assert_generates(expected_path, options, defaults={}, extras={}, message=nil)
73
73
  if expected_path =~ %r{://}
74
- fail_on(URI::InvalidURIError) do
74
+ fail_on(URI::InvalidURIError, message) do
75
75
  uri = URI.parse(expected_path)
76
76
  expected_path = uri.path.to_s.empty? ? "/" : uri.path
77
77
  end
@@ -174,7 +174,7 @@ module ActionDispatch
174
174
 
175
175
  private
176
176
  # Recognizes the route for a given path.
177
- def recognized_request_for(path, extras = {})
177
+ def recognized_request_for(path, extras = {}, msg)
178
178
  if path.is_a?(Hash)
179
179
  method = path[:method]
180
180
  path = path[:path]
@@ -186,7 +186,7 @@ module ActionDispatch
186
186
  request = ActionController::TestRequest.new
187
187
 
188
188
  if path =~ %r{://}
189
- fail_on(URI::InvalidURIError) do
189
+ fail_on(URI::InvalidURIError, msg) do
190
190
  uri = URI.parse(path)
191
191
  request.env["rack.url_scheme"] = uri.scheme || "http"
192
192
  request.host = uri.host if uri.host
@@ -200,7 +200,7 @@ module ActionDispatch
200
200
 
201
201
  request.request_method = method if method
202
202
 
203
- params = fail_on(ActionController::RoutingError) do
203
+ params = fail_on(ActionController::RoutingError, msg) do
204
204
  @routes.recognize_path(path, { :method => method, :extras => extras })
205
205
  end
206
206
  request.path_parameters = params.with_indifferent_access
@@ -208,10 +208,10 @@ module ActionDispatch
208
208
  request
209
209
  end
210
210
 
211
- def fail_on(exception_class)
211
+ def fail_on(exception_class, message)
212
212
  yield
213
213
  rescue exception_class => e
214
- raise Minitest::Assertion, e.message
214
+ raise Minitest::Assertion, message || e.message
215
215
  end
216
216
  end
217
217
  end
@@ -1,3 +1,3 @@
1
1
  require 'active_support/deprecation'
2
2
 
3
- ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::SelectorAssertions has been has been extracted to the rails-dom-testing gem.")
3
+ ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::SelectorAssertions has been extracted to the rails-dom-testing gem.")
@@ -1,3 +1,3 @@
1
1
  require 'active_support/deprecation'
2
2
 
3
- ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::TagAssertions has been has been extracted to the rails-dom-testing gem.")
3
+ ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::TagAssertions has been extracted to the rails-dom-testing gem.")
@@ -1,5 +1,5 @@
1
1
  module ActionPack
2
- # Returns the version of the currently loaded ActionPack as a <tt>Gem::Version</tt>
2
+ # Returns the version of the currently loaded Action Pack as a <tt>Gem::Version</tt>
3
3
  def self.gem_version
4
4
  Gem::Version.new VERSION::STRING
5
5
  end
@@ -8,7 +8,7 @@ module ActionPack
8
8
  MAJOR = 4
9
9
  MINOR = 2
10
10
  TINY = 0
11
- PRE = "beta1"
11
+ PRE = "beta2"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actionpack
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0.beta1
4
+ version: 4.2.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-20 00:00:00.000000000 Z
11
+ date: 2014-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.0.beta1
19
+ version: 4.2.0.beta2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 4.2.0.beta1
26
+ version: 4.2.0.beta2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rack
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.6.2
55
55
  - !ruby/object:Gem::Dependency
56
- name: rails-deprecated_sanitizer
56
+ name: rails-html-sanitizer
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
@@ -61,7 +61,7 @@ dependencies:
61
61
  version: '1.0'
62
62
  - - ">="
63
63
  - !ruby/object:Gem::Version
64
- version: 1.0.2
64
+ version: 1.0.1
65
65
  type: :runtime
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
@@ -71,7 +71,7 @@ dependencies:
71
71
  version: '1.0'
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: 1.0.2
74
+ version: 1.0.1
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: rails-dom-testing
77
77
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +81,7 @@ dependencies:
81
81
  version: '1.0'
82
82
  - - ">="
83
83
  - !ruby/object:Gem::Version
84
- version: 1.0.2
84
+ version: 1.0.3
85
85
  type: :runtime
86
86
  prerelease: false
87
87
  version_requirements: !ruby/object:Gem::Requirement
@@ -91,35 +91,35 @@ dependencies:
91
91
  version: '1.0'
92
92
  - - ">="
93
93
  - !ruby/object:Gem::Version
94
- version: 1.0.2
94
+ version: 1.0.3
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: actionview
97
97
  requirement: !ruby/object:Gem::Requirement
98
98
  requirements:
99
99
  - - '='
100
100
  - !ruby/object:Gem::Version
101
- version: 4.2.0.beta1
101
+ version: 4.2.0.beta2
102
102
  type: :runtime
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
105
105
  requirements:
106
106
  - - '='
107
107
  - !ruby/object:Gem::Version
108
- version: 4.2.0.beta1
108
+ version: 4.2.0.beta2
109
109
  - !ruby/object:Gem::Dependency
110
110
  name: activemodel
111
111
  requirement: !ruby/object:Gem::Requirement
112
112
  requirements:
113
113
  - - '='
114
114
  - !ruby/object:Gem::Version
115
- version: 4.2.0.beta1
115
+ version: 4.2.0.beta2
116
116
  type: :development
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - '='
121
121
  - !ruby/object:Gem::Version
122
- version: 4.2.0.beta1
122
+ version: 4.2.0.beta2
123
123
  description: Web apps on Rails. Simple, battle-tested conventions for building and
124
124
  testing MVC web applications. Works with any Rack-compatible server.
125
125
  email: david@loudthinking.com