-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
162 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package middleware | ||
|
||
import ( | ||
"regexp" | ||
"strings" | ||
|
||
"github.com/vicanso/cod" | ||
) | ||
|
||
var ( | ||
defaultCompressRegexp = regexp.MustCompile("text|javascript|json") | ||
) | ||
|
||
const ( | ||
defaultCompresMinLength = 1024 | ||
gzipCompress = "gzip" | ||
) | ||
|
||
type ( | ||
// CompressConfig compress config | ||
CompressConfig struct { | ||
// Level 压缩率级别 | ||
Level int | ||
// MinLength 最小压缩长度 | ||
MinLength int | ||
// Checker 校验数据是否可压缩 | ||
Checker *regexp.Regexp | ||
Skipper Skipper | ||
} | ||
) | ||
|
||
// NewCompresss create a new compress middleware | ||
func NewCompresss(config CompressConfig) cod.Handler { | ||
minLength := config.MinLength | ||
if minLength == 0 { | ||
minLength = defaultCompresMinLength | ||
} | ||
skiper := config.Skipper | ||
if skiper == nil { | ||
skiper = DefaultSkipper | ||
} | ||
checker := config.Checker | ||
if checker == nil { | ||
checker = defaultCompressRegexp | ||
} | ||
return func(c *cod.Context) (err error) { | ||
if skiper(c) { | ||
return c.Next() | ||
} | ||
err = c.Next() | ||
if err != nil { | ||
return | ||
} | ||
respHeader := c.Headers | ||
encoding := respHeader.Get(cod.HeaderContentEncoding) | ||
// encoding 不为空,已做处理,无需要压缩 | ||
if encoding != "" { | ||
return | ||
} | ||
contentType := respHeader.Get(cod.HeaderContentType) | ||
buf := c.BodyBytes | ||
// 如果数据长度少于最小压缩长度或数据类型为非可压缩,则返回 | ||
if len(buf) < minLength || !checker.MatchString(contentType) { | ||
return | ||
} | ||
|
||
acceptEncoding := c.Header(cod.HeaderAcceptEncoding) | ||
// 如果请求端不接受gzip,则返回 | ||
if !strings.Contains(acceptEncoding, gzipCompress) { | ||
return | ||
} | ||
|
||
gzipBuf, e := doGzip(buf, config.Level) | ||
// 如果压缩成功,则使用压缩数据 | ||
// 失败则忽略 | ||
if e == nil { | ||
c.SetHeader(cod.HeaderContentEncoding, gzipCompress) | ||
c.BodyBytes = gzipBuf | ||
} | ||
|
||
return | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package middleware | ||
|
||
import ( | ||
"math/rand" | ||
"net/http/httptest" | ||
"testing" | ||
"time" | ||
|
||
"github.com/vicanso/cod" | ||
) | ||
|
||
var letterRunes = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_") | ||
|
||
// randomString get random string | ||
func randomString(n int) string { | ||
b := make([]rune, n) | ||
rand.Seed(time.Now().UnixNano()) | ||
for i := range b { | ||
b[i] = letterRunes[rand.Intn(len(letterRunes))] | ||
} | ||
return string(b) | ||
} | ||
|
||
func TestCompress(t *testing.T) { | ||
fn := NewCompresss(CompressConfig{ | ||
Level: 1, | ||
MinLength: 1, | ||
}) | ||
|
||
req := httptest.NewRequest("GET", "/users/me", nil) | ||
req.Header.Set(cod.HeaderAcceptEncoding, "gzip") | ||
resp := httptest.NewRecorder() | ||
c := cod.NewContext(resp, req) | ||
c.Headers.Set(cod.HeaderContentType, "text/html") | ||
c.BodyBytes = []byte("<html><body>" + randomString(8192) + "</body></html>") | ||
originalSize := len(c.BodyBytes) | ||
done := false | ||
c.Next = func() error { | ||
done = true | ||
return nil | ||
} | ||
err := fn(c) | ||
if err != nil || !done { | ||
t.Fatalf("compress middleware fail, %v", err) | ||
} | ||
if len(c.BodyBytes) >= originalSize { | ||
t.Fatalf("compress fail") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters