Skip to content

Commit 883a9d2

Browse files
committed
attempt to process esi in parallel
1 parent dfdfaa8 commit 883a9d2

File tree

16 files changed

+117
-36
lines changed

16 files changed

+117
-36
lines changed

.github/workflows/middlewares.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
name: Install Go
1717
uses: actions/setup-go@v3
1818
with:
19-
go-version: 1.19
19+
go-version: 1.22
2020
-
2121
name: Checkout code
2222
uses: actions/checkout@v3

.github/workflows/non-regression.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ jobs:
2020
name: install Go
2121
uses: actions/setup-go@v3
2222
with:
23-
go-version: 1.19
23+
go-version: 1.22
2424
-
2525
name: golangci-lint
26-
uses: golangci/golangci-lint-action@v3
26+
uses: golangci/golangci-lint-action@v6
2727
-
2828
name: install xcaddy
2929
run: go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
name: Set up Go
1414
uses: actions/setup-go@v2
1515
with:
16-
go-version: 1.19
16+
go-version: 1.22
1717
-
1818
name: Checkout
1919
uses: actions/checkout@v2

.golangci.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,16 @@ linters:
77
disable:
88
- bodyclose
99
- cyclop
10-
- exhaustivestruct
10+
- depguard
1111
- exhaustruct
1212
- forbidigo
1313
- gochecknoglobals
1414
- gci
15-
- golint
1615
- gomnd
17-
- ifshort
1816
- ireturn
1917
- nestif
2018
- nonamedreturns
21-
- nosnakecase
19+
- mnd
2220
- revive
2321
- testpackage
2422
- stylecheck

esi/esi.go

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package esi
22

33
import (
44
"net/http"
5+
"slices"
6+
"sync"
57
)
68

79
func findTagName(b []byte) Tag {
@@ -47,14 +49,6 @@ func HasOpenedTags(b []byte) bool {
4749
return esi.FindIndex(b) != nil || escapeRg.FindIndex(b) != nil
4850
}
4951

50-
func CanProcess(b []byte) bool {
51-
if tag := findTagName(b); tag != nil {
52-
return tag.HasClose(b)
53-
}
54-
55-
return false
56-
}
57-
5852
func ReadToTag(next []byte, pointer int) (startTagPosition, esiPointer int, t Tag) {
5953
var isEscapeTag bool
6054

@@ -83,35 +77,81 @@ func ReadToTag(next []byte, pointer int) (startTagPosition, esiPointer int, t Ta
8377

8478
func Parse(b []byte, req *http.Request) []byte {
8579
pointer := 0
80+
includes := make(map[int]Tag)
8681

8782
for pointer < len(b) {
88-
var escapeTag bool
89-
9083
next := b[pointer:]
9184
tagIdx := esi.FindIndex(next)
9285

9386
if escIdx := escapeRg.FindIndex(next); escIdx != nil && (tagIdx == nil || escIdx[0] < tagIdx[0]) {
9487
tagIdx = escIdx
9588
tagIdx[1] = escIdx[0]
96-
escapeTag = true
9789
}
9890

9991
if tagIdx == nil {
10092
break
10193
}
10294

103-
esiPointer := tagIdx[1]
104-
t := findTagName(next[esiPointer:])
95+
t := findTagName(next[tagIdx[1]:])
10596

106-
if escapeTag {
107-
esiPointer += 7
97+
if t != nil {
98+
includes[pointer+tagIdx[0]] = t
10899
}
109100

110-
res, p := t.Process(next[esiPointer:], req)
111-
esiPointer += p
101+
pointer += tagIdx[1]
102+
}
103+
104+
if len(includes) == 0 {
105+
return b
106+
}
107+
108+
return processEsiTags(b, req, includes)
109+
}
110+
111+
func processEsiTags(b []byte, req *http.Request, includes map[int]Tag) []byte {
112+
type Response struct {
113+
Start int
114+
End int
115+
Res []byte
116+
Tag Tag
117+
}
118+
119+
var wg sync.WaitGroup
120+
121+
responses := make(chan Response, len(includes))
122+
123+
for start, t := range includes {
124+
wg.Add(1)
125+
126+
go func(s int, tag Tag) {
127+
defer wg.Done()
128+
129+
data, length := tag.Process(b[s:], req)
130+
131+
responses <- Response{
132+
Start: s,
133+
End: s + length,
134+
Res: data,
135+
Tag: tag,
136+
}
137+
}(start, t)
138+
}
139+
140+
wg.Wait()
141+
close(responses)
142+
143+
// we need to replace from the bottom to top
144+
sorted := make([]Response, 0, len(responses))
145+
for r := range responses {
146+
sorted = append(sorted, r)
147+
}
148+
149+
slices.SortFunc(sorted, func(a, b Response) int {
150+
return b.Start - a.Start
151+
})
112152

113-
b = append(b[:pointer], append(next[:tagIdx[0]], append(res, next[esiPointer:]...)...)...)
114-
pointer += len(res) + tagIdx[0]
153+
for _, r := range sorted {
154+
b = append(b[:r.Start], append(r.Res, b[r.End:]...)...)
115155
}
116156

117157
return b

esi/include.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
const include = "include"
1313

1414
var (
15-
closeInclude = regexp.MustCompile("/>")
15+
closeInclude = regexp.MustCompile(">")
1616
srcAttribute = regexp.MustCompile(`src="?(.+?)"?( |/>)`)
1717
altAttribute = regexp.MustCompile(`alt="?(.+?)"?( |/>)`)
1818
onErrorAttribute = regexp.MustCompile(`onerror="?(.+?)"?( |/>)`)

esi/type.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import (
66

77
type (
88
Tag interface {
9-
Process([]byte, *http.Request) ([]byte, int)
10-
HasClose([]byte) bool
11-
GetClosePosition([]byte) int
9+
Process(body []byte, request *http.Request) ([]byte, int)
10+
HasClose(body []byte) bool
11+
GetClosePosition(body []byte) int
1212
}
1313

1414
baseTag struct {

esi/vars.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ type varsTag struct {
7676
*baseTag
7777
}
7878

79+
const varTagLength = len("<esi:vars>")
80+
7981
// Input (e.g. comment text="This is a comment." />).
8082
func (c *varsTag) Process(b []byte, req *http.Request) ([]byte, int) {
8183
found := closeVars.FindIndex(b)
@@ -85,7 +87,7 @@ func (c *varsTag) Process(b []byte, req *http.Request) ([]byte, int) {
8587

8688
c.length = found[1]
8789

88-
return interpretedVar.ReplaceAllFunc(b[5:found[0]], func(b []byte) []byte {
90+
return interpretedVar.ReplaceAllFunc(b[varTagLength:found[0]], func(b []byte) []byte {
8991
return []byte(parseVariables(b, req))
9092
}), c.length
9193
}

esi/when.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func validateTest(b []byte, req *http.Request) bool {
2323
} else if r := comparison.FindSubmatch(b); r != nil {
2424
r1 := strings.TrimSpace(parseVariables(r[1], req))
2525
r2 := strings.TrimSpace(parseVariables(r[3], req))
26+
2627
switch string(r[2]) {
2728
case "==":
2829
return r1 == r2

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module github.com/darkweak/go-esi
22

3-
go 1.19
3+
go 1.22

middleware/caddy/esi.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"github.com/darkweak/go-esi/writer"
1313
)
1414

15-
var bufPool *sync.Pool = &sync.Pool{
15+
var bufPool = &sync.Pool{
1616
New: func() any {
1717
return &bytes.Buffer{}
1818
},

middleware/caddy/go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module github.com/darkweak/go-esi/middleware/caddy
22

3-
go 1.19
3+
go 1.22
4+
5+
toolchain go1.23.1
46

57
require (
68
github.com/caddyserver/caddy/v2 v2.6.4

0 commit comments

Comments
 (0)