mirror of
https://github.com/caddyserver/caddy.git
synced 2026-11-11 19:37:55 +00:00
httpcaddyfile: allocate route groups across named and site routes
Share the adaptation group counter with named-route extraction because group satisfaction is request-wide. Cover nested invoke and handle_path while retaining sibling exclusivity. Addresses scan report fb62a11d-5561-49e3-87df-c175ea5a1f4d. Code written by GitHub Copilot (GPT-6.1 Sol, Claude Opus 5.5); reviewed by mholt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
ec849f542c
commit
b0731f7d2a
2 files changed
+100
-2
No files matched your search
@@ -104,7 +104,7 @@ func (st ServerType) Setup(
|
||||
// with actual identifiers used by Caddy
|
||||
replacer := NewShorthandReplacer()
|
||||
|
||||
originalServerBlocks, err = st.extractNamedRoutes(originalServerBlocks, options, &warnings, replacer)
|
||||
originalServerBlocks, err = st.extractNamedRoutes(originalServerBlocks, options, &warnings, replacer, gc)
|
||||
if err != nil {
|
||||
return nil, warnings, err
|
||||
}
|
||||
@@ -477,11 +477,11 @@ func (ServerType) extractNamedRoutes(
|
||||
options map[string]any,
|
||||
warnings *[]caddyconfig.Warning,
|
||||
replacer ShorthandReplacer,
|
||||
gc counter,
|
||||
) ([]serverBlock, error) {
|
||||
namedRoutes := map[string]*caddyhttp.Route{}
|
||||
namedRouteInvokes := map[string][]string{}
|
||||
|
||||
gc := counter{new(int)}
|
||||
state := make(map[string]any)
|
||||
|
||||
// copy the server blocks so we can
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package httpcaddyfile_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
_ "github.com/caddyserver/caddy/v2/modules/caddyhttp/rewrite"
|
||||
)
|
||||
|
||||
func TestNamedRouteGroupsAreDistinct(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name, named, site string
|
||||
}{
|
||||
{
|
||||
name: "handle",
|
||||
named: `&(guard) {
|
||||
handle /api/admin {
|
||||
respond "denied" 403
|
||||
}
|
||||
handle {
|
||||
respond "public"
|
||||
}
|
||||
}`,
|
||||
site: `handle /api/* {
|
||||
invoke guard
|
||||
respond "allowed"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "handle_path",
|
||||
named: `&(guard) {
|
||||
handle /admin {
|
||||
respond "denied" 403
|
||||
}
|
||||
handle {
|
||||
respond "public"
|
||||
}
|
||||
}`,
|
||||
site: `handle_path /api/* {
|
||||
invoke guard
|
||||
respond "allowed"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
name: "nested invoke",
|
||||
named: `&(inner) {
|
||||
handle /api/admin {
|
||||
respond "denied" 403
|
||||
}
|
||||
handle {
|
||||
respond "public"
|
||||
}
|
||||
}
|
||||
&(guard) {
|
||||
handle /api/* {
|
||||
invoke inner
|
||||
}
|
||||
handle {
|
||||
respond "outer"
|
||||
}
|
||||
}`,
|
||||
site: `handle /api/* {
|
||||
invoke guard
|
||||
respond "allowed"
|
||||
}`,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
server, handler := adaptedRouteHandler(t, "{\nadmin off\nauto_https off\n}\n"+tc.named+"\n:9080 {\n"+tc.site+`
|
||||
handle {
|
||||
respond "fallback" 404
|
||||
}
|
||||
}`)
|
||||
for _, request := range []struct {
|
||||
path string
|
||||
code int
|
||||
body string
|
||||
}{
|
||||
{"/api/admin", http.StatusForbidden, "denied"},
|
||||
{"/api/public", http.StatusOK, "public"},
|
||||
{"/other", http.StatusNotFound, "fallback"},
|
||||
} {
|
||||
req := httptest.NewRequest(http.MethodGet, request.path, nil)
|
||||
req = caddyhttp.PrepareRequest(req, caddy.NewReplacer(), nil, server)
|
||||
rec := httptest.NewRecorder()
|
||||
if err := handler.ServeHTTP(rec, req); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if rec.Code != request.code || rec.Body.String() != request.body {
|
||||
t.Errorf("%s: got %d %q, want %d %q", request.path, rec.Code, rec.Body.String(), request.code, request.body)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user