class Rack::Deflater
This middleware enables content encoding of http responses, usually for purposes of compression.
Currently supported encodings:
-
gzip
-
identity (no transformation)
This middleware automatically detects when encoding is supported and allowed. For example no encoding is made when a cache directive of ‘no-transform’ is present, when the response status code is one that doesn’t allow an entity body, or when the body is empty.
Note that despite the name, Deflater does not support the deflate encoding.
Constants
- GZIP_MTIME
Public Class Methods
Source
# File lib/rack/deflater.rb, line 45 def initialize(app, options = {}) @app = app @condition = options[:if] @compressible_types = options[:include] @sync = options.fetch(:sync, true) @deflaters = options[:deflaters] @available_encodings = %w(gzip) @deflaters&.each_key { |key| @available_encodings << key } @available_encodings << 'identity' @available_encodings.freeze end
Creates Rack::Deflater middleware. Options:
- :if
-
a lambda enabling / disabling deflation based on returned boolean value (e.g
use Rack::Deflater, :if => lambda { |*, body| sum=0; body.each { |i| sum += i.length }; sum > 512 }). However, be aware that calling ‘body.each` inside the block will break cases where `body.each` is not idempotent, such as when it is anIOinstance. - :include
-
a list of content types that should be compressed. By default, all content types are compressed.
- :sync
-
determines if the stream is going to be flushed after every chunk. Flushing after every chunk reduces latency for time-sensitive streaming applications, but hurts compression and throughput. Defaults to
true. - :deflaters
-
a hash of custom deflaters, where keys are encoding names and values are callables
that take (headers, body) and return a deflated body object. When provided, these custom deflaters will be used if the client's accept-encoding header matches.
Public Instance Methods
Source
# File lib/rack/deflater.rb, line 57 def call(env) status, headers, body = response = @app.call(env) unless should_deflate?(env, status, headers, body) return response end request = Request.new(env) encoding = Utils.select_best_encoding(@available_encodings, request.accept_encoding) # Set the Vary HTTP header. vary = headers["vary"].to_s.split(",").map(&:strip) unless vary.include?("*") || vary.any?{|v| v.downcase == 'accept-encoding'} headers["vary"] = vary.push("Accept-Encoding").join(",") end case encoding when "gzip" headers['content-encoding'] = "gzip" headers.delete(CONTENT_LENGTH) response[2] = GzipStream.new(body, GZIP_MTIME, @sync) response when "identity" response else if deflater = @deflaters&.[](encoding) headers['content-encoding'] = encoding headers.delete(CONTENT_LENGTH) response[2] = deflater.call(headers, body) response else # Only possible encoding values here are 'gzip', 'identity', and nil message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." bp = Rack::BodyProxy.new([message]) { body.close if body.respond_to?(:close) } [406, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => message.length.to_s }, bp] end end end