{% if !flag?(:without_zlib) %} require "compress/deflate" require "compress/gzip" {% end %} # A handler that configures an `HTTP::Server::Response` to compress the response # output, either using gzip or deflate, depending on the `Accept-Encoding` request header. # # NOTE: To use `CompressHandler`, you must explicitly import it with `require "http"` class HTTP::CompressHandler include HTTP::Handler def call(context : HTTP::Server::Context) : Nil {% if flag?(:without_zlib) %} call_next(context) {% else %} context.response.output = CompressIO.new(context.response.output, context) call_next(context) {% end %} end {% unless flag?(:without_zlib) %} private class CompressIO < IO def initialize(@io : IO, @context : HTTP::Server::Context) @checked = false end def read(slice : Bytes) raise NotImplementedError.new("read") end def write(slice : Bytes) : Nil check_output unless @checked @io.write(slice) end def flush @io.flush end def close @io.close end private def check_output @checked = true return if @context.response.wrote_headers? return if @context.response.headers.has_key?("Content-Encoding") request_headers = @context.request.headers if request_headers.includes_word?("Accept-Encoding", "gzip") @context.response.headers["Content-Encoding"] = "gzip" @context.response.headers.delete("Content-Length") @io = Compress::Gzip::Writer.new(@io, sync_close: true) elsif request_headers.includes_word?("Accept-Encoding", "deflate") @context.response.headers["Content-Encoding"] = "deflate" @context.response.headers.delete("Content-Length") @io = Compress::Deflate::Writer.new(@io, sync_close: true) end end end {% end %} end