Skip to content

Commit 552f6dd

Browse files
authored
Merge pull request #1488 from ruby-grape/fix-1429
Ensure calling before filters when receiving OPTIONS request
2 parents 0a9461f + 45a871e commit 552f6dd

File tree

8 files changed

+77
-35
lines changed

8 files changed

+77
-35
lines changed

.rubocop_todo.yml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config`
3-
# on 2016-04-27 13:48:11 -0500 using RuboCop version 0.39.0.
3+
# on 2016-09-11 17:59:25 +0900 using RuboCop version 0.39.0.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new
77
# versions of RuboCop, may require this file to be generated again.
88

9-
# Offense count: 39
9+
# Offense count: 42
1010
Metrics/AbcSize:
1111
Max: 44
1212

@@ -17,37 +17,37 @@ Metrics/BlockNesting:
1717
# Offense count: 7
1818
# Configuration parameters: CountComments.
1919
Metrics/ClassLength:
20-
Max: 266
20+
Max: 277
2121

22-
# Offense count: 24
22+
# Offense count: 28
2323
Metrics/CyclomaticComplexity:
2424
Max: 14
2525

26-
# Offense count: 874
26+
# Offense count: 933
2727
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
2828
# URISchemes: http, https
2929
Metrics/LineLength:
3030
Max: 215
3131

32-
# Offense count: 48
32+
# Offense count: 52
3333
# Configuration parameters: CountComments.
3434
Metrics/MethodLength:
35-
Max: 34
35+
Max: 33
3636

37-
# Offense count: 7
37+
# Offense count: 8
3838
# Configuration parameters: CountComments.
3939
Metrics/ModuleLength:
4040
Max: 212
4141

42-
# Offense count: 15
42+
# Offense count: 18
4343
Metrics/PerceivedComplexity:
44-
Max: 16
44+
Max: 14
4545

46-
# Offense count: 111
46+
# Offense count: 114
4747
Style/Documentation:
4848
Enabled: false
4949

50-
# Offense count: 14
50+
# Offense count: 16
5151
# Configuration parameters: EnforcedStyle, SupportedStyles.
5252
# SupportedStyles: compact, exploded
5353
Style/RaiseArgs:

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33

44
* [#1480](https://github.com/ruby-grape/grape/pull/1480): Use the ruby-grape-danger gem for PR linting - [@dblock](https://github.com/dblock).
55
* [#1486](https://github.com/ruby-grape/grape/pull/1486): Implemented except in values validator - [@jonmchan](https://github.com/jonmchan).
6+
* [#1470](https://github.com/ruby-grape/grape/pull/1470): Drop support for ruby-2.0 - [@namusyaka](https://github.com/namusyaka).
67
* Your contribution here.
78

89
#### Fixes
910

1011
* [#1479](https://github.com/ruby-grape/grape/pull/1479): Support inserting middleware before/after anonymous classes in the middleware stack - [@rosa](https://github.com/rosa).
12+
* [#1488](https://github.com/ruby-grape/grape/pull/1488): Ensure calling before filters when receiving OPTIONS request - [@namusyaka](https://github.com/namusyaka), [@jlfaber](https://github.com/jlfaber).
1113

1214
0.17.0 (7/29/2016)
1315
==================
@@ -20,7 +22,6 @@
2022
* [#1398](https://github.com/ruby-grape/grape/pull/1398): Add `rescue_from :grape_exceptions` - allow Grape to use the built-in `Grape::Exception` handing and use `rescue :all` behavior for everything else - [@mmclead](https://github.com/mmclead).
2123
* [#1443](https://github.com/ruby-grape/grape/pull/1443): Extend `given` to receive a `Proc` - [@glaucocustodio](https://github.com/glaucocustodio).
2224
* [#1455](https://github.com/ruby-grape/grape/pull/1455): Add an automated PR linter - [@orta](https://github.com/orta).
23-
* [#1470](https://github.com/ruby-grape/grape/pull/1470): Drop support for ruby-2.0 - [@namusyaka](https://github.com/namusyaka).
2425
* Your contribution here.
2526

2627
#### Fixes

lib/grape/api.rb

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ def add_head_not_allowed_methods_and_options_methods
173173
without_versioning do
174174
routes_map.each do |_, config|
175175
methods = config[:methods]
176-
path = config[:path]
177176
allowed_methods = methods.dup
178177

179178
unless self.class.namespace_inheritable(:do_not_route_head)
@@ -182,8 +181,8 @@ def add_head_not_allowed_methods_and_options_methods
182181

183182
allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods).join(', ')
184183

185-
unless self.class.namespace_inheritable(:do_not_route_options)
186-
generate_options_method(path, allow_header, config) unless allowed_methods.include?(Grape::Http::Headers::OPTIONS)
184+
unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Grape::Http::Headers::OPTIONS)
185+
config[:endpoint].options[:options_route_enabled] = true
187186
end
188187

189188
attributes = config.merge(allowed_methods: allowed_methods, allow_header: allow_header)
@@ -193,15 +192,6 @@ def add_head_not_allowed_methods_and_options_methods
193192
end
194193
end
195194

196-
# Generate an 'OPTIONS' route for a pre-exisiting user defined route
197-
def generate_options_method(path, allow_header, options = {})
198-
self.class.options(path, options) do
199-
header 'Allow', allow_header
200-
status 204
201-
''
202-
end
203-
end
204-
205195
# Generate a route that returns an HTTP 405 response for a user defined
206196
# path on methods not specified
207197
def generate_not_allowed_method(pattern, attributes = {})

lib/grape/endpoint.rb

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,16 +248,21 @@ def run
248248

249249
run_filters befores, :before
250250

251-
allowed_methods = env[Grape::Env::GRAPE_METHOD_NOT_ALLOWED]
252-
raise Grape::Exceptions::MethodNotAllowed, header.merge('Allow' => allowed_methods) if allowed_methods
251+
allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS]
252+
raise Grape::Exceptions::MethodNotAllowed, header.merge('Allow' => allowed_methods) if !options? && allowed_methods
253253

254254
run_filters before_validations, :before_validation
255-
256255
run_validators validations, request
257-
258256
run_filters after_validations, :after_validation
259257

260-
response_object = @block ? @block.call(self) : nil
258+
response_object =
259+
if options?
260+
header 'Allow', allowed_methods
261+
status 204
262+
''
263+
else
264+
@block ? @block.call(self) : nil
265+
end
261266
run_filters afters, :after
262267
cookies.write(header)
263268

@@ -373,5 +378,10 @@ def afters
373378
def validations
374379
route_setting(:saved_validations) || []
375380
end
381+
382+
def options?
383+
options[:options_route_enabled] &&
384+
env[Grape::Http::Headers::REQUEST_METHOD] == Grape::Http::Headers::OPTIONS
385+
end
376386
end
377387
end

lib/grape/middleware/versioner/header.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Header < Base
3232
def before
3333
strict_header_checks if strict?
3434

35-
if media_type || env[Grape::Env::GRAPE_METHOD_NOT_ALLOWED]
35+
if media_type || env[Grape::Env::GRAPE_ALLOWED_METHODS]
3636
media_type_header_handler
3737
elsif headers_contain_wrong_vendor?
3838
fail_with_invalid_accept_header!('API vendor not found.')

lib/grape/router.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def transaction(env)
9595
neighbor = greedy_match?(input)
9696
return unless neighbor
9797

98-
(!cascade && neighbor) ? method_not_allowed(env, neighbor.allow_header, neighbor.endpoint) : nil
98+
(!cascade && neighbor) ? call_with_allow_headers(env, neighbor.allow_header, neighbor.endpoint) : nil
9999
end
100100

101101
def make_routing_args(default_args, route, input)
@@ -132,8 +132,8 @@ def greedy_match?(input)
132132
@neutral_map.detect { |route| last_match["_#{route.index}"] }
133133
end
134134

135-
def method_not_allowed(env, methods, endpoint)
136-
env[Grape::Env::GRAPE_METHOD_NOT_ALLOWED] = methods
135+
def call_with_allow_headers(env, methods, endpoint)
136+
env[Grape::Env::GRAPE_ALLOWED_METHODS] = methods
137137
endpoint.call(env)
138138
end
139139

lib/grape/util/env.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ module Env
1818
GRAPE_REQUEST_HEADERS = 'grape.request.headers'.freeze
1919
GRAPE_REQUEST_PARAMS = 'grape.request.params'.freeze
2020
GRAPE_ROUTING_ARGS = 'grape.routing_args'.freeze
21-
GRAPE_METHOD_NOT_ALLOWED = 'grape.method_not_allowed'.freeze
21+
GRAPE_ALLOWED_METHODS = 'grape.allowed_methods'.freeze
2222
end
2323
end

spec/grape/api_spec.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,47 @@ class DummyFormatClass
665665
end
666666
end
667667

668+
describe 'adds an OPTIONS route for namespaced endpoints that' do
669+
before do
670+
subject.before { header 'X-Custom-Header', 'foo' }
671+
subject.namespace :example do
672+
before { header 'X-Custom-Header-2', 'foo' }
673+
get :inner do
674+
'example/inner'
675+
end
676+
end
677+
options '/example/inner'
678+
end
679+
680+
it 'returns a 204' do
681+
expect(last_response.status).to eql 204
682+
end
683+
684+
it 'has an empty body' do
685+
expect(last_response.body).to be_blank
686+
end
687+
688+
it 'has an Allow header' do
689+
expect(last_response.headers['Allow']).to eql 'OPTIONS, GET, HEAD'
690+
end
691+
692+
it 'calls the outer before filter' do
693+
expect(last_response.headers['X-Custom-Header']).to eql 'foo'
694+
end
695+
696+
it 'calls the inner before filter' do
697+
expect(last_response.headers['X-Custom-Header-2']).to eql 'foo'
698+
end
699+
700+
it 'has no Content-Type' do
701+
expect(last_response.content_type).to be_nil
702+
end
703+
704+
it 'has no Content-Length' do
705+
expect(last_response.content_length).to be_nil
706+
end
707+
end
708+
668709
describe 'adds a 405 Not Allowed route that' do
669710
before do
670711
subject.before { header 'X-Custom-Header', 'foo' }

0 commit comments

Comments
 (0)