1
0
mirror of https://github.com/astaxie/beego.git synced 2024-11-22 13:00:54 +00:00

add some gzip future

This commit is contained in:
JessonChan 2016-03-17 19:09:21 +08:00
parent c8bbfb75f0
commit 48147f50d8

View File

@ -25,8 +25,35 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"github.com/astaxie/beego/config"
) )
var (
//Content will only be compressed if content length is either unknown or greater than minGzipSize.
gzipMinLength int
//Default size==20B like nginx
defaultGzipMinLength=20
//The compression level used for deflate compression. (0-9).
gzipCompressLevel int
//List of HTTP methods to compress. If not set, only GET requests are compressed.
includedMethods map[string]bool
getMethodOnly bool
)
func InitGzip(cf config.Configer) {
gzipMinLength = cf.DefaultInt("gzipMinLength", defaultGzipMinLength)
gzipCompressLevel = cf.DefaultInt("gzipCompressLevel", flate.DefaultCompression)
if gzipCompressLevel < flate.DefaultCompression || gzipCompressLevel > flate.BestCompression {
gzipCompressLevel = flate.BestSpeed
}
methods := cf.DefaultStrings("includedMethods", []string{"GET"})
getMethodOnly = len(methods) == 1 && strings.ToUpper(methods[0]) == "GET"
for _, v := range methods {
includedMethods[strings.ToUpper(v)] = true
}
}
type resetWriter interface { type resetWriter interface {
io.Writer io.Writer
Reset(w io.Writer) Reset(w io.Writer)
@ -41,20 +68,20 @@ func (n nopResetWriter) Reset(w io.Writer) {
} }
type acceptEncoder struct { type acceptEncoder struct {
name string name string
levelEncode func(int) resetWriter levelEncode func(int) resetWriter
bestSpeedPool *sync.Pool customCompressLevelPool *sync.Pool
bestCompressionPool *sync.Pool bestCompressionPool *sync.Pool
} }
func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter { func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter {
if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil { if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil {
return nopResetWriter{wr} return nopResetWriter{wr}
} }
var rwr resetWriter var rwr resetWriter
switch level { switch level {
case flate.BestSpeed: case flate.BestSpeed:
rwr = ac.bestSpeedPool.Get().(resetWriter) rwr = ac.customCompressLevelPool.Get().(resetWriter)
case flate.BestCompression: case flate.BestCompression:
rwr = ac.bestCompressionPool.Get().(resetWriter) rwr = ac.bestCompressionPool.Get().(resetWriter)
default: default:
@ -65,13 +92,16 @@ func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter {
} }
func (ac acceptEncoder) put(wr resetWriter, level int) { func (ac acceptEncoder) put(wr resetWriter, level int) {
if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil { if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil {
return return
} }
wr.Reset(nil) wr.Reset(nil)
//notice
//compressionLevel==BestCompression DOES NOT MATTER
//sync.Pool will not memory leak
switch level { switch level {
case flate.BestSpeed: case gzipCompressLevel:
ac.bestSpeedPool.Put(wr) ac.customCompressLevelPool.Put(wr)
case flate.BestCompression: case flate.BestCompression:
ac.bestCompressionPool.Put(wr) ac.bestCompressionPool.Put(wr)
} }
@ -79,28 +109,22 @@ func (ac acceptEncoder) put(wr resetWriter, level int) {
var ( var (
noneCompressEncoder = acceptEncoder{"", nil, nil, nil} noneCompressEncoder = acceptEncoder{"", nil, nil, nil}
gzipCompressEncoder = acceptEncoder{"gzip", gzipCompressEncoder = acceptEncoder{
func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr }, name: "gzip",
&sync.Pool{ levelEncode: func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr },
New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestSpeed); return wr }, customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, gzipCompressLevel); return wr }},
}, bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }},
&sync.Pool{
New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr },
},
} }
//according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed //according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed
//deflate //deflate
//The "zlib" format defined in RFC 1950 [31] in combination with //The "zlib" format defined in RFC 1950 [31] in combination with
//the "deflate" compression mechanism described in RFC 1951 [29]. //the "deflate" compression mechanism described in RFC 1951 [29].
deflateCompressEncoder = acceptEncoder{"deflate", deflateCompressEncoder = acceptEncoder{
func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr }, name: "deflate",
&sync.Pool{ levelEncode: func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr },
New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestSpeed); return wr }, customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, gzipCompressLevel); return wr }},
}, bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr }},
&sync.Pool{
New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr },
},
} }
) )
@ -120,7 +144,11 @@ func WriteFile(encoding string, writer io.Writer, file *os.File) (bool, string,
// WriteBody reads writes content to writer by the specific encoding(gzip/deflate) // WriteBody reads writes content to writer by the specific encoding(gzip/deflate)
func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) { func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) {
return writeLevel(encoding, writer, bytes.NewReader(content), flate.BestSpeed) if encoding == "" || len(content) < gzipMinLength {
_, err := writer.Write(content)
return false, "", err
}
return writeLevel(encoding, writer, bytes.NewReader(content), gzipCompressLevel)
} }
// writeLevel reads from reader,writes to writer by specific encoding and compress level // writeLevel reads from reader,writes to writer by specific encoding and compress level
@ -156,7 +184,10 @@ func ParseEncoding(r *http.Request) string {
if r == nil { if r == nil {
return "" return ""
} }
return parseEncoding(r) if (getMethodOnly && r.Method == "GET") || includedMethods[r.Method] {
return parseEncoding(r)
}
return ""
} }
type q struct { type q struct {