-
Notifications
You must be signed in to change notification settings - Fork 2
/
gzip_response.go
135 lines (113 loc) · 3.46 KB
/
gzip_response.go
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright (c) Jeevanandam M (https://github.com/jeevatkm)
// go-aah/ahttp source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package ahttp
import (
"bufio"
"compress/gzip"
"io"
"net"
"net/http"
"sync"
)
var (
// GzipLevel holds value from app config.
GzipLevel int
grPool = &sync.Pool{New: func() interface{} { return &GzipResponse{} }}
gwPool = &sync.Pool{}
// interface compliance
_ http.CloseNotifier = (*GzipResponse)(nil)
_ http.Flusher = (*GzipResponse)(nil)
_ http.Hijacker = (*GzipResponse)(nil)
_ http.Pusher = (*GzipResponse)(nil)
_ io.Closer = (*GzipResponse)(nil)
_ ResponseWriter = (*GzipResponse)(nil)
)
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// GzipResponse
//___________________________________
// GzipResponse extends `ahttp.Response` to provides gzip compression for response
// bytes to the underlying response.
type GzipResponse struct {
r *Response
gw *gzip.Writer
}
// Status method returns HTTP response status code. If status is not yet written
// it reurns 0.
func (g *GzipResponse) Status() int {
return g.r.Status()
}
// WriteHeader method writes given status code into Response.
func (g *GzipResponse) WriteHeader(code int) {
g.r.WriteHeader(code)
}
// Header method returns response header map.
func (g *GzipResponse) Header() http.Header {
return g.r.Header()
}
// Write method writes bytes into Response.
func (g *GzipResponse) Write(b []byte) (int, error) {
g.r.WriteHeader(http.StatusOK)
size, err := g.gw.Write(b)
g.r.bytesWritten += size
return size, err
}
// BytesWritten method returns no. of bytes already written into HTTP response.
func (g *GzipResponse) BytesWritten() int {
return g.r.BytesWritten()
}
// Close method closes the writer if possible.
func (g *GzipResponse) Close() error {
if err := g.gw.Close(); err != nil {
return err
}
return g.r.Close()
}
// Unwrap method returns the underlying `http.ResponseWriter`
func (g *GzipResponse) Unwrap() http.ResponseWriter {
return g.r.Unwrap()
}
// CloseNotify method calls underlying CloseNotify method if it's compatible
func (g *GzipResponse) CloseNotify() <-chan bool {
return g.r.CloseNotify()
}
// Flush method calls underlying Flush method if it's compatible
func (g *GzipResponse) Flush() {
if g.gw != nil {
_ = g.gw.Flush()
}
g.r.Flush()
}
// Hijack method calls underlying Hijack method if it's compatible otherwise
// returns an error. It becomes the caller's responsibility to manage
// and close the connection.
func (g *GzipResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return g.r.Hijack()
}
// Push method calls underlying Push method HTTP/2 if compatible otherwise
// returns nil
func (g *GzipResponse) Push(target string, opts *http.PushOptions) error {
return g.r.Push(target, opts)
}
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// GzipResponse Unexported methods
//___________________________________
// releaseGzipResponse method resets and puts the gzip response into pool.
func releaseGzipResponse(gw *GzipResponse) {
_ = gw.Close()
gwPool.Put(gw.gw)
releaseResponse(gw.r)
grPool.Put(gw)
}
func acquireGzipWriter(w io.Writer) *gzip.Writer {
gw := gwPool.Get()
if gw == nil {
if ngw, err := gzip.NewWriterLevel(w, GzipLevel); err == nil {
return ngw
}
return nil
}
ngw := gw.(*gzip.Writer)
ngw.Reset(w)
return ngw
}