2021-09-29 19:37:32 +08:00
|
|
|
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
|
|
|
|
|
|
|
|
|
|
|
package serverconfigs
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
|
|
|
|
|
"github.com/iwind/TeaGo/lists"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2021-10-18 11:56:58 +08:00
|
|
|
|
var DefaultHTTPCompressionTypes = []HTTPCompressionType{HTTPCompressionTypeBrotli, HTTPCompressionTypeGzip, HTTPCompressionTypeDeflate}
|
2021-09-29 19:37:32 +08:00
|
|
|
|
|
|
|
|
|
|
type HTTPCompressionRef struct {
|
|
|
|
|
|
Id int64 `yaml:"id" json:"id"`
|
|
|
|
|
|
IsOn bool `yaml:"isOn" json:"isOn"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// HTTPCompressionConfig 内容压缩配置
|
|
|
|
|
|
type HTTPCompressionConfig struct {
|
|
|
|
|
|
IsPrior bool `yaml:"isPrior" json:"isPrior"`
|
|
|
|
|
|
IsOn bool `yaml:"isOn" json:"isOn"`
|
|
|
|
|
|
|
|
|
|
|
|
UseDefaultTypes bool `yaml:"useDefaultTypes" json:"useDefaultTypes"` // 是否使用默认的类型
|
|
|
|
|
|
Types []HTTPCompressionType `yaml:"types" json:"types"` // 支持的类型,如果为空表示默认顺序
|
|
|
|
|
|
Level int8 `yaml:"level" json:"level"` // 级别:1-12
|
2021-10-18 16:49:24 +08:00
|
|
|
|
DecompressData bool `yaml:"decompressData" json:"decompressData"` // 是否解压已压缩内容
|
2021-09-29 19:37:32 +08:00
|
|
|
|
|
|
|
|
|
|
GzipRef *HTTPCompressionRef `yaml:"gzipRef" json:"gzipRef"`
|
|
|
|
|
|
DeflateRef *HTTPCompressionRef `yaml:"deflateRef" json:"deflateRef"`
|
|
|
|
|
|
BrotliRef *HTTPCompressionRef `yaml:"brotliRef" json:"brotliRef"`
|
|
|
|
|
|
|
|
|
|
|
|
Gzip *HTTPGzipCompressionConfig `yaml:"gzip" json:"gzip"`
|
|
|
|
|
|
Deflate *HTTPDeflateCompressionConfig `yaml:"deflate" json:"deflate"`
|
|
|
|
|
|
Brotli *HTTPBrotliCompressionConfig `yaml:"brotli" json:"brotli"`
|
|
|
|
|
|
|
2022-12-30 11:43:53 +08:00
|
|
|
|
MinLength *shared.SizeCapacity `yaml:"minLength" json:"minLength"` // 最小压缩对象比如4m, 24k
|
|
|
|
|
|
MaxLength *shared.SizeCapacity `yaml:"maxLength" json:"maxLength"` // 最大压缩对象
|
|
|
|
|
|
MimeTypes []string `yaml:"mimeTypes" json:"mimeTypes"` // 支持的MimeType,支持image/*这样的通配符使用
|
|
|
|
|
|
Extensions []string `yaml:"extensions" json:"extensions"` // 文件扩展名,包含点符号,不区分大小写
|
2022-12-30 12:04:23 +08:00
|
|
|
|
ExceptExtensions []string `yaml:"exceptExtensions" json:"exceptExtensions"` // 例外扩展名
|
2022-12-30 11:43:53 +08:00
|
|
|
|
Conds *shared.HTTPRequestCondsConfig `yaml:"conds" json:"conds"` // 匹配条件
|
|
|
|
|
|
EnablePartialContent bool `yaml:"enablePartialContent" json:"enablePartialContent"` // 支持PartialContent压缩
|
2021-09-29 19:37:32 +08:00
|
|
|
|
|
2022-12-30 12:04:23 +08:00
|
|
|
|
minLength int64
|
|
|
|
|
|
maxLength int64
|
|
|
|
|
|
mimeTypeRules []*shared.MimeTypeRule
|
|
|
|
|
|
extensions []string
|
|
|
|
|
|
exceptExtensions []string
|
2021-09-29 19:37:32 +08:00
|
|
|
|
|
|
|
|
|
|
types []HTTPCompressionType
|
|
|
|
|
|
|
|
|
|
|
|
supportGzip bool
|
|
|
|
|
|
supportDeflate bool
|
|
|
|
|
|
supportBrotli bool
|
2022-06-27 22:41:11 +08:00
|
|
|
|
supportZSTD bool
|
2021-09-29 19:37:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Init 初始化
|
|
|
|
|
|
func (this *HTTPCompressionConfig) Init() error {
|
|
|
|
|
|
if this.MinLength != nil {
|
|
|
|
|
|
this.minLength = this.MinLength.Bytes()
|
|
|
|
|
|
}
|
|
|
|
|
|
if this.MaxLength != nil {
|
|
|
|
|
|
this.maxLength = this.MaxLength.Bytes()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if this.Conds != nil {
|
|
|
|
|
|
err := this.Conds.Init()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// mime types
|
|
|
|
|
|
this.mimeTypeRules = []*shared.MimeTypeRule{}
|
|
|
|
|
|
for _, mimeType := range this.MimeTypes {
|
|
|
|
|
|
rule, err := shared.NewMimeTypeRule(mimeType)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
this.mimeTypeRules = append(this.mimeTypeRules, rule)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// extensions
|
|
|
|
|
|
this.extensions = []string{}
|
|
|
|
|
|
for _, ext := range this.Extensions {
|
|
|
|
|
|
ext = strings.ToLower(ext)
|
|
|
|
|
|
if len(ext) > 0 && ext[0] != '.' {
|
|
|
|
|
|
ext = "." + ext
|
|
|
|
|
|
}
|
|
|
|
|
|
this.extensions = append(this.extensions, ext)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-12-30 12:04:23 +08:00
|
|
|
|
this.exceptExtensions = []string{}
|
|
|
|
|
|
for _, ext := range this.ExceptExtensions {
|
|
|
|
|
|
ext = strings.ToLower(ext)
|
|
|
|
|
|
if len(ext) > 0 && ext[0] != '.' {
|
|
|
|
|
|
ext = "." + ext
|
|
|
|
|
|
}
|
|
|
|
|
|
this.exceptExtensions = append(this.exceptExtensions, ext)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-09-29 19:37:32 +08:00
|
|
|
|
if this.Gzip != nil {
|
|
|
|
|
|
err := this.Gzip.Init()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if this.Deflate != nil {
|
|
|
|
|
|
err := this.Deflate.Init()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if this.Brotli != nil {
|
|
|
|
|
|
err := this.Brotli.Init()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var supportedTypes = []HTTPCompressionType{}
|
|
|
|
|
|
if !this.UseDefaultTypes {
|
|
|
|
|
|
supportedTypes = append(supportedTypes, this.Types...)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
supportedTypes = append(supportedTypes, DefaultHTTPCompressionTypes...)
|
|
|
|
|
|
}
|
|
|
|
|
|
this.types = supportedTypes
|
|
|
|
|
|
|
|
|
|
|
|
this.supportGzip = false
|
|
|
|
|
|
this.supportDeflate = false
|
|
|
|
|
|
this.supportDeflate = false
|
|
|
|
|
|
for _, supportType := range supportedTypes {
|
|
|
|
|
|
switch supportType {
|
|
|
|
|
|
case HTTPCompressionTypeGzip:
|
|
|
|
|
|
if this.GzipRef == nil || (this.GzipRef != nil && this.GzipRef.IsOn && this.Gzip != nil && this.Gzip.IsOn) {
|
|
|
|
|
|
this.supportGzip = true
|
|
|
|
|
|
}
|
|
|
|
|
|
case HTTPCompressionTypeDeflate:
|
|
|
|
|
|
if this.DeflateRef == nil || (this.DeflateRef != nil && this.DeflateRef.IsOn && this.Deflate != nil && this.Deflate.IsOn) {
|
|
|
|
|
|
this.supportDeflate = true
|
|
|
|
|
|
}
|
|
|
|
|
|
case HTTPCompressionTypeBrotli:
|
|
|
|
|
|
if this.BrotliRef == nil || (this.BrotliRef != nil && this.BrotliRef.IsOn && this.Brotli != nil && this.Brotli.IsOn) {
|
|
|
|
|
|
this.supportBrotli = true
|
|
|
|
|
|
}
|
2022-06-27 22:41:11 +08:00
|
|
|
|
case HTTPCompressionTypeZSTD:
|
|
|
|
|
|
this.supportZSTD = true
|
2021-09-29 19:37:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MinBytes 可压缩最小尺寸
|
|
|
|
|
|
func (this *HTTPCompressionConfig) MinBytes() int64 {
|
|
|
|
|
|
return this.minLength
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MaxBytes 可压缩最大尺寸
|
|
|
|
|
|
func (this *HTTPCompressionConfig) MaxBytes() int64 {
|
|
|
|
|
|
return this.maxLength
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MatchResponse 是否匹配响应
|
|
|
|
|
|
func (this *HTTPCompressionConfig) MatchResponse(mimeType string, contentLength int64, requestExt string, formatter shared.Formatter) bool {
|
|
|
|
|
|
if this.Conds != nil && formatter != nil {
|
2021-09-29 20:11:54 +08:00
|
|
|
|
if !this.Conds.MatchRequest(formatter) {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
2021-09-29 19:37:32 +08:00
|
|
|
|
if !this.Conds.MatchResponse(formatter) {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// min length
|
|
|
|
|
|
if this.minLength > 0 && contentLength < this.minLength {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// max length
|
|
|
|
|
|
if this.maxLength > 0 && contentLength > this.maxLength {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-12-30 12:04:23 +08:00
|
|
|
|
// except extensions
|
|
|
|
|
|
if len(this.exceptExtensions) > 0 {
|
|
|
|
|
|
if len(requestExt) > 0 {
|
|
|
|
|
|
for _, ext := range this.exceptExtensions {
|
|
|
|
|
|
if ext == requestExt {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-09-29 19:37:32 +08:00
|
|
|
|
// extensions
|
|
|
|
|
|
if len(this.extensions) > 0 {
|
|
|
|
|
|
if len(requestExt) > 0 {
|
|
|
|
|
|
for _, ext := range this.extensions {
|
|
|
|
|
|
if ext == requestExt {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// mime types
|
|
|
|
|
|
if len(this.mimeTypeRules) > 0 {
|
|
|
|
|
|
if len(mimeType) > 0 {
|
|
|
|
|
|
var index = strings.Index(mimeType, ";")
|
|
|
|
|
|
if index >= 0 {
|
|
|
|
|
|
mimeType = mimeType[:index]
|
|
|
|
|
|
}
|
|
|
|
|
|
for _, rule := range this.mimeTypeRules {
|
|
|
|
|
|
if rule.Match(mimeType) {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有指定条件,则所有的都能压缩
|
|
|
|
|
|
if len(this.extensions) == 0 && len(this.mimeTypeRules) == 0 {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MatchAcceptEncoding 根据Accept-Encoding选择优先的压缩方式
|
|
|
|
|
|
func (this *HTTPCompressionConfig) MatchAcceptEncoding(acceptEncodings string) (compressionType HTTPCompressionType, compressionEncoding string, ok bool) {
|
|
|
|
|
|
if len(acceptEncodings) == 0 {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if len(this.types) == 0 {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var pieces = strings.Split(acceptEncodings, ",")
|
|
|
|
|
|
var encodings = []string{}
|
|
|
|
|
|
for _, piece := range pieces {
|
|
|
|
|
|
var qualityIndex = strings.Index(piece, ";")
|
|
|
|
|
|
if qualityIndex >= 0 {
|
|
|
|
|
|
// TODO 实现优先级
|
|
|
|
|
|
piece = piece[:qualityIndex]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
encodings = append(encodings, strings.TrimSpace(piece))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if len(encodings) == 0 {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, supportType := range this.types {
|
|
|
|
|
|
switch supportType {
|
|
|
|
|
|
case HTTPCompressionTypeGzip:
|
|
|
|
|
|
if this.supportGzip && lists.ContainsString(encodings, "gzip") {
|
|
|
|
|
|
return HTTPCompressionTypeGzip, "gzip", true
|
|
|
|
|
|
}
|
|
|
|
|
|
case HTTPCompressionTypeDeflate:
|
|
|
|
|
|
if this.supportDeflate && lists.ContainsString(encodings, "deflate") {
|
|
|
|
|
|
return HTTPCompressionTypeDeflate, "deflate", true
|
|
|
|
|
|
}
|
|
|
|
|
|
case HTTPCompressionTypeBrotli:
|
|
|
|
|
|
if this.supportBrotli && lists.ContainsString(encodings, "br") {
|
|
|
|
|
|
return HTTPCompressionTypeBrotli, "br", true
|
|
|
|
|
|
}
|
2022-06-27 22:41:11 +08:00
|
|
|
|
case HTTPCompressionTypeZSTD:
|
|
|
|
|
|
if this.supportZSTD && lists.ContainsString(encodings, "zstd") {
|
|
|
|
|
|
return HTTPCompressionTypeZSTD, "zstd", true
|
|
|
|
|
|
}
|
2021-09-29 19:37:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return "", "", false
|
|
|
|
|
|
}
|