actionpack 4.1.7 → 4.2.11

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 (112) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +404 -451
  3. data/README.rdoc +7 -2
  4. data/lib/abstract_controller/base.rb +16 -6
  5. data/lib/abstract_controller/callbacks.rb +28 -51
  6. data/lib/abstract_controller/helpers.rb +11 -4
  7. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  8. data/lib/abstract_controller/rendering.rb +7 -1
  9. data/lib/abstract_controller/url_for.rb +1 -1
  10. data/lib/action_controller/base.rb +3 -2
  11. data/lib/action_controller/caching/fragments.rb +7 -1
  12. data/lib/action_controller/caching.rb +1 -1
  13. data/lib/action_controller/log_subscriber.rb +26 -26
  14. data/lib/action_controller/metal/conditional_get.rb +37 -12
  15. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  16. data/lib/action_controller/metal/exceptions.rb +1 -1
  17. data/lib/action_controller/metal/force_ssl.rb +1 -1
  18. data/lib/action_controller/metal/head.rb +7 -3
  19. data/lib/action_controller/metal/http_authentication.rb +20 -10
  20. data/lib/action_controller/metal/instrumentation.rb +8 -5
  21. data/lib/action_controller/metal/live.rb +57 -6
  22. data/lib/action_controller/metal/mime_responds.rb +25 -246
  23. data/lib/action_controller/metal/params_wrapper.rb +5 -5
  24. data/lib/action_controller/metal/rack_delegation.rb +1 -1
  25. data/lib/action_controller/metal/redirecting.rb +14 -8
  26. data/lib/action_controller/metal/renderers.rb +29 -11
  27. data/lib/action_controller/metal/rendering.rb +2 -6
  28. data/lib/action_controller/metal/request_forgery_protection.rb +78 -7
  29. data/lib/action_controller/metal/streaming.rb +1 -1
  30. data/lib/action_controller/metal/strong_parameters.rb +129 -14
  31. data/lib/action_controller/metal/url_for.rb +11 -12
  32. data/lib/action_controller/metal.rb +12 -11
  33. data/lib/action_controller/model_naming.rb +1 -1
  34. data/lib/action_controller/railtie.rb +4 -0
  35. data/lib/action_controller/test_case.rb +119 -75
  36. data/lib/action_controller.rb +1 -1
  37. data/lib/action_dispatch/http/cache.rb +5 -4
  38. data/lib/action_dispatch/http/filter_parameters.rb +2 -2
  39. data/lib/action_dispatch/http/headers.rb +43 -9
  40. data/lib/action_dispatch/http/mime_negotiation.rb +10 -3
  41. data/lib/action_dispatch/http/mime_type.rb +18 -4
  42. data/lib/action_dispatch/http/parameter_filter.rb +1 -1
  43. data/lib/action_dispatch/http/parameters.rb +11 -26
  44. data/lib/action_dispatch/http/request.rb +37 -11
  45. data/lib/action_dispatch/http/response.rb +74 -23
  46. data/lib/action_dispatch/http/upload.rb +9 -8
  47. data/lib/action_dispatch/http/url.rb +89 -70
  48. data/lib/action_dispatch/journey/formatter.rb +34 -18
  49. data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
  50. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
  51. data/lib/action_dispatch/journey/gtg/transition_table.rb +20 -28
  52. data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
  53. data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
  54. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
  55. data/lib/action_dispatch/journey/nodes/node.rb +4 -0
  56. data/lib/action_dispatch/journey/parser.rb +52 -60
  57. data/lib/action_dispatch/journey/parser.y +11 -10
  58. data/lib/action_dispatch/journey/path/pattern.rb +16 -19
  59. data/lib/action_dispatch/journey/route.rb +4 -19
  60. data/lib/action_dispatch/journey/router/strexp.rb +9 -6
  61. data/lib/action_dispatch/journey/router/utils.rb +1 -1
  62. data/lib/action_dispatch/journey/router.rb +53 -77
  63. data/lib/action_dispatch/journey/routes.rb +4 -0
  64. data/lib/action_dispatch/journey/scanner.rb +5 -5
  65. data/lib/action_dispatch/journey/visitors.rb +81 -92
  66. data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
  67. data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
  68. data/lib/action_dispatch/middleware/callbacks.rb +1 -1
  69. data/lib/action_dispatch/middleware/cookies.rb +34 -34
  70. data/lib/action_dispatch/middleware/debug_exceptions.rb +15 -4
  71. data/lib/action_dispatch/middleware/exception_wrapper.rb +50 -18
  72. data/lib/action_dispatch/middleware/flash.rb +13 -7
  73. data/lib/action_dispatch/middleware/params_parser.rb +1 -1
  74. data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
  75. data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
  76. data/lib/action_dispatch/middleware/request_id.rb +1 -1
  77. data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
  78. data/lib/action_dispatch/middleware/show_exceptions.rb +1 -0
  79. data/lib/action_dispatch/middleware/ssl.rb +1 -1
  80. data/lib/action_dispatch/middleware/static.rb +75 -39
  81. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
  82. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +37 -9
  83. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +2 -8
  84. data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +0 -0
  85. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  86. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
  87. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -0
  88. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +2 -0
  89. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -24
  90. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +0 -1
  91. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
  92. data/lib/action_dispatch/railtie.rb +2 -0
  93. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  94. data/lib/action_dispatch/routing/inspector.rb +5 -12
  95. data/lib/action_dispatch/routing/mapper.rb +414 -283
  96. data/lib/action_dispatch/routing/polymorphic_routes.rb +191 -79
  97. data/lib/action_dispatch/routing/redirection.rb +10 -12
  98. data/lib/action_dispatch/routing/route_set.rb +300 -173
  99. data/lib/action_dispatch/routing/routes_proxy.rb +5 -4
  100. data/lib/action_dispatch/routing/url_for.rb +17 -5
  101. data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
  102. data/lib/action_dispatch/testing/assertions/response.rb +2 -7
  103. data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
  104. data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
  105. data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
  106. data/lib/action_dispatch/testing/assertions.rb +11 -7
  107. data/lib/action_dispatch/testing/integration.rb +28 -20
  108. data/lib/action_dispatch/testing/test_request.rb +1 -1
  109. data/lib/action_dispatch/testing/test_response.rb +1 -5
  110. data/lib/action_pack/gem_version.rb +3 -3
  111. metadata +55 -13
  112. data/lib/action_controller/metal/responder.rb +0 -297
@@ -17,6 +17,7 @@ module ActionController
17
17
  autoload :ConditionalGet
18
18
  autoload :Cookies
19
19
  autoload :DataStreaming
20
+ autoload :EtagWithTemplateDigest
20
21
  autoload :Flash
21
22
  autoload :ForceSSL
22
23
  autoload :Head
@@ -33,7 +34,6 @@ module ActionController
33
34
  autoload :Rendering
34
35
  autoload :RequestForgeryProtection
35
36
  autoload :Rescue
36
- autoload :Responder
37
37
  autoload :Streaming
38
38
  autoload :StrongParameters
39
39
  autoload :Testing
@@ -69,17 +69,17 @@ module ActionDispatch
69
69
  end
70
70
 
71
71
  def date
72
- if date_header = headers['Date']
72
+ if date_header = headers[DATE]
73
73
  Time.httpdate(date_header)
74
74
  end
75
75
  end
76
76
 
77
77
  def date?
78
- headers.include?('Date')
78
+ headers.include?(DATE)
79
79
  end
80
80
 
81
81
  def date=(utc_time)
82
- headers['Date'] = utc_time.httpdate
82
+ headers[DATE] = utc_time.httpdate
83
83
  end
84
84
 
85
85
  def etag=(etag)
@@ -89,10 +89,11 @@ module ActionDispatch
89
89
 
90
90
  private
91
91
 
92
+ DATE = 'Date'.freeze
92
93
  LAST_MODIFIED = "Last-Modified".freeze
93
94
  ETAG = "ETag".freeze
94
95
  CACHE_CONTROL = "Cache-Control".freeze
95
- SPECIAL_KEYS = %w[extras no-cache max-age public must-revalidate]
96
+ SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public must-revalidate])
96
97
 
97
98
  def cache_control_segments
98
99
  if cache_control = self[CACHE_CONTROL]
@@ -6,8 +6,8 @@ module ActionDispatch
6
6
  module Http
7
7
  # Allows you to specify sensitive parameters which will be replaced from
8
8
  # the request log by looking in the query string of the request and all
9
- # subhashes of the params hash to filter. If a block is given, each key and
10
- # value of the params hash and all subhashes is passed to it, the value
9
+ # sub-hashes of the params hash to filter. If a block is given, each key and
10
+ # value of the params hash and all sub-hashes is passed to it, the value
11
11
  # or key can be replaced using String#replace or similar method.
12
12
  #
13
13
  # env["action_dispatch.parameter_filter"] = [:password]
@@ -1,27 +1,47 @@
1
1
  module ActionDispatch
2
2
  module Http
3
+ # Provides access to the request's HTTP headers from the environment.
4
+ #
5
+ # env = { "CONTENT_TYPE" => "text/plain" }
6
+ # headers = ActionDispatch::Http::Headers.new(env)
7
+ # headers["Content-Type"] # => "text/plain"
3
8
  class Headers
4
- CGI_VARIABLES = %w(
5
- CONTENT_TYPE CONTENT_LENGTH
6
- HTTPS AUTH_TYPE GATEWAY_INTERFACE
7
- PATH_INFO PATH_TRANSLATED QUERY_STRING
8
- REMOTE_ADDR REMOTE_HOST REMOTE_IDENT REMOTE_USER
9
- REQUEST_METHOD SCRIPT_NAME
10
- SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE
11
- )
9
+ CGI_VARIABLES = Set.new(%W[
10
+ AUTH_TYPE
11
+ CONTENT_LENGTH
12
+ CONTENT_TYPE
13
+ GATEWAY_INTERFACE
14
+ HTTPS
15
+ PATH_INFO
16
+ PATH_TRANSLATED
17
+ QUERY_STRING
18
+ REMOTE_ADDR
19
+ REMOTE_HOST
20
+ REMOTE_IDENT
21
+ REMOTE_USER
22
+ REQUEST_METHOD
23
+ SCRIPT_NAME
24
+ SERVER_NAME
25
+ SERVER_PORT
26
+ SERVER_PROTOCOL
27
+ SERVER_SOFTWARE
28
+ ]).freeze
29
+
12
30
  HTTP_HEADER = /\A[A-Za-z0-9-]+\z/
13
31
 
14
32
  include Enumerable
15
33
  attr_reader :env
16
34
 
17
- def initialize(env = {})
35
+ def initialize(env = {}) # :nodoc:
18
36
  @env = env
19
37
  end
20
38
 
39
+ # Returns the value for the given key mapped to @env.
21
40
  def [](key)
22
41
  @env[env_name(key)]
23
42
  end
24
43
 
44
+ # Sets the given value for the key mapped to @env.
25
45
  def []=(key, value)
26
46
  @env[env_name(key)] = value
27
47
  end
@@ -31,6 +51,13 @@ module ActionDispatch
31
51
  end
32
52
  alias :include? :key?
33
53
 
54
+ # Returns the value for the given key mapped to @env.
55
+ #
56
+ # If the key is not found and an optional code block is not provided,
57
+ # raises a <tt>KeyError</tt> exception.
58
+ #
59
+ # If the code block is provided, then it will be run and
60
+ # its result returned.
34
61
  def fetch(key, *args, &block)
35
62
  @env.fetch env_name(key), *args, &block
36
63
  end
@@ -39,12 +66,17 @@ module ActionDispatch
39
66
  @env.each(&block)
40
67
  end
41
68
 
69
+ # Returns a new Http::Headers instance containing the contents of
70
+ # <tt>headers_or_env</tt> and the original instance.
42
71
  def merge(headers_or_env)
43
72
  headers = Http::Headers.new(env.dup)
44
73
  headers.merge!(headers_or_env)
45
74
  headers
46
75
  end
47
76
 
77
+ # Adds the contents of <tt>headers_or_env</tt> to original instance
78
+ # entries; duplicate keys are overwritten with the values from
79
+ # <tt>headers_or_env</tt>.
48
80
  def merge!(headers_or_env)
49
81
  headers_or_env.each do |key, value|
50
82
  self[env_name(key)] = value
@@ -52,6 +84,8 @@ module ActionDispatch
52
84
  end
53
85
 
54
86
  private
87
+ # Converts a HTTP header name to an environment variable name if it is
88
+ # not contained within the headers hash.
55
89
  def env_name(key)
56
90
  key = key.to_s
57
91
  if key =~ HTTP_HEADER
@@ -54,8 +54,14 @@ module ActionDispatch
54
54
  end
55
55
 
56
56
  def formats
57
- @env["action_dispatch.request.formats"] ||=
58
- if parameters[:format]
57
+ @env["action_dispatch.request.formats"] ||= begin
58
+ params_readable = begin
59
+ parameters[:format]
60
+ rescue ActionController::BadRequest
61
+ false
62
+ end
63
+
64
+ if params_readable
59
65
  Array(Mime[parameters[:format]])
60
66
  elsif use_accept_header && valid_accept_header
61
67
  accepts
@@ -64,13 +70,14 @@ module ActionDispatch
64
70
  else
65
71
  [Mime::HTML]
66
72
  end
73
+ end
67
74
  end
68
75
 
69
76
  # Sets the \variant for template.
70
77
  def variant=(variant)
71
78
  if variant.is_a?(Symbol)
72
79
  @variant = [variant]
73
- elsif variant.is_a?(Array) && variant.any? && variant.all?{ |v| v.is_a?(Symbol) }
80
+ elsif variant.nil? || variant.is_a?(Array) && variant.any? && variant.all?{ |v| v.is_a?(Symbol) }
74
81
  @variant = variant
75
82
  else
76
83
  raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols, not a #{variant.class}. " \
@@ -23,7 +23,7 @@ module Mime
23
23
 
24
24
  SET = Mimes.new
25
25
  EXTENSION_LOOKUP = {}
26
- LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
26
+ LOOKUP = {}
27
27
 
28
28
  class << self
29
29
  def [](type)
@@ -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
@@ -146,7 +146,7 @@ module Mime
146
146
  end
147
147
 
148
148
  def lookup(string)
149
- LOOKUP[string]
149
+ LOOKUP[string] || Type.new(string)
150
150
  end
151
151
 
152
152
  def lookup_by_extension(extension)
@@ -225,9 +225,12 @@ module Mime
225
225
  end
226
226
  end
227
227
 
228
+ attr_reader :hash
229
+
228
230
  def initialize(string, symbol = nil, synonyms = [])
229
231
  @symbol, @synonyms = symbol, synonyms
230
232
  @string = string
233
+ @hash = [@string, @synonyms, @symbol].hash
231
234
  end
232
235
 
233
236
  def to_s
@@ -261,6 +264,13 @@ module Mime
261
264
  end
262
265
  end
263
266
 
267
+ def eql?(other)
268
+ super || (self.class == other.class &&
269
+ @string == other.string &&
270
+ @synonyms == other.synonyms &&
271
+ @symbol == other.symbol)
272
+ end
273
+
264
274
  def =~(mime_type)
265
275
  return false if mime_type.blank?
266
276
  regexp = Regexp.new(Regexp.quote(mime_type.to_s))
@@ -274,6 +284,10 @@ module Mime
274
284
  end
275
285
 
276
286
 
287
+ protected
288
+
289
+ attr_reader :string, :synonyms
290
+
277
291
  private
278
292
 
279
293
  def to_ary; end
@@ -56,7 +56,7 @@ module ActionDispatch
56
56
  elsif value.is_a?(Array)
57
57
  value = value.map { |v| v.is_a?(Hash) ? call(v) : v }
58
58
  elsif blocks.any?
59
- key = key.dup
59
+ key = key.dup if key.duplicable?
60
60
  value = value.dup if value.duplicable?
61
61
  blocks.each { |b| b.call(key, value) }
62
62
  end
@@ -1,13 +1,11 @@
1
1
  require 'active_support/core_ext/hash/keys'
2
2
  require 'active_support/core_ext/hash/indifferent_access'
3
+ require 'active_support/deprecation'
3
4
 
4
5
  module ActionDispatch
5
6
  module Http
6
7
  module Parameters
7
- def initialize(env)
8
- super
9
- @symbolized_path_params = nil
10
- end
8
+ PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
11
9
 
12
10
  # Returns both GET and POST \parameters in a single hash.
13
11
  def parameters
@@ -18,55 +16,42 @@ module ActionDispatch
18
16
  query_parameters.dup
19
17
  end
20
18
  params.merge!(path_parameters)
21
- params.with_indifferent_access
22
19
  end
23
20
  end
24
21
  alias :params :parameters
25
22
 
26
23
  def path_parameters=(parameters) #:nodoc:
27
- @symbolized_path_params = nil
28
- @env.delete("action_dispatch.request.parameters")
29
- @env["action_dispatch.request.path_parameters"] = parameters
24
+ @env.delete('action_dispatch.request.parameters')
25
+ @env[PARAMETERS_KEY] = parameters
30
26
  end
31
27
 
32
- # The same as <tt>path_parameters</tt> with explicitly symbolized keys.
33
28
  def symbolized_path_parameters
34
- @symbolized_path_params ||= path_parameters.symbolize_keys
29
+ ActiveSupport::Deprecation.warn(
30
+ '`symbolized_path_parameters` is deprecated. Please use `path_parameters`.'
31
+ )
32
+ path_parameters
35
33
  end
36
34
 
37
35
  # Returns a hash with the \parameters used to form the \path of the request.
38
36
  # Returned hash keys are strings:
39
37
  #
40
38
  # {'action' => 'my_action', 'controller' => 'my_controller'}
41
- #
42
- # See <tt>symbolized_path_parameters</tt> for symbolized keys.
43
39
  def path_parameters
44
- @env["action_dispatch.request.path_parameters"] ||= {}
45
- end
46
-
47
- def reset_parameters #:nodoc:
48
- @env.delete("action_dispatch.request.parameters")
40
+ @env[PARAMETERS_KEY] ||= {}
49
41
  end
50
42
 
51
43
  private
52
44
 
53
- # Convert nested Hash to HashWithIndifferentAccess
54
- # and UTF-8 encode both keys and values in nested Hash.
45
+ # Convert nested Hash to HashWithIndifferentAccess.
55
46
  #
56
- # TODO: Validate that the characters are UTF-8. If they aren't,
57
- # you'll get a weird error down the road, but our form handling
58
- # should really prevent that from happening
59
47
  def normalize_encode_params(params)
60
48
  case params
61
- when String
62
- params.force_encoding(Encoding::UTF_8).encode!
63
49
  when Hash
64
50
  if params.has_key?(:tempfile)
65
51
  UploadedFile.new(params)
66
52
  else
67
53
  params.each_with_object({}) do |(key, val), new_hash|
68
- new_key = key.is_a?(String) ? key.dup.force_encoding(Encoding::UTF_8).encode! : key
69
- new_hash[new_key] = if val.is_a?(Array)
54
+ new_hash[key] = if val.is_a?(Array)
70
55
  val.map! { |el| normalize_encode_params(el) }
71
56
  else
72
57
  normalize_encode_params(val)
@@ -23,7 +23,7 @@ module ActionDispatch
23
23
  autoload :Session, 'action_dispatch/request/session'
24
24
  autoload :Utils, 'action_dispatch/request/utils'
25
25
 
26
- LOCALHOST = Regexp.union [/^127\.0\.0\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/]
26
+ LOCALHOST = Regexp.union [/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/]
27
27
 
28
28
  ENV_METHODS = %w[ AUTH_TYPE GATEWAY_INTERFACE
29
29
  PATH_TRANSLATED REMOTE_HOST
@@ -53,6 +53,17 @@ module ActionDispatch
53
53
  @uuid = nil
54
54
  end
55
55
 
56
+ def check_path_parameters!
57
+ # If any of the path parameters has an invalid encoding then
58
+ # raise since it's likely to trigger errors further on.
59
+ path_parameters.each do |key, value|
60
+ next unless value.respond_to?(:valid_encoding?)
61
+ unless value.valid_encoding?
62
+ raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
63
+ end
64
+ end
65
+ end
66
+
56
67
  def key?(key)
57
68
  @env.key?(key)
58
69
  end
@@ -64,6 +75,7 @@ module ActionDispatch
64
75
  # Ordered Collections Protocol (WebDAV) (http://www.ietf.org/rfc/rfc3648.txt)
65
76
  # Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (http://www.ietf.org/rfc/rfc3744.txt)
66
77
  # Web Distributed Authoring and Versioning (WebDAV) SEARCH (http://www.ietf.org/rfc/rfc5323.txt)
78
+ # Calendar Extensions to WebDAV (http://www.ietf.org/rfc/rfc4791.txt)
67
79
  # PATCH Method for HTTP (http://www.ietf.org/rfc/rfc5789.txt)
68
80
  RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
69
81
  RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
@@ -71,9 +83,10 @@ module ActionDispatch
71
83
  RFC3648 = %w(ORDERPATCH)
72
84
  RFC3744 = %w(ACL)
73
85
  RFC5323 = %w(SEARCH)
86
+ RFC4791 = %w(MKCALENDAR)
74
87
  RFC5789 = %w(PATCH)
75
88
 
76
- HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789
89
+ HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
77
90
 
78
91
  HTTP_METHOD_LOOKUP = {}
79
92
 
@@ -92,6 +105,12 @@ module ActionDispatch
92
105
  @request_method ||= check_method(env["REQUEST_METHOD"])
93
106
  end
94
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
+
95
114
  # Returns a symbol form of the #request_method
96
115
  def request_method_symbol
97
116
  HTTP_METHOD_LOOKUP[request_method]
@@ -152,6 +171,13 @@ module ActionDispatch
152
171
  Http::Headers.new(@env)
153
172
  end
154
173
 
174
+ # Returns a +String+ with the last requested path including their params.
175
+ #
176
+ # # get '/foo'
177
+ # request.original_fullpath # => '/foo'
178
+ #
179
+ # # get '/foo?bar'
180
+ # request.original_fullpath # => '/foo?bar'
155
181
  def original_fullpath
156
182
  @original_fullpath ||= (env["ORIGINAL_FULLPATH"] || fullpath)
157
183
  end
@@ -189,8 +215,8 @@ module ActionDispatch
189
215
  end
190
216
 
191
217
  # Returns true if the "X-Requested-With" header contains "XMLHttpRequest"
192
- # (case-insensitive). All major JavaScript libraries send this header with
193
- # every Ajax request.
218
+ # (case-insensitive), which may need to be manually added depending on the
219
+ # choice of JavaScript libraries and frameworks.
194
220
  def xml_http_request?
195
221
  @env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/i
196
222
  end
@@ -205,7 +231,7 @@ module ActionDispatch
205
231
  @remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
206
232
  end
207
233
 
208
- # Returns the unique request id, which is based off either the X-Request-Id header that can
234
+ # Returns the unique request id, which is based on either the X-Request-Id header that can
209
235
  # be generated by a firewall, load balancer, or web server or by the RequestId middleware
210
236
  # (which sets the action_dispatch.request_id environment variable).
211
237
  #
@@ -271,16 +297,16 @@ module ActionDispatch
271
297
 
272
298
  # Override Rack's GET method to support indifferent access
273
299
  def GET
274
- @env["action_dispatch.request.query_parameters"] ||= Utils.deep_munge((normalize_encode_params(super) || {}))
275
- rescue TypeError => e
300
+ @env["action_dispatch.request.query_parameters"] ||= Utils.deep_munge(normalize_encode_params(super || {}))
301
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
276
302
  raise ActionController::BadRequest.new(:query, e)
277
303
  end
278
304
  alias :query_parameters :GET
279
305
 
280
306
  # Override Rack's POST method to support indifferent access
281
307
  def POST
282
- @env["action_dispatch.request.request_parameters"] ||= Utils.deep_munge((normalize_encode_params(super) || {}))
283
- rescue TypeError => e
308
+ @env["action_dispatch.request.request_parameters"] ||= Utils.deep_munge(normalize_encode_params(super || {}))
309
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
284
310
  raise ActionController::BadRequest.new(:request, e)
285
311
  end
286
312
  alias :request_parameters :POST
@@ -302,7 +328,7 @@ module ActionDispatch
302
328
  # Extracted into ActionDispatch::Request::Utils.deep_munge, but kept here for backwards compatibility.
303
329
  def deep_munge(hash)
304
330
  ActiveSupport::Deprecation.warn(
305
- "This method has been extracted into ActionDispatch::Request::Utils.deep_munge. Please start using that instead."
331
+ 'This method has been extracted into `ActionDispatch::Request::Utils.deep_munge`. Please start using that instead.'
306
332
  )
307
333
 
308
334
  Utils.deep_munge(hash)
@@ -315,7 +341,7 @@ module ActionDispatch
315
341
 
316
342
  private
317
343
  def check_method(name)
318
- HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
344
+ HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
319
345
  name
320
346
  end
321
347
  end