class Rack::Brotli::Deflater
This middleware enables compression of http responses.
Currently supported compression algorithms:
* br
The middleware automatically detects when compression is supported and allowed. For example no transformation is made when a cache directive of 'no-transform' is present, or when the response status code is one that doesn't allow an entity body.
Public Class Methods
new(app, options = {})
click to toggle source
Creates Rack::Brotli
middleware.
- app
-
rack app instance
- options
-
hash of deflater options, i.e. 'if' - a lambda enabling / disabling deflation based on returned boolean value
e.g use Rack::Brotli, :if => lambda { |env, status, headers, body| body.map(&:bytesize).reduce(0, :+) > 512 }
'include' - a list of content types that should be compressed 'deflater' -
Brotli
compression options
# File lib/rack/brotli/deflater.rb 27 def initialize(app, options = {}) 28 @app = app 29 30 @condition = options[:if] 31 @compressible_types = options[:include] 32 @deflater_options = { quality: 5 } 33 @deflater_options.merge!(options[:deflater]) if options[:deflater] 34 @deflater_options 35 end
Public Instance Methods
call(env)
click to toggle source
# File lib/rack/brotli/deflater.rb 37 def call(env) 38 status, headers, body = @app.call(env) 39 headers = header_hash(headers) 40 41 unless should_deflate?(env, status, headers, body) 42 return [status, headers, body] 43 end 44 45 request = Rack::Request.new(env) 46 47 encoding = Rack::Utils.select_best_encoding(%w(br), 48 request.accept_encoding) 49 50 return [status, headers, body] unless encoding 51 52 # Set the Vary HTTP header. 53 vary = headers["Vary"].to_s.split(",").map(&:strip) 54 unless vary.include?("*") || vary.include?("Accept-Encoding") 55 headers["Vary"] = vary.push("Accept-Encoding").join(",") 56 end 57 58 case encoding 59 when "br" 60 headers['Content-Encoding'] = "br" 61 headers.delete('Content-Length') 62 [status, headers, BrotliStream.new(body, @deflater_options)] 63 when nil 64 message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." 65 bp = Rack::BodyProxy.new([message]) { body.close if body.respond_to?(:close) } 66 [406, {'Content-Type' => "text/plain", 'Content-Length' => message.length.to_s}, bp] 67 end 68 end
Private Instance Methods
header_hash(headers)
click to toggle source
# File lib/rack/brotli/deflater.rb 96 def header_hash(headers) 97 if headers.is_a?(Rack::Utils::HeaderHash) 98 headers 99 else 100 Rack::Utils::HeaderHash.new(headers) # rack < 2.2 101 end 102 end
should_deflate?(env, status, headers, body)
click to toggle source
# File lib/rack/brotli/deflater.rb 104 def should_deflate?(env, status, headers, body) 105 # Skip compressing empty entity body responses and responses with 106 # no-transform set. 107 if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) || 108 /\bno-transform\b/.match?(headers['Cache-Control'].to_s) || 109 headers['Content-Encoding']&.!~(/\bidentity\b/) 110 return false 111 end 112 113 # Skip if @compressible_types are given and does not include request's content type 114 return false if @compressible_types && !(headers.has_key?('Content-Type') && @compressible_types.include?(headers['Content-Type'][/[^;]*/])) 115 116 # Skip if @condition lambda is given and evaluates to false 117 return false if @condition && !@condition.call(env, status, headers, body) 118 119 # No point in compressing empty body, also handles usage with 120 # Rack::Sendfile. 121 return false if headers['Content-Length'] == '0' 122 123 true 124 end