aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md19
-rw-r--r--actionpack/lib/abstract_controller/url_for.rb2
-rw-r--r--actionpack/lib/action_controller/caching/fragments.rb8
-rw-r--r--actionpack/lib/action_controller/metal.rb4
-rw-r--r--actionpack/lib/action_controller/metal/head.rb2
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb16
-rw-r--r--actionpack/lib/action_controller/metal/live.rb3
-rw-r--r--actionpack/lib/action_controller/metal/rack_delegation.rb2
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb12
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb16
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb3
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb57
-rw-r--r--actionpack/lib/action_dispatch/journey/formatter.rb8
-rw-r--r--actionpack/lib/action_dispatch/journey/parser.rb88
-rw-r--r--actionpack/lib/action_dispatch/journey/parser.y5
-rw-r--r--actionpack/lib/action_dispatch/journey/path/pattern.rb4
-rw-r--r--actionpack/lib/action_dispatch/journey/route.rb11
-rw-r--r--actionpack/lib/action_dispatch/journey/router.rb12
-rw-r--r--actionpack/lib/action_dispatch/journey/visitors.rb173
-rw-r--r--actionpack/lib/action_dispatch/middleware/public_exceptions.rb5
-rw-r--r--actionpack/lib/action_dispatch/routing.rb1
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb61
-rw-r--r--actionpack/test/abstract/collector_test.rb16
-rw-r--r--actionpack/test/controller/caching_test.rb16
-rw-r--r--actionpack/test/controller/http_basic_authentication_test.rb7
-rw-r--r--actionpack/test/controller/integration_test.rb31
-rw-r--r--actionpack/test/controller/live_stream_test.rb16
-rw-r--r--actionpack/test/controller/mime/respond_with_test.rb33
-rw-r--r--actionpack/test/controller/url_for_test.rb20
-rw-r--r--actionpack/test/dispatch/routing/route_set_test.rb4
-rw-r--r--actionpack/test/dispatch/routing_test.rb5
-rw-r--r--actionpack/test/journey/router_test.rb67
35 files changed, 459 insertions, 282 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 5123713c6b..be1f53faf5 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,22 @@
+* Fix 'Stack level too deep' when rendering `head :ok` in an action method
+ called 'status' in a controller.
+
+ Fixes #13905.
+
+ *Christiaan Van den Poel*
+
+* Add MKCALENDAR HTTP method (RFC 4791).
+
+ *Sergey Karpesh*
+
+* Instrument fragment cache metrics.
+
+ Adds `:controller`: and `:action` keys to the instrumentation payload
+ for the `*_fragment.action_controller` notifications. This allows tracking
+ e.g. the fragment cache hit rates for each controller action.
+
+ *Daniel Schierbeck*
+
* Always use the provided port if the protocol is relative.
Fixes #15043.
diff --git a/actionpack/lib/abstract_controller/url_for.rb b/actionpack/lib/abstract_controller/url_for.rb
index 4a95e1f276..72d07b0927 100644
--- a/actionpack/lib/abstract_controller/url_for.rb
+++ b/actionpack/lib/abstract_controller/url_for.rb
@@ -11,7 +11,7 @@ module AbstractController
def _routes
raise "In order to use #url_for, you must include routing helpers explicitly. " \
- "For instance, `include Rails.application.routes.url_helpers"
+ "For instance, `include Rails.application.routes.url_helpers`."
end
module ClassMethods
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb
index 879d5fdd94..2694d4c12f 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/action_controller/caching/fragments.rb
@@ -90,7 +90,13 @@ module ActionController
end
def instrument_fragment_cache(name, key) # :nodoc:
- ActiveSupport::Notifications.instrument("#{name}.action_controller", :key => key){ yield }
+ payload = {
+ controller: controller_name,
+ action: action_name,
+ key: key
+ }
+
+ ActiveSupport::Notifications.instrument("#{name}.action_controller", payload) { yield }
end
end
end
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 0f4cc7a8f5..696fbf6e09 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -232,5 +232,9 @@ module ActionController
new.dispatch(name, klass.new(env))
end
end
+
+ def _status_code
+ @_status
+ end
end
end
diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb
index 43407f5b78..84a9112144 100644
--- a/actionpack/lib/action_controller/metal/head.rb
+++ b/actionpack/lib/action_controller/metal/head.rb
@@ -27,7 +27,7 @@ module ActionController
self.status = status
self.location = url_for(location) if location
- if include_content?(self.status)
+ if include_content?(self._status_code)
self.content_type = content_type || (Mime[formats.first] if formats)
self.response.charset = false if self.response
self.response_body = " "
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 2eb7853aa6..3111992f82 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -90,17 +90,29 @@ module ActionController
end
def authenticate(request, &login_procedure)
- unless request.authorization.blank?
+ if has_basic_credentials?(request)
login_procedure.call(*user_name_and_password(request))
end
end
+ def has_basic_credentials?(request)
+ request.authorization.present? && (auth_scheme(request) == 'Basic')
+ end
+
def user_name_and_password(request)
decode_credentials(request).split(':', 2)
end
def decode_credentials(request)
- ::Base64.decode64(request.authorization.split(' ', 2).last || '')
+ ::Base64.decode64(auth_param(request) || '')
+ end
+
+ def auth_scheme(request)
+ request.authorization.split(' ', 2).first
+ end
+
+ def auth_param(request)
+ request.authorization.split(' ', 2).second
end
def encode_credentials(user_name, password)
diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb
index acf40b2e16..4c0554d27b 100644
--- a/actionpack/lib/action_controller/metal/live.rb
+++ b/actionpack/lib/action_controller/metal/live.rb
@@ -102,7 +102,8 @@ module ActionController
end
end
- @stream.write "data: #{json}\n\n"
+ message = json.gsub("\n", "\ndata: ")
+ @stream.write "data: #{message}\n\n"
end
end
diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb
index bdf6e88699..6921834044 100644
--- a/actionpack/lib/action_controller/metal/rack_delegation.rb
+++ b/actionpack/lib/action_controller/metal/rack_delegation.rb
@@ -6,7 +6,7 @@ module ActionController
extend ActiveSupport::Concern
delegate :headers, :status=, :location=, :content_type=,
- :status, :location, :content_type, :to => "@_response"
+ :status, :location, :content_type, :_status_code, :to => "@_response"
def dispatch(action, request)
set_response!(request)
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 2812038938..136e086d0d 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -14,7 +14,7 @@ module ActionController
include ActionController::RackDelegation
include ActionController::UrlFor
- # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
+ # Redirects the browser to the target specified in +options+. This parameter can be any one of:
#
# * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
# * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
@@ -24,6 +24,8 @@ module ActionController
# * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
# Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
#
+ # === Examples:
+ #
# redirect_to action: "show", id: 5
# redirect_to post
# redirect_to "http://www.rubyonrails.org"
@@ -32,7 +34,7 @@ module ActionController
# redirect_to :back
# redirect_to proc { edit_post_url(@post) }
#
- # The redirection happens as a "302 Found" header unless otherwise specified.
+ # The redirection happens as a "302 Found" header unless otherwise specified using the <tt>:status</tt> option:
#
# redirect_to post_url(@post), status: :found
# redirect_to action: 'atom', status: :moved_permanently
@@ -60,8 +62,10 @@ module ActionController
# redirect_to post_url(@post), status: 301, flash: { updated_post_id: @post.id }
# redirect_to({ action: 'atom' }, alert: "Something serious happened")
#
- # When using <tt>redirect_to :back</tt>, if there is no referrer, ActionController::RedirectBackError will be raised. You may specify some fallback
- # behavior for this case by rescuing ActionController::RedirectBackError.
+ # When using <tt>redirect_to :back</tt>, if there is no referrer,
+ # <tt>ActionController::RedirectBackError</tt> will be raised. You
+ # may specify some fallback behavior for this case by rescuing
+ # <tt>ActionController::RedirectBackError</tt>.
def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index 0443b73953..29ce5abd55 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -6,6 +6,11 @@ module ActionController
Renderers.add(key, &block)
end
+ # See <tt>Renderers.remove</tt>
+ def self.remove_renderer(key)
+ Renderers.remove(key)
+ end
+
class MissingRenderer < LoadError
def initialize(format)
super "No renderer defined for format: #{format}"
@@ -83,6 +88,17 @@ module ActionController
RENDERERS << key.to_sym
end
+ # This method is the opposite of add method.
+ #
+ # Usage:
+ #
+ # ActionController::Renderers.remove(:csv)
+ def self.remove(key)
+ RENDERERS.delete(key.to_sym)
+ method = "_render_option_#{key}"
+ remove_method(method) if method_defined?(method)
+ end
+
module All
extend ActiveSupport::Concern
include Renderers
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 37d4a96ee1..89c3545323 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -23,12 +23,12 @@ module ActionController
include AbstractController::UrlFor
def url_options
- @_url_options ||= super.reverse_merge(
+ @_url_options ||= {
:host => request.host,
:port => request.optional_port,
:protocol => request.protocol,
:_recall => request.symbolized_path_parameters
- ).freeze
+ }.merge(super).freeze
if (same_origin = _routes.equal?(env["action_dispatch.routes".freeze])) ||
(script_name = env["ROUTES_#{_routes.object_id}_SCRIPT_NAME"]) ||
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index dcb299ed03..378d7393ff 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -25,8 +25,8 @@ module ActionDispatch
def path_parameters=(parameters) #:nodoc:
@symbolized_path_params = nil
- @env.delete("action_dispatch.request.parameters")
- @env["action_dispatch.request.path_parameters"] = parameters
+ @env.delete(Routing::RouteSet::PARAMETERS_KEY)
+ @env[Routing::RouteSet::PARAMETERS_KEY] = parameters
end
# The same as <tt>path_parameters</tt> with explicitly symbolized keys.
@@ -41,7 +41,7 @@ module ActionDispatch
#
# See <tt>symbolized_path_parameters</tt> for symbolized keys.
def path_parameters
- @env["action_dispatch.request.path_parameters"] ||= {}
+ @env[Routing::RouteSet::PARAMETERS_KEY] ||= {}
end
def reset_parameters #:nodoc:
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index daa06e96e6..cdb3e44b3a 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -64,6 +64,7 @@ module ActionDispatch
# Ordered Collections Protocol (WebDAV) (http://www.ietf.org/rfc/rfc3648.txt)
# Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (http://www.ietf.org/rfc/rfc3744.txt)
# Web Distributed Authoring and Versioning (WebDAV) SEARCH (http://www.ietf.org/rfc/rfc5323.txt)
+ # Calendar Extensions to WebDAV (http://www.ietf.org/rfc/rfc4791.txt)
# PATCH Method for HTTP (http://www.ietf.org/rfc/rfc5789.txt)
RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
@@ -71,9 +72,10 @@ module ActionDispatch
RFC3648 = %w(ORDERPATCH)
RFC3744 = %w(ACL)
RFC5323 = %w(SEARCH)
+ RFC4791 = %w(MKCALENDAR)
RFC5789 = %w(PATCH)
- HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789
+ HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
HTTP_METHOD_LOOKUP = {}
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 3d27ff2b24..eaea93b730 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -296,6 +296,9 @@ module ActionDispatch # :nodoc:
cookies
end
+ def _status_code
+ @status
+ end
private
def before_committed
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index c9860af909..a6c17f50a5 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -30,19 +30,25 @@ module ActionDispatch
end
def url_for(options)
+ unless options[:host] || options[:only_path]
+ raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
+ end
+
path = options[:script_name].to_s.chomp("/")
path << options[:path].to_s
- result = build_host_url(options)
-
if options[:trailing_slash]
if path.include?('?')
- result << path.sub(/\?/, '/\&')
+ path.sub!(/\?/, '/\&')
else
- result << path.sub(/[^\/]\z|\A\z/, '\&/')
+ path.sub!(/[^\/]\z|\A\z/, '\&/')
end
- else
- result << path
+ end
+
+ result = path
+
+ unless options[:only_path]
+ result.prepend build_host_url(options)
end
if options.key? :params
@@ -61,28 +67,25 @@ module ActionDispatch
private
def build_host_url(options)
- unless options[:host] || options[:only_path]
- raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
+ if match = options[:host].match(HOST_REGEXP)
+ options[:protocol] ||= match[1] unless options[:protocol] == false
+ options[:host] = match[2]
+ options[:port] = match[3] unless options.key?(:port)
end
- result = ""
+ options[:protocol] = normalize_protocol(options)
+ options[:host] = normalize_host(options)
+ options[:port] = normalize_port(options)
- unless options[:only_path]
- if match = options[:host].match(HOST_REGEXP)
- options[:protocol] ||= match[1] unless options[:protocol] == false
- options[:host] = match[2]
- options[:port] = match[3] unless options.key?(:port)
- end
-
- options[:protocol] = normalize_protocol(options)
- options[:host] = normalize_host(options)
- options[:port] = normalize_port(options)
+ result = options[:protocol]
- result << options[:protocol]
- result << rewrite_authentication(options)
- result << options[:host]
- result << ":#{options[:port]}" if options[:port]
+ if options[:user] && options[:password]
+ result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
end
+
+ result << options[:host]
+ result << ":#{options[:port]}" if options[:port]
+
result
end
@@ -94,14 +97,6 @@ module ActionDispatch
(options[:subdomain] == true || !options.key?(:subdomain)) && options[:domain].nil?
end
- def rewrite_authentication(options)
- if options[:user] && options[:password]
- "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
- else
- ""
- end
- end
-
def normalize_protocol(options)
case options[:protocol]
when nil
diff --git a/actionpack/lib/action_dispatch/journey/formatter.rb b/actionpack/lib/action_dispatch/journey/formatter.rb
index 57f0963731..7eaf8e49ce 100644
--- a/actionpack/lib/action_dispatch/journey/formatter.rb
+++ b/actionpack/lib/action_dispatch/journey/formatter.rb
@@ -12,7 +12,7 @@ module ActionDispatch
@cache = nil
end
- def generate(type, name, options, recall = {}, parameterize = nil)
+ def generate(name, options, recall = {}, parameterize = nil)
constraints = recall.merge(options)
missing_keys = []
@@ -30,6 +30,12 @@ module ActionDispatch
parameterized_parts.key?(key) || route.defaults.key?(key)
end
+ defaults = route.defaults
+ required_parts = route.required_parts
+ parameterized_parts.delete_if do |key, value|
+ value.to_s == defaults[key].to_s && !required_parts.include?(key)
+ end
+
return [route.format(parameterized_parts), params]
end
diff --git a/actionpack/lib/action_dispatch/journey/parser.rb b/actionpack/lib/action_dispatch/journey/parser.rb
index 430812fafe..d129ba7e16 100644
--- a/actionpack/lib/action_dispatch/journey/parser.rb
+++ b/actionpack/lib/action_dispatch/journey/parser.rb
@@ -1,7 +1,7 @@
#
# DO NOT MODIFY!!!!
-# This file is automatically generated by Racc 1.4.9
-# from Racc grammar file "".
+# This file is automatically generated by Racc 1.4.11
+# from Racc grammer file "".
#
require 'racc/parser.rb'
@@ -9,42 +9,38 @@ require 'racc/parser.rb'
require 'action_dispatch/journey/parser_extras'
module ActionDispatch
- module Journey # :nodoc:
- class Parser < Racc::Parser # :nodoc:
+ module Journey
+ class Parser < Racc::Parser
##### State transition tables begin ###
racc_action_table = [
- 17, 21, 13, 15, 14, 7, nil, 16, 8, 19,
- 13, 15, 14, 7, 23, 16, 8, 19, 13, 15,
- 14, 7, nil, 16, 8, 13, 15, 14, 7, nil,
- 16, 8, 13, 15, 14, 7, nil, 16, 8 ]
+ 13, 15, 14, 7, 21, 16, 8, 19, 13, 15,
+ 14, 7, 17, 16, 8, 13, 15, 14, 7, 24,
+ 16, 8, 13, 15, 14, 7, 19, 16, 8 ]
racc_action_check = [
- 1, 17, 1, 1, 1, 1, nil, 1, 1, 1,
- 20, 20, 20, 20, 20, 20, 20, 20, 7, 7,
- 7, 7, nil, 7, 7, 19, 19, 19, 19, nil,
- 19, 19, 0, 0, 0, 0, nil, 0, 0 ]
+ 2, 2, 2, 2, 17, 2, 2, 2, 0, 0,
+ 0, 0, 1, 0, 0, 19, 19, 19, 19, 20,
+ 19, 19, 7, 7, 7, 7, 22, 7, 7 ]
racc_action_pointer = [
- 30, 0, nil, nil, nil, nil, nil, 16, nil, nil,
- nil, nil, nil, nil, nil, nil, nil, 1, nil, 23,
- 8, nil, nil, nil ]
+ 6, 12, -2, nil, nil, nil, nil, 20, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, 4, nil, 13,
+ 13, nil, 17, nil, nil ]
racc_action_default = [
- -18, -18, -2, -3, -4, -5, -6, -18, -9, -10,
- -11, -12, -13, -14, -15, -16, -17, -18, -1, -18,
- -18, 24, -8, -7 ]
+ -19, -19, -2, -3, -4, -5, -6, -19, -10, -11,
+ -12, -13, -14, -15, -16, -17, -18, -19, -1, -19,
+ -19, 25, -8, -9, -7 ]
racc_goto_table = [
- 18, 1, nil, nil, nil, nil, nil, nil, 20, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, 22, 18 ]
+ 1, 22, 18, 23, nil, nil, nil, 20 ]
racc_goto_check = [
- 2, 1, nil, nil, nil, nil, nil, nil, 1, nil,
- nil, nil, nil, nil, nil, nil, nil, nil, 2, 2 ]
+ 1, 2, 1, 3, nil, nil, nil, 1 ]
racc_goto_pointer = [
- nil, 1, -1, nil, nil, nil, nil, nil, nil, nil,
+ nil, 0, -18, -16, nil, nil, nil, nil, nil, nil,
nil ]
racc_goto_default = [
@@ -61,19 +57,20 @@ racc_reduce_table = [
1, 12, :_reduce_none,
3, 15, :_reduce_7,
3, 13, :_reduce_8,
- 1, 16, :_reduce_9,
+ 3, 13, :_reduce_9,
+ 1, 16, :_reduce_10,
1, 14, :_reduce_none,
1, 14, :_reduce_none,
1, 14, :_reduce_none,
1, 14, :_reduce_none,
- 1, 19, :_reduce_14,
- 1, 17, :_reduce_15,
- 1, 18, :_reduce_16,
- 1, 20, :_reduce_17 ]
+ 1, 19, :_reduce_15,
+ 1, 17, :_reduce_16,
+ 1, 18, :_reduce_17,
+ 1, 20, :_reduce_18 ]
-racc_reduce_n = 18
+racc_reduce_n = 19
-racc_shift_n = 24
+racc_shift_n = 25
racc_token_table = {
false => 0,
@@ -137,12 +134,12 @@ Racc_debug_parser = false
# reduce 0 omitted
def _reduce_1(val, _values, result)
- result = Cat.new(val.first, val.last)
+ result = Cat.new(val.first, val.last)
result
end
def _reduce_2(val, _values, result)
- result = val.first
+ result = val.first
result
end
@@ -155,21 +152,24 @@ end
# reduce 6 omitted
def _reduce_7(val, _values, result)
- result = Group.new(val[1])
+ result = Group.new(val[1])
result
end
def _reduce_8(val, _values, result)
- result = Or.new([val.first, val.last])
+ result = Or.new([val.first, val.last])
result
end
def _reduce_9(val, _values, result)
- result = Star.new(Symbol.new(val.last))
+ result = Or.new([val.first, val.last])
result
end
-# reduce 10 omitted
+def _reduce_10(val, _values, result)
+ result = Star.new(Symbol.new(val.last))
+ result
+end
# reduce 11 omitted
@@ -177,23 +177,25 @@ end
# reduce 13 omitted
-def _reduce_14(val, _values, result)
- result = Slash.new('/')
- result
-end
+# reduce 14 omitted
def _reduce_15(val, _values, result)
- result = Symbol.new(val.first)
+ result = Slash.new('/')
result
end
def _reduce_16(val, _values, result)
- result = Literal.new(val.first)
+ result = Symbol.new(val.first)
result
end
def _reduce_17(val, _values, result)
- result = Dot.new(val.first)
+ result = Literal.new(val.first)
+ result
+end
+
+def _reduce_18(val, _values, result)
+ result = Dot.new(val.first)
result
end
diff --git a/actionpack/lib/action_dispatch/journey/parser.y b/actionpack/lib/action_dispatch/journey/parser.y
index 040f8d5922..0ead222551 100644
--- a/actionpack/lib/action_dispatch/journey/parser.y
+++ b/actionpack/lib/action_dispatch/journey/parser.y
@@ -4,7 +4,7 @@ token SLASH LITERAL SYMBOL LPAREN RPAREN DOT STAR OR
rule
expressions
- : expressions expression { result = Cat.new(val.first, val.last) }
+ : expression expressions { result = Cat.new(val.first, val.last) }
| expression { result = val.first }
| or
;
@@ -17,7 +17,8 @@ rule
: LPAREN expressions RPAREN { result = Group.new(val[1]) }
;
or
- : expressions OR expression { result = Or.new([val.first, val.last]) }
+ : expression OR expression { result = Or.new([val.first, val.last]) }
+ | expression OR or { result = Or.new([val.first, val.last]) }
;
star
: STAR { result = Star.new(Symbol.new(val.last)) }
diff --git a/actionpack/lib/action_dispatch/journey/path/pattern.rb b/actionpack/lib/action_dispatch/journey/path/pattern.rb
index fb155e516f..cb0a02c298 100644
--- a/actionpack/lib/action_dispatch/journey/path/pattern.rb
+++ b/actionpack/lib/action_dispatch/journey/path/pattern.rb
@@ -30,6 +30,10 @@ module ActionDispatch
@offsets = nil
end
+ def build_formatter
+ Visitors::FormatBuilder.new.accept(spec)
+ end
+
def ast
@spec.grep(Nodes::Symbol).each do |node|
re = @requirements[node.to_sym]
diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb
index 2b399d3ee3..cc3c7f20cb 100644
--- a/actionpack/lib/action_dispatch/journey/route.rb
+++ b/actionpack/lib/action_dispatch/journey/route.rb
@@ -31,6 +31,7 @@ module ActionDispatch
@parts = nil
@decorated_ast = nil
@precedence = 0
+ @path_formatter = @path.build_formatter
end
def ast
@@ -72,15 +73,7 @@ module ActionDispatch
alias :segment_keys :parts
def format(path_options)
- path_options.delete_if do |key, value|
- value.to_s == defaults[key].to_s && !required_parts.include?(key)
- end
-
- Visitors::Formatter.new(path_options).accept(path.spec)
- end
-
- def optimized_path
- Visitors::OptimizedPath.new.accept(path.spec)
+ @path_formatter.evaluate path_options
end
def optional_parts
diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb
index 36561c71a1..3bfa03713d 100644
--- a/actionpack/lib/action_dispatch/journey/router.rb
+++ b/actionpack/lib/action_dispatch/journey/router.rb
@@ -90,7 +90,7 @@ module ActionDispatch
req.env['PATH_INFO'] = match.post_match.sub(/^([^\/])/, '/\1')
end
- yield(route, nil, parameters)
+ yield(route, parameters)
end
end
@@ -136,11 +136,11 @@ module ActionDispatch
routes.map! { |r|
match_data = r.path.match(req.path_info)
- match_names = match_data.names.map { |n| n.to_sym }
- match_values = match_data.captures.map { |v| v && Utils.unescape_uri(v) }
- info = Hash[match_names.zip(match_values).find_all { |_, y| y }]
-
- [match_data, r.defaults.merge(info), r]
+ path_parameters = r.defaults.dup
+ match_data.names.zip(match_data.captures) { |name,val|
+ path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
+ }
+ [match_data, path_parameters, r]
}
end
diff --git a/actionpack/lib/action_dispatch/journey/visitors.rb b/actionpack/lib/action_dispatch/journey/visitors.rb
index d9f634623d..52b4c8b489 100644
--- a/actionpack/lib/action_dispatch/journey/visitors.rb
+++ b/actionpack/lib/action_dispatch/journey/visitors.rb
@@ -1,14 +1,57 @@
# encoding: utf-8
-require 'thread_safe'
-
module ActionDispatch
module Journey # :nodoc:
+ class Format
+ ESCAPE_PATH = ->(value) { Router::Utils.escape_path(value) }
+ ESCAPE_SEGMENT = ->(value) { Router::Utils.escape_segment(value) }
+
+ class Parameter < Struct.new(:name, :escaper)
+ def escape(value); escaper.call value; end
+ end
+
+ def self.required_path(symbol)
+ Parameter.new symbol, ESCAPE_PATH
+ end
+
+ def self.required_segment(symbol)
+ Parameter.new symbol, ESCAPE_SEGMENT
+ end
+
+ def initialize(parts)
+ @parts = parts
+ @children = []
+ @parameters = []
+
+ parts.each_with_index do |object,i|
+ case object
+ when Journey::Format
+ @children << i
+ when Parameter
+ @parameters << i
+ end
+ end
+ end
+
+ def evaluate(hash)
+ parts = @parts.dup
+
+ @parameters.each do |index|
+ param = parts[index]
+ value = hash[param.name]
+ return ''.freeze unless value
+ parts[index] = param.escape value
+ end
+
+ @children.each { |index| parts[index] = parts[index].evaluate(hash) }
+
+ parts.join
+ end
+ end
+
module Visitors # :nodoc:
class Visitor # :nodoc:
- DISPATCH_CACHE = ThreadSafe::Cache.new { |h,k|
- h[k] = :"visit_#{k}"
- }
+ DISPATCH_CACHE = {}
def accept(node)
visit(node)
@@ -38,11 +81,41 @@ module ActionDispatch
def visit_STAR(n); unary(n); end
def terminal(node); end
- %w{ LITERAL SYMBOL SLASH DOT }.each do |t|
- class_eval %{ def visit_#{t}(n); terminal(n); end }, __FILE__, __LINE__
+ def visit_LITERAL(n); terminal(n); end
+ def visit_SYMBOL(n); terminal(n); end
+ def visit_SLASH(n); terminal(n); end
+ def visit_DOT(n); terminal(n); end
+
+ private_instance_methods(false).each do |pim|
+ next unless pim =~ /^visit_(.*)$/
+ DISPATCH_CACHE[$1.to_sym] = pim
end
end
+ class FormatBuilder < Visitor # :nodoc:
+ def accept(node); Journey::Format.new(super); end
+ def terminal(node); [node.left]; end
+
+ def binary(node)
+ visit(node.left) + visit(node.right)
+ end
+
+ def visit_GROUP(n); [Journey::Format.new(unary(n))]; end
+
+ def visit_STAR(n)
+ [Journey::Format.required_path(n.left.to_sym)]
+ end
+
+ def visit_SYMBOL(n)
+ symbol = n.to_sym
+ if symbol == :controller
+ [Journey::Format.required_path(symbol)]
+ else
+ [Journey::Format.required_segment(symbol)]
+ end
+ end
+ end
+
# Loop through the requirements AST
class Each < Visitor # :nodoc:
attr_reader :block
@@ -52,8 +125,8 @@ module ActionDispatch
end
def visit(node)
- super
block.call(node)
+ super
end
end
@@ -77,90 +150,6 @@ module ActionDispatch
end
end
- class OptimizedPath < Visitor # :nodoc:
- def accept(node)
- Array(visit(node))
- end
-
- private
-
- def visit_CAT(node)
- [visit(node.left), visit(node.right)].flatten
- end
-
- def visit_SYMBOL(node)
- node.left[1..-1].to_sym
- end
-
- def visit_STAR(node)
- visit(node.left)
- end
-
- def visit_GROUP(node)
- []
- end
-
- %w{ LITERAL SLASH DOT }.each do |t|
- class_eval %{ def visit_#{t}(n); n.left; end }, __FILE__, __LINE__
- end
- end
-
- # Used for formatting urls (url_for)
- class Formatter < Visitor # :nodoc:
- attr_reader :options
-
- def initialize(options)
- @options = options
- end
-
- private
- def escape_path(value)
- Router::Utils.escape_path(value)
- end
-
- def escape_segment(value)
- Router::Utils.escape_segment(value)
- end
-
- def visit(node, optional = false)
- case node.type
- when :LITERAL, :SLASH, :DOT
- node.left
- when :STAR
- visit_STAR(node.left)
- when :GROUP
- visit(node.left, true)
- when :CAT
- visit_CAT(node, optional)
- when :SYMBOL
- visit_SYMBOL(node, node.to_sym)
- end
- end
-
- def visit_CAT(node, optional)
- left = visit(node.left, optional)
- right = visit(node.right, optional)
-
- if optional && !(right && left)
- ""
- else
- [left, right].join
- end
- end
-
- def visit_STAR(node)
- if value = options[node.to_sym]
- escape_path(value)
- end
- end
-
- def visit_SYMBOL(node, name)
- if value = options[name]
- name == :controller ? escape_path(value) : escape_segment(value)
- end
- end
- end
-
class Dot < Visitor # :nodoc:
def initialize
@nodes = []
diff --git a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
index cbb2d475b1..6c8944e067 100644
--- a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb
@@ -32,9 +32,8 @@ module ActionDispatch
end
def render_html(status)
- found = false
- path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale
- path = "#{public_path}/#{status}.html" unless path && (found = File.exist?(path))
+ path = "#{public_path}/#{status}.#{I18n.locale}.html"
+ path = "#{public_path}/#{status}.html" unless (found = File.exist?(path))
if found || File.exist?(path)
render_format(status, 'text/html', File.read(path))
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 9cd884daa3..ce03164ca9 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -1,6 +1,7 @@
# encoding: UTF-8
require 'active_support/core_ext/object/to_param'
require 'active_support/core_ext/regexp'
+require 'active_support/dependencies/autoload'
module ActionDispatch
# The routing module provides URL rewriting in native Ruby. It's a way to
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index fd163a47f4..8c2e821573 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -1,11 +1,13 @@
require 'action_dispatch/journey'
require 'forwardable'
require 'thread_safe'
+require 'active_support/concern'
require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/module/remove_method'
require 'active_support/core_ext/array/extract_options'
require 'action_controller/metal/exceptions'
+require 'action_dispatch/http/request'
module ActionDispatch
module Routing
@@ -155,7 +157,7 @@ module ActionDispatch
end
def self.optimize_helper?(route)
- !route.glob? && route.requirements.except(:controller, :action, :host).empty?
+ !route.glob? && route.path.requirements.empty?
end
class OptimizedUrlHelper < UrlHelper # :nodoc:
@@ -163,10 +165,8 @@ module ActionDispatch
def initialize(route, options)
super
- @klass = Journey::Router::Utils
@required_parts = @route.required_parts
@arg_size = @required_parts.size
- @optimized_path = @route.optimized_path
end
def call(t, args)
@@ -182,18 +182,14 @@ module ActionDispatch
private
def optimized_helper(args)
- params = Hash[parameterize_args(args)]
+ params = parameterize_args(args)
missing_keys = missing_keys(params)
unless missing_keys.empty?
raise_generation_error(params, missing_keys)
end
- @optimized_path.map{ |segment| replace_segment(params, segment) }.join
- end
-
- def replace_segment(params, segment)
- Symbol === segment ? @klass.escape_segment(params[segment]) : segment
+ @route.format params
end
def optimize_routes_generation?(t)
@@ -201,7 +197,9 @@ module ActionDispatch
end
def parameterize_args(args)
- @required_parts.zip(args.map(&:to_param))
+ params = {}
+ @required_parts.zip(args.map(&:to_param)) { |k,v| params[k] = v }
+ params
end
def missing_keys(args)
@@ -224,21 +222,23 @@ module ActionDispatch
end
def call(t, args)
- options = t.url_options.merge @options
- hash = handle_positional_args(t, args, options, @segment_keys)
+ controller_options = t.url_options
+ options = controller_options.merge @options
+ hash = handle_positional_args(controller_options, args, options, @segment_keys)
t._routes.url_for(hash)
end
- def handle_positional_args(t, args, result, keys)
+ def handle_positional_args(controller_options, args, result, path_params)
inner_options = args.extract_options!
if args.size > 0
- if args.size < keys.size - 1 # take format into account
- keys -= t.url_options.keys
- keys -= result.keys
+ if args.size < path_params.size - 1 # take format into account
+ path_params -= controller_options.keys
+ path_params -= result.keys
end
- keys -= inner_options.keys
- result.merge!(Hash[keys.zip(args)])
+ path_params.each { |param|
+ result[param] = inner_options[param] || args.shift
+ }
end
result.merge!(inner_options)
@@ -596,7 +596,7 @@ module ActionDispatch
# Generates a path from routes, returns [path, params].
# If no route is generated the formatter will raise ActionController::UrlGenerationError
def generate
- @set.formatter.generate(:path_info, named_route, options, recall, PARAMETERIZE)
+ @set.formatter.generate(named_route, options, recall, PARAMETERIZE)
end
def different_controller?
@@ -669,15 +669,18 @@ module ActionDispatch
RESERVED_OPTIONS.each { |ro| path_options.delete ro }
path, params = generate(path_options, recall)
- params.merge!(options[:params] || {})
-
- ActionDispatch::Http::URL.url_for(options.merge!({
- :path => path,
- :script_name => script_name,
- :params => params,
- :user => user,
- :password => password
- }))
+
+ if options.key? :params
+ params.merge! options[:params]
+ end
+
+ options[:path] = path
+ options[:script_name] = script_name
+ options[:params] = params
+ options[:user] = user
+ options[:password] = password
+
+ ActionDispatch::Http::URL.url_for(options)
end
def call(env)
@@ -696,7 +699,7 @@ module ActionDispatch
end
req = @request_class.new(env)
- @router.recognize(req) do |route, _matches, params|
+ @router.recognize(req) do |route, params|
params.merge!(extras)
params.each do |key, value|
if value.is_a?(String)
diff --git a/actionpack/test/abstract/collector_test.rb b/actionpack/test/abstract/collector_test.rb
index b1a5044399..fc59bf19c4 100644
--- a/actionpack/test/abstract/collector_test.rb
+++ b/actionpack/test/abstract/collector_test.rb
@@ -24,15 +24,21 @@ module AbstractController
test "does not respond to unknown mime types" do
collector = MyCollector.new
- assert !collector.respond_to?(:unknown)
+ assert_not_respond_to collector, :unknown
end
test "register mime types on method missing" do
AbstractController::Collector.send(:remove_method, :js)
- collector = MyCollector.new
- assert !collector.respond_to?(:js)
- collector.js
- assert_respond_to collector, :js
+ begin
+ collector = MyCollector.new
+ assert_not_respond_to collector, :js
+ collector.js
+ assert_respond_to collector, :js
+ ensure
+ unless AbstractController::Collector.method_defined? :js
+ AbstractController::Collector.generate_method_for_mime :js
+ end
+ end
end
test "does not register unknown mime types" do
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 58a86ce9af..c0e6a2ebd1 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -227,6 +227,22 @@ CACHED
@store.read("views/test.host/functional_caching/inline_fragment_cached/#{template_digest("functional_caching/inline_fragment_cached")}"))
end
+ def test_fragment_cache_instrumentation
+ payload = nil
+
+ subscriber = proc do |*args|
+ event = ActiveSupport::Notifications::Event.new(*args)
+ payload = event.payload
+ end
+
+ ActiveSupport::Notifications.subscribed(subscriber, "read_fragment.action_controller") do
+ get :inline_fragment_cached
+ end
+
+ assert_equal "functional_caching", payload[:controller]
+ assert_equal "inline_fragment_cached", payload[:action]
+ end
+
def test_html_formatted_fragment_caching
get :formatted_fragment_cached, :format => "html"
assert_response :success
diff --git a/actionpack/test/controller/http_basic_authentication_test.rb b/actionpack/test/controller/http_basic_authentication_test.rb
index 90548d4294..9052fc6962 100644
--- a/actionpack/test/controller/http_basic_authentication_test.rb
+++ b/actionpack/test/controller/http_basic_authentication_test.rb
@@ -129,6 +129,13 @@ class HttpBasicAuthenticationTest < ActionController::TestCase
assert_response :unauthorized
end
+ test "authentication request with wrong scheme" do
+ header = 'Bearer ' + encode_credentials('David', 'Goliath').split(' ', 2)[1]
+ @request.env['HTTP_AUTHORIZATION'] = header
+ get :search
+ assert_response :unauthorized
+ end
+
private
def encode_credentials(username, password)
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 200a2dcc47..214eab2f0d 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -775,3 +775,34 @@ class UrlOptionsIntegrationTest < ActionDispatch::IntegrationTest
assert_equal "/foo/1/edit", url_for(:action => 'edit', :only_path => true)
end
end
+
+class HeadWithStatusActionIntegrationTest < ActionDispatch::IntegrationTest
+ class FooController < ActionController::Base
+ def status
+ head :ok
+ end
+ end
+
+ def self.routes
+ @routes ||= ActionDispatch::Routing::RouteSet.new
+ end
+
+ def self.call(env)
+ routes.call(env)
+ end
+
+ def app
+ self.class
+ end
+
+ routes.draw do
+ get "/foo/status" => 'head_with_status_action_integration_test/foo#status'
+ end
+
+ test "get /foo/status with head result does not cause stack overflow error" do
+ assert_nothing_raised do
+ get '/foo/status'
+ end
+ assert_response :ok
+ end
+end
diff --git a/actionpack/test/controller/live_stream_test.rb b/actionpack/test/controller/live_stream_test.rb
index 947f64176b..1dca36374a 100644
--- a/actionpack/test/controller/live_stream_test.rb
+++ b/actionpack/test/controller/live_stream_test.rb
@@ -39,6 +39,13 @@ module ActionController
ensure
sse.close
end
+
+ def sse_with_multiple_line_message
+ sse = SSE.new(response.stream)
+ sse.write("first line.\nsecond line.")
+ ensure
+ sse.close
+ end
end
tests SSETestController
@@ -87,6 +94,15 @@ module ActionController
assert_match(/data: {\"name\":\"Ryan\"}/, second_response)
assert_match(/id: 2/, second_response)
end
+
+ def test_sse_with_multiple_line_message
+ get :sse_with_multiple_line_message
+
+ wait_for_response_stream_close
+ first_response, second_response = response.body.split("\n")
+ assert_match(/data: first line/, first_response)
+ assert_match(/data: second line/, second_response)
+ end
end
class LiveStreamTest < ActionController::TestCase
diff --git a/actionpack/test/controller/mime/respond_with_test.rb b/actionpack/test/controller/mime/respond_with_test.rb
index 416b3b81a5..115f3b2f41 100644
--- a/actionpack/test/controller/mime/respond_with_test.rb
+++ b/actionpack/test/controller/mime/respond_with_test.rb
@@ -2,6 +2,10 @@ require 'abstract_unit'
require 'controller/fake_models'
class RespondWithController < ActionController::Base
+ class CustomerWithJson < Customer
+ def to_json; super; end
+ end
+
respond_to :html, :json, :touch
respond_to :xml, :except => :using_resource_with_block
respond_to :js, :only => [ :using_resource_with_block, :using_resource, 'using_hash_resource' ]
@@ -38,6 +42,10 @@ class RespondWithController < ActionController::Base
respond_with(resource, :location => "http://test.host/", :status => :created)
end
+ def using_resource_with_json
+ respond_with(CustomerWithJson.new("david", request.delete? ? nil : 13))
+ end
+
def using_invalid_resource_with_template
respond_with(resource)
end
@@ -380,9 +388,8 @@ class RespondWithControllerTest < ActionController::TestCase
end
def test_using_resource_for_put_with_json_yields_no_content_on_success
- Customer.any_instance.stubs(:to_json).returns('{"name": "David"}')
@request.accept = "application/json"
- put :using_resource
+ put :using_resource_with_json
assert_equal "application/json", @response.content_type
assert_equal 204, @response.status
assert_equal "", @response.body
@@ -431,10 +438,9 @@ class RespondWithControllerTest < ActionController::TestCase
end
def test_using_resource_for_delete_with_json_yields_no_content_on_success
- Customer.any_instance.stubs(:to_json).returns('{"name": "David"}')
Customer.any_instance.stubs(:destroyed?).returns(true)
@request.accept = "application/json"
- delete :using_resource
+ delete :using_resource_with_json
assert_equal "application/json", @response.content_type
assert_equal 204, @response.status
assert_equal "", @response.body
@@ -643,6 +649,8 @@ class RespondWithControllerTest < ActionController::TestCase
get :index, format: 'csv'
assert_equal Mime::CSV, @response.content_type
assert_equal "c,s,v", @response.body
+ ensure
+ ActionController::Renderers.remove :csv
end
def test_raises_missing_renderer_if_an_api_behavior_with_no_renderer
@@ -652,6 +660,23 @@ class RespondWithControllerTest < ActionController::TestCase
end
end
+ def test_removing_renderers
+ ActionController::Renderers.add :csv do |obj, options|
+ send_data obj.to_csv, type: Mime::CSV
+ end
+ @controller = CsvRespondWithController.new
+ @request.accept = "text/csv"
+ get :index, format: 'csv'
+ assert_equal Mime::CSV, @response.content_type
+
+ ActionController::Renderers.remove :csv
+ assert_raise ActionController::MissingRenderer do
+ get :index, format: 'csv'
+ end
+ ensure
+ ActionController::Renderers.remove :csv
+ end
+
def test_error_is_raised_if_no_respond_to_is_declared_and_respond_with_is_called
@controller = EmptyRespondWithController.new
@request.accept = "*/*"
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 0c6df16325..f52f8be101 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -11,6 +11,26 @@ module AbstractController
W.default_url_options.clear
end
+ def test_nested_optional
+ klass = Class.new {
+ include ActionDispatch::Routing::RouteSet.new.tap { |r|
+ r.draw {
+ get "/foo/(:bar/(:baz))/:zot", :as => 'fun',
+ :controller => :articles,
+ :action => :index
+ }
+ }.url_helpers
+ self.default_url_options[:host] = 'example.com'
+ }
+
+ path = klass.new.fun_path({:controller => :articles,
+ :baz => "baz",
+ :zot => "zot",
+ :only_path => true })
+ # :bar key isn't provided
+ assert_equal '/foo/zot', path
+ end
+
def add_host!
W.default_url_options[:host] = 'www.basecamphq.com'
end
diff --git a/actionpack/test/dispatch/routing/route_set_test.rb b/actionpack/test/dispatch/routing/route_set_test.rb
index 0e488d2b88..c465d56bde 100644
--- a/actionpack/test/dispatch/routing/route_set_test.rb
+++ b/actionpack/test/dispatch/routing/route_set_test.rb
@@ -81,10 +81,6 @@ module ActionDispatch
end
private
- def clear!
- @set.clear!
- end
-
def draw(&block)
@set.draw(&block)
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 0a13dcfad4..cae6b312b6 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -3553,6 +3553,7 @@ class TestHttpMethods < ActionDispatch::IntegrationTest
RFC3648 = %w(ORDERPATCH)
RFC3744 = %w(ACL)
RFC5323 = %w(SEARCH)
+ RFC4791 = %w(MKCALENDAR)
RFC5789 = %w(PATCH)
def simple_app(response)
@@ -3564,13 +3565,13 @@ class TestHttpMethods < ActionDispatch::IntegrationTest
@app = ActionDispatch::Routing::RouteSet.new
@app.draw do
- (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789).each do |method|
+ (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789).each do |method|
match '/' => s.simple_app(method), :via => method.underscore.to_sym
end
end
end
- (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789).each do |method|
+ (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789).each do |method|
test "request method #{method.underscore} can be matched" do
get '/', nil, 'REQUEST_METHOD' => method
assert_equal method, @response.body
diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb
index e54b64e0f3..9a8d644f7b 100644
--- a/actionpack/test/journey/router_test.rb
+++ b/actionpack/test/journey/router_test.rb
@@ -48,7 +48,7 @@ module ActionDispatch
env = rails_env 'PATH_INFO' => '/foo-bar-baz'
called = false
- router.recognize(env) do |r, _, params|
+ router.recognize(env) do |r, params|
called = true
end
assert called
@@ -65,7 +65,7 @@ module ActionDispatch
env = rails_env 'PATH_INFO' => '/%E3%81%BB%E3%81%92'
called = false
- router.recognize(env) do |r, _, params|
+ router.recognize(env) do |r, params|
called = true
end
assert called
@@ -83,7 +83,7 @@ module ActionDispatch
routes.add_route nil, path, requirements, {:id => nil}, {}
env = rails_env 'PATH_INFO' => '/foo/10'
- router.recognize(env) do |r, _, params|
+ router.recognize(env) do |r, params|
assert_equal({:id => '10'}, params)
end
@@ -103,7 +103,7 @@ module ActionDispatch
router.routes.add_route nil, path, requirements, {:id => nil}, {}
env = rails_env 'PATH_INFO' => '/foo/10'
- router.recognize(env) do |r, _, params|
+ router.recognize(env) do |r, params|
flunk 'route should not be found'
end
@@ -128,7 +128,7 @@ module ActionDispatch
env = rails_env 'PATH_INFO' => '/foo', 'custom.path_info' => '/bar'
recognized = false
- router.recognize(env) do |r, _, params|
+ router.recognize(env) do |r, params|
recognized = true
end
@@ -144,7 +144,7 @@ module ActionDispatch
env = rails_env 'PATH_INFO' => '/whois/example.com'
list = []
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
list << r
end
assert_equal 2, list.length
@@ -160,7 +160,7 @@ module ActionDispatch
]
assert_raises(ActionController::UrlGenerationError) do
- @formatter.generate(:path_info, nil, { :id => '10' }, { })
+ @formatter.generate(nil, { :id => '10' }, { })
end
end
@@ -169,11 +169,11 @@ module ActionDispatch
Router::Strexp.new("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false)
]
- path, _ = @formatter.generate(:path_info, nil, { :id => '10' }, { })
+ path, _ = @formatter.generate(nil, { :id => '10' }, { })
assert_equal '/foo/10', path
assert_raises(ActionController::UrlGenerationError) do
- @formatter.generate(:path_info, nil, { :id => 'aa' }, { })
+ @formatter.generate(nil, { :id => 'aa' }, { })
end
end
@@ -182,13 +182,13 @@ module ActionDispatch
Router::Strexp.new("/foo(/:id)", {:id => /\d/}, ['/', '.', '?'], false)
]
- path, _ = @formatter.generate(:path_info, nil, { :id => '10' }, { })
+ path, _ = @formatter.generate(nil, { :id => '10' }, { })
assert_equal '/foo/10', path
- path, _ = @formatter.generate(:path_info, nil, { }, { })
+ path, _ = @formatter.generate(nil, { }, { })
assert_equal '/foo', path
- path, _ = @formatter.generate(:path_info, nil, { :id => 'aa' }, { })
+ path, _ = @formatter.generate(nil, { :id => 'aa' }, { })
assert_equal '/foo/aa', path
end
@@ -199,7 +199,7 @@ module ActionDispatch
@router.routes.add_route nil, path, {}, {}, route_name
error = assert_raises(ActionController::UrlGenerationError) do
- @formatter.generate(:path_info, route_name, { }, { })
+ @formatter.generate(route_name, { }, { })
end
assert_match(/missing required keys: \[:id\]/, error.message)
@@ -230,12 +230,12 @@ module ActionDispatch
@router.routes.add_route nil, path, {}, {:id => nil}, {}
env = rails_env 'PATH_INFO' => '/foo/10'
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal({:id => '10'}, params)
end
env = rails_env 'PATH_INFO' => '/foo'
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal({:id => nil}, params)
end
end
@@ -287,14 +287,14 @@ module ActionDispatch
def test_required_part_in_recall
add_routes @router, [ "/messages/:a/:b" ]
- path, _ = @formatter.generate(:path_info, nil, { :a => 'a' }, { :b => 'b' })
+ path, _ = @formatter.generate(nil, { :a => 'a' }, { :b => 'b' })
assert_equal "/messages/a/b", path
end
def test_splat_in_recall
add_routes @router, [ "/*path" ]
- path, _ = @formatter.generate(:path_info, nil, { }, { :path => 'b' })
+ path, _ = @formatter.generate(nil, { }, { :path => 'b' })
assert_equal "/b", path
end
@@ -304,7 +304,7 @@ module ActionDispatch
"/messages/:id(.:format)"
]
- path, _ = @formatter.generate(:path_info, nil, { :id => 10 }, { :action => 'index' })
+ path, _ = @formatter.generate(nil, { :id => 10 }, { :action => 'index' })
assert_equal "/messages/index/10", path
end
@@ -315,7 +315,7 @@ module ActionDispatch
params = { :controller => "tasks", :format => nil }
extras = { :action => 'lol' }
- path, _ = @formatter.generate(:path_info, nil, params, extras)
+ path, _ = @formatter.generate(nil, params, extras)
assert_equal '/tasks', path
end
@@ -327,7 +327,7 @@ module ActionDispatch
@router.routes.add_route @app, path, {}, {}, {}
- path, _ = @formatter.generate(:path_info, nil, Hash[params], {})
+ path, _ = @formatter.generate(nil, Hash[params], {})
assert_equal '/', path
end
@@ -340,7 +340,6 @@ module ActionDispatch
[:action, "show"] ]
@formatter.generate(
- :path_info,
nil,
Hash[params],
{},
@@ -354,7 +353,7 @@ module ActionDispatch
@router.routes.add_route @app, path, {}, {}, {}
path, params = @formatter.generate(
- :path_info, nil, {:id=>1, :controller=>"tasks", :action=>"show"}, {})
+ nil, {:id=>1, :controller=>"tasks", :action=>"show"}, {})
assert_equal '/tasks/show', path
assert_equal({:id => 1}, params)
end
@@ -363,8 +362,8 @@ module ActionDispatch
path = Path::Pattern.new '/:controller(/:action)'
@router.routes.add_route @app, path, {}, {}, {}
- path, _ = @formatter.generate(:path_info,
- nil, { :controller => "tasks",
+ path, _ = @formatter.generate(nil,
+ { :controller => "tasks",
:action => "a/b c+d",
}, {})
assert_equal '/tasks/a%2Fb%20c+d', path
@@ -374,7 +373,7 @@ module ActionDispatch
path = Path::Pattern.new '/:controller(/:action)'
@router.routes.add_route @app, path, {}, {}, {}
- path, _ = @formatter.generate(:path_info,
+ path, _ = @formatter.generate(
nil, { :controller => "admin/tasks",
:action => "a/b c+d",
}, {})
@@ -385,7 +384,7 @@ module ActionDispatch
path = Path::Pattern.new '/:controller(/:action)'
@router.routes.add_route @app, path, {}, {}, {}
- path, params = @formatter.generate(:path_info,
+ path, params = @formatter.generate(
nil, { :id => 1,
:controller => "tasks",
:action => "show",
@@ -399,7 +398,7 @@ module ActionDispatch
path = Path::Pattern.new '/:controller(/:action(/:id))'
@router.routes.add_route @app, path, {}, {}, {}
- path, params = @formatter.generate(:path_info,
+ path, params = @formatter.generate(
nil,
{:controller =>"tasks", :id => 10},
{:action =>"index"})
@@ -411,7 +410,7 @@ module ActionDispatch
path = Path::Pattern.new '/:controller(/:action)'
@router.routes.add_route @app, path, {}, {}, {}
- path, params = @formatter.generate(:path_info,
+ path, params = @formatter.generate(
"tasks",
{:controller=>"tasks"},
{:controller=>"tasks", :action=>"index"})
@@ -432,7 +431,7 @@ module ActionDispatch
env = rails_env 'PATH_INFO' => request_path
called = false
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal route, r
assert_equal(expected, params)
called = true
@@ -454,7 +453,7 @@ module ActionDispatch
env = rails_env 'PATH_INFO' => request_path
called = false
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal route, r
assert_equal(expected, params)
called = true
@@ -482,7 +481,7 @@ module ActionDispatch
:id => '10'
}
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal route, r
assert_equal(expected, params)
called = true
@@ -498,7 +497,7 @@ module ActionDispatch
env = rails_env 'PATH_INFO' => '/books/list.rss'
expected = { :controller => 'books', :action => 'list', :format => 'rss' }
called = false
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal route, r
assert_equal(expected, params)
called = true
@@ -519,7 +518,7 @@ module ActionDispatch
"REQUEST_METHOD" => "HEAD"
called = false
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
called = true
end
@@ -543,7 +542,7 @@ module ActionDispatch
"REQUEST_METHOD" => "POST"
called = false
- @router.recognize(env) do |r, _, params|
+ @router.recognize(env) do |r, params|
assert_equal post, r
called = true
end