mirror of
				https://github.com/TeaOSLab/EdgeCommon.git
				synced 2025-11-04 05:00:24 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			158 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package serverconfigs
 | 
						||
 | 
						||
import (
 | 
						||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
 | 
						||
	"github.com/iwind/TeaGo/lists"
 | 
						||
	"net/http"
 | 
						||
	"strings"
 | 
						||
)
 | 
						||
 | 
						||
var DefaultSkippedResponseCacheControlValues = []string{"private", "no-cache", "no-store"}
 | 
						||
 | 
						||
type HTTPCacheRef struct {
 | 
						||
	IsOn          bool  `yaml:"isOn" json:"isOn"`
 | 
						||
	CachePolicyId int64 `yaml:"cachePolicyId" json:"cachePolicyId"`
 | 
						||
 | 
						||
	Key         string                 `yaml:"key" json:"key"`                 // 每个缓存的Key规则,里面可以有变量
 | 
						||
	Life        *shared.TimeDuration   `yaml:"life" json:"life"`               // 时间
 | 
						||
	ExpiresTime *HTTPExpiresTimeConfig `yaml:"expiresTime" json:"expiresTime"` // 客户端过期时间
 | 
						||
	Status      []int                  `yaml:"status" json:"status"`           // 缓存的状态码列表
 | 
						||
	MinSize     *shared.SizeCapacity   `yaml:"minSize" json:"minSize"`         // 能够缓存的最小尺寸
 | 
						||
	MaxSize     *shared.SizeCapacity   `yaml:"maxSize" json:"maxSize"`         // 能够缓存的最大尺寸
 | 
						||
	Methods     []string               `yaml:"methods" json:"methods"`         // 支持的请求方法
 | 
						||
 | 
						||
	SkipResponseCacheControlValues []string `yaml:"skipCacheControlValues" json:"skipCacheControlValues"`       // 可以跳过的响应的Cache-Control值
 | 
						||
	SkipResponseSetCookie          bool     `yaml:"skipSetCookie" json:"skipSetCookie"`                         // 是否跳过响应的Set-Cookie Header
 | 
						||
	EnableRequestCachePragma       bool     `yaml:"enableRequestCachePragma" json:"enableRequestCachePragma"`   // 是否支持客户端的Pragma: no-cache
 | 
						||
	AllowChunkedEncoding           bool     `yaml:"allowChunkedEncoding" json:"allowChunkedEncoding"`           // 是否允许分片内容
 | 
						||
	AllowPartialContent            bool     `yaml:"allowPartialContent" json:"allowPartialContent"`             // 支持分段内容缓存
 | 
						||
	ForcePartialContent            bool     `yaml:"forcePartialContent" json:"forcePartialContent"`             // 强制分段内容优先
 | 
						||
	AlwaysForwardRangeRequest      bool     `yaml:"alwaysForwardRangeRequest" json:"alwaysForwardRangeRequest"` // 强制Range请求回源
 | 
						||
	EnableIfNoneMatch              bool     `yaml:"enableIfNoneMatch" json:"enableIfNoneMatch"`                 // 支持If-None-match
 | 
						||
	EnableIfModifiedSince          bool     `yaml:"enableIfModifiedSince" json:"enableIfModifiedSince"`         // 支持If-Modified-Since
 | 
						||
	EnableReadingOriginAsync       bool     `yaml:"enableReadingOriginAsync" json:"enableReadingOriginAsync"`   // 允许异步读取源站
 | 
						||
 | 
						||
	Conds      *shared.HTTPRequestCondsConfig `yaml:"conds" json:"conds"`           // 复杂请求条件组合
 | 
						||
	SimpleCond *shared.HTTPRequestCond        `yaml:"simpleCond" json:"simpleCond"` // 简单条件
 | 
						||
 | 
						||
	CachePolicy *HTTPCachePolicy `yaml:"cachePolicy" json:"cachePolicy"`
 | 
						||
 | 
						||
	IsReverse bool `yaml:"isReverse" json:"isReverse"` // 是否为反向条件,反向条件的不缓存
 | 
						||
 | 
						||
	lifeSeconds                     int64
 | 
						||
	minSize                         int64
 | 
						||
	maxSize                         int64
 | 
						||
	uppercaseSkipCacheControlValues []string
 | 
						||
 | 
						||
	methodMap  map[string]bool
 | 
						||
	statusList []int
 | 
						||
}
 | 
						||
 | 
						||
func (this *HTTPCacheRef) Init() error {
 | 
						||
	if this.MinSize != nil {
 | 
						||
		this.minSize = this.MinSize.Bytes()
 | 
						||
	}
 | 
						||
	if this.MaxSize != nil {
 | 
						||
		this.maxSize = this.MaxSize.Bytes()
 | 
						||
	}
 | 
						||
	if this.Life != nil {
 | 
						||
		this.lifeSeconds = int64(this.Life.Duration().Seconds())
 | 
						||
	}
 | 
						||
 | 
						||
	// control-values
 | 
						||
	this.uppercaseSkipCacheControlValues = []string{}
 | 
						||
	for _, value := range this.SkipResponseCacheControlValues {
 | 
						||
		this.uppercaseSkipCacheControlValues = append(this.uppercaseSkipCacheControlValues, strings.ToUpper(value))
 | 
						||
	}
 | 
						||
 | 
						||
	// conds
 | 
						||
	if this.Conds != nil {
 | 
						||
		err := this.Conds.Init()
 | 
						||
		if err != nil {
 | 
						||
			return err
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	if this.SimpleCond != nil {
 | 
						||
		err := this.SimpleCond.Init()
 | 
						||
		if err != nil {
 | 
						||
			return err
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	// policy
 | 
						||
	if this.CachePolicy != nil {
 | 
						||
		err := this.CachePolicy.Init()
 | 
						||
		if err != nil {
 | 
						||
			return err
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	// methods
 | 
						||
	this.methodMap = map[string]bool{}
 | 
						||
	if len(this.Methods) > 0 {
 | 
						||
		for _, method := range this.Methods {
 | 
						||
			this.methodMap[strings.ToUpper(method)] = true
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	// status
 | 
						||
	this.statusList = this.Status
 | 
						||
	if this.AllowPartialContent {
 | 
						||
		if !lists.ContainsInt(this.statusList, http.StatusPartialContent) {
 | 
						||
			this.statusList = append(this.statusList, http.StatusPartialContent)
 | 
						||
		}
 | 
						||
	} else if lists.ContainsInt(this.statusList, http.StatusPartialContent) {
 | 
						||
		this.AllowPartialContent = true
 | 
						||
	}
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 | 
						||
 | 
						||
// MaxSizeBytes 最大数据尺寸
 | 
						||
func (this *HTTPCacheRef) MaxSizeBytes() int64 {
 | 
						||
	return this.maxSize
 | 
						||
}
 | 
						||
 | 
						||
// MinSizeBytes 最小数据尺寸
 | 
						||
func (this *HTTPCacheRef) MinSizeBytes() int64 {
 | 
						||
	return this.minSize
 | 
						||
}
 | 
						||
 | 
						||
// LifeSeconds 生命周期
 | 
						||
func (this *HTTPCacheRef) LifeSeconds() int64 {
 | 
						||
	return this.lifeSeconds
 | 
						||
}
 | 
						||
 | 
						||
// ContainsCacheControl 是否包含某个Cache-Control值
 | 
						||
func (this *HTTPCacheRef) ContainsCacheControl(value string) bool {
 | 
						||
	return lists.ContainsString(this.uppercaseSkipCacheControlValues, strings.ToUpper(value))
 | 
						||
}
 | 
						||
 | 
						||
// MatchRequest 匹配请求
 | 
						||
func (this *HTTPCacheRef) MatchRequest(req *http.Request) bool {
 | 
						||
	// 请求方法
 | 
						||
	if len(this.methodMap) > 0 {
 | 
						||
		_, ok := this.methodMap[req.Method]
 | 
						||
		if !ok {
 | 
						||
			return false
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	return true
 | 
						||
}
 | 
						||
 | 
						||
// MatchStatus 检查是否包含某个状态码
 | 
						||
func (this *HTTPCacheRef) MatchStatus(statusCode int) bool {
 | 
						||
	if len(this.statusList) == 0 {
 | 
						||
		return true
 | 
						||
	}
 | 
						||
 | 
						||
	for _, status := range this.statusList {
 | 
						||
		if status == statusCode {
 | 
						||
			return true
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return false
 | 
						||
}
 |