Skip to content

Commit

Permalink
support redirect on trailing slash
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh Hull committed Mar 23, 2011
1 parent 7325ddd commit f2d54e6
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 18 deletions.
51 changes: 35 additions & 16 deletions lib/http_router.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,20 @@ class HttpRouter
InvalidRouteException = Class.new(RuntimeError)
MissingParameterException = Class.new(RuntimeError)

def initialize(options = nil, &blk)
reset!
# Creates a new HttpRouter.
# Can be called with either <tt>HttpRouter.new(proc{|env| ... }, { .. options .. })</tt> or with the first argument omitted.
# If there is a proc first, then it's used as the default app in the case of a non-match.
# Supported options are
# * :default_app -- Default application used if there is a non-match on #call. Defaults to 404 generator.
# * :ignore_trailing_slash -- Ignore a trailing / when attempting to match. Defaults to +true+.
# * :redirect_trailing_slash -- On trailing /, redirect to the same path without the /. Defaults to +false+.
def initialize(*args, &blk)
default_app, options = args.first.is_a?(Hash) ? [nil, args.first] : [args.first, args[1]]
@options = options
@default_app = default_app || options && options[:default_app] || proc{|env| ::Rack::Response.new("Not Found", 404).finish }
@ignore_trailing_slash = options && options.key?(:ignore_trailing_slash) ? options[:ignore_trailing_slash] : true
@redirect_trailing_slash = options && options.key?(:redirect_trailing_slash) ? options[:redirect_trailing_slash] : false
reset!
instance_eval(&blk) if blk
end

Expand Down Expand Up @@ -53,21 +62,27 @@ def recognize(env)

def call(env, perform_call = true)
rack_request = Rack::Request.new(env)
request = Request.new(rack_request.path_info, rack_request, perform_call)
response = catch(:success) { @root[request] }
if !response
supported_methods = (@known_methods - [env['REQUEST_METHOD']]).select do |m|
test_env = Rack::Request.new(rack_request.env.clone)
test_env.env['REQUEST_METHOD'] = m
test_env.env['HTTP_ROUTER_405_TESTING_ACCEPTANCE'] = true
test_request = Request.new(test_env.path_info, test_env, 405)
catch(:success) { @root[test_request] }
end
supported_methods.empty? ? @default_app.call(env) : [405, {'Allow' => supported_methods.sort.join(", ")}, []]
elsif response
response
if redirect_trailing_slash? && (rack_request.head? || rack_request.get?) && rack_request.path_info[-1] == ?/
response = ::Rack::Response.new
response.redirect(request.path_info[0, request.path_info.size - 1], 302)
response.finish
else
@default_app.call(env)
request = Request.new(rack_request.path_info, rack_request, perform_call)
response = catch(:success) { @root[request] }
if !response
supported_methods = (@known_methods - [env['REQUEST_METHOD']]).select do |m|
test_env = Rack::Request.new(rack_request.env.clone)
test_env.env['REQUEST_METHOD'] = m
test_env.env['HTTP_ROUTER_405_TESTING_ACCEPTANCE'] = true
test_request = Request.new(test_env.path_info, test_env, 405)
catch(:success) { @root[test_request] }
end
supported_methods.empty? ? @default_app.call(env) : [405, {'Allow' => supported_methods.sort.join(", ")}, []]
elsif response
response
else
@default_app.call(env)
end
end
end

Expand All @@ -91,6 +106,10 @@ def ignore_trailing_slash?
@ignore_trailing_slash
end

def redirect_trailing_slash?
@redirect_trailing_slash
end

# Creates a deep-copy of the router.
def clone(klass = self.class)
cloned_router = klass.new(@options)
Expand Down
2 changes: 1 addition & 1 deletion lib/http_router/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def add_lookup(part)
end

def join_whole_path(request)
request.path.join('/')
request.path * '/'
end

private
Expand Down
2 changes: 1 addition & 1 deletion test/test_variable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_encoding
end

def test_match_path
r = router { add(%r{^/(test123|\d+)$}) }
r = router { add %r{/(test123|\d+)} }
assert_route r, '/test123'
assert_route r, '/123'
assert_route nil, '/test123andmore'
Expand Down

0 comments on commit f2d54e6

Please sign in to comment.