/
response.go
123 lines (104 loc) · 2.65 KB
/
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
// SPDX-License-Identifier: MIT
package compress
import (
"bufio"
"io"
"net"
"net/http"
"sync"
)
var respPool = &sync.Pool{
New: func() interface{} { return &response{} },
}
// 实现了 http.ResponseWriter 接口
type response struct {
c *Compress
writer io.Writer
responseWriter http.ResponseWriter
wroteHeader bool
// 压缩相关的字段
//
// 如果 f 为 nil,表示不需要压缩
f Writer
encodingName string
}
func (c *Compress) newResponse(resp http.ResponseWriter, f Writer, encodingName string) *response {
r := respPool.Get().(*response)
r.c = c
r.writer = nil
r.responseWriter = resp
r.wroteHeader = false
r.f = f
r.encodingName = encodingName
return r
}
func (resp *response) Header() http.Header { return resp.responseWriter.Header() }
func (resp *response) WriteHeader(code int) {
if !resp.wroteHeader {
resp.writeHeader(code, nil)
}
}
// NOTE: 根据接口要求,第一次调用 Write 时,会发送报头内容,
// 即 WriteHeader(200) 自动调用,即使写入的是空内容。
func (resp *response) Write(bs []byte) (int, error) {
if !resp.wroteHeader {
resp.writeHeader(http.StatusOK, bs)
}
return resp.writer.Write(bs)
}
// bs 仅作为检测 content-type 类型值
func (resp *response) writeHeader(status int, bs []byte) {
defer func() {
resp.responseWriter.WriteHeader(status)
resp.wroteHeader = true
}()
h := resp.Header()
// https://github.com/golang/go/issues/14975
h.Del("Content-Length")
ct := h.Get("Content-Type")
if ct == "" {
ct = http.DetectContentType(bs)
h.Set("Content-Type", ct)
}
if resp.f == nil || !bodyAllowedForStatus(status) || !resp.c.canCompressed(ct) {
resp.writer = resp.responseWriter
resp.c.putAlgorithm(resp.encodingName, resp.f)
resp.f = nil
return
}
resp.f.Reset(resp.responseWriter)
h.Set("Content-Encoding", resp.encodingName)
h.Add("Vary", "Content-Encoding")
resp.writer = resp.f
}
func (resp *response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if hj, ok := resp.responseWriter.(http.Hijacker); ok {
return hj.Hijack()
}
panic("未实现 http.Hijacker")
}
func (resp *response) close() {
if resp.f != nil {
if err := resp.f.Close(); err != nil {
resp.c.errlog.Println(err)
}
resp.c.putAlgorithm(resp.encodingName, resp.f)
resp.f = nil
}
respPool.Put(resp)
}
// 以下内容复制于官方标准库
//
// bodyAllowedForStatus reports whether a given response status code
// permits a body. See RFC 7230, section 3.3.
func bodyAllowedForStatus(status int) bool {
switch {
case status >= 100 && status <= 199:
return false
case status == 204:
return false
case status == 304:
return false
}
return true
}