mirror of
				https://github.com/TeaOSLab/EdgeNode.git
				synced 2025-11-04 15:51:54 +08:00 
			
		
		
		
	Partial Content从源站读取数据时验证本地缓存的Content-MD5是否一致
This commit is contained in:
		@@ -15,13 +15,14 @@ type PartialRanges struct {
 | 
			
		||||
	Version    int        `json:"version"`    // 版本号
 | 
			
		||||
	Ranges     [][2]int64 `json:"ranges"`     // 范围
 | 
			
		||||
	BodySize   int64      `json:"bodySize"`   // 总长度
 | 
			
		||||
	ContentMD5 string     `json:"contentMD5"` // 内容md5
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewPartialRanges 获取新对象
 | 
			
		||||
func NewPartialRanges(expiresAt int64) *PartialRanges {
 | 
			
		||||
	return &PartialRanges{
 | 
			
		||||
		Ranges:  [][2]int64{},
 | 
			
		||||
		Version: 1,
 | 
			
		||||
		Version: 2,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -46,6 +47,8 @@ func NewPartialRangesFromData(data []byte) (*PartialRanges, error) {
 | 
			
		||||
				if commaIndex > 0 {
 | 
			
		||||
					rs.Ranges = append(rs.Ranges, [2]int64{types.Int64(line[colonIndex+1 : commaIndex]), types.Int64(line[commaIndex+1:])})
 | 
			
		||||
				}
 | 
			
		||||
			case "m": // Content-MD5
 | 
			
		||||
				rs.ContentMD5 = string(line[colonIndex+1:])
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		data = data[index+1:]
 | 
			
		||||
@@ -171,6 +174,9 @@ func (this *PartialRanges) FindRangeAtPosition(position int64) (r rangeutils.Ran
 | 
			
		||||
func (this *PartialRanges) String() string {
 | 
			
		||||
	var s = "v:" + strconv.Itoa(this.Version) + "\n" + // version
 | 
			
		||||
		"b:" + this.formatInt64(this.BodySize) + "\n" // bodySize
 | 
			
		||||
	if len(this.ContentMD5) > 0 {
 | 
			
		||||
		s += "m:" + this.ContentMD5 + "\n" // Content-MD5
 | 
			
		||||
	}
 | 
			
		||||
	for _, r := range this.Ranges {
 | 
			
		||||
		s += "r:" + this.formatInt64(r[0]) + "," + this.formatInt64(r[1]) + "\n" // range
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,8 @@
 | 
			
		||||
package caches_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/md5"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeNode/internal/caches"
 | 
			
		||||
	"github.com/iwind/TeaGo/assert"
 | 
			
		||||
@@ -167,8 +169,13 @@ func TestPartialRanges_Encode_String(t *testing.T) {
 | 
			
		||||
	for i := 0; i < 10; i++ {
 | 
			
		||||
		r.Ranges = append(r.Ranges, [2]int64{int64(i * 100), int64(i*100 + 100)})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sum = md5.Sum([]byte("123456"))
 | 
			
		||||
	r.ContentMD5 = base64.StdEncoding.EncodeToString(sum[:])
 | 
			
		||||
 | 
			
		||||
	var before = time.Now()
 | 
			
		||||
	var data = r.String()
 | 
			
		||||
	t.Log(data)
 | 
			
		||||
	t.Log(time.Since(before).Seconds()*1000, "ms")
 | 
			
		||||
	t.Log(len(data))
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package caches
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
	fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
 | 
			
		||||
	"github.com/iwind/TeaGo/Tea"
 | 
			
		||||
	"os"
 | 
			
		||||
	"testing"
 | 
			
		||||
@@ -36,7 +37,7 @@ func TestFileReader(t *testing.T) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		_ = fp.Close()
 | 
			
		||||
	}()
 | 
			
		||||
	reader := NewFileReader(fp)
 | 
			
		||||
	reader := NewFileReader(fsutils.NewFile(fp, fsutils.FlagRead))
 | 
			
		||||
	err = reader.Init()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
@@ -75,7 +76,7 @@ func TestFileReader_ReadHeader(t *testing.T) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		_ = fp.Close()
 | 
			
		||||
	}()
 | 
			
		||||
	var reader = NewFileReader(fp)
 | 
			
		||||
	var reader = NewFileReader(fsutils.NewFile(fp, fsutils.FlagRead))
 | 
			
		||||
	err = reader.Init()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
@@ -138,7 +139,7 @@ func TestFileReader_Range(t *testing.T) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		_ = fp.Close()
 | 
			
		||||
	}()
 | 
			
		||||
	reader := NewFileReader(fp)
 | 
			
		||||
	reader := NewFileReader(fsutils.NewFile(fp, fsutils.FlagRead))
 | 
			
		||||
	err = reader.Init()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ import (
 | 
			
		||||
	fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
 | 
			
		||||
	"github.com/iwind/TeaGo/types"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -183,6 +184,14 @@ func (this *PartialFileWriter) SetBodyLength(bodyLength int64) {
 | 
			
		||||
	this.bodySize = bodyLength
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetContentMD5 设置内容MD5
 | 
			
		||||
func (this *PartialFileWriter) SetContentMD5(contentMD5 string) {
 | 
			
		||||
	if strings.Contains(contentMD5, "\n") || len(contentMD5) > 128 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	this.ranges.ContentMD5 = contentMD5
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteBodyLength 写入Body长度数据
 | 
			
		||||
func (this *PartialFileWriter) WriteBodyLength(bodyLength int64) error {
 | 
			
		||||
	if this.metaBodySize > 0 && this.metaBodySize == bodyLength {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ func TestPartialFileWriter_Write(t *testing.T) {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	var ranges = caches.NewPartialRanges(0)
 | 
			
		||||
	var writer = caches.NewPartialFileWriter(fp, "test", time.Now().Unix()+86500, -1, -1, true, true, 0, ranges, func() {
 | 
			
		||||
	var writer = caches.NewPartialFileWriter(fsutils.NewFile(fp, fsutils.FlagWrite), "test", time.Now().Unix()+86500, -1, -1, true, true, 0, ranges, func() {
 | 
			
		||||
		t.Log("end")
 | 
			
		||||
	})
 | 
			
		||||
	_, err = writer.WriteHeader([]byte("header"))
 | 
			
		||||
 
 | 
			
		||||
@@ -42,8 +42,25 @@ func (this *HTTPRequestPartialReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
			err = io.ErrUnexpectedEOF
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this.resp = resp
 | 
			
		||||
 | 
			
		||||
		// 对比Content-MD5
 | 
			
		||||
		partialReader, ok := this.cacheReader.(*caches.PartialFileReader)
 | 
			
		||||
		if ok {
 | 
			
		||||
			if partialReader.Ranges().Version >= 2 && resp.Header.Get("Content-MD5") != partialReader.Ranges().ContentMD5 {
 | 
			
		||||
				err = io.ErrUnexpectedEOF
 | 
			
		||||
 | 
			
		||||
				var storage = this.req.writer.cacheStorage
 | 
			
		||||
				if storage != nil {
 | 
			
		||||
					_ = storage.Delete(this.req.cacheKey + caches.SuffixPartial)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 准备写入
 | 
			
		||||
		this.prepareCacheWriter()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -403,6 +403,11 @@ func (this *HTTPWriter) PrepareCache(resp *http.Response, size int64) {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				partialWriter.SetBodyLength(total)
 | 
			
		||||
 | 
			
		||||
				var contentMD5 = this.rawWriter.Header().Get("Content-MD5")
 | 
			
		||||
				if len(contentMD5) > 0 {
 | 
			
		||||
					partialWriter.SetContentMD5(contentMD5)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			var filterReader = readers.NewFilterReaderCloser(resp.Body)
 | 
			
		||||
			this.cacheIsFinished = true
 | 
			
		||||
@@ -462,6 +467,11 @@ func (this *HTTPWriter) PrepareCache(resp *http.Response, size int64) {
 | 
			
		||||
				// 写入total
 | 
			
		||||
				if !writtenTotal && total > 0 {
 | 
			
		||||
					partialWriter.SetBodyLength(total)
 | 
			
		||||
					var contentMD5 = this.rawWriter.Header().Get("Content-MD5")
 | 
			
		||||
					if len(contentMD5) > 0 {
 | 
			
		||||
						partialWriter.SetContentMD5(contentMD5)
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					writtenTotal = true
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user