Skip to content

Commit 7bb76ee

Browse files
suanSuan-Aik Yeo
authored and
Suan-Aik Yeo
committed
Patch rack-accept to support all valid RFC6838 characters in media types
1 parent a7e4b2c commit 7bb76ee

File tree

6 files changed

+30
-10
lines changed

6 files changed

+30
-10
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
* Your contribution here.
77

8+
* [#1179](https://github.com/ruby-grape/grape/pull/1179): Allow all RFC6838 valid characters in header vendor - [@suan](https://github.com/suan).
89
* [#1170](https://github.com/ruby-grape/grape/pull/1170): Allow dashes and periods in header vendor - [@suan](https://github.com/suan).
910
* [#1167](https://github.com/ruby-grape/grape/pull/1167): Convenience wrapper `type: File` for validating multipart file parameters - [@dslh](https://github.com/dslh).
1011
* [#1167](https://github.com/ruby-grape/grape/pull/1167): Refactor and extend coercion and type validation system - [@dslh](https://github.com/dslh).

README.md

-3
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,6 @@ vnd.vendor-and-or-resource-v1234+format
339339
```
340340

341341
Basically all tokens between the final `-` and the `+` will be interpreted as the version.
342-
Grape also only supports alphanumerics, periods, and dashes in the vendor/resource/version parts
343-
of the media type, even though [the appropriate RFC](http://tools.ietf.org/html/rfc6838#section-4.2)
344-
technically allows far more characters.
345342

346343
Using this versioning strategy, clients should pass the desired version in the HTTP `Accept` head.
347344

gemfiles/rails_3.gemfile

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
source 'https://rubygems.org'
44

55
gem 'rails', '3.2.19'
6+
gem 'rack-cache', '<= 1.2' # Pin as next rack-cache version (1.3) removes Ruby1.9 support
67

78
group :development, :test do
89
gem 'rubocop', '~> 0.31.0'

lib/grape/middleware/versioner/header.rb

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'grape/middleware/base'
2+
require 'grape/middleware/versioner/parse_media_type_patch'
23

34
module Grape
45
module Middleware
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module Rack
2+
module Accept
3+
module Header
4+
class << self
5+
# Corrected version of https://github.com/mjackson/rack-accept/blob/master/lib/rack/accept/header.rb#L40-L44
6+
def parse_media_type(media_type)
7+
# see http://tools.ietf.org/html/rfc6838#section-4.2 for allowed characters in media type names
8+
m = media_type.to_s.match(%r{^([a-z*]+)\/([a-z0-9*\&\^\-_#\$!.+]+)(?:;([a-z0-9=;]+))?$})
9+
m ? [m[1], m[2], m[3] || ''] : []
10+
end
11+
end
12+
end
13+
14+
class MediaType
15+
def parse_media_type(media_type)
16+
Header.parse_media_type(media_type)
17+
end
18+
end
19+
end
20+
end

spec/grape/middleware/versioner/header_spec.rb

+7-7
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,8 @@
261261

262262
let(:v1_app) {
263263
Class.new(Grape::API) do
264-
version 'v1', using: :header, vendor: 'test.a-cool-resource'
265-
content_type :v1_test, 'application/vnd.test.a-cool-resource-v1+json'
264+
version 'v1', using: :header, vendor: 'test.a-cool_resource', cascade: false, strict: true
265+
content_type :v1_test, 'application/vnd.test.a-cool_resource-v1+json'
266266
formatter :v1_test, ->(object, _) { object }
267267
format :v1_test
268268

@@ -276,8 +276,8 @@
276276

277277
let(:v2_app) {
278278
Class.new(Grape::API) do
279-
version 'v2', using: :header, vendor: 'test.a-cool-resource'
280-
content_type :v2_test, 'application/vnd.test.a-cool-resource-v2+json'
279+
version 'v2', using: :header, vendor: 'test.a-cool_resource', strict: true
280+
content_type :v2_test, 'application/vnd.test.a-cool_resource-v2+json'
281281
formatter :v2_test, ->(object, _) { object }
282282
format :v2_test
283283

@@ -290,20 +290,20 @@
290290
}
291291

292292
def app
293-
subject.mount v1_app
294293
subject.mount v2_app
294+
subject.mount v1_app
295295
subject
296296
end
297297

298298
context 'with header versioned endpoints and a rescue_all block defined' do
299299
it 'responds correctly to a v1 request' do
300-
versioned_get '/users/hello', 'v1', using: :header, vendor: 'test.a-cool-resource'
300+
versioned_get '/users/hello', 'v1', using: :header, vendor: 'test.a-cool_resource'
301301
expect(last_response.body).to eq('one')
302302
expect(last_response.body).not_to include('API vendor or version not found')
303303
end
304304

305305
it 'responds correctly to a v2 request' do
306-
versioned_get '/users/hello', 'v2', using: :header, vendor: 'test.a-cool-resource'
306+
versioned_get '/users/hello', 'v2', using: :header, vendor: 'test.a-cool_resource'
307307
expect(last_response.body).to eq('two')
308308
expect(last_response.body).not_to include('API vendor or version not found')
309309
end

0 commit comments

Comments
 (0)