Skip to content
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

Support Rack::Sendfile middleware #1280

Merged
merged 1 commit into from
Feb 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* [#1252](https://github.com/ruby-grape/grape/pull/1252): Allow default to be a subset or equal to allowed values without raising IncompatibleOptionValues - [@jeradphelps](https://github.com/jeradphelps).
* [#1255](https://github.com/ruby-grape/grape/pull/1255): Allow param type definition in `route_param` - [@namusyaka](https://github.com/namusyaka).
* [#1257](https://github.com/ruby-grape/grape/pull/1257): Allow Proc, Symbol or String in `rescue_from with: ...` - [@namusyaka](https://github.com/namusyaka).
* [#1280](https://github.com/ruby-grape/grape/pull/1280): Support `Rack::Sendfile` middleware - [@lfidnl](https://github.com/lfidnl).
* [#1285](https://github.com/ruby-grape/grape/pull/1285): Add a warning for errors appearing in `after` callbacks - [@gregormelhorn](https://github.com/gregormelhorn).
* Your contribution here.

Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2328,6 +2328,30 @@ class API < Grape::API
end
```

If you want to take advantage of `Rack::Sendfile`, which intercepts responses whose body is
being served from a file and replaces it with a server specific X-Sendfile header, specify `to_path`
method in your file streamer class which returns path of served file:

```ruby
class FileStreamer
# ...

def to_path
@file_path
end

# ...
end
```

Note: don't forget turn on `Rack::Sendfile` middleware in your API:

```ruby
class API < Grape::API
use Rack::Sendfile
end
```

## Authentication

### Basic and Digest Auth
Expand Down
1 change: 1 addition & 0 deletions lib/grape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ module Util
autoload :InheritableSetting
autoload :StrictHashConfiguration
autoload :FileResponse
autoload :SendfileResponse
end

module DSL
Expand Down
2 changes: 1 addition & 1 deletion lib/grape/middleware/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def build_formatted_response(status, headers, bodies)
headers = ensure_content_type(headers)

if bodies.is_a?(Grape::Util::FileResponse)
Rack::Response.new([], status, headers) do |resp|
Grape::Util::SendfileResponse.new([], status, headers) do |resp|
resp.body = bodies.file
end
else
Expand Down
19 changes: 19 additions & 0 deletions lib/grape/util/sendfile_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Grape
module Util
# Response should respond to to_path method
# for using Rack::SendFile middleware
class SendfileResponse < Rack::Response
def respond_to?(method_name, include_all = false)
if method_name == :to_path
@body.respond_to?(:to_path, include_all)
else
super
end
end

def to_path
@body.to_path
end
end
end
end
44 changes: 44 additions & 0 deletions spec/grape/integration/rack_sendfile_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'spec_helper'

describe Rack::Sendfile do
subject do
send_file = file_streamer
app = Class.new(Grape::API) do
use Rack::Sendfile
format :json
get do
file send_file
end
end

options = {
method: 'GET',
'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect',
'HTTP_X_ACCEL_MAPPING' => '/accel/mapping/=/replaced/'
}
env = Rack::MockRequest.env_for('/', options)
app.call(env)
end

context do
let(:file_streamer) do
double(:file_streamer, to_path: '/accel/mapping/some/path')
end

it 'contains Sendfile headers' do
headers = subject[1]
expect(headers).to include('X-Accel-Redirect')
end
end

context do
let(:file_streamer) do
double(:file_streamer)
end

it 'not contains Sendfile headers' do
headers = subject[1]
expect(headers).to_not include('X-Accel-Redirect')
end
end
end
10 changes: 10 additions & 0 deletions spec/grape/middleware/formatter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,14 @@ def to_xml
end
end
end

context 'send file' do
let(:app) { ->(_env) { [200, {}, @body] } }

it 'returns Grape::Uril::SendFileReponse' do
@body = Grape::Util::FileResponse.new('file')
env = { 'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json' }
expect(subject.call(env)).to be_a(Grape::Util::SendfileResponse)
end
end
end