rack-brotli 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +9 -6
- data/lib/rack/brotli/deflater.rb +68 -41
- data/lib/rack/brotli/version.rb +1 -1
- metadata +10 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b74bec06cbe4c1bb630015f38590e272bffa0bf0ae35543625bff909872d920
|
4
|
+
data.tar.gz: a34a2637ad36992b49368ed62cfc1ffeb195588d2eec5fe04c542b624447e8ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 677a662e25d59d451e7fd8477fa135febf135df5e9764282c2340df9c848a4c2e3579a7b7cb6de0ddde4cbeb2bda3478ff3f43377fc888db202f1bb6172f3c47
|
7
|
+
data.tar.gz: f5c9643048b9002d0aad3b35e76c6b783c46306c26ab9e34cac5a6a3b25c1d7a0793793303acdfbb474a6dbd96fe2d881eb9eee30cd96d72f218aa74a01e4bb9
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Rack::Brotli [](https://badge.fury.io/rb/rack-brotli) [](https://badge.fury.io/rb/rack-brotli) [](https://github.com/marcotc/rack-brotli/actions/workflows/test.yml)
|
2
2
|
|
3
3
|
`Rack::Brotli` compresses `Rack` responses using [Google's Brotli](https://github.com/google/brotli) compression algorithm.
|
4
4
|
|
@@ -17,7 +17,10 @@ Requiring `'rack/brotli'` will autoload `Rack::Brotli` module. The following exa
|
|
17
17
|
require 'rack'
|
18
18
|
require 'rack/brotli'
|
19
19
|
|
20
|
-
use Rack::Brotli
|
20
|
+
use Rack::Brotli # Default compression quality is 5
|
21
|
+
|
22
|
+
# You can also provide native Brotli compression options:
|
23
|
+
# use Rack::Brotli, quality: 11
|
21
24
|
|
22
25
|
run theapp
|
23
26
|
```
|
@@ -26,10 +29,10 @@ run theapp
|
|
26
29
|
|
27
30
|
To run the entire test suite, run
|
28
31
|
|
29
|
-
rake test
|
32
|
+
bundle exec rake test
|
30
33
|
|
31
34
|
### Links
|
32
35
|
|
33
|
-
* rack-brotli
|
34
|
-
*
|
35
|
-
* Rack
|
36
|
+
* rack-brotli: <http://github.com/marcotc/rack-brotli>
|
37
|
+
* Brotli for Ruby: <https://github.com/miyucy/brotli>
|
38
|
+
* Rack: <http://github.com/rack/rack>
|
data/lib/rack/brotli/deflater.rb
CHANGED
@@ -1,17 +1,13 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'brotli'
|
4
|
+
require "rack/utils"
|
5
|
+
require 'rack/request'
|
6
|
+
require 'rack/body_proxy'
|
3
7
|
|
4
8
|
module Rack::Brotli
|
5
|
-
# This middleware enables compression of http responses
|
6
|
-
#
|
7
|
-
# Currently supported compression algorithms:
|
8
|
-
#
|
9
|
-
# * br
|
10
|
-
#
|
11
|
-
# The middleware automatically detects when compression is supported
|
12
|
-
# and allowed. For example no transformation is made when a cache
|
13
|
-
# directive of 'no-transform' is present, or when the response status
|
14
|
-
# code is one that doesn't allow an entity body.
|
9
|
+
# This middleware enables compression of http responses with the `br` encoding,
|
10
|
+
# when support is detected and allowed.
|
15
11
|
class Deflater
|
16
12
|
##
|
17
13
|
# Creates Rack::Brotli middleware.
|
@@ -21,80 +17,107 @@ module Rack::Brotli
|
|
21
17
|
# 'if' - a lambda enabling / disabling deflation based on returned boolean value
|
22
18
|
# e.g use Rack::Brotli, :if => lambda { |env, status, headers, body| body.map(&:bytesize).reduce(0, :+) > 512 }
|
23
19
|
# 'include' - a list of content types that should be compressed
|
24
|
-
# 'deflater' - Brotli compression options
|
20
|
+
# 'deflater' - Brotli compression options Hash (see https://brotli.org/encode.html#a4d4 and https://github.com/miyucy/brotli/blob/ea0e058031177e5cc42e361f7d2702a951048a31/ext/brotli/brotli.c#L119-L180)
|
21
|
+
# - 'mode'
|
22
|
+
# - 'quality'
|
23
|
+
# - 'lgwin'
|
24
|
+
# - 'lgblock'
|
25
25
|
def initialize(app, options = {})
|
26
26
|
@app = app
|
27
27
|
|
28
28
|
@condition = options[:if]
|
29
29
|
@compressible_types = options[:include]
|
30
|
-
@deflater_options = { quality: 5 }.merge(options
|
30
|
+
@deflater_options = { quality: 5 }.merge(options.fetch(:deflater, {}))
|
31
|
+
@sync = options.fetch(:sync, true)
|
31
32
|
end
|
32
33
|
|
33
34
|
def call(env)
|
34
|
-
status, headers, body = @app.call(env)
|
35
|
-
headers = Rack::Utils::HeaderHash.new(headers)
|
35
|
+
status, headers, body = response = @app.call(env)
|
36
36
|
|
37
37
|
unless should_deflate?(env, status, headers, body)
|
38
|
-
return
|
38
|
+
return response
|
39
39
|
end
|
40
40
|
|
41
41
|
request = Rack::Request.new(env)
|
42
42
|
|
43
|
-
encoding = Rack::Utils.select_best_encoding(%w(br),
|
44
|
-
request.accept_encoding)
|
45
|
-
|
46
|
-
return [status, headers, body] unless encoding
|
43
|
+
encoding = Rack::Utils.select_best_encoding(%w(br identity), request.accept_encoding)
|
47
44
|
|
48
45
|
# Set the Vary HTTP header.
|
49
|
-
vary = headers["
|
50
|
-
unless vary.include?("*") || vary.
|
51
|
-
headers["
|
46
|
+
vary = headers["vary"].to_s.split(",").map(&:strip)
|
47
|
+
unless vary.include?("*") || vary.any?{|v| v.downcase == 'accept-encoding'}
|
48
|
+
headers["vary"] = vary.push("Accept-Encoding").join(",")
|
52
49
|
end
|
53
50
|
|
54
51
|
case encoding
|
55
52
|
when "br"
|
56
|
-
headers['
|
53
|
+
headers['content-encoding'] = "br"
|
57
54
|
headers.delete(Rack::CONTENT_LENGTH)
|
58
|
-
[
|
59
|
-
|
55
|
+
response[2] = BrotliStream.new(body, @sync, @deflater_options)
|
56
|
+
response
|
57
|
+
when "identity"
|
58
|
+
response
|
59
|
+
else
|
60
|
+
# Only possible encoding values here are 'br', 'identity', and nil
|
60
61
|
message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
|
61
62
|
bp = Rack::BodyProxy.new([message]) { body.close if body.respond_to?(:close) }
|
62
|
-
[406, {Rack::CONTENT_TYPE => "text/plain", Rack::CONTENT_LENGTH => message.length.to_s}, bp]
|
63
|
+
[406, { Rack::CONTENT_TYPE => "text/plain", Rack::CONTENT_LENGTH => message.length.to_s }, bp]
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
67
|
+
# Body class used for encoded responses.
|
66
68
|
class BrotliStream
|
67
|
-
include Rack::Utils
|
68
69
|
|
69
|
-
|
70
|
+
BUFFER_LENGTH = 128 * 1_024
|
71
|
+
|
72
|
+
def initialize(body, sync, br_options)
|
70
73
|
@body = body
|
71
|
-
@
|
74
|
+
@br_options = br_options
|
75
|
+
@sync = sync
|
72
76
|
end
|
73
77
|
|
78
|
+
# Yield compressed strings to the given block.
|
74
79
|
def each(&block)
|
75
80
|
@writer = block
|
76
|
-
|
77
|
-
@body.each
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
+
br = Brotli::Writer.new(self, @br_options)
|
82
|
+
# @body.each is equivalent to @body.gets (slow)
|
83
|
+
if @body.is_a? ::File # XXX: Should probably be ::IO
|
84
|
+
while part = @body.read(BUFFER_LENGTH)
|
85
|
+
br.write(part)
|
86
|
+
br.flush if @sync
|
87
|
+
end
|
88
|
+
else
|
89
|
+
@body.each { |part|
|
90
|
+
# Skip empty strings, as they would result in no output,
|
91
|
+
# and flushing empty parts could raise an IO error.
|
92
|
+
next if part.empty?
|
93
|
+
br.write(part)
|
94
|
+
br.flush if @sync
|
95
|
+
}
|
96
|
+
end
|
81
97
|
ensure
|
82
|
-
|
98
|
+
br.finish
|
83
99
|
end
|
84
100
|
|
101
|
+
# Call the block passed to #each with the compressed data.
|
102
|
+
def write(data)
|
103
|
+
@writer.call(data)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Close the original body if possible.
|
85
107
|
def close
|
86
108
|
@body.close if @body.respond_to?(:close)
|
87
109
|
end
|
88
110
|
end
|
89
|
-
|
111
|
+
|
90
112
|
private
|
91
113
|
|
114
|
+
# Whether the body should be compressed.
|
92
115
|
def should_deflate?(env, status, headers, body)
|
93
116
|
# Skip compressing empty entity body responses and responses with
|
94
117
|
# no-transform set.
|
95
|
-
if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.
|
96
|
-
|
97
|
-
|
118
|
+
if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) ||
|
119
|
+
/\bno-transform\b/.match?(headers[Rack::CACHE_CONTROL].to_s) ||
|
120
|
+
headers['content-encoding']&.!~(/\bidentity\b/)
|
98
121
|
return false
|
99
122
|
end
|
100
123
|
|
@@ -104,6 +127,10 @@ module Rack::Brotli
|
|
104
127
|
# Skip if @condition lambda is given and evaluates to false
|
105
128
|
return false if @condition && !@condition.call(env, status, headers, body)
|
106
129
|
|
130
|
+
# No point in compressing empty body, also handles usage with
|
131
|
+
# Rack::Sendfile.
|
132
|
+
return false if headers[Rack::CONTENT_LENGTH] == '0'
|
133
|
+
|
107
134
|
true
|
108
135
|
end
|
109
136
|
end
|
data/lib/rack/brotli/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-brotli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marco Costa
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -16,90 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '3'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: brotli
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: '0.3'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 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.6'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '5.6'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rake
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '12'
|
76
|
-
- - ">="
|
77
|
-
- !ruby/object:Gem::Version
|
78
|
-
version: 12.3.3
|
79
|
-
type: :development
|
80
|
-
prerelease: false
|
81
|
-
version_requirements: !ruby/object:Gem::Requirement
|
82
|
-
requirements:
|
83
|
-
- - "~>"
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
version: '12'
|
86
|
-
- - ">="
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: 12.3.3
|
89
|
-
- !ruby/object:Gem::Dependency
|
90
|
-
name: rdoc
|
91
|
-
requirement: !ruby/object:Gem::Requirement
|
92
|
-
requirements:
|
93
|
-
- - "~>"
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
version: '3.12'
|
96
|
-
type: :development
|
97
|
-
prerelease: false
|
98
|
-
version_requirements: !ruby/object:Gem::Requirement
|
99
|
-
requirements:
|
100
|
-
- - "~>"
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
version: '3.12'
|
40
|
+
version: '0.3'
|
103
41
|
description: Rack::Brotli enables Google's Brotli compression on HTTP responses
|
104
42
|
email: marco@marcotc.com
|
105
43
|
executables: []
|
@@ -117,7 +55,7 @@ homepage: http://github.com/marcotc/rack-brotli/
|
|
117
55
|
licenses:
|
118
56
|
- MIT
|
119
57
|
metadata: {}
|
120
|
-
post_install_message:
|
58
|
+
post_install_message:
|
121
59
|
rdoc_options:
|
122
60
|
- "--line-numbers"
|
123
61
|
- "--inline-source"
|
@@ -138,8 +76,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
76
|
- !ruby/object:Gem::Version
|
139
77
|
version: '0'
|
140
78
|
requirements: []
|
141
|
-
rubygems_version: 3.
|
142
|
-
signing_key:
|
79
|
+
rubygems_version: 3.3.7
|
80
|
+
signing_key:
|
143
81
|
specification_version: 2
|
144
82
|
summary: Brotli compression for Rack responses
|
145
83
|
test_files: []
|