rack-easy_brotli 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/COPYING +19 -0
- data/README.md +40 -0
- data/lib/rack/brotli.rb +16 -0
- data/lib/rack/brotli/deflater.rb +140 -0
- data/lib/rack/brotli/instrument.rb +11 -0
- data/lib/rack/brotli/railtie.rb +11 -0
- data/lib/rack/brotli/version.rb +11 -0
- data/lib/rack/easy_brotli.rb +1 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 90c6a421a62be6d4257439c1f4c3b551bbd130347746aa169a32057cb0acb77c
|
4
|
+
data.tar.gz: 9d07efecfaab4ea4a1e451888d21cc711a0885dff2b69ef2ffc4ef63b6f26739
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: adb6aebce3c4c444b6320104b5b1212cf437ae8c32cecd88a3cb75f409702f10c3d295cdb18a16c6382f71b713cc5e70a959320ea3fced996697299822b07e6e
|
7
|
+
data.tar.gz: a924c24565f9ce5dea893277147023622002172c10015abaf61ca6a945117ec573ac5a6d51d8dba17b21bb609e7ea0b95c783757657bb1b8a60f58334a4e6a18
|
data/COPYING
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
Copyright (c) 2008 The Committers
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
of this software and associated documentation files (the "Software"), to
|
6
|
+
deal in the Software without restriction, including without limitation the
|
7
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
8
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
9
|
+
furnished to do so, subject to the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be included in
|
12
|
+
all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
17
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
18
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
19
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Rack::Brotli [![Gem Version](https://badge.fury.io/rb/rack-brotli.svg)](https://badge.fury.io/rb/rack-brotli) [![Build Status](https://travis-ci.org/marcotc/rack-brotli.svg?branch=master)](https://travis-ci.org/marcotc/rack-brotli)
|
2
|
+
|
3
|
+
`Rack::Brotli` compresses `Rack` responses using [Google's Brotli](https://github.com/google/brotli) compression algorithm.
|
4
|
+
|
5
|
+
Brotli generally compresses better than `gzip` for the same CPU cost and is supported by [Chrome, Firefox, IE and Opera](http://caniuse.com/#feat=brotli).
|
6
|
+
|
7
|
+
### Use
|
8
|
+
|
9
|
+
Install gem:
|
10
|
+
|
11
|
+
gem install rack-easy_brotli
|
12
|
+
|
13
|
+
Requiring `'rack/brotli'` will autoload `Rack::Brotli` module. The following example shows what a simple rackup
|
14
|
+
(`config.ru`) file might look like:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
require 'rack'
|
18
|
+
require 'rack/brotli'
|
19
|
+
|
20
|
+
use Rack::Brotli
|
21
|
+
|
22
|
+
run theapp
|
23
|
+
```
|
24
|
+
|
25
|
+
bundler
|
26
|
+
```ruby
|
27
|
+
gem 'rack-easy_brotli'
|
28
|
+
```
|
29
|
+
|
30
|
+
### Testing
|
31
|
+
|
32
|
+
To run the entire test suite, run
|
33
|
+
|
34
|
+
rake test
|
35
|
+
|
36
|
+
### Links
|
37
|
+
|
38
|
+
* rack-brotli on GitHub:: <http://github.com/marcotc/rack-brotli>
|
39
|
+
* Rack:: <http://rack.rubyforge.org/>
|
40
|
+
* Rack On GitHub:: <http://github.com/rack/rack>
|
data/lib/rack/brotli.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative 'brotli/instrument'
|
2
|
+
require_relative 'brotli/deflater'
|
3
|
+
require_relative 'brotli/version'
|
4
|
+
require_relative 'brotli/railtie' if defined?(::Rails)
|
5
|
+
|
6
|
+
module Rack
|
7
|
+
module Brotli
|
8
|
+
def self.release
|
9
|
+
Version.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.new(app, options={})
|
13
|
+
Rack::Brotli::Deflater.new(app, options)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "brotli"
|
4
|
+
require 'rack/utils'
|
5
|
+
|
6
|
+
module Rack::Brotli
|
7
|
+
# This middleware enables compression of http responses.
|
8
|
+
#
|
9
|
+
# Currently supported compression algorithms:
|
10
|
+
#
|
11
|
+
# * br
|
12
|
+
#
|
13
|
+
# The middleware automatically detects when compression is supported
|
14
|
+
# and allowed. For example no transformation is made when a cache
|
15
|
+
# directive of 'no-transform' is present, or when the response status
|
16
|
+
# code is one that doesn't allow an entity body.
|
17
|
+
class Deflater
|
18
|
+
##
|
19
|
+
# Creates Rack::Brotli middleware.
|
20
|
+
#
|
21
|
+
# [app] rack app instance
|
22
|
+
# [options] hash of deflater options, i.e.
|
23
|
+
# 'if' - a lambda enabling / disabling deflation based on returned boolean value
|
24
|
+
# e.g use Rack::Brotli, :if => lambda { |env, status, headers, body| body.map(&:bytesize).reduce(0, :+) > 512 }
|
25
|
+
# 'include' - a list of content types that should be compressed
|
26
|
+
# 'deflater' - Brotli compression options
|
27
|
+
def initialize(app, options = {})
|
28
|
+
@app = app
|
29
|
+
|
30
|
+
@condition = options[:if]
|
31
|
+
@compressible_types = options[:include]
|
32
|
+
if defined?(ActiveSupport::Notifications)
|
33
|
+
@notifier = ActiveSupport::Notifications
|
34
|
+
else
|
35
|
+
@notifier = Rack::Brotli::Instrument
|
36
|
+
end
|
37
|
+
@deflater_options = { quality: 5 }
|
38
|
+
@deflater_options.merge!(options[:deflater]) if options[:deflater]
|
39
|
+
@deflater_options
|
40
|
+
end
|
41
|
+
|
42
|
+
def call(env)
|
43
|
+
status, headers, body = @app.call(env)
|
44
|
+
headers = header_hash(headers)
|
45
|
+
|
46
|
+
unless should_deflate?(env, status, headers, body)
|
47
|
+
return [status, headers, body]
|
48
|
+
end
|
49
|
+
|
50
|
+
request = Rack::Request.new(env)
|
51
|
+
|
52
|
+
encoding = Rack::Utils.select_best_encoding(%w(br),
|
53
|
+
request.accept_encoding)
|
54
|
+
|
55
|
+
return [status, headers, body] unless encoding
|
56
|
+
|
57
|
+
instrument(request) do
|
58
|
+
# Set the Vary HTTP header.
|
59
|
+
vary = headers["Vary"].to_s.split(",").map(&:strip)
|
60
|
+
unless vary.include?("*") || vary.include?("Accept-Encoding")
|
61
|
+
headers["Vary"] = vary.push("Accept-Encoding").join(",")
|
62
|
+
end
|
63
|
+
|
64
|
+
case encoding
|
65
|
+
when "br"
|
66
|
+
headers['Content-Encoding'] = "br"
|
67
|
+
headers.delete('Content-Length')
|
68
|
+
[status, headers, BrotliStream.new(body, @deflater_options)]
|
69
|
+
when nil
|
70
|
+
message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
|
71
|
+
bp = Rack::BodyProxy.new([message]) { body.close if body.respond_to?(:close) }
|
72
|
+
[406, {'Content-Type' => "text/plain", 'Content-Length' => message.length.to_s}, bp]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class BrotliStream
|
78
|
+
include Rack::Utils
|
79
|
+
|
80
|
+
def initialize(body, options)
|
81
|
+
@body = body
|
82
|
+
@options = options
|
83
|
+
end
|
84
|
+
|
85
|
+
def each(&block)
|
86
|
+
@writer = block
|
87
|
+
buffer = +''
|
88
|
+
@body.each { |part|
|
89
|
+
buffer << part
|
90
|
+
}
|
91
|
+
yield ::Brotli.deflate(buffer, @options)
|
92
|
+
ensure
|
93
|
+
@writer = nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def close
|
97
|
+
@body.close if @body.respond_to?(:close)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# instrument for performance metrics
|
104
|
+
def instrument(request, &block)
|
105
|
+
@notifier.instrument("rack.brotli", request: request) do
|
106
|
+
yield
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def header_hash(headers)
|
111
|
+
if headers.is_a?(Rack::Utils::HeaderHash)
|
112
|
+
header
|
113
|
+
else
|
114
|
+
Rack::Utils::HeaderHash.new(headers) # rack < 2.2
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def should_deflate?(env, status, headers, body)
|
119
|
+
# Skip compressing empty entity body responses and responses with
|
120
|
+
# no-transform set.
|
121
|
+
if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) ||
|
122
|
+
/\bno-transform\b/.match?(headers['Cache-Control'].to_s) ||
|
123
|
+
headers['Content-Encoding']&.!~(/\bidentity\b/)
|
124
|
+
return false
|
125
|
+
end
|
126
|
+
|
127
|
+
# Skip if @compressible_types are given and does not include request's content type
|
128
|
+
return false if @compressible_types && !(headers.has_key?('Content-Type') && @compressible_types.include?(headers['Content-Type'][/[^;]*/]))
|
129
|
+
|
130
|
+
# Skip if @condition lambda is given and evaluates to false
|
131
|
+
return false if @condition && !@condition.call(env, status, headers, body)
|
132
|
+
|
133
|
+
# No point in compressing empty body, also handles usage with
|
134
|
+
# Rack::Sendfile.
|
135
|
+
return false if headers['Content-Length'] == '0'
|
136
|
+
|
137
|
+
true
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'rack/brotli'
|
metadata
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-easy_brotli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Marco Costa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-05-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: brotli
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.4.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.4.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
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: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 5.14.4
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 5.14.4
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 13.0.3
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 13.0.3
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rdoc
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 6.3.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 6.3.1
|
97
|
+
description: Rack::Brotli enables Google's Brotli compression on HTTP responses
|
98
|
+
email: marco@marcotc.com
|
99
|
+
executables: []
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files:
|
102
|
+
- README.md
|
103
|
+
- COPYING
|
104
|
+
files:
|
105
|
+
- COPYING
|
106
|
+
- README.md
|
107
|
+
- lib/rack/brotli.rb
|
108
|
+
- lib/rack/brotli/deflater.rb
|
109
|
+
- lib/rack/brotli/instrument.rb
|
110
|
+
- lib/rack/brotli/railtie.rb
|
111
|
+
- lib/rack/brotli/version.rb
|
112
|
+
- lib/rack/easy_brotli.rb
|
113
|
+
homepage: http://github.com/marcotc/rack-brotli/
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options:
|
119
|
+
- "--line-numbers"
|
120
|
+
- "--inline-source"
|
121
|
+
- "--title"
|
122
|
+
- rack-brotli
|
123
|
+
- "--main"
|
124
|
+
- README
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 2.5.0
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
requirements: []
|
138
|
+
rubygems_version: 3.2.17
|
139
|
+
signing_key:
|
140
|
+
specification_version: 2
|
141
|
+
summary: Brotli compression for Rack responses
|
142
|
+
test_files: []
|