Skip to content

Commit 499f6c6

Browse files
committed
Modify the priority of ANY routes, fixes #1089
1 parent 0261ab8 commit 499f6c6

File tree

8 files changed

+47
-12
lines changed

8 files changed

+47
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Next Release
1212
#### Fixes
1313

1414
* [#1505](https://github.com/ruby-grape/grape/pull/1505): Run `before` and `after` callbacks, but skip the rest when handling OPTIONS - [@jlfaber](https://github.com/jlfaber).
15+
* [#1517](https://github.com/ruby-grape/grape/pull/1517): Modify the priority of ANY routes, fixes #1089 - [@namusyaka](https://github.com/namusyaka), [@wagenet](https://github.com/wagenet).
1516

1617
0.18.0 (10/7/2016)
1718
==================

UPGRADING.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@ Upgrading Grape
33

44
### Upgrading to >= 0.18.1
55

6+
#### Modify the priority of :any routes
7+
8+
Conventional, the :any routes had been searched after matching first route and 405 routes.
9+
This version adds the :any routes processing before 405 processing, so the behavior of following code will be changed.
10+
11+
```ruby
12+
post :example do
13+
'example'
14+
end
15+
route :any, '*path' do
16+
error! :not_found, 404
17+
end
18+
19+
get '/example' #=> before: 405, currently: 404
20+
```
21+
622
#### Removed param processing from built-in OPTIONS handler
723

824
When a request is made to the built-in `OPTIONS` handler, only the `before` and `after`

lib/grape/api.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def add_head_not_allowed_methods_and_options_methods
161161
route_settings[:endpoint] = route.app
162162

163163
# using the :any shorthand produces [nil] for route methods, substitute all manually
164-
route_settings[:methods] = %w(GET PUT POST DELETE PATCH HEAD OPTIONS) if route_settings[:methods].include?('ANY')
164+
route_settings[:methods] = %w(GET PUT POST DELETE PATCH HEAD OPTIONS) if route_settings[:methods].include?('*')
165165
end
166166
end
167167

lib/grape/dsl/routing.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def mount(mounts)
9999
method: :any,
100100
path: path,
101101
app: app,
102+
route_options: { anchor: false },
102103
forward_match: !app.respond_to?(:inheritable_setting),
103104
for: self
104105
)
@@ -118,6 +119,7 @@ def mount(mounts)
118119
# end
119120
# end
120121
def route(methods, paths = ['/'], route_options = {}, &block)
122+
methods = '*' if methods == :any
121123
endpoint_options = {
122124
method: methods,
123125
path: paths,

lib/grape/http/headers.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ module Headers
1616
HEAD = 'HEAD'.freeze
1717
OPTIONS = 'OPTIONS'.freeze
1818

19+
SUPPORTED_METHODS = [GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS].freeze
20+
1921
HTTP_ACCEPT_VERSION = 'HTTP_ACCEPT_VERSION'.freeze
2022
X_CASCADE = 'X-Cascade'.freeze
2123
HTTP_TRANSFER_ENCODING = 'HTTP_TRANSFER_ENCODING'.freeze

lib/grape/router.rb

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ def self.normalize_path(path)
1919
path
2020
end
2121

22+
def self.supported_methods
23+
@supported_methods ||= Grape::Http::Headers::SUPPORTED_METHODS + ['*']
24+
end
25+
2226
def initialize
2327
@neutral_map = []
2428
@map = Hash.new { |hash, key| hash[key] = [] }
@@ -28,7 +32,8 @@ def initialize
2832
def compile!
2933
return if compiled
3034
@union = Regexp.union(@neutral_map.map(&:regexp))
31-
map.each do |method, routes|
35+
self.class.supported_methods.each do |method|
36+
routes = map[method]
3237
@optimized_map[method] = routes.map.with_index do |route, index|
3338
route.index = index
3439
route.regexp = /(?<_#{index}>#{route.pattern.to_regexp})/
@@ -77,7 +82,7 @@ def identity(env)
7782
def rotation(env, exact_route = nil)
7883
response = nil
7984
input, method, routing_args = *extract_required_args(env)
80-
routes_for(method).each do |route|
85+
map[method].each do |route|
8186
next if exact_route == route
8287
next unless route.match?(input)
8388
env[Grape::Env::GRAPE_ROUTING_ARGS] = make_routing_args(routing_args, route, input)
@@ -92,8 +97,18 @@ def transaction(env)
9297
response = yield(input, method, routing_args)
9398

9499
return response if response && !(cascade = cascade?(response))
100+
95101
neighbor = greedy_match?(input)
96-
return unless neighbor
102+
103+
if neighbor && method == 'OPTIONS'
104+
return (!cascade && neighbor) ? call_with_allow_headers(env, neighbor.allow_header, neighbor.endpoint) : nil
105+
end
106+
107+
if route = match?(input, '*')
108+
env[Grape::Env::GRAPE_ROUTING_ARGS] = make_routing_args(routing_args, route, input)
109+
response = route.exec(env)
110+
return response if response && !(cascade = cascade?(response))
111+
end
97112

98113
(!cascade && neighbor) ? call_with_allow_headers(env, neighbor.allow_header, neighbor.endpoint) : nil
99114
end
@@ -141,10 +156,6 @@ def cascade?(response)
141156
response && response[1][Grape::Http::Headers::X_CASCADE] == 'pass'
142157
end
143158

144-
def routes_for(method)
145-
map[method] + map['ANY']
146-
end
147-
148159
def string_for(input)
149160
self.class.normalize_path(input)
150161
end

lib/grape/router/pattern.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,13 @@ def pattern_options
3535
end
3636

3737
def build_path(pattern, anchor: false, suffix: nil, **_options)
38-
pattern << '*path' unless anchor || pattern.end_with?('*path')
38+
unless anchor || pattern.end_with?('*path')
39+
pattern << ?/ unless pattern.end_with?(?/)
40+
pattern << '*path'
41+
end
42+
pattern = pattern.split(?/).tap { |parts|
43+
parts[parts.length - 1] = ?? + parts.last
44+
}.join(?/) if pattern.end_with?('*path')
3945
pattern + suffix.to_s
4046
end
4147

spec/grape/api_spec.rb

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -786,9 +786,6 @@ class DummyFormatClass
786786
subject.post :example do
787787
'example'
788788
end
789-
subject.route :any, '*path' do
790-
error! :not_found, 404
791-
end
792789
get '/example'
793790
end
794791

0 commit comments

Comments
 (0)