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
25 def initialize(app, options = {})
26   @app = app
27 
28   @condition = options[:if]
29   @compressible_types = options[:include]
30   @deflater_options = { quality: 5 }.merge(options[:deflater] || {})
31 end

Public Instance Methods

call(env) click to toggle source
   # File lib/rack/brotli/deflater.rb
33 def call(env)
34   status, headers, body = @app.call(env)
35   headers = Rack::Utils::HeaderHash.new(headers)
36 
37   unless should_deflate?(env, status, headers, body)
38     return [status, headers, body]
39   end
40 
41   request = Rack::Request.new(env)
42 
43   encoding = Rack::Utils.select_best_encoding(%w(br),
44                                         request.accept_encoding)
45 
46   return [status, headers, body] unless encoding
47 
48   # Set the Vary HTTP header.
49   vary = headers["Vary"].to_s.split(",").map(&:strip)
50   unless vary.include?("*") || vary.include?("Accept-Encoding")
51     headers["Vary"] = vary.push("Accept-Encoding").join(",")
52   end
53 
54   case encoding
55   when "br"
56     headers['Content-Encoding'] = "br"
57     headers.delete(Rack::CONTENT_LENGTH)
58     [status, headers, BrotliStream.new(body, @deflater_options)]
59   when nil
60     message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
61     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   end
64 end

Private Instance Methods

should_deflate?(env, status, headers, body) click to toggle source
    # File lib/rack/brotli/deflater.rb
 93 def should_deflate?(env, status, headers, body)
 94   # Skip compressing empty entity body responses and responses with
 95   # no-transform set.
 96   if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) ||
 97       headers[Rack::CACHE_CONTROL].to_s =~ /\bno-transform\b/ ||
 98      (headers['Content-Encoding'] && headers['Content-Encoding'] !~ /\bidentity\b/)
 99     return false
100   end
101 
102   # Skip if @compressible_types are given and does not include request's content type
103   return false if @compressible_types && !(headers.has_key?(Rack::CONTENT_TYPE) && @compressible_types.include?(headers[Rack::CONTENT_TYPE][/[^;]*/]))
104 
105   # Skip if @condition lambda is given and evaluates to false
106   return false if @condition && !@condition.call(env, status, headers, body)
107 
108   true
109 end