fix(lint): improve styling and fix lint errors

This commit is contained in:
yusing
2026-02-10 16:57:41 +08:00
parent 978dd886c0
commit a0d0ad0958
42 changed files with 317 additions and 341 deletions

View File

@@ -91,7 +91,7 @@ func (p *Provider) GetType() provider.Type {
return p.t
}
// to work with json marshaller.
// MarshalText implements encoding.TextMarshaler.
func (p *Provider) MarshalText() ([]byte, error) {
return []byte(p.String()), nil
}

View File

@@ -57,7 +57,7 @@ type (
PathPatterns []string `json:"path_patterns,omitempty" extensions:"x-nullable"`
Rules rules.Rules `json:"rules,omitempty" extensions:"x-nullable"`
RuleFile string `json:"rule_file,omitempty" extensions:"x-nullable"`
HealthCheck types.HealthCheckConfig `json:"healthcheck,omitempty" extensions:"x-nullable"` // null on load-balancer routes
HealthCheck types.HealthCheckConfig `json:"healthcheck,omitzero" extensions:"x-nullable"` // null on load-balancer routes
LoadBalance *types.LoadBalancerConfig `json:"load_balance,omitempty" extensions:"x-nullable"`
Middlewares map[string]types.LabelMap `json:"middlewares,omitempty" extensions:"x-nullable"`
Homepage *homepage.ItemConfig `json:"homepage"`
@@ -276,10 +276,10 @@ func (r *Route) validate() error {
case route.SchemeFileServer:
r.Host = ""
r.Port.Proxy = 0
r.LisURL = gperr.Collect(&errs, nettypes.ParseURL, fmt.Sprintf("https://%s", net.JoinHostPort(r.Bind, strconv.Itoa(r.Port.Listening))))
r.LisURL = gperr.Collect(&errs, nettypes.ParseURL, "https://"+net.JoinHostPort(r.Bind, strconv.Itoa(r.Port.Listening)))
r.ProxyURL = gperr.Collect(&errs, nettypes.ParseURL, "file://"+r.Root)
case route.SchemeHTTP, route.SchemeHTTPS, route.SchemeH2C:
r.LisURL = gperr.Collect(&errs, nettypes.ParseURL, fmt.Sprintf("https://%s", net.JoinHostPort(r.Bind, strconv.Itoa(r.Port.Listening))))
r.LisURL = gperr.Collect(&errs, nettypes.ParseURL, "https://"+net.JoinHostPort(r.Bind, strconv.Itoa(r.Port.Listening)))
r.ProxyURL = gperr.Collect(&errs, nettypes.ParseURL, fmt.Sprintf("%s://%s", r.Scheme, net.JoinHostPort(r.Host, strconv.Itoa(r.Port.Proxy))))
case route.SchemeTCP, route.SchemeUDP:
bindIP := net.ParseIP(r.Bind)
@@ -588,10 +588,9 @@ func (r *Route) References() []string {
return []string{r.Proxmox.VMName, aliasRef, r.Proxmox.Services[0]}
}
return []string{r.Proxmox.Services[0], aliasRef}
} else {
if r.Proxmox.VMName != aliasRef {
return []string{r.Proxmox.VMName, aliasRef}
}
}
if r.Proxmox.VMName != aliasRef {
return []string{r.Proxmox.VMName, aliasRef}
}
}
return []string{aliasRef}

View File

@@ -76,6 +76,7 @@ var commands = map[string]struct {
if len(args) != 0 {
return nil, ErrExpectNoArg
}
//nolint:nilnil
return nil, nil
},
build: func(args any) CommandHandler {
@@ -329,7 +330,7 @@ var commands = map[string]struct {
helpExample(CommandSet, "header", "User-Agent", "godoxy"),
),
args: map[string]string{
"target": fmt.Sprintf("the target to set, can be %s", strings.Join(AllFields, ", ")),
"target": "the target to set, can be " + strings.Join(AllFields, ", "),
"field": "the field to set",
"value": "the value to set",
},
@@ -349,7 +350,7 @@ var commands = map[string]struct {
helpExample(CommandAdd, "header", "X-Foo", "bar"),
),
args: map[string]string{
"target": fmt.Sprintf("the target to add, can be %s", strings.Join(AllFields, ", ")),
"target": "the target to add, can be " + strings.Join(AllFields, ", "),
"field": "the field to add",
"value": "the value to add",
},
@@ -369,7 +370,7 @@ var commands = map[string]struct {
helpExample(CommandRemove, "header", "User-Agent"),
),
args: map[string]string{
"target": fmt.Sprintf("the target to remove, can be %s", strings.Join(AllFields, ", ")),
"target": "the target to remove, can be " + strings.Join(AllFields, ", "),
"field": "the field to remove",
},
},
@@ -511,8 +512,10 @@ var commands = map[string]struct {
},
}
type onLogArgs = Tuple3[zerolog.Level, io.WriteCloser, templateString]
type onNotifyArgs = Tuple4[zerolog.Level, string, templateString, templateString]
type (
onLogArgs = Tuple3[zerolog.Level, io.WriteCloser, templateString]
onNotifyArgs = Tuple4[zerolog.Level, string, templateString, templateString]
)
// Parse implements strutils.Parser.
func (cmd *Command) Parse(v string) error {

View File

@@ -53,7 +53,7 @@ func TestLogCommand_TemporaryFile(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("POST", "/api/users", nil)
req := httptest.NewRequest(http.MethodPost, "/api/users", nil)
req.Header.Set("User-Agent", "test-agent")
w := httptest.NewRecorder()
@@ -70,7 +70,7 @@ func TestLogCommand_TemporaryFile(t *testing.T) {
}
func TestLogCommand_StdoutAndStderr(t *testing.T) {
upstream := mockUpstream(200, "success")
upstream := mockUpstream(http.StatusOK, "success")
var rules Rules
err := parseRules(`
@@ -85,7 +85,7 @@ func TestLogCommand_StdoutAndStderr(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/test", nil)
req := httptest.NewRequest(http.MethodGet, "/test", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
@@ -96,7 +96,7 @@ func TestLogCommand_StdoutAndStderr(t *testing.T) {
}
func TestLogCommand_DifferentLogLevels(t *testing.T) {
upstream := mockUpstream(404, "not found")
upstream := mockUpstream(http.StatusNotFound, "not found")
infoFile := TestRandomFileName()
warnFile := TestRandomFileName()
@@ -140,7 +140,7 @@ func TestLogCommand_TemplateVariables(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Custom-Header", "custom-value")
w.Header().Set("Content-Length", "42")
w.WriteHeader(201)
w.WriteHeader(http.StatusCreated)
w.Write([]byte("created"))
})
@@ -176,13 +176,13 @@ func TestLogCommand_ConditionalLogging(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/error":
w.WriteHeader(500)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("internal server error"))
case "/notfound":
w.WriteHeader(404)
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("not found"))
default:
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
}
})
@@ -206,22 +206,22 @@ func TestLogCommand_ConditionalLogging(t *testing.T) {
handler := rules.BuildHandler(upstream)
// Test success request
req1 := httptest.NewRequest("GET", "/success", nil)
req1 := httptest.NewRequest(http.MethodGet, "/success", nil)
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, http.StatusOK, w1.Code)
// Test not found request
req2 := httptest.NewRequest("GET", "/notfound", nil)
req2 := httptest.NewRequest(http.MethodGet, "/notfound", nil)
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 404, w2.Code)
assert.Equal(t, http.StatusNotFound, w2.Code)
// Test server error request
req3 := httptest.NewRequest("POST", "/error", nil)
req3 := httptest.NewRequest(http.MethodPost, "/error", nil)
w3 := httptest.NewRecorder()
handler.ServeHTTP(w3, req3)
assert.Equal(t, 500, w3.Code)
assert.Equal(t, http.StatusInternalServerError, w3.Code)
// Verify success log
successContent := TestFileContent(successFile)
@@ -238,7 +238,7 @@ func TestLogCommand_ConditionalLogging(t *testing.T) {
}
func TestLogCommand_MultipleLogEntries(t *testing.T) {
upstream := mockUpstream(200, "response")
upstream := mockUpstream(http.StatusOK, "response")
tempFile := TestRandomFileName()
@@ -266,7 +266,7 @@ func TestLogCommand_MultipleLogEntries(t *testing.T) {
req := httptest.NewRequest(reqInfo.method, reqInfo.path, nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
}
// Verify all requests were logged

View File

@@ -67,7 +67,7 @@ func TestFieldHandler_Header(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
tt.setup(req)
w := httptest.NewRecorder()
@@ -126,8 +126,8 @@ func TestFieldHandler_ResponseHeader(t *testing.T) {
verify: func(w *httptest.ResponseRecorder) {
values := w.Header()["X-Response-Test"]
require.Len(t, values, 2)
assert.Equal(t, values[0], "existing-value")
assert.Equal(t, values[1], "additional-value")
assert.Equal(t, "existing-value", values[0])
assert.Equal(t, "additional-value", values[1])
},
},
{
@@ -143,7 +143,7 @@ func TestFieldHandler_ResponseHeader(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
if tt.setup != nil {
tt.setup(w)
@@ -232,7 +232,7 @@ func TestFieldHandler_Query(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
tt.setup(req)
w := httptest.NewRecorder()
@@ -330,7 +330,7 @@ func TestFieldHandler_Cookie(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
tt.setup(req)
w := httptest.NewRecorder()
@@ -396,7 +396,7 @@ func TestFieldHandler_Body(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
tt.setup(req)
w := httptest.NewRecorder()
@@ -440,7 +440,7 @@ func TestFieldHandler_ResponseBody(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
tt.setup(req)
w := httptest.NewRecorder()
@@ -494,7 +494,7 @@ func TestFieldHandler_StatusCode(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
rm := httputils.NewResponseModifier(w)
var cmd Command

View File

@@ -23,9 +23,8 @@ import (
)
// mockUpstream creates a simple upstream handler for testing
func mockUpstream(status int, body string) http.HandlerFunc {
func mockUpstream(body string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(status)
w.Write([]byte(body))
}
}
@@ -51,7 +50,7 @@ func parseRules(data string, target *Rules) error {
func TestHTTPFlow_BasicPreRules(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Custom-Header", r.Header.Get("X-Custom-Header"))
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("upstream response"))
})
@@ -65,18 +64,18 @@ func TestHTTPFlow_BasicPreRules(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "upstream response", w.Body.String())
assert.Equal(t, "test-value", w.Header().Get("X-Custom-Header"))
}
func TestHTTPFlow_BypassRule(t *testing.T) {
upstream := mockUpstream(200, "upstream response")
upstream := mockUpstream("upstream response")
var rules Rules
err := parseRules(`
@@ -91,17 +90,17 @@ func TestHTTPFlow_BypassRule(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/bypass", nil)
req := httptest.NewRequest(http.MethodGet, "/bypass", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "upstream response", w.Body.String())
}
func TestHTTPFlow_TerminatingCommand(t *testing.T) {
upstream := mockUpstream(200, "should not be called")
upstream := mockUpstream("should not be called")
var rules Rules
err := parseRules(`
@@ -116,18 +115,18 @@ func TestHTTPFlow_TerminatingCommand(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/error", nil)
req := httptest.NewRequest(http.MethodGet, "/error", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 403, w.Code)
assert.Equal(t, http.StatusForbidden, w.Code)
assert.Equal(t, "Forbidden\n", w.Body.String())
assert.Empty(t, w.Header().Get("X-Header"))
}
func TestHTTPFlow_RedirectFlow(t *testing.T) {
upstream := mockUpstream(200, "should not be called")
upstream := mockUpstream("should not be called")
var rules Rules
err := parseRules(`
@@ -139,18 +138,18 @@ func TestHTTPFlow_RedirectFlow(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/old-path", nil)
req := httptest.NewRequest(http.MethodGet, "/old-path", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 307, w.Code) // TemporaryRedirect
assert.Equal(t, http.StatusTemporaryRedirect, w.Code) // TemporaryRedirect
assert.Equal(t, "/new-path", w.Header().Get("Location"))
}
func TestHTTPFlow_RewriteFlow(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("path: " + r.URL.Path))
})
@@ -164,18 +163,18 @@ func TestHTTPFlow_RewriteFlow(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/api/users", nil)
req := httptest.NewRequest(http.MethodGet, "/api/users", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "path: /v1/users", w.Body.String())
}
func TestHTTPFlow_MultiplePreRules(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("upstream: " + r.Header.Get("X-Request-Id")))
})
@@ -192,18 +191,18 @@ func TestHTTPFlow_MultiplePreRules(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "upstream: req-123", w.Body.String())
assert.Equal(t, "token-456", req.Header.Get("X-Auth-Token"))
}
func TestHTTPFlow_PostResponseRule(t *testing.T) {
upstream := mockUpstreamWithHeaders(200, "success", http.Header{
upstream := mockUpstreamWithHeaders(http.StatusOK, "success", http.Header{
"X-Upstream": []string{"upstream-value"},
})
@@ -219,12 +218,12 @@ func TestHTTPFlow_PostResponseRule(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/test", nil)
req := httptest.NewRequest(http.MethodGet, "/test", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "success", w.Body.String())
assert.Equal(t, "upstream-value", w.Header().Get("X-Upstream"))
@@ -237,10 +236,10 @@ func TestHTTPFlow_PostResponseRule(t *testing.T) {
func TestHTTPFlow_ResponseRuleWithStatusCondition(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/success" {
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
} else {
w.WriteHeader(404)
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("not found"))
}
})
@@ -260,18 +259,18 @@ func TestHTTPFlow_ResponseRuleWithStatusCondition(t *testing.T) {
handler := rules.BuildHandler(upstream)
// Test successful request (should not log)
req1 := httptest.NewRequest("GET", "/success", nil)
req1 := httptest.NewRequest(http.MethodGet, "/success", nil)
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, http.StatusOK, w1.Code)
// Test error request (should log)
req2 := httptest.NewRequest("GET", "/notfound", nil)
req2 := httptest.NewRequest(http.MethodGet, "/notfound", nil)
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 404, w2.Code)
assert.Equal(t, http.StatusNotFound, w2.Code)
// Check log file
content := TestFileContent(tempFile)
@@ -283,7 +282,7 @@ func TestHTTPFlow_ResponseRuleWithStatusCondition(t *testing.T) {
func TestHTTPFlow_ConditionalRules(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("hello " + r.Header.Get("X-Username")))
})
@@ -304,19 +303,19 @@ func TestHTTPFlow_ConditionalRules(t *testing.T) {
handler := rules.BuildHandler(upstream)
// Test with Authorization header
req1 := httptest.NewRequest("GET", "/", nil)
req1 := httptest.NewRequest(http.MethodGet, "/", nil)
req1.Header.Set("Authorization", "Bearer token")
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, http.StatusOK, w1.Code)
assert.Equal(t, "hello authenticated-user", w1.Body.String())
assert.Equal(t, "authenticated-user", w1.Header().Get("X-Username"))
// Test without Authorization header
req2 := httptest.NewRequest("GET", "/", nil)
req2 := httptest.NewRequest(http.MethodGet, "/", nil)
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 200, w2.Code)
assert.Equal(t, http.StatusOK, w2.Code)
assert.Equal(t, "hello anonymous", w2.Body.String())
assert.Equal(t, "anonymous", w2.Header().Get("X-Username"))
}
@@ -326,13 +325,13 @@ func TestHTTPFlow_ComplexFlowWithPreAndPostRules(t *testing.T) {
// Simulate different responses based on path
if r.URL.Path == "/protected" {
if r.Header.Get("X-Auth") != "valid" {
w.WriteHeader(401)
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("unauthorized"))
return
}
}
w.Header().Set("X-Response-Time", "100ms")
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
})
@@ -360,32 +359,32 @@ func TestHTTPFlow_ComplexFlowWithPreAndPostRules(t *testing.T) {
handler := rules.BuildHandler(upstream)
// Test successful request
req1 := httptest.NewRequest("GET", "/public", nil)
req1 := httptest.NewRequest(http.MethodGet, "/public", nil)
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, http.StatusOK, w1.Code)
assert.Equal(t, "success", w1.Body.String())
assert.Equal(t, "random_uuid", w1.Header().Get("X-Correlation-Id"))
assert.Equal(t, "100ms", w1.Header().Get("X-Response-Time"))
// Test unauthorized protected request
req2 := httptest.NewRequest("GET", "/protected", nil)
req2 := httptest.NewRequest(http.MethodGet, "/protected", nil)
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 401, w2.Code)
assert.Equal(t, w2.Body.String(), "Unauthorized\n")
assert.Equal(t, http.StatusUnauthorized, w2.Code)
assert.Equal(t, "Unauthorized\n", w2.Body.String())
// Test authorized protected request
req3 := httptest.NewRequest("GET", "/protected", nil)
req3 := httptest.NewRequest(http.MethodGet, "/protected", nil)
req3.SetBasicAuth("user", "pass")
w3 := httptest.NewRecorder()
handler.ServeHTTP(w3, req3)
// This should fail because our simple upstream expects X-Auth: valid header
// but the basic auth requirement should add the appropriate header
assert.Equal(t, 401, w3.Code)
assert.Equal(t, http.StatusUnauthorized, w3.Code)
// Check log files
logContent := TestFileContent(logFile)
@@ -404,7 +403,7 @@ func TestHTTPFlow_ComplexFlowWithPreAndPostRules(t *testing.T) {
}
func TestHTTPFlow_DefaultRule(t *testing.T) {
upstream := mockUpstream(200, "upstream response")
upstream := mockUpstream("upstream response")
var rules Rules
err := parseRules(`
@@ -419,20 +418,20 @@ func TestHTTPFlow_DefaultRule(t *testing.T) {
handler := rules.BuildHandler(upstream)
// Test default rule
req1 := httptest.NewRequest("GET", "/regular", nil)
req1 := httptest.NewRequest(http.MethodGet, "/regular", nil)
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, http.StatusOK, w1.Code)
assert.Equal(t, "true", w1.Header().Get("X-Default-Applied"))
assert.Empty(t, w1.Header().Get("X-Special-Handled"))
// Test special rule + default rule
req2 := httptest.NewRequest("GET", "/special", nil)
req2 := httptest.NewRequest(http.MethodGet, "/special", nil)
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 200, w2.Code)
assert.Equal(t, http.StatusOK, w2.Code)
assert.Equal(t, "true", w2.Header().Get("X-Default-Applied"))
assert.Equal(t, "true", w2.Header().Get("X-Special-Handled"))
}
@@ -442,7 +441,7 @@ func TestHTTPFlow_HeaderManipulation(t *testing.T) {
// Echo back a header
headerValue := r.Header.Get("X-Test-Header")
w.Header().Set("X-Echoed-Header", headerValue)
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("header echoed"))
})
@@ -460,14 +459,14 @@ func TestHTTPFlow_HeaderManipulation(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("X-Secret", "secret-value")
req.Header.Set("X-Test-Header", "original-value")
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "modified-value", w.Header().Get("X-Echoed-Header"))
assert.Equal(t, "custom-value", w.Header().Get("X-Custom-Header"))
// Ensure the secret header was removed and not passed to upstream
@@ -477,7 +476,7 @@ func TestHTTPFlow_HeaderManipulation(t *testing.T) {
func TestHTTPFlow_QueryParameterHandling(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("query: " + query.Get("param")))
})
@@ -491,25 +490,23 @@ func TestHTTPFlow_QueryParameterHandling(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/path?param=original", nil)
req := httptest.NewRequest(http.MethodGet, "/path?param=original", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
// The set command should have modified the query parameter
assert.Equal(t, "query: added-value", w.Body.String())
}
func TestHTTPFlow_ServeCommand(t *testing.T) {
// Create a temporary directory with test files
tempDir, err := os.MkdirTemp("", "test-serve-*")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
tempDir := t.TempDir()
// Create test files directly in the temp directory
testFile := filepath.Join(tempDir, "index.html")
err = os.WriteFile(testFile, []byte("<h1>Test Page</h1>"), 0644)
err := os.WriteFile(testFile, []byte("<h1>Test Page</h1>"), 0o644)
require.NoError(t, err)
var rules Rules
@@ -520,7 +517,7 @@ func TestHTTPFlow_ServeCommand(t *testing.T) {
`, tempDir), &rules)
require.NoError(t, err)
handler := rules.BuildHandler(mockUpstream(200, "should not be called"))
handler := rules.BuildHandler(mockUpstream("should not be called"))
// Test serving a file - serve command serves files relative to the root directory
// The path /files/index.html gets mapped to tempDir + "/files/index.html"
@@ -533,7 +530,7 @@ func TestHTTPFlow_ServeCommand(t *testing.T) {
err = os.WriteFile(filesIndexFile, []byte("<h1>Test Page</h1>"), 0644)
require.NoError(t, err)
req1 := httptest.NewRequest("GET", "/files/index.html", nil)
req1 := httptest.NewRequest(http.MethodGet, "/files/index.html", nil)
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
@@ -542,18 +539,18 @@ func TestHTTPFlow_ServeCommand(t *testing.T) {
assert.NotEqual(t, "should not be called", w1.Body.String())
// Test file not found
req2 := httptest.NewRequest("GET", "/files/nonexistent.html", nil)
req2 := httptest.NewRequest(http.MethodGet, "/files/nonexistent.html", nil)
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 404, w2.Code)
assert.Equal(t, http.StatusNotFound, w2.Code)
}
func TestHTTPFlow_ProxyCommand(t *testing.T) {
// Create a mock upstream server
upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Upstream-Header", "upstream-value")
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("upstream response"))
}))
defer upstreamServer.Close()
@@ -566,15 +563,15 @@ func TestHTTPFlow_ProxyCommand(t *testing.T) {
`, upstreamServer.URL), &rules)
require.NoError(t, err)
handler := rules.BuildHandler(mockUpstream(200, "should not be called"))
handler := rules.BuildHandler(mockUpstream("should not be called"))
req := httptest.NewRequest("GET", "/api/test", nil)
req := httptest.NewRequest(http.MethodGet, "/api/test", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
// The proxy command should forward the request to the upstream server
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "upstream response", w.Body.String())
assert.Equal(t, "upstream-value", w.Header().Get("X-Upstream-Header"))
}
@@ -585,7 +582,7 @@ func TestHTTPFlow_NotifyCommand(t *testing.T) {
func TestHTTPFlow_FormConditions(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("form processed"))
})
@@ -604,28 +601,28 @@ func TestHTTPFlow_FormConditions(t *testing.T) {
// Test form condition
formData := url.Values{"username": {"john_doe"}}
req1 := httptest.NewRequest("POST", "/", strings.NewReader(formData.Encode()))
req1 := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(formData.Encode()))
req1.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, http.StatusOK, w1.Code)
assert.Equal(t, "john_doe", w1.Header().Get("X-Username"))
// Test postform condition
postFormData := url.Values{"email": {"john@example.com"}}
req2 := httptest.NewRequest("POST", "/", strings.NewReader(postFormData.Encode()))
req2 := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(postFormData.Encode()))
req2.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 200, w2.Code)
assert.Equal(t, http.StatusOK, w2.Code)
assert.Equal(t, "john@example.com", w2.Header().Get("X-Email"))
}
func TestHTTPFlow_RemoteConditions(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("remote processed"))
})
@@ -643,27 +640,27 @@ func TestHTTPFlow_RemoteConditions(t *testing.T) {
handler := rules.BuildHandler(upstream)
// Test localhost condition
req1 := httptest.NewRequest("GET", "/", nil)
req1 := httptest.NewRequest(http.MethodGet, "/", nil)
req1.RemoteAddr = "127.0.0.1:12345"
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, http.StatusOK, w1.Code)
assert.Equal(t, "local", w1.Header().Get("X-Access"))
// Test private network block
req2 := httptest.NewRequest("GET", "/", nil)
req2 := httptest.NewRequest(http.MethodGet, "/", nil)
req2.RemoteAddr = "192.168.1.100:12345"
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 403, w2.Code)
assert.Equal(t, http.StatusForbidden, w2.Code)
assert.Equal(t, "Private network blocked\n", w2.Body.String())
}
func TestHTTPFlow_BasicAuthConditions(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("auth processed"))
})
@@ -687,27 +684,27 @@ func TestHTTPFlow_BasicAuthConditions(t *testing.T) {
handler := rules.BuildHandler(upstream)
// Test admin user
req1 := httptest.NewRequest("GET", "/", nil)
req1 := httptest.NewRequest(http.MethodGet, "/", nil)
req1.SetBasicAuth("admin", "adminpass")
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, http.StatusOK, w1.Code)
assert.Equal(t, "admin", w1.Header().Get("X-Auth-Status"))
// Test guest user
req2 := httptest.NewRequest("GET", "/", nil)
req2 := httptest.NewRequest(http.MethodGet, "/", nil)
req2.SetBasicAuth("guest", "guestpass")
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 200, w2.Code)
assert.Equal(t, http.StatusOK, w2.Code)
assert.Equal(t, "guest", w2.Header().Get("X-Auth-Status"))
}
func TestHTTPFlow_RouteConditions(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("route processed"))
})
@@ -725,29 +722,29 @@ func TestHTTPFlow_RouteConditions(t *testing.T) {
handler := rules.BuildHandler(upstream)
// Test API route
req1 := httptest.NewRequest("GET", "/", nil)
req1 := httptest.NewRequest(http.MethodGet, "/", nil)
req1 = routes.WithRouteContext(req1, mockRoute("backend"))
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, http.StatusOK, w1.Code)
assert.Equal(t, "backend", w1.Header().Get("X-Route"))
// Test admin route
req2 := httptest.NewRequest("GET", "/", nil)
req2 := httptest.NewRequest(http.MethodGet, "/", nil)
req2 = routes.WithRouteContext(req2, mockRoute("frontend"))
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 200, w2.Code)
assert.Equal(t, http.StatusOK, w2.Code)
assert.Equal(t, "frontend", w2.Header().Get("X-Route"))
}
func TestHTTPFlow_ResponseStatusConditions(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(405)
w.WriteHeader(http.StatusMethodNotAllowed)
w.Write([]byte("method not allowed"))
})
@@ -762,18 +759,18 @@ func TestHTTPFlow_ResponseStatusConditions(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 405, w.Code)
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
assert.Equal(t, "error\n", w.Body.String())
}
func TestHTTPFlow_ResponseHeaderConditions(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Response-Header", "response header")
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("processed"))
})
@@ -788,11 +785,11 @@ func TestHTTPFlow_ResponseHeaderConditions(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 405, w.Code)
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
assert.Equal(t, "error\n", w.Body.String())
})
t.Run("with_value", func(t *testing.T) {
@@ -806,11 +803,11 @@ func TestHTTPFlow_ResponseHeaderConditions(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 405, w.Code)
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
assert.Equal(t, "error\n", w.Body.String())
})
@@ -825,18 +822,18 @@ func TestHTTPFlow_ResponseHeaderConditions(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/", nil)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "processed", w.Body.String())
})
}
func TestHTTPFlow_ComplexRuleCombinations(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("complex processed"))
})
@@ -867,26 +864,26 @@ func TestHTTPFlow_ComplexRuleCombinations(t *testing.T) {
handler := rules.BuildHandler(upstream)
// Test admin API (should match first rule)
req1 := httptest.NewRequest("POST", "/api/admin/users", nil)
req1 := httptest.NewRequest(http.MethodPost, "/api/admin/users", nil)
req1.Header.Set("Authorization", "Bearer token")
w1 := httptest.NewRecorder()
handler.ServeHTTP(w1, req1)
assert.Equal(t, 200, w1.Code)
assert.Equal(t, http.StatusOK, w1.Code)
assert.Equal(t, "admin", w1.Header().Get("X-Access-Level"))
assert.Equal(t, "v1", w1.Header()["X-API-Version"][0])
// Test user API (should match second rule)
req2 := httptest.NewRequest("GET", "/api/users/profile", nil)
req2 := httptest.NewRequest(http.MethodGet, "/api/users/profile", nil)
w2 := httptest.NewRecorder()
handler.ServeHTTP(w2, req2)
assert.Equal(t, 200, w2.Code)
assert.Equal(t, http.StatusOK, w2.Code)
assert.Equal(t, "user", w2.Header().Get("X-Access-Level"))
assert.Equal(t, "v1", w2.Header()["X-API-Version"][0])
// Test public API (should match third rule)
req3 := httptest.NewRequest("GET", "/api/public/info", nil)
req3 := httptest.NewRequest(http.MethodGet, "/api/public/info", nil)
w3 := httptest.NewRecorder()
handler.ServeHTTP(w3, req3)
@@ -897,7 +894,7 @@ func TestHTTPFlow_ComplexRuleCombinations(t *testing.T) {
func TestHTTPFlow_ResponseModifier(t *testing.T) {
upstream := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
w.Write([]byte("original response"))
})
@@ -912,12 +909,12 @@ func TestHTTPFlow_ResponseModifier(t *testing.T) {
handler := rules.BuildHandler(upstream)
req := httptest.NewRequest("GET", "/test", nil)
req := httptest.NewRequest(http.MethodGet, "/test", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "true", w.Header().Get("X-Modified"))
assert.Equal(t, "Modified: GET /test\n", w.Body.String())
}

View File

@@ -41,6 +41,7 @@ const (
OnRoute = "route"
// on response
OnResponseHeader = "resp_header"
OnStatus = "status"
)
@@ -63,6 +64,7 @@ var checkers = map[string]struct {
if len(args) != 0 {
return nil, ErrExpectNoArg
}
//nolint:nilnil
return nil, nil
},
builder: func(args any) CheckFunc { return func(w http.ResponseWriter, r *http.Request) bool { return false } }, // this should never be called

View File

@@ -1,11 +1,9 @@
package rules
import (
"os"
"strconv"
"testing"
gperr "github.com/yusing/goutils/errs"
expect "github.com/yusing/goutils/testing"
)
@@ -15,7 +13,6 @@ func TestParser(t *testing.T) {
input string
subject string
args []string
wantErr gperr.Error
}{
{
name: "basic",
@@ -93,10 +90,6 @@ func TestParser(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
subject, args, err := parse(tt.input)
if tt.wantErr != nil {
expect.ErrorIs(t, tt.wantErr, err)
return
}
// t.Log(subject, args, err)
expect.NoError(t, err)
expect.Equal(t, subject, tt.subject)
@@ -105,12 +98,8 @@ func TestParser(t *testing.T) {
}
t.Run("env substitution", func(t *testing.T) {
// Set up test environment variables
os.Setenv("CLOUDFLARE_API_KEY", "test-api-key-123")
os.Setenv("DOMAIN", "example.com")
defer func() {
os.Unsetenv("CLOUDFLARE_API_KEY")
os.Unsetenv("DOMAIN")
}()
t.Setenv("CLOUDFLARE_API_KEY", "test-api-key-123")
t.Setenv("DOMAIN", "example.com")
tests := []struct {
name string

View File

@@ -2,6 +2,7 @@ package rules
import (
"io"
"net/http"
"net/http/httptest"
"net/url"
"testing"
@@ -11,9 +12,9 @@ import (
func BenchmarkExpandVars(b *testing.B) {
testResponseModifier := httputils.NewResponseModifier(httptest.NewRecorder())
testResponseModifier.WriteHeader(200)
testResponseModifier.WriteHeader(http.StatusOK)
testResponseModifier.Write([]byte("Hello, world!"))
testRequest := httptest.NewRequest("GET", "/", nil)
testRequest := httptest.NewRequest(http.MethodGet, "/", nil)
testRequest.Header.Set("User-Agent", "test-agent/1.0")
testRequest.Header.Set("X-Custom", "value1,value2")
testRequest.ContentLength = 12345

View File

@@ -203,7 +203,7 @@ func TestExpandVars(t *testing.T) {
postFormData.Add("postmulti", "first")
postFormData.Add("postmulti", "second")
testRequest := httptest.NewRequest("POST", "https://example.com:8080/api/users?param1=value1&param2=value2#fragment", strings.NewReader(postFormData.Encode()))
testRequest := httptest.NewRequest(http.MethodPost, "https://example.com:8080/api/users?param1=value1&param2=value2#fragment", strings.NewReader(postFormData.Encode()))
testRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
testRequest.Header.Set("User-Agent", "test-agent/1.0")
testRequest.Header.Add("X-Custom", "value1")
@@ -218,7 +218,7 @@ func TestExpandVars(t *testing.T) {
testResponseModifier := httputils.NewResponseModifier(httptest.NewRecorder())
testResponseModifier.Header().Set("Content-Type", "text/html")
testResponseModifier.Header().Set("X-Custom-Resp", "resp-value")
testResponseModifier.WriteHeader(200)
testResponseModifier.WriteHeader(http.StatusOK)
// set content length to 9876 by writing 9876 'a' bytes
testResponseModifier.Write(bytes.Repeat([]byte("a"), 9876))
@@ -498,12 +498,12 @@ func TestExpandVars(t *testing.T) {
func TestExpandVars_Integration(t *testing.T) {
t.Run("complex log format", func(t *testing.T) {
testRequest := httptest.NewRequest("GET", "https://api.example.com/users/123?sort=asc", nil)
testRequest := httptest.NewRequest(http.MethodGet, "https://api.example.com/users/123?sort=asc", nil)
testRequest.Header.Set("User-Agent", "curl/7.68.0")
testRequest.RemoteAddr = "10.0.0.1:54321"
testResponseModifier := httputils.NewResponseModifier(httptest.NewRecorder())
testResponseModifier.WriteHeader(200)
testResponseModifier.WriteHeader(http.StatusOK)
var out strings.Builder
err := ExpandVars(testResponseModifier, testRequest,
@@ -515,7 +515,7 @@ func TestExpandVars_Integration(t *testing.T) {
})
t.Run("with query parameters", func(t *testing.T) {
testRequest := httptest.NewRequest("GET", "http://example.com/search?q=test&page=1", nil)
testRequest := httptest.NewRequest(http.MethodGet, "http://example.com/search?q=test&page=1", nil)
testResponseModifier := httputils.NewResponseModifier(httptest.NewRecorder())
@@ -529,12 +529,12 @@ func TestExpandVars_Integration(t *testing.T) {
})
t.Run("response headers", func(t *testing.T) {
testRequest := httptest.NewRequest("GET", "/", nil)
testRequest := httptest.NewRequest(http.MethodGet, "/", nil)
testResponseModifier := httputils.NewResponseModifier(httptest.NewRecorder())
testResponseModifier.Header().Set("Cache-Control", "no-cache")
testResponseModifier.Header().Set("X-Rate-Limit", "100")
testResponseModifier.WriteHeader(200)
testResponseModifier.WriteHeader(http.StatusOK)
var out strings.Builder
err := ExpandVars(testResponseModifier, testRequest,
@@ -554,7 +554,7 @@ func TestExpandVars_RequestSchemes(t *testing.T) {
}{
{
name: "http scheme",
request: httptest.NewRequest("GET", "http://example.com/", nil),
request: httptest.NewRequest(http.MethodGet, "http://example.com/", nil),
expected: "http",
},
{
@@ -581,7 +581,7 @@ func TestExpandVars_RequestSchemes(t *testing.T) {
func TestExpandVars_UpstreamVariables(t *testing.T) {
// Upstream variables require context from routes package
testRequest := httptest.NewRequest("GET", "/", nil)
testRequest := httptest.NewRequest(http.MethodGet, "/", nil)
testResponseModifier := httputils.NewResponseModifier(httptest.NewRecorder())
@@ -607,7 +607,7 @@ func TestExpandVars_UpstreamVariables(t *testing.T) {
func TestExpandVars_NoHostPort(t *testing.T) {
// Test request without port in Host header
testRequest := httptest.NewRequest("GET", "/", nil)
testRequest := httptest.NewRequest(http.MethodGet, "/", nil)
testRequest.Host = "example.com" // No port
testResponseModifier := httputils.NewResponseModifier(httptest.NewRecorder())
@@ -623,13 +623,13 @@ func TestExpandVars_NoHostPort(t *testing.T) {
var out strings.Builder
err := ExpandVars(testResponseModifier, testRequest, "$req_port", &out)
require.NoError(t, err)
require.Equal(t, "", out.String())
require.Empty(t, out.String())
})
}
func TestExpandVars_NoRemotePort(t *testing.T) {
// Test request without port in RemoteAddr
testRequest := httptest.NewRequest("GET", "/", nil)
testRequest := httptest.NewRequest(http.MethodGet, "/", nil)
testRequest.RemoteAddr = "192.168.1.1" // No port
testResponseModifier := httputils.NewResponseModifier(httptest.NewRecorder())
@@ -638,19 +638,19 @@ func TestExpandVars_NoRemotePort(t *testing.T) {
var out strings.Builder
err := ExpandVars(testResponseModifier, testRequest, "$remote_host", &out)
require.NoError(t, err)
require.Equal(t, "", out.String())
require.Empty(t, out.String())
})
t.Run("remote_port without port", func(t *testing.T) {
var out strings.Builder
err := ExpandVars(testResponseModifier, testRequest, "$remote_port", &out)
require.NoError(t, err)
require.Equal(t, "", out.String())
require.Empty(t, out.String())
})
}
func TestExpandVars_WhitespaceHandling(t *testing.T) {
testRequest := httptest.NewRequest("GET", "/test", nil)
testRequest := httptest.NewRequest(http.MethodGet, "/test", nil)
testResponseModifier := httputils.NewResponseModifier(httptest.NewRecorder())
var out strings.Builder

View File

@@ -27,6 +27,7 @@ type HTTPConfig struct {
// BuildTLSConfig creates a TLS configuration based on the HTTP config options.
func (cfg *HTTPConfig) BuildTLSConfig(targetURL *url.URL) (*tls.Config, error) {
//nolint:gosec
tlsConfig := &tls.Config{}
// Handle InsecureSkipVerify (legacy NoTLSVerify option)