...
1 package restful
2
3
4
5
6
7 import (
8 "bufio"
9 "compress/gzip"
10 "compress/zlib"
11 "errors"
12 "io"
13 "net"
14 "net/http"
15 "strings"
16 )
17
18
19 var EnableContentEncoding = false
20
21
22 type CompressingResponseWriter struct {
23 writer http.ResponseWriter
24 compressor io.WriteCloser
25 encoding string
26 }
27
28
29 func (c *CompressingResponseWriter) Header() http.Header {
30 return c.writer.Header()
31 }
32
33
34 func (c *CompressingResponseWriter) WriteHeader(status int) {
35 c.writer.WriteHeader(status)
36 }
37
38
39
40 func (c *CompressingResponseWriter) Write(bytes []byte) (int, error) {
41 if c.isCompressorClosed() {
42 return -1, errors.New("Compressing error: tried to write data using closed compressor")
43 }
44 return c.compressor.Write(bytes)
45 }
46
47
48 func (c *CompressingResponseWriter) CloseNotify() <-chan bool {
49 return c.writer.(http.CloseNotifier).CloseNotify()
50 }
51
52
53 func (c *CompressingResponseWriter) Flush() {
54 flusher, ok := c.writer.(http.Flusher)
55 if !ok {
56
57 return
58 }
59 flusher.Flush()
60 }
61
62
63 func (c *CompressingResponseWriter) Close() error {
64 if c.isCompressorClosed() {
65 return errors.New("Compressing error: tried to close already closed compressor")
66 }
67
68 c.compressor.Close()
69 if ENCODING_GZIP == c.encoding {
70 currentCompressorProvider.ReleaseGzipWriter(c.compressor.(*gzip.Writer))
71 }
72 if ENCODING_DEFLATE == c.encoding {
73 currentCompressorProvider.ReleaseZlibWriter(c.compressor.(*zlib.Writer))
74 }
75
76 c.compressor = nil
77 return nil
78 }
79
80 func (c *CompressingResponseWriter) isCompressorClosed() bool {
81 return nil == c.compressor
82 }
83
84
85
86
87 func (c *CompressingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
88 hijacker, ok := c.writer.(http.Hijacker)
89 if !ok {
90 return nil, nil, errors.New("ResponseWriter doesn't support Hijacker interface")
91 }
92 return hijacker.Hijack()
93 }
94
95
96
97 func wantsCompressedResponse(httpRequest *http.Request, httpWriter http.ResponseWriter) (bool, string) {
98 if contentEncoding := httpWriter.Header().Get(HEADER_ContentEncoding); contentEncoding != "" {
99 return false, ""
100 }
101 header := httpRequest.Header.Get(HEADER_AcceptEncoding)
102 gi := strings.Index(header, ENCODING_GZIP)
103 zi := strings.Index(header, ENCODING_DEFLATE)
104
105 if gi == -1 {
106 return zi != -1, ENCODING_DEFLATE
107 } else if zi == -1 {
108 return gi != -1, ENCODING_GZIP
109 } else {
110 if gi < zi {
111 return true, ENCODING_GZIP
112 }
113 return true, ENCODING_DEFLATE
114 }
115 }
116
117
118 func NewCompressingResponseWriter(httpWriter http.ResponseWriter, encoding string) (*CompressingResponseWriter, error) {
119 httpWriter.Header().Set(HEADER_ContentEncoding, encoding)
120 c := new(CompressingResponseWriter)
121 c.writer = httpWriter
122 var err error
123 if ENCODING_GZIP == encoding {
124 w := currentCompressorProvider.AcquireGzipWriter()
125 w.Reset(httpWriter)
126 c.compressor = w
127 c.encoding = ENCODING_GZIP
128 } else if ENCODING_DEFLATE == encoding {
129 w := currentCompressorProvider.AcquireZlibWriter()
130 w.Reset(httpWriter)
131 c.compressor = w
132 c.encoding = ENCODING_DEFLATE
133 } else {
134 return nil, errors.New("Unknown encoding:" + encoding)
135 }
136 return c, err
137 }
138
View as plain text