-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
compress_handler.cr
63 lines (52 loc) · 1.77 KB
/
compress_handler.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
{% 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.
class HTTP::CompressHandler
include HTTP::Handler
def call(context)
{% 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