Compress
package revel
type WriteFlusher interface {
Write([]byte) (int, error)
Flush() error
}
type CompressResponseWriter struct {
http.ResponseWriter
}
func CompressFilter(c *Controller, fc []Filter) {
writer := CompressResponseWriter{c.Response.Out, nil, "", false}
writer.DetectCompressionType(c.Request, c.Response)
c.Response.Out = &writer
fc[0](c, fc[1:])
}
func (c *CompressResponseWriter) WriteHeader(status int) {
c.headersWritten = true
c.prepareHeaders()
c.ResponseWriter.WriteHeader(status)
}
func (c *CompressResponseWriter) Write(b []byte) (int, error) {
if !c.headersWritten {
c.prepareHeaders()
c.headersWritten = true
}
if c.compressionType != "" {
defer c.compressWriter.Flush()
return c.compressWriter.Write(b)
} else {
return c.ResponseWriter.Write(b)
}
}
func (c *CompressResponseWriter) DetectCompressionType(req *Request, resp *Response) {
if Config.BoolDefault("results.compressed", false) {
acceptedEncodings := strings.Split(req.Request.Header.Get("Accept-Encoding"), ",")
largestQ := 0.0
chosenEncoding := len(compressionTypes)
for _, encoding := range acceptedEncodings {
encoding = strings.TrimSpace(encoding)
encodingParts := strings.SplitN(encoding, ";", 2)
if len(encodingParts) > 1 {
num, err := strconv.ParseFloat(strings.TrimSpace(encodingParts[1])[2:], 32)
if err != nil {
continue
}
if num >= largestQ && num > 0 {
if encodingParts[0] == "*" {
chosenEncoding = 0
largestQ = num
continue
}
for i, encoding := range compressionTypes {
if encoding == encodingParts[0] {
if i < chosenEncoding {
largestQ = num
chosenEncoding = i
}
break
}
}
}
} else {
if encodingParts[0] == "*" {
chosenEncoding = 0
largestQ = 1
break
}
for i, encoding := range compressionTypes {
if encoding == encodingParts[0] {
if i < chosenEncoding {
largestQ = 1.0
chosenEncoding = i
}
break
}
}
}
}
if largestQ == 0 {
return
}
c.compressionType = compressionTypes[chosenEncoding]
switch c.compressionType {
case "gzip":
c.compressWriter = gzip.NewWriter(resp.Out)
case "deflate":
c.compressWriter = zlib.NewWriter(resp.Out)
}
}
}