-
Notifications
You must be signed in to change notification settings - Fork 6
/
response.go
114 lines (98 loc) · 2.28 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
package torproxy
import (
"bytes"
"compress/gzip"
"io"
"net/http"
"sync"
"golang.org/x/net/proxy"
)
type TorResponse struct {
headers http.Header
body []byte
bodyReader bytes.Buffer
bodyWriter bytes.Buffer
status int
request *http.Request
dialer proxy.Dialer
}
var bufferPool = sync.Pool{New: createBuffer}
func createBuffer() interface{} {
return make([]byte, 0, 32*1024)
}
// Header returns response headers
func (t *TorResponse) Header() http.Header {
return t.headers
}
func (t *TorResponse) Write(body []byte) (int, error) {
reader := bytes.NewReader(body)
pooledIoCopy(&t.bodyReader, reader)
t.body = body
return len(body), nil
}
// Body returns response's body. This method should only get called after WriteBody()
func (t *TorResponse) Body() []byte {
return t.bodyWriter.Bytes()
}
// WriteHeader Writes the given status code to response
func (t *TorResponse) WriteHeader(status int) {
t.status = status
}
func (t *TorResponse) ReplaceBody(scheme, to, host string) error {
replacedBody := bytes.Replace(t.bodyWriter.Bytes(), []byte(scheme+"://"+to), []byte(scheme+"://"+host), -1)
t.bodyWriter.Reset()
if _, err := t.bodyWriter.Write(replacedBody); err != nil {
return err
}
return nil
}
func (t *TorResponse) WriteBody() error {
switch t.Header().Get("Content-Encoding") {
case "gzip":
reader, err := gzip.NewReader(&t.bodyReader)
if err != nil {
return err
}
defer reader.Close()
_, err = io.Copy(&t.bodyWriter, reader)
if err != nil {
return err
}
t.Header().Del("Content-Encoding")
default:
_, err := io.Copy(&t.bodyWriter, &t.bodyReader)
if err != nil {
return err
}
}
return nil
}
var skipHeaders = map[string]struct{}{
"Content-Type": {},
"Content-Disposition": {},
"Accept-Ranges": {},
"Set-Cookie": {},
"Cache-Control": {},
"Expires": {},
}
func copyHeader(dst, src http.Header) {
for k, vv := range src {
if _, ok := dst[k]; ok {
if _, shouldSkip := skipHeaders[k]; shouldSkip {
continue
}
if k != "Server" {
dst.Del(k)
}
}
for _, v := range vv {
dst.Add(k, v)
}
}
}
func pooledIoCopy(dst io.Writer, src io.Reader) {
buf := bufferPool.Get().([]byte)
defer bufferPool.Put(buf)
bufCap := cap(buf)
io.CopyBuffer(dst, src, buf[0:bufCap:bufCap])
}