mirror of
https://github.com/infinite-iroha/touka.git
synced 2026-06-13 15:47:38 +08:00
perf: optimize wildcard header deletion; test: assert invalid regex returns 500
- refactor Delete logic to iterate headers once, reducing ToLower calls from O(patterns * headers) to O(headers) - rewrite invalid regex test to verify runtime 500 response
This commit is contained in:
parent
c0e31c449e
commit
5d9bb3187d
2 changed files with 78 additions and 27 deletions
|
|
@ -136,39 +136,64 @@ func (ops *HeaderOps) applyTo(hdr http.Header, repl *reverseProxyReplacer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var deleteAll bool
|
||||||
|
var exactDeletes []string
|
||||||
|
var suffixPatterns, prefixPatterns, containsPatterns []string
|
||||||
|
|
||||||
for _, fieldName := range ops.Delete {
|
for _, fieldName := range ops.Delete {
|
||||||
fieldName = strings.ToLower(repl.Replace(fieldName))
|
fieldName = strings.ToLower(repl.Replace(fieldName))
|
||||||
if fieldName == "*" {
|
if fieldName == "*" {
|
||||||
for k := range hdr {
|
deleteAll = true
|
||||||
hdr.Del(k)
|
break
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(fieldName, "*") && strings.HasSuffix(fieldName, "*"):
|
case strings.HasPrefix(fieldName, "*") && strings.HasSuffix(fieldName, "*"):
|
||||||
pattern := fieldName[1:len(fieldName)-1]
|
containsPatterns = append(containsPatterns, fieldName[1:len(fieldName)-1])
|
||||||
for k := range hdr {
|
|
||||||
if strings.Contains(strings.ToLower(k), pattern) {
|
|
||||||
hdr.Del(k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case strings.HasPrefix(fieldName, "*"):
|
case strings.HasPrefix(fieldName, "*"):
|
||||||
suffix := fieldName[1:]
|
suffixPatterns = append(suffixPatterns, fieldName[1:])
|
||||||
for k := range hdr {
|
|
||||||
if strings.HasSuffix(strings.ToLower(k), suffix) {
|
|
||||||
hdr.Del(k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case strings.HasSuffix(fieldName, "*"):
|
case strings.HasSuffix(fieldName, "*"):
|
||||||
prefix := fieldName[:len(fieldName)-1]
|
prefixPatterns = append(prefixPatterns, fieldName[:len(fieldName)-1])
|
||||||
for k := range hdr {
|
default:
|
||||||
if strings.HasPrefix(strings.ToLower(k), prefix) {
|
exactDeletes = append(exactDeletes, fieldName)
|
||||||
hdr.Del(k)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if deleteAll {
|
||||||
|
for k := range hdr {
|
||||||
|
hdr.Del(k)
|
||||||
|
}
|
||||||
|
} else if len(exactDeletes) > 0 || len(suffixPatterns) > 0 || len(prefixPatterns) > 0 || len(containsPatterns) > 0 {
|
||||||
|
toDelete := make([]string, 0, len(exactDeletes))
|
||||||
|
for k := range hdr {
|
||||||
|
kl := strings.ToLower(k)
|
||||||
|
for _, d := range exactDeletes {
|
||||||
|
if kl == d {
|
||||||
|
toDelete = append(toDelete, k)
|
||||||
|
goto skip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
for _, p := range containsPatterns {
|
||||||
hdr.Del(fieldName)
|
if strings.Contains(kl, p) {
|
||||||
|
toDelete = append(toDelete, k)
|
||||||
|
goto skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, p := range suffixPatterns {
|
||||||
|
if strings.HasSuffix(kl, p) {
|
||||||
|
toDelete = append(toDelete, k)
|
||||||
|
goto skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, p := range prefixPatterns {
|
||||||
|
if strings.HasPrefix(kl, p) {
|
||||||
|
toDelete = append(toDelete, k)
|
||||||
|
goto skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
skip:
|
||||||
|
}
|
||||||
|
for _, k := range toDelete {
|
||||||
|
hdr.Del(k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -193,15 +193,41 @@ func TestReverseProxyHeaderOpsReplaceResponse(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReverseProxyHeaderOpsProvisionInvalidRegexp(t *testing.T) {
|
func TestReverseProxyHeaderOpsProvisionInvalidRegexp(t *testing.T) {
|
||||||
_ = New()
|
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
ReverseProxy(ReverseProxyConfig{
|
w.WriteHeader(http.StatusOK)
|
||||||
Target: mustParseURL(t, "http://example.com"),
|
_, _ = w.Write([]byte("ok"))
|
||||||
|
}))
|
||||||
|
defer backend.Close()
|
||||||
|
|
||||||
|
target, err := url.Parse(backend.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parse target: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
engine := New()
|
||||||
|
engine.GET("/test", ReverseProxy(ReverseProxyConfig{
|
||||||
|
Target: target,
|
||||||
RequestHeaders: &HeaderOps{
|
RequestHeaders: &HeaderOps{
|
||||||
Replace: map[string][]Replacement{
|
Replace: map[string][]Replacement{
|
||||||
"X-Test": {{SearchRegexp: "[invalid"}},
|
"X-Test": {{SearchRegexp: "[invalid"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}))
|
||||||
|
|
||||||
|
proxy := httptest.NewServer(engine)
|
||||||
|
defer proxy.Close()
|
||||||
|
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, proxy.URL+"/test", nil)
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("request failed: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
_, _ = io.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusInternalServerError {
|
||||||
|
t.Errorf("expected status 500, got %d", resp.StatusCode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReplacementApply(t *testing.T) {
|
func TestReplacementApply(t *testing.T) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue