-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Set response headers based on Rack version #2355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
608bd18
1b6b7a4
cd71b14
6bfc616
ff4c6b5
5ecb7c7
32ca429
2d87076
0a88e94
7b51e0f
d0850d5
ba8c0e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -185,7 +185,7 @@ def redirect(url, permanent: false, body: nil, **_options) | |
status 302 | ||
body_message ||= "This resource has been moved temporarily to #{url}." | ||
end | ||
header 'Location', url | ||
header Grape::Http::Headers::LOCATION, url | ||
content_type 'text/plain' | ||
body body_message | ||
end | ||
|
@@ -328,9 +328,9 @@ def sendfile(value = nil) | |
def stream(value = nil) | ||
return if value.nil? && @stream.nil? | ||
|
||
header 'Content-Length', nil | ||
header 'Transfer-Encoding', nil | ||
header 'Cache-Control', 'no-cache' # Skips ETag generation (reading the response up front) | ||
header Grape::Http::Headers::CONTENT_LENGTH, nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use |
||
header Grape::Http::Headers::TRANSFER_ENCODING, nil | ||
header Grape::Http::Headers::CACHE_CONTROL, 'no-cache' # Skips ETag generation (reading the response up front) | ||
if value.is_a?(String) | ||
file_body = Grape::ServeStream::FileBody.new(value) | ||
@stream = Grape::ServeStream::StreamResponse.new(file_body) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,7 +47,11 @@ def build_headers | |
end | ||
|
||
def transform_header(header) | ||
-header[5..].split('_').each(&:capitalize!).join('-') | ||
if Gem::Version.new(Rack.release) < Gem::Version.new('3') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This executes in a tight loop, which is bad for performance. You want this check outside. We also have it in a few places. It should look like this: if Grape::Rack.rack3?
def transform_header(header)
-header[5..].split('_').map(&:capitalize).join('-')
end
else
def transform_header(header)
-header[5..].tr('_', '-').downcase
end
end There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added Can do this though if really needs to be |
||
-header[5..].split('_').map(&:capitalize).join('-') | ||
else | ||
-header[5..].tr('_', '-').downcase | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,5 @@ | |
|
||
module Grape | ||
# The current version of Grape. | ||
VERSION = '1.8.1' | ||
VERSION = '1.9.0' | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -162,9 +162,18 @@ def validate(request) | |
return unless request.params.key? @attrs.first | ||
# check if admin flag is set to true | ||
return unless @option | ||
|
||
# check if user is admin or not | ||
# as an example get a token from request and check if it's admin or not | ||
raise Grape::Exceptions::Validation.new(params: @attrs, message: 'Can not set Admin only field.') unless request.headers['X-Access-Token'] == 'admin' | ||
raise Grape::Exceptions::Validation.new(params: @attrs, message: 'Can not set Admin only field.') unless request.headers[access_header] == 'admin' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, tried that, but got...
which was annoying, as don't like the defining it twice either. |
||
end | ||
|
||
def access_header | ||
if Gem::Version.new(Rack.release) < Gem::Version.new('3') | ||
'X-Access-Token' | ||
else | ||
'x-access-token' | ||
end | ||
end | ||
end | ||
end | ||
|
@@ -197,14 +206,14 @@ def validate(request) | |
end | ||
|
||
it 'does not fail when we send admin fields and we are admin' do | ||
header 'X-Access-Token', 'admin' | ||
header rack_versioned_headers[:x_access_token], 'admin' | ||
get '/', admin_field: 'tester', non_admin_field: 'toaster', admin_false_field: 'test' | ||
expect(last_response.status).to eq 200 | ||
expect(last_response.body).to eq 'bacon' | ||
end | ||
|
||
it 'fails when we send admin fields and we are not admin' do | ||
header 'X-Access-Token', 'user' | ||
header rack_versioned_headers[:x_access_token], 'user' | ||
get '/', admin_field: 'tester', non_admin_field: 'toaster', admin_false_field: 'test' | ||
expect(last_response.status).to eq 400 | ||
expect(last_response.body).to include 'Can not set Admin only field.' | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -689,7 +689,7 @@ class DummyFormatClass | |
'example' | ||
end | ||
put '/example' | ||
expect(last_response.headers['Content-Type']).to eql 'text/plain' | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eql 'text/plain' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we get rid of |
||
end | ||
|
||
describe 'adds an OPTIONS route that' do | ||
|
@@ -1196,32 +1196,32 @@ class DummyFormatClass | |
|
||
it 'sets content type for txt format' do | ||
get '/foo' | ||
expect(last_response.headers['Content-Type']).to eq('text/plain') | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eq('text/plain') | ||
end | ||
|
||
it 'does not set Cache-Control' do | ||
get '/foo' | ||
expect(last_response.headers['Cache-Control']).to be_nil | ||
expect(last_response.headers[rack_versioned_headers[:cache_control]]).to be_nil | ||
end | ||
|
||
it 'sets content type for xml' do | ||
get '/foo.xml' | ||
expect(last_response.headers['Content-Type']).to eq('application/xml') | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eq('application/xml') | ||
end | ||
|
||
it 'sets content type for json' do | ||
get '/foo.json' | ||
expect(last_response.headers['Content-Type']).to eq('application/json') | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eq('application/json') | ||
end | ||
|
||
it 'sets content type for serializable hash format' do | ||
get '/foo.serializable_hash' | ||
expect(last_response.headers['Content-Type']).to eq('application/json') | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eq('application/json') | ||
end | ||
|
||
it 'sets content type for binary format' do | ||
get '/foo.binary' | ||
expect(last_response.headers['Content-Type']).to eq('application/octet-stream') | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eq('application/octet-stream') | ||
end | ||
|
||
it 'returns raw data when content type binary' do | ||
|
@@ -1230,7 +1230,7 @@ class DummyFormatClass | |
subject.format :binary | ||
subject.get('/binary_file') { File.binread(image_filename) } | ||
get '/binary_file' | ||
expect(last_response.headers['Content-Type']).to eq('application/octet-stream') | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eq('application/octet-stream') | ||
expect(last_response.body).to eq(file) | ||
end | ||
|
||
|
@@ -1242,8 +1242,8 @@ class DummyFormatClass | |
|
||
subject.get('/file') { file test_file } | ||
get '/file' | ||
expect(last_response.headers['Content-Length']).to eq('25') | ||
expect(last_response.headers['Content-Type']).to eq('text/plain') | ||
expect(last_response.headers[rack_versioned_headers[:content_length]]).to eq('25') | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eq('text/plain') | ||
expect(last_response.body).to eq(file_content) | ||
end | ||
|
||
|
@@ -1257,34 +1257,34 @@ class DummyFormatClass | |
subject.get('/stream') { stream test_stream } | ||
get '/stream', {}, 'HTTP_VERSION' => 'HTTP/1.1', 'SERVER_PROTOCOL' => 'HTTP/1.1' | ||
|
||
expect(last_response.headers['Content-Type']).to eq('text/plain') | ||
expect(last_response.headers['Content-Length']).to be_nil | ||
expect(last_response.headers['Cache-Control']).to eq('no-cache') | ||
expect(last_response.headers['Transfer-Encoding']).to eq('chunked') | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eq('text/plain') | ||
expect(last_response.headers[rack_versioned_headers[:content_length]]).to be_nil | ||
expect(last_response.headers[rack_versioned_headers[:cache_control]]).to eq('no-cache') | ||
expect(last_response.headers[rack_versioned_headers[:transfer_encoding]]).to eq('chunked') | ||
|
||
expect(last_response.body).to eq("c\r\nThis is some\r\nd\r\n file content\r\n0\r\n\r\n") | ||
end | ||
|
||
it 'sets content type for error' do | ||
subject.get('/error') { error!('error in plain text', 500) } | ||
get '/error' | ||
expect(last_response.headers['Content-Type']).to eql 'text/plain' | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eql 'text/plain' | ||
end | ||
|
||
it 'sets content type for json error' do | ||
subject.format :json | ||
subject.get('/error') { error!('error in json', 500) } | ||
get '/error.json' | ||
expect(last_response.status).to be 500 | ||
expect(last_response.headers['Content-Type']).to eql 'application/json' | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eql 'application/json' | ||
end | ||
|
||
it 'sets content type for xml error' do | ||
subject.format :xml | ||
subject.get('/error') { error!('error in xml', 500) } | ||
get '/error' | ||
expect(last_response.status).to be 500 | ||
expect(last_response.headers['Content-Type']).to eql 'application/xml' | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eql 'application/xml' | ||
end | ||
|
||
it 'includes extension in format' do | ||
|
@@ -1314,12 +1314,12 @@ class DummyFormatClass | |
|
||
it 'sets content type' do | ||
get '/custom.custom' | ||
expect(last_response.headers['Content-Type']).to eql 'application/custom' | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eql 'application/custom' | ||
end | ||
|
||
it 'sets content type for error' do | ||
get '/error.custom' | ||
expect(last_response.headers['Content-Type']).to eql 'application/custom' | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eql 'application/custom' | ||
end | ||
end | ||
|
||
|
@@ -1339,7 +1339,7 @@ class DummyFormatClass | |
image_filename = 'grape.png' | ||
post url, file: Rack::Test::UploadedFile.new(image_filename, 'image/png', true) | ||
expect(last_response.status).to eq(201) | ||
expect(last_response.headers['Content-Type']).to eq('image/png') | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eq('image/png') | ||
expect(last_response.headers['Content-Disposition']).to eq("attachment; filename*=UTF-8''grape.png") | ||
File.open(image_filename, 'rb') do |io| | ||
expect(last_response.body).to eq io.read | ||
|
@@ -1351,7 +1351,7 @@ class DummyFormatClass | |
filename = __FILE__ | ||
post '/attachment.rb', file: Rack::Test::UploadedFile.new(filename, 'application/x-ruby', true) | ||
expect(last_response.status).to eq(201) | ||
expect(last_response.headers['Content-Type']).to eq('application/x-ruby') | ||
expect(last_response.headers[rack_versioned_headers[:content_type]]).to eq('application/x-ruby') | ||
expect(last_response.headers['Content-Disposition']).to eq("attachment; filename*=UTF-8''api_spec.rb") | ||
File.open(filename, 'rb') do |io| | ||
expect(last_response.body).to eq io.read | ||
|
@@ -3311,7 +3311,7 @@ def static | |
it 'is able to cascade' do | ||
subject.mount lambda { |env| | ||
headers = {} | ||
headers['X-Cascade'] == 'pass' if env['PATH_INFO'].exclude?('boo') | ||
headers[rack_versioned_headers[:x_cascade]] == 'pass' if env['PATH_INFO'].exclude?('boo') | ||
[200, headers, ['Farfegnugen']] | ||
} => '/' | ||
|
||
|
@@ -4081,14 +4081,14 @@ def before | |
subject.version 'v1', using: :path, cascade: true | ||
get '/v1/hello' | ||
expect(last_response.status).to eq(404) | ||
expect(last_response.headers['X-Cascade']).to eq('pass') | ||
expect(last_response.headers[rack_versioned_headers[:x_cascade]]).to eq('pass') | ||
end | ||
|
||
it 'does not cascade' do | ||
subject.version 'v2', using: :path, cascade: false | ||
get '/v2/hello' | ||
expect(last_response.status).to eq(404) | ||
expect(last_response.headers.keys).not_to include 'X-Cascade' | ||
expect(last_response.headers.keys).not_to include rack_versioned_headers[:x_cascade] | ||
end | ||
end | ||
|
||
|
@@ -4097,14 +4097,14 @@ def before | |
subject.cascade true | ||
get '/hello' | ||
expect(last_response.status).to eq(404) | ||
expect(last_response.headers['X-Cascade']).to eq('pass') | ||
expect(last_response.headers[rack_versioned_headers[:x_cascade]]).to eq('pass') | ||
end | ||
|
||
it 'does not cascade' do | ||
subject.cascade false | ||
get '/hello' | ||
expect(last_response.status).to eq(404) | ||
expect(last_response.headers.keys).not_to include 'X-Cascade' | ||
expect(last_response.headers.keys).not_to include rack_versioned_headers[:x_cascade] | ||
end | ||
end | ||
end | ||
|
Uh oh!
There was an error while loading. Please reload this page.