Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8c8d80e3b | ||
|
|
c43b6b37ea | ||
|
|
ac2d57d2f1 | ||
|
|
83ac62cda3 | ||
|
|
c0909a2cd0 | ||
|
|
a73b9f2674 | ||
|
|
3e79b71afc | ||
|
|
d3caccbb55 | ||
|
|
f95bac8d38 | ||
|
|
41d2ab728b | ||
|
|
b319061e85 | ||
|
|
99b8686a49 | ||
|
|
fe8c5b505a | ||
|
|
f88d0982ed | ||
|
|
a9389d53e1 | ||
|
|
fc4b45fec7 | ||
|
|
9b22e6cf69 | ||
|
|
7bd7f7da45 | ||
|
|
b68e6517df | ||
|
|
bbae229d08 | ||
|
|
c73a6cbfe8 | ||
|
|
e869e8e4d6 | ||
|
|
bde4e8507f | ||
|
|
5ae25cffa0 | ||
|
|
44b721d0d3 | ||
|
|
a2d6b7e0a8 | ||
|
|
95d65481e3 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
*_plus.go
|
*_plus.go
|
||||||
|
*_plus_test.go
|
||||||
*-plus.sh
|
*-plus.sh
|
||||||
@@ -55,7 +55,7 @@ function build() {
|
|||||||
cp -R "$ROOT"/pages "$DIST"/
|
cp -R "$ROOT"/pages "$DIST"/
|
||||||
|
|
||||||
# we support TOA on linux/amd64 only
|
# we support TOA on linux/amd64 only
|
||||||
if [ "$OS" == "linux" -a "$ARCH" == "amd64" ]
|
if [ "$OS" == "linux" ] && [ "$ARCH" == "amd64" ]
|
||||||
then
|
then
|
||||||
cp -R "$ROOT"/edge-toa "$DIST"
|
cp -R "$ROOT"/edge-toa "$DIST"
|
||||||
fi
|
fi
|
||||||
@@ -114,7 +114,10 @@ function build() {
|
|||||||
if [ ! -z $CC_PATH ]; then
|
if [ ! -z $CC_PATH ]; then
|
||||||
env CC=$MUSL_DIR/$CC_PATH CXX=$MUSL_DIR/$CXX_PATH GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 go build -trimpath -tags $BUILD_TAG -o "$DIST"/bin/${NAME} -ldflags "-linkmode external -extldflags -static -s -w" "$ROOT"/../cmd/edge-node/main.go
|
env CC=$MUSL_DIR/$CC_PATH CXX=$MUSL_DIR/$CXX_PATH GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 go build -trimpath -tags $BUILD_TAG -o "$DIST"/bin/${NAME} -ldflags "-linkmode external -extldflags -static -s -w" "$ROOT"/../cmd/edge-node/main.go
|
||||||
else
|
else
|
||||||
env GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 go build -trimpath -tags $TAG -o "$DIST"/bin/${NAME} -ldflags="-s -w" "$ROOT"/../cmd/edge-node/main.go
|
if [[ `uname` == *"Linux"* ]] && [ "$OS" == "linux" ] && [[ "$ARCH" == "amd64" || "$ARCH" == "arm64" ]] && [ "$TAG" == "plus" ]; then
|
||||||
|
BUILD_TAG="plus,script"
|
||||||
|
fi
|
||||||
|
env GOOS="${OS}" GOARCH="${ARCH}" CGO_ENABLED=1 go build -trimpath -tags $BUILD_TAG -o "$DIST"/bin/${NAME} -ldflags="-s -w" "$ROOT"/../cmd/edge-node/main.go
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# delete hidden files
|
# delete hidden files
|
||||||
|
|||||||
9
build/test.sh
Executable file
9
build/test.sh
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
TAG=${1}
|
||||||
|
|
||||||
|
if [ -z "$TAG" ]; then
|
||||||
|
TAG="community"
|
||||||
|
fi
|
||||||
|
|
||||||
|
go test -v ../... -tags=${TAG}
|
||||||
@@ -12,6 +12,11 @@ import (
|
|||||||
|
|
||||||
func TestFileListDB_ListLFUItems(t *testing.T) {
|
func TestFileListDB_ListLFUItems(t *testing.T) {
|
||||||
var db = caches.NewFileListDB()
|
var db = caches.NewFileListDB()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = db.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := db.Open(Tea.Root + "/data/cache-db-large.db")
|
err := db.Open(Tea.Root + "/data/cache-db-large.db")
|
||||||
//err := db.Open(Tea.Root + "/data/cache-index/p1/db-0.db")
|
//err := db.Open(Tea.Root + "/data/cache-index/p1/db-0.db")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -22,10 +27,6 @@ func TestFileListDB_ListLFUItems(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
_ = db.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
hashList, err := db.ListLFUItems(100)
|
hashList, err := db.ListLFUItems(100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -35,25 +36,38 @@ func TestFileListDB_ListLFUItems(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileListDB_IncreaseHitAsync(t *testing.T) {
|
func TestFileListDB_IncreaseHitAsync(t *testing.T) {
|
||||||
var db = caches.NewFileListDB()
|
var db = caches.NewFileListDB()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = db.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := db.Open(Tea.Root + "/data/cache-db-large.db")
|
err := db.Open(Tea.Root + "/data/cache-db-large.db")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.Init()
|
err = db.Init()
|
||||||
err = db.IncreaseHitAsync("4598e5231ba47d6ec7aa9ea640ff2eaf")
|
err = db.IncreaseHitAsync("4598e5231ba47d6ec7aa9ea640ff2eaf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait transaction
|
// wait transaction
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFileListDB_CleanMatchKey(t *testing.T) {
|
func TestFileListDB_CleanMatchKey(t *testing.T) {
|
||||||
var db = caches.NewFileListDB()
|
var db = caches.NewFileListDB()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = db.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := db.Open(Tea.Root + "/data/cache-db-large.db")
|
err := db.Open(Tea.Root + "/data/cache-db-large.db")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.Init()
|
err = db.Init()
|
||||||
|
|
||||||
err = db.CleanMatchKey("https://*.goedge.cn/large-text")
|
err = db.CleanMatchKey("https://*.goedge.cn/large-text")
|
||||||
@@ -69,10 +83,16 @@ func TestFileListDB_CleanMatchKey(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileListDB_CleanMatchPrefix(t *testing.T) {
|
func TestFileListDB_CleanMatchPrefix(t *testing.T) {
|
||||||
var db = caches.NewFileListDB()
|
var db = caches.NewFileListDB()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = db.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := db.Open(Tea.Root + "/data/cache-db-large.db")
|
err := db.Open(Tea.Root + "/data/cache-db-large.db")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.Init()
|
err = db.Init()
|
||||||
|
|
||||||
err = db.CleanMatchPrefix("https://*.goedge.cn/large-text")
|
err = db.CleanMatchPrefix("https://*.goedge.cn/large-text")
|
||||||
|
|||||||
@@ -59,15 +59,16 @@ func TestFileListHashMap_BigInt(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileListHashMap_Load(t *testing.T) {
|
func TestFileListHashMap_Load(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1").(*caches.FileList)
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1").(*caches.FileList)
|
||||||
err := list.Init()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = list.Close()
|
_ = list.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
err := list.Init()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
var m = caches.NewFileListHashMap()
|
var m = caches.NewFileListHashMap()
|
||||||
var before = time.Now()
|
var before = time.Now()
|
||||||
var db = list.GetDB("abc")
|
var db = list.GetDB("abc")
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package caches_test
|
|||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/caches"
|
"github.com/TeaOSLab/EdgeNode/internal/caches"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/rands"
|
"github.com/iwind/TeaGo/rands"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
@@ -17,6 +18,11 @@ import (
|
|||||||
|
|
||||||
func TestFileList_Init(t *testing.T) {
|
func TestFileList_Init(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -29,6 +35,11 @@ func TestFileList_Init(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileList_Add(t *testing.T) {
|
func TestFileList_Add(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1").(*caches.FileList)
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1").(*caches.FileList)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -59,16 +70,21 @@ func TestFileList_Add(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileList_Add_Many(t *testing.T) {
|
func TestFileList_Add_Many(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
if !testutils.IsSingleTesting() {
|
||||||
err := list.Init()
|
return
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = list.Close()
|
_ = list.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
err := list.Init()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
var before = time.Now()
|
var before = time.Now()
|
||||||
for i := 0; i < 10_000_000; i++ {
|
for i := 0; i < 10_000_000; i++ {
|
||||||
u := "https://edge.teaos.cn/123456" + strconv.Itoa(i)
|
u := "https://edge.teaos.cn/123456" + strconv.Itoa(i)
|
||||||
@@ -92,15 +108,15 @@ func TestFileList_Add_Many(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileList_Exist(t *testing.T) {
|
func TestFileList_Exist(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1").(*caches.FileList)
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1").(*caches.FileList)
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
_ = list.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
total, _ := list.Count()
|
total, _ := list.Count()
|
||||||
t.Log("total:", total)
|
t.Log("total:", total)
|
||||||
|
|
||||||
@@ -130,7 +146,7 @@ func TestFileList_Exist_Many_DB(t *testing.T) {
|
|||||||
// 测试在多个数据库下的性能
|
// 测试在多个数据库下的性能
|
||||||
var listSlice = []caches.ListInterface{}
|
var listSlice = []caches.ListInterface{}
|
||||||
for i := 1; i <= 10; i++ {
|
for i := 1; i <= 10; i++ {
|
||||||
list := caches.NewFileList(Tea.Root + "/data/data" + strconv.Itoa(i))
|
var list = caches.NewFileList(Tea.Root + "/data/data" + strconv.Itoa(i))
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -138,6 +154,12 @@ func TestFileList_Exist_Many_DB(t *testing.T) {
|
|||||||
listSlice = append(listSlice, list)
|
listSlice = append(listSlice, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
for _, list := range listSlice {
|
||||||
|
_ = list.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
var wg = sync.WaitGroup{}
|
var wg = sync.WaitGroup{}
|
||||||
var threads = 8
|
var threads = 8
|
||||||
wg.Add(threads)
|
wg.Add(threads)
|
||||||
@@ -181,15 +203,16 @@ func TestFileList_Exist_Many_DB(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileList_CleanPrefix(t *testing.T) {
|
func TestFileList_CleanPrefix(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
||||||
err := list.Init()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = list.Close()
|
_ = list.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
err := list.Init()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
before := time.Now()
|
before := time.Now()
|
||||||
err = list.CleanPrefix("123")
|
err = list.CleanPrefix("123")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -200,15 +223,15 @@ func TestFileList_CleanPrefix(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileList_Remove(t *testing.T) {
|
func TestFileList_Remove(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1").(*caches.FileList)
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1").(*caches.FileList)
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
_ = list.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
list.OnRemove(func(item *caches.Item) {
|
list.OnRemove(func(item *caches.Item) {
|
||||||
t.Logf("remove %#v", item)
|
t.Logf("remove %#v", item)
|
||||||
})
|
})
|
||||||
@@ -224,13 +247,15 @@ func TestFileList_Remove(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileList_Purge(t *testing.T) {
|
func TestFileList_Purge(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
|
||||||
_ = list.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
var count = 0
|
var count = 0
|
||||||
_, err = list.Purge(caches.CountFileDB*2, func(hash string) error {
|
_, err = list.Purge(caches.CountFileDB*2, func(hash string) error {
|
||||||
@@ -246,13 +271,15 @@ func TestFileList_Purge(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileList_PurgeLFU(t *testing.T) {
|
func TestFileList_PurgeLFU(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
|
||||||
_ = list.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = list.IncreaseHit(stringutil.Md5("123456"))
|
err = list.IncreaseHit(stringutil.Md5("123456"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -273,15 +300,16 @@ func TestFileList_PurgeLFU(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileList_Stat(t *testing.T) {
|
func TestFileList_Stat(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
||||||
err := list.Init()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = list.Close()
|
_ = list.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
err := list.Init()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
stat, err := list.Stat(nil)
|
stat, err := list.Stat(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -291,6 +319,11 @@ func TestFileList_Stat(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileList_Count(t *testing.T) {
|
func TestFileList_Count(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data")
|
var list = caches.NewFileList(Tea.Root + "/data")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -305,7 +338,12 @@ func TestFileList_Count(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileList_CleanAll(t *testing.T) {
|
func TestFileList_CleanAll(t *testing.T) {
|
||||||
list := caches.NewFileList(Tea.Root + "/data")
|
var list = caches.NewFileList(Tea.Root + "/data")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -320,6 +358,11 @@ func TestFileList_CleanAll(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileList_IncreaseHit(t *testing.T) {
|
func TestFileList_IncreaseHit(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -333,7 +376,13 @@ func TestFileList_IncreaseHit(t *testing.T) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
t.Log(time.Since(before).Seconds()*1000, "ms")
|
t.Log(time.Since(before).Seconds()*1000, "ms")
|
||||||
}()
|
}()
|
||||||
for i := 0; i < 1000_000; i++ {
|
|
||||||
|
var count = 1_000_000
|
||||||
|
|
||||||
|
if !testutils.IsSingleTesting() {
|
||||||
|
count = 10
|
||||||
|
}
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
err = list.IncreaseHit(stringutil.Md5("abc" + types.String(i)))
|
err = list.IncreaseHit(stringutil.Md5("abc" + types.String(i)))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -344,6 +393,11 @@ func TestFileList_IncreaseHit(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileList_UpgradeV3(t *testing.T) {
|
func TestFileList_UpgradeV3(t *testing.T) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p43").(*caches.FileList)
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p43").(*caches.FileList)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -363,6 +417,11 @@ func TestFileList_UpgradeV3(t *testing.T) {
|
|||||||
|
|
||||||
func BenchmarkFileList_Exist(b *testing.B) {
|
func BenchmarkFileList_Exist(b *testing.B) {
|
||||||
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
var list = caches.NewFileList(Tea.Root + "/data/cache-index/p1")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = list.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err := list.Init()
|
err := list.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package caches
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
|
||||||
"github.com/cespare/xxhash"
|
"github.com/cespare/xxhash"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"github.com/iwind/TeaGo/rands"
|
"github.com/iwind/TeaGo/rands"
|
||||||
@@ -107,7 +108,9 @@ func TestMemoryList_Purge_Large_List(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(1 * time.Hour)
|
if testutils.IsSingleTesting() {
|
||||||
|
time.Sleep(1 * time.Hour)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryList_Stat(t *testing.T) {
|
func TestMemoryList_Stat(t *testing.T) {
|
||||||
@@ -255,9 +258,11 @@ func TestMemoryList_GC(t *testing.T) {
|
|||||||
//runtime.GC()
|
//runtime.GC()
|
||||||
t.Log("gc cost:", time.Since(before).Seconds()*1000, "ms")
|
t.Log("gc cost:", time.Since(before).Seconds()*1000, "ms")
|
||||||
|
|
||||||
timeout := time.NewTimer(2 * time.Minute)
|
if testutils.IsSingleTesting() {
|
||||||
<-timeout.C
|
timeout := time.NewTimer(2 * time.Minute)
|
||||||
t.Log("2 minutes passed")
|
<-timeout.C
|
||||||
|
t.Log("2 minutes passed")
|
||||||
|
|
||||||
time.Sleep(30 * time.Minute)
|
time.Sleep(30 * time.Minute)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package caches_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/caches"
|
"github.com/TeaOSLab/EdgeNode/internal/caches"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -23,7 +24,9 @@ func TestNewOpenFileCache_Close(t *testing.T) {
|
|||||||
cache.Get("d.txt")
|
cache.Get("d.txt")
|
||||||
cache.Close("a.txt")
|
cache.Close("a.txt")
|
||||||
|
|
||||||
time.Sleep(100 * time.Second)
|
if testutils.IsSingleTesting() {
|
||||||
|
time.Sleep(100 * time.Second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewOpenFileCache_CloseAll(t *testing.T) {
|
func TestNewOpenFileCache_CloseAll(t *testing.T) {
|
||||||
|
|||||||
@@ -8,21 +8,29 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFileReader(t *testing.T) {
|
func TestFileReader(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, path, _ := storage.keyPath("my-key")
|
_, path, _ := storage.keyPath("my-key")
|
||||||
|
|
||||||
fp, err := os.Open(path)
|
fp, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
t.Log("file '" + path + "' not exists")
|
||||||
|
return
|
||||||
|
}
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -58,6 +66,10 @@ func TestFileReader_ReadHeader(t *testing.T) {
|
|||||||
var path = "/Users/WorkSpace/EdgeProject/EdgeCache/p43/12/6b/126bbed90fc80f2bdfb19558948b0d49.cache"
|
var path = "/Users/WorkSpace/EdgeProject/EdgeCache/p43/12/6b/126bbed90fc80f2bdfb19558948b0d49.cache"
|
||||||
fp, err := os.Open(path)
|
fp, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
t.Log("'" + path + "' not exists")
|
||||||
|
return
|
||||||
|
}
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -66,6 +78,11 @@ func TestFileReader_ReadHeader(t *testing.T) {
|
|||||||
var reader = NewFileReader(fp)
|
var reader = NewFileReader(fp)
|
||||||
err = reader.Init()
|
err = reader.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
t.Log("file '" + path + "' not exists")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
var buf = make([]byte, 16*1024)
|
var buf = make([]byte, 16*1024)
|
||||||
@@ -79,13 +96,16 @@ func TestFileReader_ReadHeader(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileReader_Range(t *testing.T) {
|
func TestFileReader_Range(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -109,6 +129,10 @@ func TestFileReader_Range(t *testing.T) {
|
|||||||
|
|
||||||
fp, err := os.Open(path)
|
fp, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
t.Log("'" + path + "' not exists")
|
||||||
|
return
|
||||||
|
}
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
@@ -899,7 +899,10 @@ func (this *FileStorage) Stop() {
|
|||||||
memoryStorage.Stop()
|
memoryStorage.Stop()
|
||||||
})
|
})
|
||||||
|
|
||||||
_ = this.list.Reset()
|
if this.list != nil {
|
||||||
|
_ = this.list.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
if this.purgeTicker != nil {
|
if this.purgeTicker != nil {
|
||||||
this.purgeTicker.Stop()
|
this.purgeTicker.Stop()
|
||||||
}
|
}
|
||||||
@@ -907,7 +910,9 @@ func (this *FileStorage) Stop() {
|
|||||||
this.hotTicker.Stop()
|
this.hotTicker.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = this.list.Close()
|
if this.list != nil {
|
||||||
|
_ = this.list.Close()
|
||||||
|
}
|
||||||
|
|
||||||
var openFileCache = this.openFileCache
|
var openFileCache = this.openFileCache
|
||||||
if openFileCache != nil {
|
if openFileCache != nil {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFileStorage_Init(t *testing.T) {
|
func TestFileStorage_Init(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
@@ -26,6 +26,8 @@ func TestFileStorage_Init(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -44,13 +46,16 @@ func TestFileStorage_Init(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_OpenWriter(t *testing.T) {
|
func TestFileStorage_OpenWriter(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -95,6 +100,9 @@ func TestFileStorage_OpenWriter_Partial(t *testing.T) {
|
|||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -123,13 +131,16 @@ func TestFileStorage_OpenWriter_Partial(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_OpenWriter_HTTP(t *testing.T) {
|
func TestFileStorage_OpenWriter_HTTP(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -188,13 +199,16 @@ func TestFileStorage_OpenWriter_HTTP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_Concurrent_Open_DifferentFile(t *testing.T) {
|
func TestFileStorage_Concurrent_Open_DifferentFile(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -243,13 +257,16 @@ func TestFileStorage_Concurrent_Open_DifferentFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_Concurrent_Open_SameFile(t *testing.T) {
|
func TestFileStorage_Concurrent_Open_SameFile(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -299,13 +316,16 @@ func TestFileStorage_Concurrent_Open_SameFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_Read(t *testing.T) {
|
func TestFileStorage_Read(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -335,13 +355,16 @@ func TestFileStorage_Read(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_Read_HTTP_Response(t *testing.T) {
|
func TestFileStorage_Read_HTTP_Response(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -388,13 +411,16 @@ func TestFileStorage_Read_HTTP_Response(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_Read_NotFound(t *testing.T) {
|
func TestFileStorage_Read_NotFound(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -421,13 +447,16 @@ func TestFileStorage_Read_NotFound(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_Delete(t *testing.T) {
|
func TestFileStorage_Delete(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -440,13 +469,16 @@ func TestFileStorage_Delete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_Stat(t *testing.T) {
|
func TestFileStorage_Stat(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -465,13 +497,16 @@ func TestFileStorage_Stat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_CleanAll(t *testing.T) {
|
func TestFileStorage_CleanAll(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -496,13 +531,16 @@ func TestFileStorage_CleanAll(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStorage_Stop(t *testing.T) {
|
func TestFileStorage_Stop(t *testing.T) {
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -518,6 +556,9 @@ func TestFileStorage_DecodeFile(t *testing.T) {
|
|||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -528,6 +569,9 @@ func TestFileStorage_DecodeFile(t *testing.T) {
|
|||||||
|
|
||||||
func TestFileStorage_RemoveCacheFile(t *testing.T) {
|
func TestFileStorage_RemoveCacheFile(t *testing.T) {
|
||||||
var storage = NewFileStorage(nil)
|
var storage = NewFileStorage(nil)
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
t.Log(storage.removeCacheFile("/Users/WorkSpace/EdgeProject/EdgeCache/p43/15/7e/157eba0dfc6dfb6fbbf20b1f9e584674.cache"))
|
t.Log(storage.removeCacheFile("/Users/WorkSpace/EdgeProject/EdgeCache/p43/15/7e/157eba0dfc6dfb6fbbf20b1f9e584674.cache"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,13 +580,16 @@ func BenchmarkFileStorage_Read(b *testing.B) {
|
|||||||
|
|
||||||
_ = utils.SetRLimit(1024 * 1024)
|
_ = utils.SetRLimit(1024 * 1024)
|
||||||
|
|
||||||
storage := NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"dir": Tea.Root + "/caches",
|
"dir": Tea.Root + "/caches",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer storage.Stop()
|
||||||
|
|
||||||
err := storage.Init()
|
err := storage.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package conns
|
package conns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@@ -10,14 +11,14 @@ import (
|
|||||||
var SharedMap = NewMap()
|
var SharedMap = NewMap()
|
||||||
|
|
||||||
type Map struct {
|
type Map struct {
|
||||||
m map[string]map[int]net.Conn // ip => { port => Conn }
|
m map[string]map[string]net.Conn // ip => { network_port => Conn }
|
||||||
|
|
||||||
locker sync.RWMutex
|
locker sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMap() *Map {
|
func NewMap() *Map {
|
||||||
return &Map{
|
return &Map{
|
||||||
m: map[string]map[int]net.Conn{},
|
m: map[string]map[string]net.Conn{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,21 +26,19 @@ func (this *Map) Add(conn net.Conn) {
|
|||||||
if conn == nil {
|
if conn == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tcpAddr, ok := conn.RemoteAddr().(*net.TCPAddr)
|
|
||||||
|
key, ip, ok := this.connAddr(conn)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var ip = tcpAddr.IP.String()
|
|
||||||
var port = tcpAddr.Port
|
|
||||||
|
|
||||||
this.locker.Lock()
|
this.locker.Lock()
|
||||||
defer this.locker.Unlock()
|
defer this.locker.Unlock()
|
||||||
connMap, ok := this.m[ip]
|
connMap, ok := this.m[ip]
|
||||||
if !ok {
|
if !ok {
|
||||||
this.m[ip] = map[int]net.Conn{port: conn}
|
this.m[ip] = map[string]net.Conn{key: conn}
|
||||||
} else {
|
} else {
|
||||||
connMap[port] = conn
|
connMap[key] = conn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,14 +46,11 @@ func (this *Map) Remove(conn net.Conn) {
|
|||||||
if conn == nil {
|
if conn == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tcpAddr, ok := conn.RemoteAddr().(*net.TCPAddr)
|
key, ip, ok := this.connAddr(conn)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var ip = tcpAddr.IP.String()
|
|
||||||
var port = tcpAddr.Port
|
|
||||||
|
|
||||||
this.locker.Lock()
|
this.locker.Lock()
|
||||||
defer this.locker.Unlock()
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
@@ -62,7 +58,7 @@ func (this *Map) Remove(conn net.Conn) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
delete(connMap, port)
|
delete(connMap, key)
|
||||||
|
|
||||||
if len(connMap) == 0 {
|
if len(connMap) == 0 {
|
||||||
delete(this.m, ip)
|
delete(this.m, ip)
|
||||||
@@ -121,3 +117,24 @@ func (this *Map) AllConns() []net.Conn {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Map) connAddr(conn net.Conn) (key string, ip string, ok bool) {
|
||||||
|
if conn == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var addr = conn.RemoteAddr()
|
||||||
|
switch realAddr := addr.(type) {
|
||||||
|
case *net.TCPAddr:
|
||||||
|
return addr.Network() + types.String(realAddr.Port), realAddr.IP.String(), true
|
||||||
|
case *net.UDPAddr:
|
||||||
|
return addr.Network() + types.String(realAddr.Port), realAddr.IP.String(), true
|
||||||
|
default:
|
||||||
|
var s = addr.String()
|
||||||
|
host, port, err := net.SplitHostPort(s)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return addr.Network() + port, host, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "1.1.0"
|
Version = "1.2.0"
|
||||||
|
|
||||||
ProductName = "Edge Node"
|
ProductName = "Edge Node"
|
||||||
ProcessName = "edge-node"
|
ProcessName = "edge-node"
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ func TestIPListManager_check(t *testing.T) {
|
|||||||
func TestIPListManager_loop(t *testing.T) {
|
func TestIPListManager_loop(t *testing.T) {
|
||||||
manager := NewIPListManager()
|
manager := NewIPListManager()
|
||||||
manager.Start()
|
manager.Start()
|
||||||
manager.pageSize = 10
|
|
||||||
err := manager.loop()
|
err := manager.loop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/metrics"
|
"github.com/TeaOSLab/EdgeNode/internal/metrics"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
|
||||||
_ "github.com/iwind/TeaGo/bootstrap"
|
_ "github.com/iwind/TeaGo/bootstrap"
|
||||||
"github.com/iwind/TeaGo/rands"
|
"github.com/iwind/TeaGo/rands"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -79,6 +80,10 @@ func TestTask_Add(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTask_Add_Many(t *testing.T) {
|
func TestTask_Add_Many(t *testing.T) {
|
||||||
|
if !testutils.IsSingleTesting() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var task = metrics.NewTask(&serverconfigs.MetricItemConfig{
|
var task = metrics.NewTask(&serverconfigs.MetricItemConfig{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
IsOn: false,
|
IsOn: false,
|
||||||
|
|||||||
@@ -61,11 +61,16 @@ func NewClientConn(rawConn net.Conn, isHTTP bool, isTLS bool, isInAllowList bool
|
|||||||
isTLS: isTLS,
|
isTLS: isTLS,
|
||||||
isHTTP: isHTTP,
|
isHTTP: isHTTP,
|
||||||
isLO: strings.HasPrefix(remoteAddr, "127.0.0.1:") || strings.HasPrefix(remoteAddr, "[::1]:"),
|
isLO: strings.HasPrefix(remoteAddr, "127.0.0.1:") || strings.HasPrefix(remoteAddr, "[::1]:"),
|
||||||
isNoStat: connutils.IsNoStatConn(rawConn.RemoteAddr().String()),
|
isNoStat: connutils.IsNoStatConn(remoteAddr),
|
||||||
isInAllowList: isInAllowList,
|
isInAllowList: isInAllowList,
|
||||||
createdAt: fasttime.Now().Unix(),
|
createdAt: fasttime.Now().Unix(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if existsLnNodeIP(conn.RawIP()) {
|
||||||
|
conn.SetIsPersistent(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 超时等设置
|
||||||
var globalServerConfig = sharedNodeConfig.GlobalServerConfig
|
var globalServerConfig = sharedNodeConfig.GlobalServerConfig
|
||||||
if globalServerConfig != nil {
|
if globalServerConfig != nil {
|
||||||
var performanceConfig = globalServerConfig.Performance
|
var performanceConfig = globalServerConfig.Performance
|
||||||
@@ -129,7 +134,7 @@ func (this *ClientConn) Read(b []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 忽略白名单和局域网
|
// 忽略白名单和局域网
|
||||||
if this.isHTTP && !this.isInAllowList && !utils.IsLocalIP(this.RawIP()) {
|
if !this.isPersistent && this.isHTTP && !this.isInAllowList && !utils.IsLocalIP(this.RawIP()) {
|
||||||
// SYN Flood检测
|
// SYN Flood检测
|
||||||
if this.serverId == 0 || !this.hasResetSYNFlood {
|
if this.serverId == 0 || !this.hasResetSYNFlood {
|
||||||
var synFloodConfig = sharedNodeConfig.SYNFloodConfig()
|
var synFloodConfig = sharedNodeConfig.SYNFloodConfig()
|
||||||
@@ -165,8 +170,7 @@ func (this *ClientConn) Write(b []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设置写超时时间
|
// 设置写超时时间
|
||||||
if this.autoWriteTimeout {
|
if !this.isPersistent && this.autoWriteTimeout {
|
||||||
// TODO L2 -> L1 写入时不限制时间
|
|
||||||
var timeoutSeconds = len(b) / 1024
|
var timeoutSeconds = len(b) / 1024
|
||||||
if timeoutSeconds < 3 {
|
if timeoutSeconds < 3 {
|
||||||
timeoutSeconds = 3
|
timeoutSeconds = 3
|
||||||
|
|||||||
@@ -54,12 +54,13 @@ func (this *BaseClientConn) SetServerId(serverId int64) (goNext bool) {
|
|||||||
goNext = true
|
goNext = true
|
||||||
|
|
||||||
// 检查服务相关IP黑名单
|
// 检查服务相关IP黑名单
|
||||||
if serverId > 0 && len(this.rawIP) > 0 {
|
var rawIP = this.RawIP()
|
||||||
|
if serverId > 0 && len(rawIP) > 0 {
|
||||||
// 是否在白名单中
|
// 是否在白名单中
|
||||||
ok, _, expiresAt := iplibrary.AllowIP(this.rawIP, serverId)
|
ok, _, expiresAt := iplibrary.AllowIP(rawIP, serverId)
|
||||||
if !ok {
|
if !ok {
|
||||||
_ = this.rawConn.Close()
|
_ = this.rawConn.Close()
|
||||||
firewalls.DropTemporaryTo(this.rawIP, expiresAt)
|
firewalls.DropTemporaryTo(rawIP, expiresAt)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,8 +124,8 @@ func (this *BaseClientConn) TCPConn() (tcpConn *net.TCPConn, ok bool) {
|
|||||||
switch conn := this.rawConn.(type) {
|
switch conn := this.rawConn.(type) {
|
||||||
case *tls.Conn:
|
case *tls.Conn:
|
||||||
var internalConn = conn.NetConn()
|
var internalConn = conn.NetConn()
|
||||||
clientConn, ok := internalConn.(*ClientConn)
|
clientConn, isClientConn := internalConn.(*ClientConn)
|
||||||
if ok {
|
if isClientConn {
|
||||||
return clientConn.TCPConn()
|
return clientConn.TCPConn()
|
||||||
}
|
}
|
||||||
tcpConn, ok = internalConn.(*net.TCPConn)
|
tcpConn, ok = internalConn.(*net.TCPConn)
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ type HTTPRequest struct {
|
|||||||
ServerAddr string // 实际启动的服务器监听地址
|
ServerAddr string // 实际启动的服务器监听地址
|
||||||
IsHTTP bool
|
IsHTTP bool
|
||||||
IsHTTPS bool
|
IsHTTPS bool
|
||||||
|
IsHTTP3 bool
|
||||||
|
|
||||||
// 共享参数
|
// 共享参数
|
||||||
nodeConfig *nodeconfigs.NodeConfig
|
nodeConfig *nodeconfigs.NodeConfig
|
||||||
@@ -479,6 +480,17 @@ func (this *HTTPRequest) configureWeb(web *serverconfigs.HTTPWebConfig, isTop bo
|
|||||||
// remote addr
|
// remote addr
|
||||||
if web.RemoteAddr != nil && (web.RemoteAddr.IsPrior || isTop) && web.RemoteAddr.IsOn {
|
if web.RemoteAddr != nil && (web.RemoteAddr.IsPrior || isTop) && web.RemoteAddr.IsOn {
|
||||||
this.web.RemoteAddr = web.RemoteAddr
|
this.web.RemoteAddr = web.RemoteAddr
|
||||||
|
|
||||||
|
// check if from proxy
|
||||||
|
if len(this.web.RemoteAddr.Value) > 0 && this.web.RemoteAddr.Value != "${rawRemoteAddr}" {
|
||||||
|
var requestConn = this.RawReq.Context().Value(HTTPConnContextKey)
|
||||||
|
if requestConn != nil {
|
||||||
|
requestClientConn, ok := requestConn.(ClientConnInterface)
|
||||||
|
if ok {
|
||||||
|
requestClientConn.SetIsPersistent(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// charset
|
// charset
|
||||||
@@ -1698,8 +1710,8 @@ func (this *HTTPRequest) fixRequestHeader(header http.Header) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理自定义Response Header
|
// ProcessResponseHeaders 处理自定义Response Header
|
||||||
func (this *HTTPRequest) processResponseHeaders(responseHeader http.Header, statusCode int) {
|
func (this *HTTPRequest) ProcessResponseHeaders(responseHeader http.Header, statusCode int) {
|
||||||
// 删除/添加/替换Header
|
// 删除/添加/替换Header
|
||||||
// TODO 实现AddTrailers
|
// TODO 实现AddTrailers
|
||||||
if this.web.ResponseHeaderPolicy != nil && this.web.ResponseHeaderPolicy.IsOn {
|
if this.web.ResponseHeaderPolicy != nil && this.web.ResponseHeaderPolicy.IsOn {
|
||||||
@@ -1828,6 +1840,11 @@ func (this *HTTPRequest) processResponseHeaders(responseHeader http.Header, stat
|
|||||||
this.ReqServer.HTTPS.SSLPolicy.HSTS.Match(this.ReqHost) {
|
this.ReqServer.HTTPS.SSLPolicy.HSTS.Match(this.ReqHost) {
|
||||||
responseHeader.Set(this.ReqServer.HTTPS.SSLPolicy.HSTS.HeaderKey(), this.ReqServer.HTTPS.SSLPolicy.HSTS.HeaderValue())
|
responseHeader.Set(this.ReqServer.HTTPS.SSLPolicy.HSTS.HeaderKey(), this.ReqServer.HTTPS.SSLPolicy.HSTS.HeaderValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTTP/3
|
||||||
|
if this.IsHTTPS && !this.IsHTTP3 && this.ReqServer.SupportsHTTP3() {
|
||||||
|
this.processHTTP3Headers(responseHeader)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加错误信息
|
// 添加错误信息
|
||||||
@@ -1897,7 +1914,7 @@ func (this *HTTPRequest) canIgnore(err error) bool {
|
|||||||
|
|
||||||
// 检查连接是否已关闭
|
// 检查连接是否已关闭
|
||||||
func (this *HTTPRequest) isConnClosed() bool {
|
func (this *HTTPRequest) isConnClosed() bool {
|
||||||
requestConn := this.RawReq.Context().Value(HTTPConnContextKey)
|
var requestConn = this.RawReq.Context().Value(HTTPConnContextKey)
|
||||||
if requestConn == nil {
|
if requestConn == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
var addStatusHeader = this.web.Cache.AddStatusHeader
|
var addStatusHeader = this.web.Cache.AddStatusHeader
|
||||||
if addStatusHeader {
|
if addStatusHeader {
|
||||||
defer func() {
|
defer func() {
|
||||||
cacheStatus := this.varMapping["cache.status"]
|
var cacheStatus = this.varMapping["cache.status"]
|
||||||
if cacheStatus != "HIT" {
|
if cacheStatus != "HIT" {
|
||||||
this.writer.Header().Set("X-Cache", cacheStatus)
|
this.writer.Header().Set("X-Cache", cacheStatus)
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查服务独立的缓存条件
|
// 检查服务独立的缓存条件
|
||||||
refType := ""
|
var refType = ""
|
||||||
for _, cacheRef := range this.web.Cache.CacheRefs {
|
for _, cacheRef := range this.web.Cache.CacheRefs {
|
||||||
if !cacheRef.IsOn {
|
if !cacheRef.IsOn {
|
||||||
continue
|
continue
|
||||||
@@ -131,7 +131,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
this.varMapping["cache.key"] = key
|
this.varMapping["cache.key"] = key
|
||||||
|
|
||||||
// 读取缓存
|
// 读取缓存
|
||||||
storage := caches.SharedManager.FindStorageWithPolicy(cachePolicy.Id)
|
var storage = caches.SharedManager.FindStorageWithPolicy(cachePolicy.Id)
|
||||||
if storage == nil {
|
if storage == nil {
|
||||||
this.cacheRef = nil
|
this.cacheRef = nil
|
||||||
return
|
return
|
||||||
@@ -241,16 +241,19 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
reader, err = storage.OpenReader(key, useStale, false)
|
reader, err = storage.OpenReader(key, useStale, false)
|
||||||
if err != nil && this.cacheRef.AllowPartialContent {
|
if err != nil && this.cacheRef.AllowPartialContent {
|
||||||
// 尝试读取分片的缓存内容
|
// 尝试读取分片的缓存内容
|
||||||
if len(rangeHeader) == 0 {
|
if len(rangeHeader) == 0 && this.cacheRef.ForcePartialContent {
|
||||||
// 默认读取开头
|
// 默认读取开头
|
||||||
rangeHeader = "bytes=0-"
|
rangeHeader = "bytes=0-"
|
||||||
}
|
}
|
||||||
pReader, ranges := this.tryPartialReader(storage, key, useStale, rangeHeader)
|
|
||||||
if pReader != nil {
|
if len(rangeHeader) > 0 {
|
||||||
isPartialCache = true
|
pReader, ranges := this.tryPartialReader(storage, key, useStale, rangeHeader)
|
||||||
reader = pReader
|
if pReader != nil {
|
||||||
partialRanges = ranges
|
isPartialCache = true
|
||||||
err = nil
|
reader = pReader
|
||||||
|
partialRanges = ranges
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,13 +304,13 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
this.writer.SetSentHeaderBytes(reader.HeaderSize())
|
this.writer.SetSentHeaderBytes(reader.HeaderSize())
|
||||||
var headerPool = this.bytePool(reader.HeaderSize())
|
var headerPool = this.bytePool(reader.HeaderSize())
|
||||||
var headerBuf = headerPool.Get()
|
var headerBuf = headerPool.Get()
|
||||||
err = reader.ReadHeader(headerBuf, func(n int) (goNext bool, err error) {
|
err = reader.ReadHeader(headerBuf, func(n int) (goNext bool, readErr error) {
|
||||||
headerData = append(headerData, headerBuf[:n]...)
|
headerData = append(headerData, headerBuf[:n]...)
|
||||||
for {
|
for {
|
||||||
nIndex := bytes.Index(headerData, []byte{'\n'})
|
var nIndex = bytes.Index(headerData, []byte{'\n'})
|
||||||
if nIndex >= 0 {
|
if nIndex >= 0 {
|
||||||
row := headerData[:nIndex]
|
var row = headerData[:nIndex]
|
||||||
spaceIndex := bytes.Index(row, []byte{':'})
|
var spaceIndex = bytes.Index(row, []byte{':'})
|
||||||
if spaceIndex <= 0 {
|
if spaceIndex <= 0 {
|
||||||
return false, errors.New("invalid header '" + string(row) + "'")
|
return false, errors.New("invalid header '" + string(row) + "'")
|
||||||
}
|
}
|
||||||
@@ -375,7 +378,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
// 支持 If-None-Match
|
// 支持 If-None-Match
|
||||||
if !this.isLnRequest && !isPartialCache && len(eTag) > 0 && this.requestHeader("If-None-Match") == eTag {
|
if !this.isLnRequest && !isPartialCache && len(eTag) > 0 && this.requestHeader("If-None-Match") == eTag {
|
||||||
// 自定义Header
|
// 自定义Header
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusNotModified)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusNotModified)
|
||||||
this.addExpiresHeader(reader.ExpiresAt())
|
this.addExpiresHeader(reader.ExpiresAt())
|
||||||
this.writer.WriteHeader(http.StatusNotModified)
|
this.writer.WriteHeader(http.StatusNotModified)
|
||||||
this.isCached = true
|
this.isCached = true
|
||||||
@@ -387,7 +390,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
// 支持 If-Modified-Since
|
// 支持 If-Modified-Since
|
||||||
if !this.isLnRequest && !isPartialCache && len(modifiedTime) > 0 && this.requestHeader("If-Modified-Since") == modifiedTime {
|
if !this.isLnRequest && !isPartialCache && len(modifiedTime) > 0 && this.requestHeader("If-Modified-Since") == modifiedTime {
|
||||||
// 自定义Header
|
// 自定义Header
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusNotModified)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusNotModified)
|
||||||
this.addExpiresHeader(reader.ExpiresAt())
|
this.addExpiresHeader(reader.ExpiresAt())
|
||||||
this.writer.WriteHeader(http.StatusNotModified)
|
this.writer.WriteHeader(http.StatusNotModified)
|
||||||
this.isCached = true
|
this.isCached = true
|
||||||
@@ -396,7 +399,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processResponseHeaders(this.writer.Header(), reader.Status())
|
this.ProcessResponseHeaders(this.writer.Header(), reader.Status())
|
||||||
this.addExpiresHeader(reader.ExpiresAt())
|
this.addExpiresHeader(reader.ExpiresAt())
|
||||||
|
|
||||||
// 返回上级节点过期时间
|
// 返回上级节点过期时间
|
||||||
@@ -425,7 +428,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
if supportRange {
|
if supportRange {
|
||||||
if len(rangeHeader) > 0 {
|
if len(rangeHeader) > 0 {
|
||||||
if fileSize == 0 {
|
if fileSize == 0 {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
||||||
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -433,7 +436,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
if len(ranges) == 0 {
|
if len(ranges) == 0 {
|
||||||
ranges, ok = httpRequestParseRangeHeader(rangeHeader)
|
ranges, ok = httpRequestParseRangeHeader(rangeHeader)
|
||||||
if !ok {
|
if !ok {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
||||||
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -442,7 +445,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
for k, r := range ranges {
|
for k, r := range ranges {
|
||||||
r2, ok := r.Convert(fileSize)
|
r2, ok := r.Convert(fileSize)
|
||||||
if !ok {
|
if !ok {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
||||||
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -460,9 +463,9 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
|
|
||||||
var pool = this.bytePool(fileSize)
|
var pool = this.bytePool(fileSize)
|
||||||
var bodyBuf = pool.Get()
|
var bodyBuf = pool.Get()
|
||||||
err = reader.ReadBodyRange(bodyBuf, ranges[0].Start(), ranges[0].End(), func(n int) (goNext bool, err error) {
|
err = reader.ReadBodyRange(bodyBuf, ranges[0].Start(), ranges[0].End(), func(n int) (goNext bool, readErr error) {
|
||||||
_, err = this.writer.Write(bodyBuf[:n])
|
_, readErr = this.writer.Write(bodyBuf[:n])
|
||||||
if err != nil {
|
if readErr != nil {
|
||||||
return false, errWritingToClient
|
return false, errWritingToClient
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
@@ -472,7 +475,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
this.varMapping["cache.status"] = "MISS"
|
this.varMapping["cache.status"] = "MISS"
|
||||||
|
|
||||||
if err == caches.ErrInvalidRange {
|
if err == caches.ErrInvalidRange {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
||||||
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -485,7 +488,7 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
var boundary = httpRequestGenBoundary()
|
var boundary = httpRequestGenBoundary()
|
||||||
respHeader.Set("Content-Type", "multipart/byteranges; boundary="+boundary)
|
respHeader.Set("Content-Type", "multipart/byteranges; boundary="+boundary)
|
||||||
respHeader.Del("Content-Length")
|
respHeader.Del("Content-Length")
|
||||||
contentType := respHeader.Get("Content-Type")
|
var contentType = respHeader.Get("Content-Type")
|
||||||
|
|
||||||
this.writer.WriteHeader(http.StatusPartialContent)
|
this.writer.WriteHeader(http.StatusPartialContent)
|
||||||
|
|
||||||
@@ -516,9 +519,9 @@ func (this *HTTPRequest) doCacheRead(useStale bool) (shouldStop bool) {
|
|||||||
|
|
||||||
var pool = this.bytePool(fileSize)
|
var pool = this.bytePool(fileSize)
|
||||||
var bodyBuf = pool.Get()
|
var bodyBuf = pool.Get()
|
||||||
err := reader.ReadBodyRange(bodyBuf, r.Start(), r.End(), func(n int) (goNext bool, err error) {
|
err = reader.ReadBodyRange(bodyBuf, r.Start(), r.End(), func(n int) (goNext bool, readErr error) {
|
||||||
_, err = this.writer.Write(bodyBuf[:n])
|
_, readErr = this.writer.Write(bodyBuf[:n])
|
||||||
if err != nil {
|
if readErr != nil {
|
||||||
return false, errWritingToClient
|
return false, errWritingToClient
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func (this *HTTPRequest) writeCode(statusCode int, enMessage string, zhMessage s
|
|||||||
return "${" + varName + "}"
|
return "${" + varName + "}"
|
||||||
})
|
})
|
||||||
|
|
||||||
this.processResponseHeaders(this.writer.Header(), statusCode)
|
this.ProcessResponseHeaders(this.writer.Header(), statusCode)
|
||||||
this.writer.WriteHeader(statusCode)
|
this.writer.WriteHeader(statusCode)
|
||||||
|
|
||||||
_, _ = this.writer.Write([]byte(pageContent))
|
_, _ = this.writer.Write([]byte(pageContent))
|
||||||
@@ -110,7 +110,7 @@ func (this *HTTPRequest) write50x(err error, statusCode int, enMessage string, z
|
|||||||
return "${" + varName + "}"
|
return "${" + varName + "}"
|
||||||
})
|
})
|
||||||
|
|
||||||
this.processResponseHeaders(this.writer.Header(), statusCode)
|
this.ProcessResponseHeaders(this.writer.Header(), statusCode)
|
||||||
this.writer.WriteHeader(statusCode)
|
this.writer.WriteHeader(statusCode)
|
||||||
|
|
||||||
_, _ = this.writer.Write([]byte(pageContent))
|
_, _ = this.writer.Write([]byte(pageContent))
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ func (this *HTTPRequest) doFastcgi() (shouldStop bool) {
|
|||||||
|
|
||||||
// 响应Header
|
// 响应Header
|
||||||
this.writer.AddHeaders(resp.Header)
|
this.writer.AddHeaders(resp.Header)
|
||||||
this.processResponseHeaders(this.writer.Header(), resp.StatusCode)
|
this.ProcessResponseHeaders(this.writer.Header(), resp.StatusCode)
|
||||||
|
|
||||||
// 准备
|
// 准备
|
||||||
this.writer.Prepare(resp, resp.ContentLength, resp.StatusCode, true)
|
this.writer.Prepare(resp, resp.ContentLength, resp.StatusCode, true)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func (this *HTTPRequest) doHostRedirect() (blocked bool) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processResponseHeaders(this.writer.Header(), status)
|
this.ProcessResponseHeaders(this.writer.Header(), status)
|
||||||
http.Redirect(this.RawWriter, this.RawReq, afterURL, status)
|
http.Redirect(this.RawWriter, this.RawReq, afterURL, status)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ func (this *HTTPRequest) doHostRedirect() (blocked bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processResponseHeaders(this.writer.Header(), status)
|
this.ProcessResponseHeaders(this.writer.Header(), status)
|
||||||
http.Redirect(this.RawWriter, this.RawReq, afterURL, status)
|
http.Redirect(this.RawWriter, this.RawReq, afterURL, status)
|
||||||
return true
|
return true
|
||||||
} else { // 精准匹配
|
} else { // 精准匹配
|
||||||
@@ -119,7 +119,7 @@ func (this *HTTPRequest) doHostRedirect() (blocked bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processResponseHeaders(this.writer.Header(), status)
|
this.ProcessResponseHeaders(this.writer.Header(), status)
|
||||||
http.Redirect(this.RawWriter, this.RawReq, afterURL, status)
|
http.Redirect(this.RawWriter, this.RawReq, afterURL, status)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ func (this *HTTPRequest) doHostRedirect() (blocked bool) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processResponseHeaders(this.writer.Header(), status)
|
this.ProcessResponseHeaders(this.writer.Header(), status)
|
||||||
|
|
||||||
// 参数
|
// 参数
|
||||||
var qIndex = strings.Index(this.uri, "?")
|
var qIndex = strings.Index(this.uri, "?")
|
||||||
@@ -211,7 +211,7 @@ func (this *HTTPRequest) doHostRedirect() (blocked bool) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processResponseHeaders(this.writer.Header(), status)
|
this.ProcessResponseHeaders(this.writer.Header(), status)
|
||||||
http.Redirect(this.RawWriter, this.RawReq, afterURL, status)
|
http.Redirect(this.RawWriter, this.RawReq, afterURL, status)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
10
internal/nodes/http_request_http3.go
Normal file
10
internal/nodes/http_request_http3.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
|
package nodes
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func (this *HTTPRequest) processHTTP3Headers(respHeader http.Header) {
|
||||||
|
// stub
|
||||||
|
}
|
||||||
@@ -12,6 +12,10 @@ const (
|
|||||||
LNExpiresHeader = "X-Edge-Ln-Expires"
|
LNExpiresHeader = "X-Edge-Ln-Expires"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func existsLnNodeIP(nodeIP string) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (this *HTTPRequest) checkLnRequest() bool {
|
func (this *HTTPRequest) checkLnRequest() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/ttlcache"
|
"github.com/TeaOSLab/EdgeNode/internal/ttlcache"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -32,7 +33,14 @@ func (this *HTTPRequest) doMismatch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 根据配置进行相应的处理
|
// 根据配置进行相应的处理
|
||||||
if sharedNodeConfig.GlobalServerConfig != nil && sharedNodeConfig.GlobalServerConfig.HTTPAll.MatchDomainStrictly {
|
var globalServerConfig = sharedNodeConfig.GlobalServerConfig
|
||||||
|
if globalServerConfig != nil && globalServerConfig.HTTPAll.MatchDomainStrictly {
|
||||||
|
// 是否正在访问IP
|
||||||
|
if globalServerConfig.HTTPAll.NodeIPShowPage && net.ParseIP(this.ReqHost) != nil {
|
||||||
|
_, _ = this.writer.WriteString(globalServerConfig.HTTPAll.NodeIPPageHTML)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 检查cc
|
// 检查cc
|
||||||
// TODO 可以在管理端配置是否开启以及最多尝试次数
|
// TODO 可以在管理端配置是否开启以及最多尝试次数
|
||||||
// 要考虑到服务在切换集群时,域名未生效状态时,用户访问的仍然是老集群中的节点,就会产生找不到域名的情况
|
// 要考虑到服务在切换集群时,域名未生效状态时,用户访问的仍然是老集群中的节点,就会产生找不到域名的情况
|
||||||
@@ -47,7 +55,7 @@ func (this *HTTPRequest) doMismatch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理当前连接
|
// 处理当前连接
|
||||||
var httpAllConfig = sharedNodeConfig.GlobalServerConfig.HTTPAll
|
var httpAllConfig = globalServerConfig.HTTPAll
|
||||||
var mismatchAction = httpAllConfig.DomainMismatchAction
|
var mismatchAction = httpAllConfig.DomainMismatchAction
|
||||||
if mismatchAction != nil && mismatchAction.Code == "page" {
|
if mismatchAction != nil && mismatchAction.Code == "page" {
|
||||||
if mismatchAction.Options != nil {
|
if mismatchAction.Options != nil {
|
||||||
|
|||||||
15
internal/nodes/http_request_oss.go
Normal file
15
internal/nodes/http_request_oss.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
|
package nodes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (this *HTTPRequest) doOSSOrigin(origin *serverconfigs.OriginConfig) (resp *http.Response, goNext bool, errorCode string, err error) {
|
||||||
|
// stub
|
||||||
|
return nil, false, "", errors.New("not implemented")
|
||||||
|
}
|
||||||
@@ -9,11 +9,8 @@ import (
|
|||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var urlPrefixRegexp = regexp.MustCompile("^(?i)(http|https|ftp)://")
|
|
||||||
|
|
||||||
// 请求特殊页面
|
// 请求特殊页面
|
||||||
func (this *HTTPRequest) doPage(status int) (shouldStop bool) {
|
func (this *HTTPRequest) doPage(status int) (shouldStop bool) {
|
||||||
if len(this.web.Pages) == 0 {
|
if len(this.web.Pages) == 0 {
|
||||||
@@ -49,7 +46,7 @@ func (this *HTTPRequest) doPageLookup(pages []*serverconfigs.HTTPPageConfig, sta
|
|||||||
for _, page := range pages {
|
for _, page := range pages {
|
||||||
if page.Match(status) {
|
if page.Match(status) {
|
||||||
if len(page.BodyType) == 0 || page.BodyType == shared.BodyTypeURL {
|
if len(page.BodyType) == 0 || page.BodyType == shared.BodyTypeURL {
|
||||||
if urlPrefixRegexp.MatchString(page.URL) {
|
if urlSchemeRegexp.MatchString(page.URL) {
|
||||||
var newStatus = page.NewStatus
|
var newStatus = page.NewStatus
|
||||||
if newStatus <= 0 {
|
if newStatus <= 0 {
|
||||||
newStatus = status
|
newStatus = status
|
||||||
@@ -87,11 +84,11 @@ func (this *HTTPRequest) doPageLookup(pages []*serverconfigs.HTTPPageConfig, sta
|
|||||||
// 修改状态码
|
// 修改状态码
|
||||||
if page.NewStatus > 0 {
|
if page.NewStatus > 0 {
|
||||||
// 自定义响应Headers
|
// 自定义响应Headers
|
||||||
this.processResponseHeaders(this.writer.Header(), page.NewStatus)
|
this.ProcessResponseHeaders(this.writer.Header(), page.NewStatus)
|
||||||
this.writer.Prepare(nil, stat.Size(), page.NewStatus, true)
|
this.writer.Prepare(nil, stat.Size(), page.NewStatus, true)
|
||||||
this.writer.WriteHeader(page.NewStatus)
|
this.writer.WriteHeader(page.NewStatus)
|
||||||
} else {
|
} else {
|
||||||
this.processResponseHeaders(this.writer.Header(), status)
|
this.ProcessResponseHeaders(this.writer.Header(), status)
|
||||||
this.writer.Prepare(nil, stat.Size(), status, true)
|
this.writer.Prepare(nil, stat.Size(), status, true)
|
||||||
this.writer.WriteHeader(status)
|
this.writer.WriteHeader(status)
|
||||||
}
|
}
|
||||||
@@ -126,11 +123,11 @@ func (this *HTTPRequest) doPageLookup(pages []*serverconfigs.HTTPPageConfig, sta
|
|||||||
// 修改状态码
|
// 修改状态码
|
||||||
if page.NewStatus > 0 {
|
if page.NewStatus > 0 {
|
||||||
// 自定义响应Headers
|
// 自定义响应Headers
|
||||||
this.processResponseHeaders(this.writer.Header(), page.NewStatus)
|
this.ProcessResponseHeaders(this.writer.Header(), page.NewStatus)
|
||||||
this.writer.Prepare(nil, int64(len(content)), page.NewStatus, true)
|
this.writer.Prepare(nil, int64(len(content)), page.NewStatus, true)
|
||||||
this.writer.WriteHeader(page.NewStatus)
|
this.writer.WriteHeader(page.NewStatus)
|
||||||
} else {
|
} else {
|
||||||
this.processResponseHeaders(this.writer.Header(), status)
|
this.ProcessResponseHeaders(this.writer.Header(), status)
|
||||||
this.writer.Prepare(nil, int64(len(content)), status, true)
|
this.writer.Prepare(nil, int64(len(content)), status, true)
|
||||||
this.writer.WriteHeader(status)
|
this.writer.WriteHeader(status)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ func (this *HTTPRequest) doPlanExpires() {
|
|||||||
this.tags = append(this.tags, "plan")
|
this.tags = append(this.tags, "plan")
|
||||||
|
|
||||||
var statusCode = http.StatusNotFound
|
var statusCode = http.StatusNotFound
|
||||||
this.processResponseHeaders(this.writer.Header(), statusCode)
|
this.ProcessResponseHeaders(this.writer.Header(), statusCode)
|
||||||
|
|
||||||
this.writer.WriteHeader(statusCode)
|
this.writer.WriteHeader(statusCode)
|
||||||
_, _ = this.writer.WriteString(this.Format(serverconfigs.DefaultPlanExpireNoticePageBody))
|
_, _ = this.writer.WriteString(this.Format(serverconfigs.DefaultPlanExpireNoticePageBody))
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func (this *HTTPRequest) doRedirectToHTTPS(redirectToHTTPSConfig *serverconfigs.
|
|||||||
}
|
}
|
||||||
|
|
||||||
var newURL = "https://" + host + this.RawReq.RequestURI
|
var newURL = "https://" + host + this.RawReq.RequestURI
|
||||||
this.processResponseHeaders(this.writer.Header(), statusCode)
|
this.ProcessResponseHeaders(this.writer.Header(), statusCode)
|
||||||
http.Redirect(this.writer, this.RawReq, newURL, statusCode)
|
http.Redirect(this.writer, this.RawReq, newURL, statusCode)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -12,13 +12,29 @@ func (this *HTTPRequest) doCheckReferers() (shouldStop bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var origin = this.RawReq.Header.Get("Origin")
|
||||||
|
|
||||||
const cacheSeconds = "3600" // 时间不能过长,防止修改设置后长期无法生效
|
const cacheSeconds = "3600" // 时间不能过长,防止修改设置后长期无法生效
|
||||||
|
|
||||||
|
// 处理用到Origin的特殊功能
|
||||||
|
if this.web.Referers.CheckOrigin && len(origin) > 0 {
|
||||||
|
// 处理Websocket
|
||||||
|
if this.web.Websocket != nil && this.web.Websocket.IsOn && this.RawReq.Header.Get("Upgrade") == "websocket" {
|
||||||
|
originHost, _ := httpParseHost(origin)
|
||||||
|
if len(originHost) > 0 && this.web.Websocket.MatchOrigin(originHost) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var refererURL = this.RawReq.Header.Get("Referer")
|
var refererURL = this.RawReq.Header.Get("Referer")
|
||||||
if len(refererURL) == 0 && this.web.Referers.CheckOrigin {
|
if len(refererURL) == 0 && this.web.Referers.CheckOrigin {
|
||||||
var origin = this.RawReq.Header.Get("Origin")
|
|
||||||
if len(origin) > 0 && origin != "null" {
|
if len(origin) > 0 && origin != "null" {
|
||||||
refererURL = "https://" + origin // 因为Origin都只有域名部分,所以为了下面的URL 分析需要加上https://
|
if urlSchemeRegexp.MatchString(origin) {
|
||||||
|
refererURL = origin
|
||||||
|
} else {
|
||||||
|
refererURL = "https://" + origin
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,19 +66,21 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
|
|
||||||
// 二级节点
|
// 二级节点
|
||||||
var hasMultipleLnNodes = false
|
var hasMultipleLnNodes = false
|
||||||
if this.cacheRef != nil {
|
if this.cacheRef != nil || (this.nodeConfig != nil && this.nodeConfig.GlobalServerConfig != nil && this.nodeConfig.GlobalServerConfig.HTTPAll.ForceLnRequest) {
|
||||||
origin, lnNodeId, hasMultipleLnNodes = this.getLnOrigin(failedLnNodeIds)
|
origin, lnNodeId, hasMultipleLnNodes = this.getLnOrigin(failedLnNodeIds)
|
||||||
if origin != nil {
|
if origin != nil {
|
||||||
// 强制变更原来访问的域名
|
// 强制变更原来访问的域名
|
||||||
requestHost = this.ReqHost
|
requestHost = this.ReqHost
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回源Header中去除If-None-Match和If-Modified-Since
|
if this.cacheRef != nil {
|
||||||
if !this.cacheRef.EnableIfNoneMatch {
|
// 回源Header中去除If-None-Match和If-Modified-Since
|
||||||
this.DeleteHeader("If-None-Match")
|
if !this.cacheRef.EnableIfNoneMatch {
|
||||||
}
|
this.DeleteHeader("If-None-Match")
|
||||||
if !this.cacheRef.EnableIfModifiedSince {
|
}
|
||||||
this.DeleteHeader("If-Modified-Since")
|
if !this.cacheRef.EnableIfModifiedSince {
|
||||||
|
this.DeleteHeader("If-Modified-Since")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,14 +117,20 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
requestHostHasVariables = origin.RequestHostHasVariables()
|
requestHostHasVariables = origin.RequestHostHasVariables()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理OSS
|
||||||
|
var isHTTPOrigin = origin.OSS == nil
|
||||||
|
|
||||||
// 处理Scheme
|
// 处理Scheme
|
||||||
if origin.Addr == nil {
|
if isHTTPOrigin && origin.Addr == nil {
|
||||||
err := errors.New(this.URL() + ": Origin '" + strconv.FormatInt(origin.Id, 10) + "' does not has a address")
|
err := errors.New(this.URL() + ": Origin '" + strconv.FormatInt(origin.Id, 10) + "' does not has a address")
|
||||||
remotelogs.ErrorServer("HTTP_REQUEST_REVERSE_PROXY", err.Error())
|
remotelogs.ErrorServer("HTTP_REQUEST_REVERSE_PROXY", err.Error())
|
||||||
this.write50x(err, http.StatusBadGateway, "Origin site did not has a valid address", "源站尚未配置地址", true)
|
this.write50x(err, http.StatusBadGateway, "Origin site did not has a valid address", "源站尚未配置地址", true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.RawReq.URL.Scheme = origin.Addr.Protocol.Primary().Scheme()
|
|
||||||
|
if isHTTPOrigin {
|
||||||
|
this.RawReq.URL.Scheme = origin.Addr.Protocol.Primary().Scheme()
|
||||||
|
}
|
||||||
|
|
||||||
// StripPrefix
|
// StripPrefix
|
||||||
if len(stripPrefix) > 0 {
|
if len(stripPrefix) > 0 {
|
||||||
@@ -159,63 +167,66 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
this.uri = utils.CleanPath(this.uri)
|
this.uri = utils.CleanPath(this.uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取源站地址
|
var originAddr = ""
|
||||||
var originAddr = origin.Addr.PickAddress()
|
if isHTTPOrigin {
|
||||||
if origin.Addr.HostHasVariables() {
|
// 获取源站地址
|
||||||
originAddr = this.Format(originAddr)
|
originAddr = origin.Addr.PickAddress()
|
||||||
}
|
if origin.Addr.HostHasVariables() {
|
||||||
|
originAddr = this.Format(originAddr)
|
||||||
// 端口跟随
|
|
||||||
if origin.FollowPort {
|
|
||||||
var originHostIndex = strings.Index(originAddr, ":")
|
|
||||||
if originHostIndex < 0 {
|
|
||||||
var originErr = errors.New(this.URL() + ": Invalid origin address '" + originAddr + "', lacking port")
|
|
||||||
remotelogs.ErrorServer("HTTP_REQUEST_REVERSE_PROXY", originErr.Error())
|
|
||||||
this.write50x(originErr, http.StatusBadGateway, "No port in origin site address", "源站地址中没有配置端口", true)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
originAddr = originAddr[:originHostIndex+1] + types.String(this.requestServerPort())
|
|
||||||
}
|
|
||||||
this.originAddr = originAddr
|
|
||||||
|
|
||||||
// RequestHost
|
// 端口跟随
|
||||||
if len(requestHost) > 0 {
|
if origin.FollowPort {
|
||||||
if requestHostHasVariables {
|
var originHostIndex = strings.Index(originAddr, ":")
|
||||||
this.RawReq.Host = this.Format(requestHost)
|
if originHostIndex < 0 {
|
||||||
|
var originErr = errors.New(this.URL() + ": Invalid origin address '" + originAddr + "', lacking port")
|
||||||
|
remotelogs.ErrorServer("HTTP_REQUEST_REVERSE_PROXY", originErr.Error())
|
||||||
|
this.write50x(originErr, http.StatusBadGateway, "No port in origin site address", "源站地址中没有配置端口", true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
originAddr = originAddr[:originHostIndex+1] + types.String(this.requestServerPort())
|
||||||
|
}
|
||||||
|
this.originAddr = originAddr
|
||||||
|
|
||||||
|
// RequestHost
|
||||||
|
if len(requestHost) > 0 {
|
||||||
|
if requestHostHasVariables {
|
||||||
|
this.RawReq.Host = this.Format(requestHost)
|
||||||
|
} else {
|
||||||
|
this.RawReq.Host = requestHost
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否移除端口
|
||||||
|
if this.reverseProxy.RequestHostExcludingPort {
|
||||||
|
this.RawReq.Host = utils.ParseAddrHost(this.RawReq.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.RawReq.URL.Host = this.RawReq.Host
|
||||||
|
} else if this.reverseProxy.RequestHostType == serverconfigs.RequestHostTypeOrigin {
|
||||||
|
// 源站主机名
|
||||||
|
var hostname = originAddr
|
||||||
|
if origin.Addr.Protocol.IsHTTPFamily() {
|
||||||
|
hostname = strings.TrimSuffix(hostname, ":80")
|
||||||
|
} else if origin.Addr.Protocol.IsHTTPSFamily() {
|
||||||
|
hostname = strings.TrimSuffix(hostname, ":443")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.RawReq.Host = hostname
|
||||||
|
|
||||||
|
// 是否移除端口
|
||||||
|
if this.reverseProxy.RequestHostExcludingPort {
|
||||||
|
this.RawReq.Host = utils.ParseAddrHost(this.RawReq.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.RawReq.URL.Host = this.RawReq.Host
|
||||||
} else {
|
} else {
|
||||||
this.RawReq.Host = requestHost
|
this.RawReq.URL.Host = this.ReqHost
|
||||||
}
|
|
||||||
|
|
||||||
// 是否移除端口
|
// 是否移除端口
|
||||||
if this.reverseProxy.RequestHostExcludingPort {
|
if this.reverseProxy.RequestHostExcludingPort {
|
||||||
this.RawReq.Host = utils.ParseAddrHost(this.RawReq.Host)
|
this.RawReq.Host = utils.ParseAddrHost(this.RawReq.Host)
|
||||||
}
|
this.RawReq.URL.Host = utils.ParseAddrHost(this.RawReq.URL.Host)
|
||||||
|
}
|
||||||
this.RawReq.URL.Host = this.RawReq.Host
|
|
||||||
} else if this.reverseProxy.RequestHostType == serverconfigs.RequestHostTypeOrigin {
|
|
||||||
// 源站主机名
|
|
||||||
var hostname = originAddr
|
|
||||||
if origin.Addr.Protocol.IsHTTPFamily() {
|
|
||||||
hostname = strings.TrimSuffix(hostname, ":80")
|
|
||||||
} else if origin.Addr.Protocol.IsHTTPSFamily() {
|
|
||||||
hostname = strings.TrimSuffix(hostname, ":443")
|
|
||||||
}
|
|
||||||
|
|
||||||
this.RawReq.Host = hostname
|
|
||||||
|
|
||||||
// 是否移除端口
|
|
||||||
if this.reverseProxy.RequestHostExcludingPort {
|
|
||||||
this.RawReq.Host = utils.ParseAddrHost(this.RawReq.Host)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.RawReq.URL.Host = this.RawReq.Host
|
|
||||||
} else {
|
|
||||||
this.RawReq.URL.Host = this.ReqHost
|
|
||||||
|
|
||||||
// 是否移除端口
|
|
||||||
if this.reverseProxy.RequestHostExcludingPort {
|
|
||||||
this.RawReq.Host = utils.ParseAddrHost(this.RawReq.Host)
|
|
||||||
this.RawReq.URL.Host = utils.ParseAddrHost(this.RawReq.URL.Host)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,34 +252,72 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否为Websocket请求
|
// 判断是否为Websocket请求
|
||||||
if this.RawReq.Header.Get("Upgrade") == "websocket" {
|
if isHTTPOrigin && this.RawReq.Header.Get("Upgrade") == "websocket" {
|
||||||
shouldRetry = this.doWebsocket(requestHost, isLastRetry)
|
shouldRetry = this.doWebsocket(requestHost, isLastRetry)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取请求客户端
|
var resp *http.Response
|
||||||
client, err := SharedHTTPClientPool.Client(this, origin, originAddr, this.reverseProxy.ProxyProtocol, this.reverseProxy.FollowRedirects)
|
var requestErr error
|
||||||
if err != nil {
|
var requestErrCode string
|
||||||
remotelogs.ErrorServer("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Create client failed: "+err.Error())
|
if isHTTPOrigin { // 普通HTTP(S)源站
|
||||||
this.write50x(err, http.StatusBadGateway, "Failed to create origin site client", "构造源站客户端失败", true)
|
// 修复空User-Agent问题
|
||||||
|
_, existsUserAgent := this.RawReq.Header["User-Agent"]
|
||||||
|
if !existsUserAgent {
|
||||||
|
this.RawReq.Header["User-Agent"] = []string{""}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取请求客户端
|
||||||
|
client, err := SharedHTTPClientPool.Client(this, origin, originAddr, this.reverseProxy.ProxyProtocol, this.reverseProxy.FollowRedirects)
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.ErrorServer("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Create client failed: "+err.Error())
|
||||||
|
this.write50x(err, http.StatusBadGateway, "Failed to create origin site client", "构造源站客户端失败", true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试自动纠正源站地址中的scheme
|
||||||
|
if this.RawReq.URL.Scheme == "http" && strings.HasSuffix(originAddr, ":443") {
|
||||||
|
this.RawReq.URL.Scheme = "https"
|
||||||
|
} else if this.RawReq.URL.Scheme == "https" && strings.HasSuffix(originAddr, ":80") {
|
||||||
|
this.RawReq.URL.Scheme = "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始请求
|
||||||
|
resp, requestErr = client.Do(this.RawReq)
|
||||||
|
} else if origin.OSS != nil { // OSS源站
|
||||||
|
var goNext bool
|
||||||
|
resp, goNext, requestErrCode, requestErr = this.doOSSOrigin(origin)
|
||||||
|
if requestErr == nil {
|
||||||
|
if resp == nil || !goNext {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.writeCode(http.StatusBadGateway, "The type of origin site has not been supported", "设置的源站类型尚未支持")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if requestErr != nil {
|
||||||
// 开始请求
|
|
||||||
resp, err := client.Do(this.RawReq)
|
|
||||||
if err != nil {
|
|
||||||
// 客户端取消请求,则不提示
|
// 客户端取消请求,则不提示
|
||||||
httpErr, ok := err.(*url.Error)
|
httpErr, ok := requestErr.(*url.Error)
|
||||||
if !ok {
|
if !ok {
|
||||||
SharedOriginStateManager.Fail(origin, requestHost, this.reverseProxy, func() {
|
if isHTTPOrigin {
|
||||||
this.reverseProxy.ResetScheduling()
|
SharedOriginStateManager.Fail(origin, requestHost, this.reverseProxy, func() {
|
||||||
})
|
this.reverseProxy.ResetScheduling()
|
||||||
this.write50x(err, http.StatusBadGateway, "Failed to read origin site", "源站读取失败", true)
|
})
|
||||||
remotelogs.WarnServer("HTTP_REQUEST_REVERSE_PROXY", this.RawReq.URL.String()+": Request origin server failed: "+err.Error())
|
}
|
||||||
|
|
||||||
|
if len(requestErrCode) > 0 {
|
||||||
|
this.write50x(requestErr, http.StatusBadGateway, "Failed to read origin site (error code: "+requestErrCode+")", "源站读取失败(错误代号:"+requestErrCode+")", true)
|
||||||
|
} else {
|
||||||
|
this.write50x(requestErr, http.StatusBadGateway, "Failed to read origin site", "源站读取失败", true)
|
||||||
|
}
|
||||||
|
remotelogs.WarnServer("HTTP_REQUEST_REVERSE_PROXY", this.RawReq.URL.String()+": Request origin server failed: "+requestErr.Error())
|
||||||
} else if httpErr.Err != context.Canceled {
|
} else if httpErr.Err != context.Canceled {
|
||||||
SharedOriginStateManager.Fail(origin, requestHost, this.reverseProxy, func() {
|
if isHTTPOrigin {
|
||||||
this.reverseProxy.ResetScheduling()
|
SharedOriginStateManager.Fail(origin, requestHost, this.reverseProxy, func() {
|
||||||
})
|
this.reverseProxy.ResetScheduling()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 是否需要重试
|
// 是否需要重试
|
||||||
if (originId > 0 || (lnNodeId > 0 && hasMultipleLnNodes)) && !isLastRetry {
|
if (originId > 0 || (lnNodeId > 0 && hasMultipleLnNodes)) && !isLastRetry {
|
||||||
@@ -280,21 +329,21 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
}
|
}
|
||||||
|
|
||||||
if httpErr.Err != io.EOF {
|
if httpErr.Err != io.EOF {
|
||||||
remotelogs.WarnServer("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Request origin server failed: "+err.Error())
|
remotelogs.WarnServer("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Request origin server failed: "+requestErr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if httpErr.Timeout() {
|
if httpErr.Timeout() {
|
||||||
this.write50x(err, http.StatusGatewayTimeout, "Read origin site timeout", "源站读取超时", true)
|
this.write50x(requestErr, http.StatusGatewayTimeout, "Read origin site timeout", "源站读取超时", true)
|
||||||
} else if httpErr.Temporary() {
|
} else if httpErr.Temporary() {
|
||||||
this.write50x(err, http.StatusServiceUnavailable, "Origin site unavailable now", "源站当前不可用", true)
|
this.write50x(requestErr, http.StatusServiceUnavailable, "Origin site unavailable now", "源站当前不可用", true)
|
||||||
} else {
|
} else {
|
||||||
this.write50x(err, http.StatusBadGateway, "Failed to read origin site", "源站读取失败", true)
|
this.write50x(requestErr, http.StatusBadGateway, "Failed to read origin site", "源站读取失败", true)
|
||||||
}
|
}
|
||||||
if httpErr.Err != io.EOF {
|
if httpErr.Err != io.EOF {
|
||||||
remotelogs.WarnServer("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Request origin server failed: "+err.Error())
|
remotelogs.WarnServer("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Request origin server failed: "+requestErr.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 是否为客户端方面的错误
|
// 是否为客户端方面的错误
|
||||||
@@ -314,7 +363,7 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !isClientError {
|
if !isClientError {
|
||||||
this.write50x(err, http.StatusBadGateway, "Failed to read origin site", "源站读取失败", true)
|
this.write50x(requestErr, http.StatusBadGateway, "Failed to read origin site", "源站读取失败", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if resp != nil && resp.Body != nil {
|
if resp != nil && resp.Body != nil {
|
||||||
@@ -337,7 +386,7 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
this.originStatus = int32(resp.StatusCode)
|
this.originStatus = int32(resp.StatusCode)
|
||||||
|
|
||||||
// 恢复源站状态
|
// 恢复源站状态
|
||||||
if !origin.IsOk {
|
if !origin.IsOk && isHTTPOrigin {
|
||||||
SharedOriginStateManager.Success(origin, func() {
|
SharedOriginStateManager.Success(origin, func() {
|
||||||
this.reverseProxy.ResetScheduling()
|
this.reverseProxy.ResetScheduling()
|
||||||
})
|
})
|
||||||
@@ -346,7 +395,7 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
// WAF对出站进行检查
|
// WAF对出站进行检查
|
||||||
if this.web.FirewallRef != nil && this.web.FirewallRef.IsOn {
|
if this.web.FirewallRef != nil && this.web.FirewallRef.IsOn {
|
||||||
if this.doWAFResponse(resp) {
|
if this.doWAFResponse(resp) {
|
||||||
err = resp.Body.Close()
|
err := resp.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.WarnServer("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Closing Error (WAF): "+err.Error())
|
remotelogs.WarnServer("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Closing Error (WAF): "+err.Error())
|
||||||
}
|
}
|
||||||
@@ -356,7 +405,7 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
|
|
||||||
// 特殊页面
|
// 特殊页面
|
||||||
if len(this.web.Pages) > 0 && this.doPage(resp.StatusCode) {
|
if len(this.web.Pages) > 0 && this.doPage(resp.StatusCode) {
|
||||||
err = resp.Body.Close()
|
err := resp.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.WarnServer("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Closing error (Page): "+err.Error())
|
remotelogs.WarnServer("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Closing error (Page): "+err.Error())
|
||||||
}
|
}
|
||||||
@@ -409,7 +458,7 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
|
|
||||||
// 响应Header
|
// 响应Header
|
||||||
this.writer.AddHeaders(resp.Header)
|
this.writer.AddHeaders(resp.Header)
|
||||||
this.processResponseHeaders(this.writer.Header(), resp.StatusCode)
|
this.ProcessResponseHeaders(this.writer.Header(), resp.StatusCode)
|
||||||
|
|
||||||
// 是否需要刷新
|
// 是否需要刷新
|
||||||
var shouldAutoFlush = this.reverseProxy.AutoFlush || this.RawReq.Header.Get("Accept") == "text/event-stream"
|
var shouldAutoFlush = this.reverseProxy.AutoFlush || this.RawReq.Header.Get("Accept") == "text/event-stream"
|
||||||
@@ -437,6 +486,7 @@ func (this *HTTPRequest) doOriginRequest(failedOriginIds []int64, failedLnNodeId
|
|||||||
// 输出到客户端
|
// 输出到客户端
|
||||||
var pool = this.bytePool(resp.ContentLength)
|
var pool = this.bytePool(resp.ContentLength)
|
||||||
var buf = pool.Get()
|
var buf = pool.Get()
|
||||||
|
var err error
|
||||||
if shouldAutoFlush {
|
if shouldAutoFlush {
|
||||||
for {
|
for {
|
||||||
n, readErr := resp.Body.Read(buf)
|
n, readErr := resp.Body.Read(buf)
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ func (this *HTTPRequest) doRewrite() (shouldShop bool) {
|
|||||||
// 跳转
|
// 跳转
|
||||||
if this.rewriteRule.Mode == serverconfigs.HTTPRewriteModeRedirect {
|
if this.rewriteRule.Mode == serverconfigs.HTTPRewriteModeRedirect {
|
||||||
if this.rewriteRule.RedirectStatus > 0 {
|
if this.rewriteRule.RedirectStatus > 0 {
|
||||||
this.processResponseHeaders(this.writer.Header(), this.rewriteRule.RedirectStatus)
|
this.ProcessResponseHeaders(this.writer.Header(), this.rewriteRule.RedirectStatus)
|
||||||
http.Redirect(this.writer, this.RawReq, this.rewriteReplace, this.rewriteRule.RedirectStatus)
|
http.Redirect(this.writer, this.RawReq, this.rewriteReplace, this.rewriteRule.RedirectStatus)
|
||||||
} else {
|
} else {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusTemporaryRedirect)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusTemporaryRedirect)
|
||||||
http.Redirect(this.writer, this.RawReq, this.rewriteReplace, http.StatusTemporaryRedirect)
|
http.Redirect(this.writer, this.RawReq, this.rewriteReplace, http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
// 支持 If-None-Match
|
// 支持 If-None-Match
|
||||||
if this.requestHeader("If-None-Match") == eTag {
|
if this.requestHeader("If-None-Match") == eTag {
|
||||||
// 自定义Header
|
// 自定义Header
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusNotModified)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusNotModified)
|
||||||
this.writer.WriteHeader(http.StatusNotModified)
|
this.writer.WriteHeader(http.StatusNotModified)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -225,7 +225,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
// 支持 If-Modified-Since
|
// 支持 If-Modified-Since
|
||||||
if this.requestHeader("If-Modified-Since") == modifiedTime {
|
if this.requestHeader("If-Modified-Since") == modifiedTime {
|
||||||
// 自定义Header
|
// 自定义Header
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusNotModified)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusNotModified)
|
||||||
this.writer.WriteHeader(http.StatusNotModified)
|
this.writer.WriteHeader(http.StatusNotModified)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -253,14 +253,14 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
var contentRange = this.RawReq.Header.Get("Range")
|
var contentRange = this.RawReq.Header.Get("Range")
|
||||||
if len(contentRange) > 0 {
|
if len(contentRange) > 0 {
|
||||||
if fileSize == 0 {
|
if fileSize == 0 {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
||||||
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
set, ok := httpRequestParseRangeHeader(contentRange)
|
set, ok := httpRequestParseRangeHeader(contentRange)
|
||||||
if !ok {
|
if !ok {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
||||||
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -269,7 +269,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
for k, r := range ranges {
|
for k, r := range ranges {
|
||||||
r2, ok := r.Convert(fileSize)
|
r2, ok := r.Convert(fileSize)
|
||||||
if !ok {
|
if !ok {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
||||||
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -290,7 +290,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 自定义Header
|
// 自定义Header
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusOK)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusOK)
|
||||||
|
|
||||||
// 在Range请求中不能缓存
|
// 在Range请求中不能缓存
|
||||||
if len(ranges) > 0 {
|
if len(ranges) > 0 {
|
||||||
@@ -325,7 +325,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
||||||
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -377,7 +377,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusRequestedRangeNotSatisfiable)
|
||||||
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
this.writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func (this *HTTPRequest) doShutdown() {
|
|||||||
|
|
||||||
if len(shutdown.BodyType) == 0 || shutdown.BodyType == shared.BodyTypeURL {
|
if len(shutdown.BodyType) == 0 || shutdown.BodyType == shared.BodyTypeURL {
|
||||||
// URL
|
// URL
|
||||||
if urlPrefixRegexp.MatchString(shutdown.URL) {
|
if urlSchemeRegexp.MatchString(shutdown.URL) {
|
||||||
this.doURL(http.MethodGet, shutdown.URL, "", shutdown.Status, true)
|
this.doURL(http.MethodGet, shutdown.URL, "", shutdown.Status, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -28,10 +28,10 @@ func (this *HTTPRequest) doShutdown() {
|
|||||||
if len(shutdown.URL) == 0 {
|
if len(shutdown.URL) == 0 {
|
||||||
// 自定义响应Headers
|
// 自定义响应Headers
|
||||||
if shutdown.Status > 0 {
|
if shutdown.Status > 0 {
|
||||||
this.processResponseHeaders(this.writer.Header(), shutdown.Status)
|
this.ProcessResponseHeaders(this.writer.Header(), shutdown.Status)
|
||||||
this.writer.WriteHeader(shutdown.Status)
|
this.writer.WriteHeader(shutdown.Status)
|
||||||
} else {
|
} else {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusOK)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusOK)
|
||||||
this.writer.WriteHeader(http.StatusOK)
|
this.writer.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
_, err := this.writer.WriteString("The site have been shutdown.")
|
_, err := this.writer.WriteString("The site have been shutdown.")
|
||||||
@@ -59,10 +59,10 @@ func (this *HTTPRequest) doShutdown() {
|
|||||||
|
|
||||||
// 自定义响应Headers
|
// 自定义响应Headers
|
||||||
if shutdown.Status > 0 {
|
if shutdown.Status > 0 {
|
||||||
this.processResponseHeaders(this.writer.Header(), shutdown.Status)
|
this.ProcessResponseHeaders(this.writer.Header(), shutdown.Status)
|
||||||
this.writer.WriteHeader(shutdown.Status)
|
this.writer.WriteHeader(shutdown.Status)
|
||||||
} else {
|
} else {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusOK)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusOK)
|
||||||
this.writer.WriteHeader(http.StatusOK)
|
this.writer.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
buf := utils.BytePool1k.Get()
|
buf := utils.BytePool1k.Get()
|
||||||
@@ -85,10 +85,10 @@ func (this *HTTPRequest) doShutdown() {
|
|||||||
} else if shutdown.BodyType == shared.BodyTypeHTML {
|
} else if shutdown.BodyType == shared.BodyTypeHTML {
|
||||||
// 自定义响应Headers
|
// 自定义响应Headers
|
||||||
if shutdown.Status > 0 {
|
if shutdown.Status > 0 {
|
||||||
this.processResponseHeaders(this.writer.Header(), shutdown.Status)
|
this.ProcessResponseHeaders(this.writer.Header(), shutdown.Status)
|
||||||
this.writer.WriteHeader(shutdown.Status)
|
this.writer.WriteHeader(shutdown.Status)
|
||||||
} else {
|
} else {
|
||||||
this.processResponseHeaders(this.writer.Header(), http.StatusOK)
|
this.ProcessResponseHeaders(this.writer.Header(), http.StatusOK)
|
||||||
this.writer.WriteHeader(http.StatusOK)
|
this.writer.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ func (this *HTTPRequest) doTrafficLimit() {
|
|||||||
this.tags = append(this.tags, "bandwidth")
|
this.tags = append(this.tags, "bandwidth")
|
||||||
|
|
||||||
var statusCode = 509
|
var statusCode = 509
|
||||||
this.processResponseHeaders(this.writer.Header(), statusCode)
|
this.ProcessResponseHeaders(this.writer.Header(), statusCode)
|
||||||
|
|
||||||
this.writer.WriteHeader(statusCode)
|
this.writer.WriteHeader(statusCode)
|
||||||
if len(config.NoticePageBody) != 0 {
|
if len(config.NoticePageBody) != 0 {
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ func (this *HTTPRequest) doURL(method string, url string, host string, statusCod
|
|||||||
|
|
||||||
// Header
|
// Header
|
||||||
if statusCode <= 0 {
|
if statusCode <= 0 {
|
||||||
this.processResponseHeaders(this.writer.Header(), resp.StatusCode)
|
this.ProcessResponseHeaders(this.writer.Header(), resp.StatusCode)
|
||||||
} else {
|
} else {
|
||||||
this.processResponseHeaders(this.writer.Header(), statusCode)
|
this.ProcessResponseHeaders(this.writer.Header(), statusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if supportVariables {
|
if supportVariables {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -22,6 +23,9 @@ var spiderRegexp = regexp.MustCompile(`(?i)(python|pycurl|http-client|httpclient
|
|||||||
// 内容范围正则,其中的每个括号里的内容都在被引用,不能轻易修改
|
// 内容范围正则,其中的每个括号里的内容都在被引用,不能轻易修改
|
||||||
var contentRangeRegexp = regexp.MustCompile(`^bytes (\d+)-(\d+)/(\d+|\*)`)
|
var contentRangeRegexp = regexp.MustCompile(`^bytes (\d+)-(\d+)/(\d+|\*)`)
|
||||||
|
|
||||||
|
// URL协议前缀
|
||||||
|
var urlSchemeRegexp = regexp.MustCompile("^(?i)(http|https|ftp)://")
|
||||||
|
|
||||||
// 分解Range
|
// 分解Range
|
||||||
func httpRequestParseRangeHeader(rangeValue string) (result []rangeutils.Range, ok bool) {
|
func httpRequestParseRangeHeader(rangeValue string) (result []rangeutils.Range, ok bool) {
|
||||||
// 参考RFC:https://tools.ietf.org/html/rfc7233
|
// 参考RFC:https://tools.ietf.org/html/rfc7233
|
||||||
@@ -222,3 +226,16 @@ func httpRedirect(writer http.ResponseWriter, req *http.Request, url string, cod
|
|||||||
|
|
||||||
http.Redirect(writer, req, url, code)
|
http.Redirect(writer, req, url, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分析URL中的Host部分
|
||||||
|
func httpParseHost(urlString string) (host string, err error) {
|
||||||
|
if !urlSchemeRegexp.MatchString(urlString) {
|
||||||
|
urlString = "https://" + urlString
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(urlString)
|
||||||
|
if err != nil && u != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return u.Host, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -145,6 +145,23 @@ func TestHTTPRequest_httpRequestNextId_Concurrent(t *testing.T) {
|
|||||||
a.IsTrue(countDuplicated == 0)
|
a.IsTrue(countDuplicated == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHTTPParseURL(t *testing.T) {
|
||||||
|
for _, s := range []string{
|
||||||
|
"",
|
||||||
|
"null",
|
||||||
|
"example.com",
|
||||||
|
"https://example.com",
|
||||||
|
"https://example.com/hello",
|
||||||
|
} {
|
||||||
|
host, err := httpParseHost(s)
|
||||||
|
if err == nil {
|
||||||
|
t.Log(s, "=>", host)
|
||||||
|
} else {
|
||||||
|
t.Log(s, "=>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkHTTPRequest_httpRequestNextId(b *testing.B) {
|
func BenchmarkHTTPRequest_httpRequestNextId(b *testing.B) {
|
||||||
runtime.GOMAXPROCS(1)
|
runtime.GOMAXPROCS(1)
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ func (this *HTTPRequest) doWebsocket(requestHost string, isLastRetry bool) (shou
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processResponseHeaders(resp.Header, resp.StatusCode)
|
this.ProcessResponseHeaders(resp.Header, resp.StatusCode)
|
||||||
this.writer.statusCode = resp.StatusCode
|
this.writer.statusCode = resp.StatusCode
|
||||||
|
|
||||||
// 将响应写回客户端
|
// 将响应写回客户端
|
||||||
|
|||||||
@@ -362,7 +362,10 @@ func (this *HTTPWriter) PrepareCache(resp *http.Response, size int64) {
|
|||||||
// 写入Header
|
// 写入Header
|
||||||
var headerBuf = utils.SharedBufferPool.Get()
|
var headerBuf = utils.SharedBufferPool.Get()
|
||||||
for k, v := range this.Header() {
|
for k, v := range this.Header() {
|
||||||
if k == "Set-Cookie" || (this.isPartial && k == "Content-Range") {
|
if k == "Set-Cookie" ||
|
||||||
|
k == "Strict-Transport-Security" ||
|
||||||
|
k == "Alt-Svc" ||
|
||||||
|
(this.isPartial && k == "Content-Range") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, v1 := range v {
|
for _, v1 := range v {
|
||||||
@@ -690,7 +693,10 @@ func (this *HTTPWriter) PrepareCompression(resp *http.Response, size int64) {
|
|||||||
// 写入Header
|
// 写入Header
|
||||||
var headerBuffer = utils.SharedBufferPool.Get()
|
var headerBuffer = utils.SharedBufferPool.Get()
|
||||||
for k, v := range this.Header() {
|
for k, v := range this.Header() {
|
||||||
if k == "Set-Cookie" || (this.isPartial && k == "Content-Range") {
|
if k == "Set-Cookie" ||
|
||||||
|
k == "Strict-Transport-Security" ||
|
||||||
|
k == "Alt-Svc" ||
|
||||||
|
(this.isPartial && k == "Content-Range") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, v1 := range v {
|
for _, v1 := range v {
|
||||||
@@ -837,6 +843,14 @@ func (this *HTTPWriter) WriteHeader(statusCode int) {
|
|||||||
|
|
||||||
// Send 直接发送内容,并终止请求
|
// Send 直接发送内容,并终止请求
|
||||||
func (this *HTTPWriter) Send(status int, body string) {
|
func (this *HTTPWriter) Send(status int, body string) {
|
||||||
|
this.req.ProcessResponseHeaders(this.Header(), status)
|
||||||
|
|
||||||
|
// content-length
|
||||||
|
_, hasContentLength := this.Header()["Content-Length"]
|
||||||
|
if !hasContentLength {
|
||||||
|
this.Header()["Content-Length"] = []string{types.String(len(body))}
|
||||||
|
}
|
||||||
|
|
||||||
this.WriteHeader(status)
|
this.WriteHeader(status)
|
||||||
_, _ = this.WriteString(body)
|
_, _ = this.WriteString(body)
|
||||||
this.isFinished = true
|
this.isFinished = true
|
||||||
@@ -882,6 +896,7 @@ func (this *HTTPWriter) SendResp(resp *http.Response) (int64, error) {
|
|||||||
for k, v := range resp.Header {
|
for k, v := range resp.Header {
|
||||||
this.SetHeader(k, v)
|
this.SetHeader(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.WriteHeader(resp.StatusCode)
|
this.WriteHeader(resp.StatusCode)
|
||||||
var bufPool = this.req.bytePool(resp.ContentLength)
|
var bufPool = this.req.bytePool(resp.ContentLength)
|
||||||
var buf = bufPool.Get()
|
var buf = bufPool.Get()
|
||||||
@@ -1018,7 +1033,9 @@ func (this *HTTPWriter) finishWebP() {
|
|||||||
if webpCacheWriter != nil {
|
if webpCacheWriter != nil {
|
||||||
// 写入Header
|
// 写入Header
|
||||||
for k, v := range this.Header() {
|
for k, v := range this.Header() {
|
||||||
if k == "Set-Cookie" {
|
if k == "Set-Cookie" ||
|
||||||
|
k == "Strict-Transport-Security" ||
|
||||||
|
k == "Alt-Svc" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1237,7 +1254,10 @@ func (this *HTTPWriter) finishRequest() {
|
|||||||
// 计算Header长度
|
// 计算Header长度
|
||||||
func (this *HTTPWriter) calculateHeaderLength() (result int) {
|
func (this *HTTPWriter) calculateHeaderLength() (result int) {
|
||||||
for k, v := range this.Header() {
|
for k, v := range this.Header() {
|
||||||
if k == "Set-Cookie" || (this.isPartial && k == "Content-Range") {
|
if k == "Set-Cookie" ||
|
||||||
|
k == "Strict-Transport-Security" ||
|
||||||
|
k == "Alt-Svc" ||
|
||||||
|
(this.isPartial && k == "Content-Range") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, v1 := range v {
|
for _, v1 := range v {
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ func (this *BaseListener) matchSSL(domain string) (*sslconfigs.SSLPolicy, *tls.C
|
|||||||
return nil, nil, errors.New("no tls server name found")
|
return nil, nil, errors.New("no tls server name found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过代理服务域名配置匹配
|
// 通过网站域名配置匹配
|
||||||
server, _ := this.findNamedServer(domain)
|
server, _ := this.findNamedServer(domain)
|
||||||
if server == nil {
|
if server == nil {
|
||||||
// 找不到或者此时的服务没有配置证书,需要搜索所有的Server,通过SSL证书内容中的DNSName匹配
|
// 找不到或者此时的服务没有配置证书,需要搜索所有的Server,通过SSL证书内容中的DNSName匹配
|
||||||
@@ -138,7 +138,7 @@ func (this *BaseListener) matchSSL(domain string) (*sslconfigs.SSLPolicy, *tls.C
|
|||||||
if server.SSLPolicy() == nil || !server.SSLPolicy().IsOn {
|
if server.SSLPolicy() == nil || !server.SSLPolicy().IsOn {
|
||||||
// 找不到或者此时的服务没有配置证书,需要搜索所有的Server,通过SSL证书内容中的DNSName匹配
|
// 找不到或者此时的服务没有配置证书,需要搜索所有的Server,通过SSL证书内容中的DNSName匹配
|
||||||
// 此功能仅为了兼容以往版本(v1.0.4),不应该作为常态启用
|
// 此功能仅为了兼容以往版本(v1.0.4),不应该作为常态启用
|
||||||
if globalServerConfig != nil && globalServerConfig.HTTPAll.MatchCertFromAllServers {
|
if globalServerConfig != nil && globalServerConfig.HTTPAll.MatchCertFromAllServers {
|
||||||
for _, searchingServer := range group.Servers() {
|
for _, searchingServer := range group.Servers() {
|
||||||
if searchingServer.SSLPolicy() == nil || !searchingServer.SSLPolicy().IsOn {
|
if searchingServer.SSLPolicy() == nil || !searchingServer.SSLPolicy().IsOn {
|
||||||
continue
|
continue
|
||||||
@@ -174,19 +174,26 @@ func (this *BaseListener) findNamedServer(name string) (serverConfig *serverconf
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var matchDomainStrictly = sharedNodeConfig.GlobalServerConfig != nil && sharedNodeConfig.GlobalServerConfig.HTTPAll.MatchDomainStrictly
|
var globalServerConfig = sharedNodeConfig.GlobalServerConfig
|
||||||
|
var matchDomainStrictly = globalServerConfig != nil && globalServerConfig.HTTPAll.MatchDomainStrictly
|
||||||
|
|
||||||
if sharedNodeConfig.GlobalServerConfig != nil &&
|
if globalServerConfig != nil &&
|
||||||
len(sharedNodeConfig.GlobalServerConfig.HTTPAll.DefaultDomain) > 0 &&
|
len(globalServerConfig.HTTPAll.DefaultDomain) > 0 &&
|
||||||
(!matchDomainStrictly || configutils.MatchDomains(sharedNodeConfig.GlobalServerConfig.HTTPAll.AllowMismatchDomains, name) || (sharedNodeConfig.GlobalServerConfig.HTTPAll.AllowNodeIP && net.ParseIP(name) != nil)) {
|
(!matchDomainStrictly || configutils.MatchDomains(globalServerConfig.HTTPAll.AllowMismatchDomains, name) || (globalServerConfig.HTTPAll.AllowNodeIP && net.ParseIP(name) != nil)) {
|
||||||
var defaultDomain = sharedNodeConfig.GlobalServerConfig.HTTPAll.DefaultDomain
|
if globalServerConfig.HTTPAll.AllowNodeIP &&
|
||||||
serverConfig, serverName = this.findNamedServerMatched(defaultDomain)
|
globalServerConfig.HTTPAll.NodeIPShowPage &&
|
||||||
if serverConfig != nil {
|
net.ParseIP(name) != nil {
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
var defaultDomain = globalServerConfig.HTTPAll.DefaultDomain
|
||||||
|
serverConfig, serverName = this.findNamedServerMatched(defaultDomain)
|
||||||
|
if serverConfig != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if matchDomainStrictly && !configutils.MatchDomains(sharedNodeConfig.GlobalServerConfig.HTTPAll.AllowMismatchDomains, name) && (!sharedNodeConfig.GlobalServerConfig.HTTPAll.AllowNodeIP || net.ParseIP(name) == nil) {
|
if matchDomainStrictly && !configutils.MatchDomains(globalServerConfig.HTTPAll.AllowMismatchDomains, name) && (!globalServerConfig.HTTPAll.AllowNodeIP || net.ParseIP(name) == nil) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type HTTPListener struct {
|
|||||||
addr string
|
addr string
|
||||||
isHTTP bool
|
isHTTP bool
|
||||||
isHTTPS bool
|
isHTTPS bool
|
||||||
|
isHTTP3 bool
|
||||||
httpServer *http.Server
|
httpServer *http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +200,7 @@ func (this *HTTPListener) ServeHTTP(rawWriter http.ResponseWriter, rawReq *http.
|
|||||||
ServerAddr: this.addr,
|
ServerAddr: this.addr,
|
||||||
IsHTTP: this.isHTTP,
|
IsHTTP: this.isHTTP,
|
||||||
IsHTTPS: this.isHTTPS,
|
IsHTTPS: this.isHTTPS,
|
||||||
|
IsHTTP3: this.isHTTP3,
|
||||||
|
|
||||||
nodeConfig: sharedNodeConfig,
|
nodeConfig: sharedNodeConfig,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,11 @@ func init() {
|
|||||||
|
|
||||||
// ListenerManager 端口监听管理器
|
// ListenerManager 端口监听管理器
|
||||||
type ListenerManager struct {
|
type ListenerManager struct {
|
||||||
listenersMap map[string]*Listener // addr => *Listener
|
listenersMap map[string]*Listener // addr => *Listener
|
||||||
locker sync.Mutex
|
http3Listener *HTTPListener
|
||||||
lastConfig *nodeconfigs.NodeConfig
|
|
||||||
|
locker sync.Mutex
|
||||||
|
lastConfig *nodeconfigs.NodeConfig
|
||||||
|
|
||||||
retryListenerMap map[string]*Listener // 需要重试的监听器 addr => Listener
|
retryListenerMap map[string]*Listener // 需要重试的监听器 addr => Listener
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
@@ -73,7 +75,7 @@ func NewListenerManager() *ListenerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start 启动监听
|
// Start 启动监听
|
||||||
func (this *ListenerManager) Start(node *nodeconfigs.NodeConfig) error {
|
func (this *ListenerManager) Start(nodeConfig *nodeconfigs.NodeConfig) error {
|
||||||
this.locker.Lock()
|
this.locker.Lock()
|
||||||
defer this.locker.Unlock()
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
@@ -84,12 +86,12 @@ func (this *ListenerManager) Start(node *nodeconfigs.NodeConfig) error {
|
|||||||
/**if this.lastConfig != nil && this.lastConfig.Version == node.Version {
|
/**if this.lastConfig != nil && this.lastConfig.Version == node.Version {
|
||||||
return nil
|
return nil
|
||||||
}**/
|
}**/
|
||||||
this.lastConfig = node
|
this.lastConfig = nodeConfig
|
||||||
|
|
||||||
// 所有的新地址
|
// 所有的新地址
|
||||||
groupAddrs := []string{}
|
var groupAddrs = []string{}
|
||||||
availableServerGroups := node.AvailableGroups()
|
var availableServerGroups = nodeConfig.AvailableGroups()
|
||||||
if !node.IsOn {
|
if !nodeConfig.IsOn {
|
||||||
availableServerGroups = []*serverconfigs.ServerAddressGroup{}
|
availableServerGroups = []*serverconfigs.ServerAddressGroup{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,13 +100,13 @@ func (this *ListenerManager) Start(node *nodeconfigs.NodeConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, group := range availableServerGroups {
|
for _, group := range availableServerGroups {
|
||||||
addr := group.FullAddr()
|
var addr = group.FullAddr()
|
||||||
groupAddrs = append(groupAddrs, addr)
|
groupAddrs = append(groupAddrs, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 停掉老的
|
// 停掉老的
|
||||||
for listenerKey, listener := range this.listenersMap {
|
for listenerKey, listener := range this.listenersMap {
|
||||||
addr := listener.FullAddr()
|
var addr = listener.FullAddr()
|
||||||
if !lists.ContainsString(groupAddrs, addr) {
|
if !lists.ContainsString(groupAddrs, addr) {
|
||||||
remotelogs.Println("LISTENER_MANAGER", "close '"+addr+"'")
|
remotelogs.Println("LISTENER_MANAGER", "close '"+addr+"'")
|
||||||
_ = listener.Close()
|
_ = listener.Close()
|
||||||
@@ -115,7 +117,7 @@ func (this *ListenerManager) Start(node *nodeconfigs.NodeConfig) error {
|
|||||||
|
|
||||||
// 启动新的或修改老的
|
// 启动新的或修改老的
|
||||||
for _, group := range availableServerGroups {
|
for _, group := range availableServerGroups {
|
||||||
addr := group.FullAddr()
|
var addr = group.FullAddr()
|
||||||
listener, ok := this.listenersMap[addr]
|
listener, ok := this.listenersMap[addr]
|
||||||
if ok {
|
if ok {
|
||||||
// 不需要打印reload信息,防止日志数量过多
|
// 不需要打印reload信息,防止日志数量过多
|
||||||
@@ -129,7 +131,7 @@ func (this *ListenerManager) Start(node *nodeconfigs.NodeConfig) error {
|
|||||||
// 放入到重试队列中
|
// 放入到重试队列中
|
||||||
this.retryListenerMap[addr] = listener
|
this.retryListenerMap[addr] = listener
|
||||||
|
|
||||||
firstServer := group.FirstServer()
|
var firstServer = group.FirstServer()
|
||||||
if firstServer == nil {
|
if firstServer == nil {
|
||||||
remotelogs.Error("LISTENER_MANAGER", err.Error())
|
remotelogs.Error("LISTENER_MANAGER", err.Error())
|
||||||
} else {
|
} else {
|
||||||
@@ -167,10 +169,15 @@ func (this *ListenerManager) TotalActiveConnections() int {
|
|||||||
this.locker.Lock()
|
this.locker.Lock()
|
||||||
defer this.locker.Unlock()
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
total := 0
|
var total = 0
|
||||||
for _, listener := range this.listenersMap {
|
for _, listener := range this.listenersMap {
|
||||||
total += listener.listener.CountActiveConnections()
|
total += listener.listener.CountActiveConnections()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if this.http3Listener != nil {
|
||||||
|
total += this.http3Listener.CountActiveConnections()
|
||||||
|
}
|
||||||
|
|
||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,6 +246,17 @@ func (this *ListenerManager) addToFirewalld(groupAddrs []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTTP/3相关端口
|
||||||
|
var http3Ports = sharedNodeConfig.FindHTTP3Ports()
|
||||||
|
if len(http3Ports) > 0 {
|
||||||
|
for _, port := range http3Ports {
|
||||||
|
var groupAddr = "udp://:" + types.String(port)
|
||||||
|
if !lists.ContainsString(groupAddrs, groupAddr) {
|
||||||
|
groupAddrs = append(groupAddrs, groupAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 组合端口号
|
// 组合端口号
|
||||||
var portStrings = []string{}
|
var portStrings = []string{}
|
||||||
var udpPorts = []int{}
|
var udpPorts = []int{}
|
||||||
@@ -272,7 +290,9 @@ func (this *ListenerManager) addToFirewalld(groupAddrs []string) {
|
|||||||
if newPortStrings == this.lastPortStrings {
|
if newPortStrings == this.lastPortStrings {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
this.locker.Lock()
|
||||||
this.lastPortStrings = newPortStrings
|
this.lastPortStrings = newPortStrings
|
||||||
|
this.locker.Unlock()
|
||||||
|
|
||||||
remotelogs.Println("FIREWALLD", "opening ports automatically ...")
|
remotelogs.Println("FIREWALLD", "opening ports automatically ...")
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -284,8 +304,10 @@ func (this *ListenerManager) addToFirewalld(groupAddrs []string) {
|
|||||||
var udpPortRanges = utils.MergePorts(udpPorts)
|
var udpPortRanges = utils.MergePorts(udpPorts)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
this.locker.Lock()
|
||||||
this.lastTCPPortRanges = tcpPortRanges
|
this.lastTCPPortRanges = tcpPortRanges
|
||||||
this.lastUDPPortRanges = udpPortRanges
|
this.lastUDPPortRanges = udpPortRanges
|
||||||
|
this.locker.Unlock()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 删除老的不存在的端口
|
// 删除老的不存在的端口
|
||||||
@@ -321,3 +343,28 @@ func (this *ListenerManager) addToFirewalld(groupAddrs []string) {
|
|||||||
_ = this.firewalld.AllowPortRangesPermanently(tcpPortRanges, "tcp")
|
_ = this.firewalld.AllowPortRangesPermanently(tcpPortRanges, "tcp")
|
||||||
_ = this.firewalld.AllowPortRangesPermanently(udpPortRanges, "udp")
|
_ = this.firewalld.AllowPortRangesPermanently(udpPortRanges, "udp")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *ListenerManager) reloadFirewalld() {
|
||||||
|
this.locker.Lock()
|
||||||
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
|
var nodeConfig = sharedNodeConfig
|
||||||
|
|
||||||
|
// 所有的新地址
|
||||||
|
var groupAddrs = []string{}
|
||||||
|
var availableServerGroups = nodeConfig.AvailableGroups()
|
||||||
|
if !nodeConfig.IsOn {
|
||||||
|
availableServerGroups = []*serverconfigs.ServerAddressGroup{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(availableServerGroups) == 0 {
|
||||||
|
remotelogs.Println("LISTENER_MANAGER", "no available servers to startup")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, group := range availableServerGroups {
|
||||||
|
var addr = group.FullAddr()
|
||||||
|
groupAddrs = append(groupAddrs, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
go this.addToFirewalld(groupAddrs)
|
||||||
|
}
|
||||||
|
|||||||
@@ -693,6 +693,7 @@ func (this *Node) listenSock() error {
|
|||||||
var lastReadAt int64
|
var lastReadAt int64
|
||||||
var lastWriteAt int64
|
var lastWriteAt int64
|
||||||
var lastErrString = ""
|
var lastErrString = ""
|
||||||
|
var protocol = "tcp"
|
||||||
clientConn, ok := conn.(*ClientConn)
|
clientConn, ok := conn.(*ClientConn)
|
||||||
if ok {
|
if ok {
|
||||||
createdAt = clientConn.CreatedAt()
|
createdAt = clientConn.CreatedAt()
|
||||||
@@ -703,6 +704,8 @@ func (this *Node) listenSock() error {
|
|||||||
if lastErr != nil {
|
if lastErr != nil {
|
||||||
lastErrString = lastErr.Error()
|
lastErrString = lastErr.Error()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
protocol = "udp"
|
||||||
}
|
}
|
||||||
var age int64 = -1
|
var age int64 = -1
|
||||||
var lastReadAge int64 = -1
|
var lastReadAge int64 = -1
|
||||||
@@ -719,6 +722,7 @@ func (this *Node) listenSock() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connMaps = append(connMaps, maps.Map{
|
connMaps = append(connMaps, maps.Map{
|
||||||
|
"protocol": protocol,
|
||||||
"addr": conn.RemoteAddr().String(),
|
"addr": conn.RemoteAddr().String(),
|
||||||
"age": age,
|
"age": age,
|
||||||
"readAge": lastReadAge,
|
"readAge": lastReadAge,
|
||||||
|
|||||||
@@ -33,7 +33,10 @@ type NodeStatusExecutor struct {
|
|||||||
cpuLogicalCount int
|
cpuLogicalCount int
|
||||||
cpuPhysicalCount int
|
cpuPhysicalCount int
|
||||||
|
|
||||||
lastIOCounterStat net.IOCountersStat
|
// 流量统计
|
||||||
|
lastIOCounterStat net.IOCountersStat
|
||||||
|
lastUDPInDatagrams int64
|
||||||
|
lastUDPOutDatagrams int64
|
||||||
|
|
||||||
apiCallStat *rpc.CallStat
|
apiCallStat *rpc.CallStat
|
||||||
|
|
||||||
@@ -44,6 +47,9 @@ func NewNodeStatusExecutor() *NodeStatusExecutor {
|
|||||||
return &NodeStatusExecutor{
|
return &NodeStatusExecutor{
|
||||||
ticker: time.NewTicker(30 * time.Second),
|
ticker: time.NewTicker(30 * time.Second),
|
||||||
apiCallStat: rpc.NewCallStat(10),
|
apiCallStat: rpc.NewCallStat(10),
|
||||||
|
|
||||||
|
lastUDPInDatagrams: -1,
|
||||||
|
lastUDPOutDatagrams: -1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,14 +298,14 @@ func (this *NodeStatusExecutor) updateCacheSpace(status *nodeconfigs.NodeStatus)
|
|||||||
|
|
||||||
// 流量
|
// 流量
|
||||||
func (this *NodeStatusExecutor) updateAllTraffic(status *nodeconfigs.NodeStatus) {
|
func (this *NodeStatusExecutor) updateAllTraffic(status *nodeconfigs.NodeStatus) {
|
||||||
counters, err := net.IOCounters(true)
|
trafficCounters, err := net.IOCounters(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Warn("NODE_STATUS_EXECUTOR", err.Error())
|
remotelogs.Warn("NODE_STATUS_EXECUTOR", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var allCounter = net.IOCountersStat{}
|
var allCounter = net.IOCountersStat{}
|
||||||
for _, counter := range counters {
|
for _, counter := range trafficCounters {
|
||||||
// 跳过lo
|
// 跳过lo
|
||||||
if counter.Name == "lo" {
|
if counter.Name == "lo" {
|
||||||
continue
|
continue
|
||||||
@@ -319,11 +325,49 @@ func (this *NodeStatusExecutor) updateAllTraffic(status *nodeconfigs.NodeStatus)
|
|||||||
var bytesSent = allCounter.BytesSent - this.lastIOCounterStat.BytesSent
|
var bytesSent = allCounter.BytesSent - this.lastIOCounterStat.BytesSent
|
||||||
var bytesRecv = allCounter.BytesRecv - this.lastIOCounterStat.BytesRecv
|
var bytesRecv = allCounter.BytesRecv - this.lastIOCounterStat.BytesRecv
|
||||||
|
|
||||||
|
// UDP
|
||||||
|
var udpInDatagrams int64 = 0
|
||||||
|
var udpOutDatagrams int64 = 0
|
||||||
|
protoStats, protoErr := net.ProtoCounters([]string{"udp"})
|
||||||
|
if protoErr == nil {
|
||||||
|
for _, protoStat := range protoStats {
|
||||||
|
if protoStat.Protocol == "udp" {
|
||||||
|
udpInDatagrams = protoStat.Stats["InDatagrams"]
|
||||||
|
udpOutDatagrams = protoStat.Stats["OutDatagrams"]
|
||||||
|
if udpInDatagrams < 0 {
|
||||||
|
udpInDatagrams = 0
|
||||||
|
}
|
||||||
|
if udpOutDatagrams < 0 {
|
||||||
|
udpOutDatagrams = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var avgUDPInDatagrams int64 = 0
|
||||||
|
var avgUDPOutDatagrams int64 = 0
|
||||||
|
if this.lastUDPInDatagrams >= 0 && this.lastUDPOutDatagrams >= 0 {
|
||||||
|
avgUDPInDatagrams = (udpInDatagrams - this.lastUDPInDatagrams) / int64(costSeconds)
|
||||||
|
avgUDPOutDatagrams = (udpOutDatagrams - this.lastUDPOutDatagrams) / int64(costSeconds)
|
||||||
|
if avgUDPInDatagrams < 0 {
|
||||||
|
avgUDPInDatagrams = 0
|
||||||
|
}
|
||||||
|
if avgUDPOutDatagrams < 0 {
|
||||||
|
avgUDPOutDatagrams = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastUDPInDatagrams = udpInDatagrams
|
||||||
|
this.lastUDPOutDatagrams = udpOutDatagrams
|
||||||
|
|
||||||
monitor.SharedValueQueue.Add(nodeconfigs.NodeValueItemAllTraffic, maps.Map{
|
monitor.SharedValueQueue.Add(nodeconfigs.NodeValueItemAllTraffic, maps.Map{
|
||||||
"inBytes": bytesRecv,
|
"inBytes": bytesRecv,
|
||||||
"outBytes": bytesSent,
|
"outBytes": bytesSent,
|
||||||
"avgInBytes": bytesRecv / uint64(costSeconds),
|
"avgInBytes": bytesRecv / uint64(costSeconds),
|
||||||
"avgOutBytes": bytesSent / uint64(costSeconds),
|
"avgOutBytes": bytesSent / uint64(costSeconds),
|
||||||
|
|
||||||
|
"avgUDPInDatagrams": avgUDPInDatagrams,
|
||||||
|
"avgUDPOutDatagrams": avgUDPOutDatagrams,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ func (this *Node) execTask(rpcClient *rpc.RPCClient, task *pb.NodeTask) error {
|
|||||||
err = this.execUAMPolicyChangedTask(rpcClient)
|
err = this.execUAMPolicyChangedTask(rpcClient)
|
||||||
case "httpCCPolicyChanged":
|
case "httpCCPolicyChanged":
|
||||||
err = this.execHTTPCCPolicyChangedTask(rpcClient)
|
err = this.execHTTPCCPolicyChangedTask(rpcClient)
|
||||||
|
case "http3PolicyChanged":
|
||||||
|
err = this.execHTTP3PolicyChangedTask(rpcClient)
|
||||||
case "httpPagesPolicyChanged":
|
case "httpPagesPolicyChanged":
|
||||||
err = this.execHTTPPagesPolicyChangedTask(rpcClient)
|
err = this.execHTTPPagesPolicyChangedTask(rpcClient)
|
||||||
case "updatingServers":
|
case "updatingServers":
|
||||||
@@ -128,15 +130,6 @@ func (this *Node) execNodeVersionChangedTask() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 脚本库变更
|
|
||||||
func (this *Node) execScriptsChangedTask() error {
|
|
||||||
err := this.reloadCommonScripts()
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("reload common scripts failed: " + err.Error())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 节点级别变更
|
// 节点级别变更
|
||||||
func (this *Node) execNodeLevelChangedTask(rpcClient *rpc.RPCClient) error {
|
func (this *Node) execNodeLevelChangedTask(rpcClient *rpc.RPCClient) error {
|
||||||
levelInfoResp, err := rpcClient.NodeRPC.FindNodeLevelInfo(rpcClient.Context(), &pb.FindNodeLevelInfoRequest{})
|
levelInfoResp, err := rpcClient.NodeRPC.FindNodeLevelInfo(rpcClient.Context(), &pb.FindNodeLevelInfoRequest{})
|
||||||
@@ -163,90 +156,6 @@ func (this *Node) execNodeLevelChangedTask(rpcClient *rpc.RPCClient) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UAM策略变更
|
|
||||||
func (this *Node) execUAMPolicyChangedTask(rpcClient *rpc.RPCClient) error {
|
|
||||||
remotelogs.Println("NODE", "updating uam policies ...")
|
|
||||||
resp, err := rpcClient.NodeRPC.FindNodeUAMPolicies(rpcClient.Context(), &pb.FindNodeUAMPoliciesRequest{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var uamPolicyMap = map[int64]*nodeconfigs.UAMPolicy{}
|
|
||||||
for _, policy := range resp.UamPolicies {
|
|
||||||
if len(policy.UamPolicyJSON) > 0 {
|
|
||||||
var uamPolicy = &nodeconfigs.UAMPolicy{}
|
|
||||||
err = json.Unmarshal(policy.UamPolicyJSON, uamPolicy)
|
|
||||||
if err != nil {
|
|
||||||
remotelogs.Error("NODE", "decode uam policy failed: "+err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
err = uamPolicy.Init()
|
|
||||||
if err != nil {
|
|
||||||
remotelogs.Error("NODE", "initialize uam policy failed: "+err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
uamPolicyMap[policy.NodeClusterId] = uamPolicy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sharedNodeConfig.UpdateUAMPolicies(uamPolicyMap)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP CC策略变更
|
|
||||||
func (this *Node) execHTTPCCPolicyChangedTask(rpcClient *rpc.RPCClient) error {
|
|
||||||
remotelogs.Println("NODE", "updating http cc policies ...")
|
|
||||||
resp, err := rpcClient.NodeRPC.FindNodeHTTPCCPolicies(rpcClient.Context(), &pb.FindNodeHTTPCCPoliciesRequest{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var httpCCPolicyMap = map[int64]*nodeconfigs.HTTPCCPolicy{}
|
|
||||||
for _, policy := range resp.HttpCCPolicies {
|
|
||||||
if len(policy.HttpCCPolicyJSON) > 0 {
|
|
||||||
var httpCCPolicy = nodeconfigs.NewHTTPCCPolicy()
|
|
||||||
err = json.Unmarshal(policy.HttpCCPolicyJSON, httpCCPolicy)
|
|
||||||
if err != nil {
|
|
||||||
remotelogs.Error("NODE", "decode http cc policy failed: "+err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
err = httpCCPolicy.Init()
|
|
||||||
if err != nil {
|
|
||||||
remotelogs.Error("NODE", "initialize http cc policy failed: "+err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
httpCCPolicyMap[policy.NodeClusterId] = httpCCPolicy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sharedNodeConfig.UpdateHTTPCCPolicies(httpCCPolicyMap)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自定义页面策略变更
|
|
||||||
func (this *Node) execHTTPPagesPolicyChangedTask(rpcClient *rpc.RPCClient) error {
|
|
||||||
remotelogs.Println("NODE", "updating http pages policies ...")
|
|
||||||
resp, err := rpcClient.NodeRPC.FindNodeHTTPPagesPolicies(rpcClient.Context(), &pb.FindNodeHTTPPagesPoliciesRequest{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var httpPagesPolicyMap = map[int64]*nodeconfigs.HTTPPagesPolicy{}
|
|
||||||
for _, policy := range resp.HttpPagesPolicies {
|
|
||||||
if len(policy.HttpPagesPolicyJSON) > 0 {
|
|
||||||
var httpPagesPolicy = nodeconfigs.NewHTTPPagesPolicy()
|
|
||||||
err = json.Unmarshal(policy.HttpPagesPolicyJSON, httpPagesPolicy)
|
|
||||||
if err != nil {
|
|
||||||
remotelogs.Error("NODE", "decode http pages policy failed: "+err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
err = httpPagesPolicy.Init()
|
|
||||||
if err != nil {
|
|
||||||
remotelogs.Error("NODE", "initialize http pages policy failed: "+err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
httpPagesPolicyMap[policy.NodeClusterId] = httpPagesPolicy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sharedNodeConfig.UpdateHTTPPagesPolicies(httpPagesPolicyMap)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DDoS配置变更
|
// DDoS配置变更
|
||||||
func (this *Node) execDDoSProtectionChangedTask(rpcClient *rpc.RPCClient) error {
|
func (this *Node) execDDoSProtectionChangedTask(rpcClient *rpc.RPCClient) error {
|
||||||
resp, err := rpcClient.NodeRPC.FindNodeDDoSProtection(rpcClient.Context(), &pb.FindNodeDDoSProtectionRequest{})
|
resp, err := rpcClient.NodeRPC.FindNodeDDoSProtection(rpcClient.Context(), &pb.FindNodeDDoSProtectionRequest{})
|
||||||
|
|||||||
31
internal/nodes/node_tasks_ext.go
Normal file
31
internal/nodes/node_tasks_ext.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
|
package nodes
|
||||||
|
|
||||||
|
import "github.com/TeaOSLab/EdgeNode/internal/rpc"
|
||||||
|
|
||||||
|
func (this *Node) execScriptsChangedTask() error {
|
||||||
|
// stub
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Node) execUAMPolicyChangedTask(rpcClient *rpc.RPCClient) error {
|
||||||
|
// stub
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Node) execHTTPCCPolicyChangedTask(rpcClient *rpc.RPCClient) error {
|
||||||
|
// stub
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Node) execHTTP3PolicyChangedTask(rpcClient *rpc.RPCClient) error {
|
||||||
|
// stub
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Node) execHTTPPagesPolicyChangedTask(rpcClient *rpc.RPCClient) error {
|
||||||
|
// stub
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -289,6 +289,10 @@ Loop:
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case log := <-logChan:
|
case log := <-logChan:
|
||||||
|
if log.NodeId <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// 是否已存在
|
// 是否已存在
|
||||||
var hash = xxhash.Sum64String(types.String(log.ServerId) + "_" + log.Description)
|
var hash = xxhash.Sum64String(types.String(log.ServerId) + "_" + log.Description)
|
||||||
var found = false
|
var found = false
|
||||||
@@ -312,6 +316,7 @@ Loop:
|
|||||||
break Loop
|
break Loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(logList) == 0 {
|
if len(logList) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
15
internal/utils/testutils/utils.go
Normal file
15
internal/utils/testutils/utils.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package testutils
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
// IsSingleTesting 判断当前测试环境是否为单个函数测试
|
||||||
|
func IsSingleTesting() bool {
|
||||||
|
for _, arg := range os.Args {
|
||||||
|
if arg == "-test.run" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -82,8 +82,10 @@ func (this *BlockAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, reque
|
|||||||
|
|
||||||
// output response
|
// output response
|
||||||
if this.StatusCode > 0 {
|
if this.StatusCode > 0 {
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), this.StatusCode)
|
||||||
writer.WriteHeader(this.StatusCode)
|
writer.WriteHeader(this.StatusCode)
|
||||||
} else {
|
} else {
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), http.StatusForbidden)
|
||||||
writer.WriteHeader(http.StatusForbidden)
|
writer.WriteHeader(http.StatusForbidden)
|
||||||
}
|
}
|
||||||
if len(this.URL) > 0 {
|
if len(this.URL) > 0 {
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ func (this *CaptchaAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, req
|
|||||||
// 占用一次失败次数
|
// 占用一次失败次数
|
||||||
CaptchaIncreaseFails(req, this, waf.Id, group.Id, set.Id, CaptchaPageCodeInit)
|
CaptchaIncreaseFails(req, this, waf.Id, group.Id, set.Id, CaptchaPageCodeInit)
|
||||||
|
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusTemporaryRedirect)
|
||||||
http.Redirect(writer, req.WAFRaw(), CaptchaPath+"?info="+url.QueryEscape(info), http.StatusTemporaryRedirect)
|
http.Redirect(writer, req.WAFRaw(), CaptchaPath+"?info="+url.QueryEscape(info), http.StatusTemporaryRedirect)
|
||||||
|
|
||||||
return false, false
|
return false, false
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ func (this *Get302Action) Perform(waf *WAF, group *RuleGroup, set *RuleSet, requ
|
|||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), http.StatusFound)
|
||||||
http.Redirect(writer, request.WAFRaw(), Get302Path+"?info="+url.QueryEscape(info), http.StatusFound)
|
http.Redirect(writer, request.WAFRaw(), Get302Path+"?info="+url.QueryEscape(info), http.StatusFound)
|
||||||
|
|
||||||
flusher, ok := writer.(http.Flusher)
|
flusher, ok := writer.(http.Flusher)
|
||||||
|
|||||||
@@ -75,14 +75,15 @@ func (this *JSCookieAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusOK)
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
writer.Header().Set("Cache-Control", "no-cache")
|
writer.Header().Set("Cache-Control", "no-cache")
|
||||||
|
|
||||||
var timestamp = types.String(time.Now().Unix())
|
var timestamp = types.String(time.Now().Unix())
|
||||||
|
|
||||||
var cookieValue = timestamp + "@" + types.String(set.Id) + "@" + fmt.Sprintf("%x", md5.Sum([]byte(timestamp+"@"+types.String(set.Id)+"@"+nodeConfig.NodeId)))
|
var cookieValue = timestamp + "@" + types.String(set.Id) + "@" + fmt.Sprintf("%x", md5.Sum([]byte(timestamp+"@"+types.String(set.Id)+"@"+nodeConfig.NodeId)))
|
||||||
|
var respHTML = `<!DOCTYPE html>
|
||||||
_, _ = writer.Write([]byte(`<!DOCTYPE html>
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title></title>
|
<title></title>
|
||||||
@@ -94,7 +95,10 @@ window.location.reload();
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
</body>
|
</body>
|
||||||
</html>`))
|
</html>`
|
||||||
|
writer.Header().Set("Content-Length", types.String(len(respHTML)))
|
||||||
|
writer.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = writer.Write([]byte(respHTML))
|
||||||
|
|
||||||
// 记录失败次数
|
// 记录失败次数
|
||||||
this.increaseFails(req, waf.Id, group.Id, set.Id)
|
this.increaseFails(req, waf.Id, group.Id, set.Id)
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ func (this *PageAction) WillChange() bool {
|
|||||||
|
|
||||||
// Perform the action
|
// Perform the action
|
||||||
func (this *PageAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, request requests.Request, writer http.ResponseWriter) (continueRequest bool, goNextSet bool) {
|
func (this *PageAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, request requests.Request, writer http.ResponseWriter) (continueRequest bool, goNextSet bool) {
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), this.Status)
|
||||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
writer.WriteHeader(this.Status)
|
writer.WriteHeader(this.Status)
|
||||||
_, _ = writer.Write([]byte(request.Format(this.Body)))
|
_, _ = writer.Write([]byte(request.Format(this.Body)))
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ func (this *Post307Action) Perform(waf *WAF, group *RuleGroup, set *RuleSet, req
|
|||||||
Value: info,
|
Value: info,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), http.StatusTemporaryRedirect)
|
||||||
http.Redirect(writer, request.WAFRaw(), request.WAFRaw().URL.String(), http.StatusTemporaryRedirect)
|
http.Redirect(writer, request.WAFRaw(), request.WAFRaw().URL.String(), http.StatusTemporaryRedirect)
|
||||||
|
|
||||||
flusher, ok := writer.(http.Flusher)
|
flusher, ok := writer.(http.Flusher)
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ func (this *RecordIPAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, re
|
|||||||
var expiresAt = time.Now().Unix() + int64(timeout)
|
var expiresAt = time.Now().Unix() + int64(timeout)
|
||||||
|
|
||||||
if this.Type == "black" {
|
if this.Type == "black" {
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), http.StatusForbidden)
|
||||||
writer.WriteHeader(http.StatusForbidden)
|
writer.WriteHeader(http.StatusForbidden)
|
||||||
|
|
||||||
request.WAFClose()
|
request.WAFClose()
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ func (this *RedirectAction) WillChange() bool {
|
|||||||
|
|
||||||
// Perform the action
|
// Perform the action
|
||||||
func (this *RedirectAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, request requests.Request, writer http.ResponseWriter) (continueRequest bool, goNextSet bool) {
|
func (this *RedirectAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, request requests.Request, writer http.ResponseWriter) (continueRequest bool, goNextSet bool) {
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), this.Status)
|
||||||
writer.Header().Set("Location", this.URL)
|
writer.Header().Set("Location", this.URL)
|
||||||
writer.WriteHeader(this.Status)
|
writer.WriteHeader(this.Status)
|
||||||
|
|
||||||
|
|||||||
@@ -26,18 +26,22 @@ func NewCaptchaValidator() *CaptchaValidator {
|
|||||||
func (this *CaptchaValidator) Run(req requests.Request, writer http.ResponseWriter) {
|
func (this *CaptchaValidator) Run(req requests.Request, writer http.ResponseWriter) {
|
||||||
var info = req.WAFRaw().URL.Query().Get("info")
|
var info = req.WAFRaw().URL.Query().Get("info")
|
||||||
if len(info) == 0 {
|
if len(info) == 0 {
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusBadRequest)
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("invalid request"))
|
_, _ = writer.Write([]byte("invalid request"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m, err := utils.SimpleDecryptMap(info)
|
m, err := utils.SimpleDecryptMap(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusBadRequest)
|
||||||
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("invalid request"))
|
_, _ = writer.Write([]byte("invalid request"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var timestamp = m.GetInt64("timestamp")
|
var timestamp = m.GetInt64("timestamp")
|
||||||
if timestamp < time.Now().Unix()-600 { // 10分钟之后信息过期
|
if timestamp < time.Now().Unix()-600 { // 10分钟之后信息过期
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusTemporaryRedirect)
|
||||||
http.Redirect(writer, req.WAFRaw(), m.GetString("url"), http.StatusTemporaryRedirect)
|
http.Redirect(writer, req.WAFRaw(), m.GetString("url"), http.StatusTemporaryRedirect)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -50,16 +54,19 @@ func (this *CaptchaValidator) Run(req requests.Request, writer http.ResponseWrit
|
|||||||
|
|
||||||
var waf = SharedWAFManager.FindWAF(policyId)
|
var waf = SharedWAFManager.FindWAF(policyId)
|
||||||
if waf == nil {
|
if waf == nil {
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusTemporaryRedirect)
|
||||||
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusTemporaryRedirect)
|
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusTemporaryRedirect)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var actionConfig = waf.FindAction(actionId)
|
var actionConfig = waf.FindAction(actionId)
|
||||||
if actionConfig == nil {
|
if actionConfig == nil {
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusTemporaryRedirect)
|
||||||
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusTemporaryRedirect)
|
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusTemporaryRedirect)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
captchaActionConfig, ok := actionConfig.(*CaptchaAction)
|
captchaActionConfig, ok := actionConfig.(*CaptchaAction)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusTemporaryRedirect)
|
||||||
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusTemporaryRedirect)
|
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusTemporaryRedirect)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -183,8 +190,7 @@ func (this *CaptchaValidator) show(actionConfig *CaptchaAction, req requests.Req
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
var msgHTML = `<!DOCTYPE html>
|
||||||
_, _ = writer.Write([]byte(`<!DOCTYPE html>
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>` + msgTitle + `</title>
|
<title>` + msgTitle + `</title>
|
||||||
@@ -206,7 +212,13 @@ func (this *CaptchaValidator) show(actionConfig *CaptchaAction, req requests.Req
|
|||||||
</head>
|
</head>
|
||||||
<body>` + body + `
|
<body>` + body + `
|
||||||
</body>
|
</body>
|
||||||
</html>`))
|
</html>`
|
||||||
|
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusOK)
|
||||||
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
writer.Header().Set("Content-Length", types.String(len(msgHTML)))
|
||||||
|
writer.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = writer.Write([]byte(msgHTML))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *CaptchaValidator) validate(actionConfig *CaptchaAction, policyId int64, groupId int64, setId int64, originURL string, req requests.Request, writer http.ResponseWriter) (allow bool) {
|
func (this *CaptchaValidator) validate(actionConfig *CaptchaAction, policyId int64, groupId int64, setId int64, originURL string, req requests.Request, writer http.ResponseWriter) (allow bool) {
|
||||||
@@ -226,6 +238,7 @@ func (this *CaptchaValidator) validate(actionConfig *CaptchaAction, policyId int
|
|||||||
// 加入到白名单
|
// 加入到白名单
|
||||||
SharedIPWhiteList.RecordIP("set:"+strconv.FormatInt(setId, 10), actionConfig.Scope, req.WAFServerId(), req.WAFRemoteIP(), time.Now().Unix()+int64(life), policyId, false, groupId, setId, "")
|
SharedIPWhiteList.RecordIP("set:"+strconv.FormatInt(setId, 10), actionConfig.Scope, req.WAFServerId(), req.WAFRemoteIP(), time.Now().Unix()+int64(life), policyId, false, groupId, setId, "")
|
||||||
|
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusSeeOther)
|
||||||
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusSeeOther)
|
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusSeeOther)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
@@ -235,6 +248,7 @@ func (this *CaptchaValidator) validate(actionConfig *CaptchaAction, policyId int
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.ProcessResponseHeaders(writer.Header(), http.StatusSeeOther)
|
||||||
http.Redirect(writer, req.WAFRaw(), req.WAFRaw().URL.String(), http.StatusSeeOther)
|
http.Redirect(writer, req.WAFRaw(), req.WAFRaw().URL.String(), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,18 +22,22 @@ func NewGet302Validator() *Get302Validator {
|
|||||||
func (this *Get302Validator) Run(request requests.Request, writer http.ResponseWriter) {
|
func (this *Get302Validator) Run(request requests.Request, writer http.ResponseWriter) {
|
||||||
var info = request.WAFRaw().URL.Query().Get("info")
|
var info = request.WAFRaw().URL.Query().Get("info")
|
||||||
if len(info) == 0 {
|
if len(info) == 0 {
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), http.StatusBadRequest)
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("invalid request"))
|
_, _ = writer.Write([]byte("invalid request"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m, err := utils.SimpleDecryptMap(info)
|
m, err := utils.SimpleDecryptMap(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), http.StatusBadRequest)
|
||||||
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("invalid request"))
|
_, _ = writer.Write([]byte("invalid request"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var timestamp = m.GetInt64("timestamp")
|
var timestamp = m.GetInt64("timestamp")
|
||||||
if time.Now().Unix()-timestamp > 5 { // 超过5秒认为失效
|
if time.Now().Unix()-timestamp > 5 { // 超过5秒认为失效
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), http.StatusBadRequest)
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("invalid request"))
|
_, _ = writer.Write([]byte("invalid request"))
|
||||||
return
|
return
|
||||||
@@ -49,5 +53,7 @@ func (this *Get302Validator) Run(request requests.Request, writer http.ResponseW
|
|||||||
|
|
||||||
// 返回原始URL
|
// 返回原始URL
|
||||||
var url = m.GetString("url")
|
var url = m.GetString("url")
|
||||||
|
|
||||||
|
request.ProcessResponseHeaders(writer.Header(), http.StatusFound)
|
||||||
http.Redirect(writer, request.WAFRaw(), url, http.StatusFound)
|
http.Redirect(writer, request.WAFRaw(), url, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ type Request interface {
|
|||||||
// Format 格式化变量
|
// Format 格式化变量
|
||||||
Format(string) string
|
Format(string) string
|
||||||
|
|
||||||
|
// ProcessResponseHeaders 处理响应Header
|
||||||
|
ProcessResponseHeaders(headers http.Header, status int)
|
||||||
|
|
||||||
// DisableAccessLog 在当前请求中不使用访问日志
|
// DisableAccessLog 在当前请求中不使用访问日志
|
||||||
DisableAccessLog()
|
DisableAccessLog()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user