rack_gzfile 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +41 -0
- data/Rakefile +1 -0
- data/lib/rack/gz_file/version.rb +5 -0
- data/lib/rack/gz_file.rb +45 -0
- data/lib/rack_gzfile.rb +2 -0
- data/rack_gzfile.gemspec +25 -0
- data/spec/fixtures/foo.html +1 -0
- data/spec/fixtures/i_can_has_gzip.html +1 -0
- data/spec/fixtures/i_can_has_gzip.html.gz +0 -0
- data/spec/lib/rack/gz_file_spec.rb +77 -0
- data/spec/spec_helper.rb +4 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d17f0629b61d4802b40da6dd088ab82277c09412
|
4
|
+
data.tar.gz: 3f0fb225709a01983227b70f014985505e324a13
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1c2af2da13f9473883c6868aeac25763229da118e9f7d0eac8c7284cf6396a6a9d6512e8fb6261d8dd02a00f5a72ae60b6e585baf911edb8a37b50ea4d53daf5
|
7
|
+
data.tar.gz: 7c7bf53188977357a6a3bd7daaaf123886328d0653b2d3555a8072ec54dcdcf286484ed0200945d9b9ec6ecab93d7540f816c2fb516d515a1b66e0f6563b57a0
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Brian Alexander
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# RackGzfile
|
2
|
+
|
3
|
+
By default, `rake assets:precompile` generates gzipped versions of certain types of files. Servers (like Nginx with the GzipStatic module) can then serve these gzipped assets so they can get the reduced bandwidth of gzip without needing to compress the file on every request. [This pull request](https://github.com/rack/rack/pull/479) will hopefully bring this functionality to Rack. In the meantime, this gem can be used.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rack_gzfile'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
`Rack::GzFile` can be used as a drop-in replacement for [`Rack::File`](https://github.com/rack/rack/blob/master/lib/rack/file.rb).
|
18
|
+
|
19
|
+
### Usage with `Rack::Static`
|
20
|
+
|
21
|
+
Unfortunately, `Rack::Static` is hardcoded to use `Rack::File`. [Hopefully this will be changed](https://github.com/rack/rack/pull/479#issuecomment-21907789), but in the meantime you can do an ugly monkey patch like this:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
Rack::Static.class_eval do
|
25
|
+
def initialize_with_gzip_file_server(app, options={})
|
26
|
+
initialize_without_gzip_file_server(app, options)
|
27
|
+
|
28
|
+
root = options[:root] || Dir.pwd
|
29
|
+
@file_server = Rack::GzFile.new(root, @headers)
|
30
|
+
end
|
31
|
+
alias_method_chain :initialize, :gzip_file_server
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
## Contributing
|
36
|
+
|
37
|
+
1. Fork it
|
38
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
39
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
40
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
41
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/rack/gz_file.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Rack
|
2
|
+
# Rack::GzFile behaves exactly the same as Rack::File, except that it will
|
3
|
+
# also serve up a gzip encoding of a file, if one is available on the
|
4
|
+
# filesystem.
|
5
|
+
#
|
6
|
+
# For each request, Rack::GzFile first checks the filesystem for a file with a
|
7
|
+
# .gz extension. If one is found, the appropriate encoding headers are added
|
8
|
+
# to the response and the gzip file is served.
|
9
|
+
#
|
10
|
+
# If no .gz file is found, Rack::GzFile will behave exactly like Rack::File.
|
11
|
+
class GzFile
|
12
|
+
def initialize(root, headers={}, default_mime = 'text/plain')
|
13
|
+
@file_server = if Rack::File.instance_method(:initialize).arity.abs == 2
|
14
|
+
Rack::File.new(root, headers) # for Rack < 1.5.0
|
15
|
+
else
|
16
|
+
Rack::File.new(root, headers, default_mime)
|
17
|
+
end
|
18
|
+
@default_mime = default_mime
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(env)
|
22
|
+
path_info = env['PATH_INFO']
|
23
|
+
status = nil
|
24
|
+
|
25
|
+
if env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/
|
26
|
+
status, headers, body = @file_server.call(
|
27
|
+
env.merge('PATH_INFO' => path_info + '.gz')
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
case status
|
32
|
+
when 200
|
33
|
+
headers['Content-Type'] = Mime.mime_type(::File.extname(path_info), @default_mime)
|
34
|
+
headers['Content-Encoding'] = 'gzip'
|
35
|
+
when 304
|
36
|
+
else
|
37
|
+
status, headers, body = @file_server.call(env)
|
38
|
+
end
|
39
|
+
|
40
|
+
headers['Vary'] = 'Accept-Encoding'
|
41
|
+
|
42
|
+
[status, headers, body]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/rack_gzfile.rb
ADDED
data/rack_gzfile.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rack/gz_file/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rack_gzfile"
|
8
|
+
spec.version = Rack::GzFile::VERSION
|
9
|
+
spec.authors = ["Brian Alexander"]
|
10
|
+
spec.email = ["balexand@gmail.com"]
|
11
|
+
spec.description = %q{Rack::File meets gzip_static}
|
12
|
+
spec.summary = %q{Rack::File meets gzip_static}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rack"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
I can't has gzip!
|
@@ -0,0 +1 @@
|
|
1
|
+
I can has gzip!
|
Binary file
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::GzFile do
|
4
|
+
|
5
|
+
let(:root) { File.expand_path("../../../fixtures", __FILE__) }
|
6
|
+
let(:request) { Rack::MockRequest.new(Rack::Lint.new(Rack::GzFile.new(root))) }
|
7
|
+
|
8
|
+
describe "#call" do
|
9
|
+
|
10
|
+
context "non-gzipped file requested" do
|
11
|
+
|
12
|
+
it "renders non-gzipped file" do
|
13
|
+
res = request.get('/i_can_has_gzip.html')
|
14
|
+
expect(res.status).to eq 200
|
15
|
+
expect(res.body).to eq "I can has gzip!\n"
|
16
|
+
expect(res.headers.key?('Content-Encoding')).to eq false
|
17
|
+
expect(res.headers['Vary']).to eq 'Accept-Encoding'
|
18
|
+
expect(res.headers['Content-Length']).to eq "I can has gzip!\n".size.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
context "gzipped file requested" do
|
24
|
+
|
25
|
+
it "renders gzipped file if it exists" do
|
26
|
+
res = request.get('/i_can_has_gzip.html', 'HTTP_ACCEPT_ENCODING' => 'gzip')
|
27
|
+
expect(res.status).to eq 200
|
28
|
+
expect(Zlib::GzipReader.new(StringIO.new(res.body)).read).to eq "I can has gzip!\n"
|
29
|
+
expect(res.headers['Content-Encoding']).to eq 'gzip'
|
30
|
+
expect(res.headers['Vary']).to eq 'Accept-Encoding'
|
31
|
+
expect(res.headers['Content-Length']).to eq File.size(File.join(root, "i_can_has_gzip.html.gz")).to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
it "renders non-gzipped file if gzipped file not present" do
|
35
|
+
res = request.get('/foo.html', 'HTTP_ACCEPT_ENCODING' => 'gzip')
|
36
|
+
expect(res.status).to eq 200
|
37
|
+
expect(res.body).to eq "I can't has gzip!\n"
|
38
|
+
expect(res.headers.key?('Content-Encoding')).to eq false
|
39
|
+
expect(res.headers['Vary']).to eq 'Accept-Encoding'
|
40
|
+
expect(res.headers['Content-Length']).to eq "I can't has gzip!\n".size.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
it "renders passes 304 response for gzipped file without updating headers" do
|
44
|
+
date = Time.new(2012,12,25)
|
45
|
+
File.utime date, date, File.join(root, "i_can_has_gzip.html.gz")
|
46
|
+
res = request.get('/i_can_has_gzip.html', 'HTTP_ACCEPT_ENCODING' => 'gzip', 'HTTP_IF_MODIFIED_SINCE' => date.httpdate)
|
47
|
+
|
48
|
+
expect(res.status).to eq 304
|
49
|
+
expect(res.body).to eq ""
|
50
|
+
expect(res.headers.key?('Content-Encoding')).to eq false
|
51
|
+
expect(res.headers['Vary']).to eq 'Accept-Encoding'
|
52
|
+
expect(res.headers.key?('Content-Length')).to eq false
|
53
|
+
end
|
54
|
+
|
55
|
+
it "renders normal file if arbitrary status is returned for gzipped file" do
|
56
|
+
Rack::File.any_instance.stub(:call) do |env|
|
57
|
+
case env['PATH_INFO']
|
58
|
+
when "/i_can_has_gzip.html.gz"
|
59
|
+
[500, {}, ["Something went wrong"]]
|
60
|
+
else
|
61
|
+
[200, {"Content-Type" => "text/plain"}, ["Got the non-gzipped version"]]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
res = request.get('/i_can_has_gzip.html', 'HTTP_ACCEPT_ENCODING' => 'gzip')
|
66
|
+
expect(res.status).to eq 200
|
67
|
+
expect(res.body).to eq "Got the non-gzipped version"
|
68
|
+
expect(res.headers.key?('Content-Encoding')).to eq false
|
69
|
+
expect(res.headers['Vary']).to eq 'Accept-Encoding'
|
70
|
+
expect(res.headers['Content-Length']).to eq "Got the non-gzipped version".size.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack_gzfile
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Alexander
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-08-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Rack::File meets gzip_static
|
70
|
+
email:
|
71
|
+
- balexand@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/rack/gz_file.rb
|
82
|
+
- lib/rack/gz_file/version.rb
|
83
|
+
- lib/rack_gzfile.rb
|
84
|
+
- rack_gzfile.gemspec
|
85
|
+
- spec/fixtures/foo.html
|
86
|
+
- spec/fixtures/i_can_has_gzip.html
|
87
|
+
- spec/fixtures/i_can_has_gzip.html.gz
|
88
|
+
- spec/lib/rack/gz_file_spec.rb
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
homepage: ''
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
metadata: {}
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 2.0.2
|
111
|
+
signing_key:
|
112
|
+
specification_version: 4
|
113
|
+
summary: Rack::File meets gzip_static
|
114
|
+
test_files:
|
115
|
+
- spec/fixtures/foo.html
|
116
|
+
- spec/fixtures/i_can_has_gzip.html
|
117
|
+
- spec/fixtures/i_can_has_gzip.html.gz
|
118
|
+
- spec/lib/rack/gz_file_spec.rb
|
119
|
+
- spec/spec_helper.rb
|