/
etagResponseWriter.go
105 lines (89 loc) · 2.06 KB
/
etagResponseWriter.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
package etagResponseWriter
import (
"net/http"
"github.com/go-martini/martini"
)
func ETagResponseWriter(config *ETagConfig) martini.Handler {
if config == nil {
config = NewETagConfig()
}
return func(c martini.Context, res http.ResponseWriter, req *http.Request) {
resp := &etagResponseWriter{
config: *config,
rw: res,
req: req,
}
if resp.isEnableMethod(req.Method) && !resp.isIgnoreIfHeader(req) {
c.MapTo(resp, (*http.ResponseWriter)(nil))
}
c.Next()
}
}
type etagResponseWriter struct {
config ETagConfig
rw http.ResponseWriter
req *http.Request
status int
writeStatus bool
}
func (t *etagResponseWriter) Header() http.Header {
return t.rw.Header()
}
func (t *etagResponseWriter) Write(b []byte) (int, error) {
if len(b) < t.config.MinBodyLength {
return t.write(b)
}
if !t.isEnableStatus(t.status) {
return t.write(b)
}
etag := t.config.HashFunc(b)
if match, ok := t.req.Header["If-None-Match"]; ok && match[0] == etag {
t.WriteHeader(http.StatusNotModified)
b = []byte{}
} else {
t.Header().Set("ETag", etag)
}
return t.write(b)
}
func (t *etagResponseWriter) WriteHeader(s int) {
t.status = s
}
func (t *etagResponseWriter) isEnableMethod(method string) bool {
if enable, ok := t.config.EnableMethod[method]; ok {
return enable
}
return false
}
func (t *etagResponseWriter) isEnableStatus(status int) bool {
if enable, ok := t.config.EnableStatus[status]; ok {
return enable
}
return false
}
func (t *etagResponseWriter) isIgnoreIfHeader(req *http.Request) bool {
for header, exist := range t.config.IgnoreIfHeaderExist {
value := req.Header.Get(header)
if exist {
if value != "" {
return true
}
} else {
if value == "" {
return true
}
}
}
for header, value := range t.config.IgnoreIfHeaderValue {
if req.Header.Get(header) == value {
return true
}
}
return false
}
func (t *etagResponseWriter) write(b []byte) (int, error) {
if !t.writeStatus && t.status > 0 {
t.rw.WriteHeader(t.status)
t.writeStatus = true
}
return t.rw.Write(b)
}