Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions pkg/router/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,17 @@ func (s *Server) handleGetSandboxError(c *gin.Context, err error) {

func determineUpstreamURL(sandbox *types.SandboxInfo, path string) (*url.URL, error) {
// prefer matched entrypoint by path
var matched types.SandboxEntryPoint
found := false
Comment on lines 108 to +111

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential nil pointer dereferences, it is recommended to add a defensive nil check for the sandbox parameter at the beginning of determineUpstreamURL.

func determineUpstreamURL(sandbox *types.SandboxInfo, path string) (*url.URL, error) {
	if sandbox == nil {
		return nil, fmt.Errorf("sandbox info is nil")
	}
	var matched types.SandboxEntryPoint
	found := false

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving this out for now. determineUpstreamURL is only called after session lookup returns a sandbox, so a nil guard here feels unrelated to the path matching fix.

for _, ep := range sandbox.EntryPoints {
if strings.HasPrefix(path, ep.Path) {
return buildURL(ep.Protocol, ep.Endpoint)
if entryPointPathMatches(path, ep.Path) && (!found || len(ep.Path) > len(matched.Path)) {
matched = ep
found = true
}
}
if found {
return buildURL(matched.Protocol, matched.Endpoint)
}
// fallback to first entrypoint
if len(sandbox.EntryPoints) == 0 {
return nil, fmt.Errorf("no entry point found for sandbox")
Expand All @@ -120,6 +126,17 @@ func determineUpstreamURL(sandbox *types.SandboxInfo, path string) (*url.URL, er
return buildURL(ep.Protocol, ep.Endpoint)
}

func entryPointPathMatches(path, prefix string) bool {
if path != "" && !strings.HasPrefix(path, "/") {
path = "/" + path
}
prefix = strings.TrimSuffix(prefix, "/")
if prefix == "" {
return true
}
return path == prefix || strings.HasPrefix(path, prefix+"/")
}
Comment thread
avinxshKD marked this conversation as resolved.

func buildURL(protocol, endpoint string) (*url.URL, error) {
if protocol != "" && !strings.Contains(endpoint, "://") {
endpoint = (strings.ToLower(protocol) + "://" + endpoint)
Expand Down
49 changes: 49 additions & 0 deletions pkg/router/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,55 @@ func TestHandleInvoke_NoEntryPoints(t *testing.T) {
}
}

func TestDetermineUpstreamURL_PathPrefix(t *testing.T) {
tests := []struct {
name string
path string
entryPoints []types.SandboxEntryPoint
wantHost string
}{
{
name: "longest prefix wins",
path: "/api/run",
entryPoints: []types.SandboxEntryPoint{
{Endpoint: "10.0.0.1:8080", Protocol: "HTTP", Path: "/"},
{Endpoint: "10.0.0.2:8080", Protocol: "HTTP", Path: "/api"},
},
wantHost: "10.0.0.2:8080",
},
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test only covers the boundary case when a / entrypoint exists. With only /api configured, /api2/run still falls through to the first entrypoint, so it can still route to /api; is that fallback behavior intended?

name: "prefix must end on boundary",
path: "/api2/run",
entryPoints: []types.SandboxEntryPoint{
{Endpoint: "10.0.0.1:8080", Protocol: "HTTP", Path: "/api"},
{Endpoint: "10.0.0.2:8080", Protocol: "HTTP", Path: "/"},
},
wantHost: "10.0.0.2:8080",
},
{
name: "normalizes slashes",
path: "api/run",
entryPoints: []types.SandboxEntryPoint{
{Endpoint: "10.0.0.1:8080", Protocol: "HTTP", Path: "/api/"},
},
wantHost: "10.0.0.1:8080",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sandbox := &types.SandboxInfo{EntryPoints: tt.entryPoints}
upstreamURL, err := determineUpstreamURL(sandbox, tt.path)
if err != nil {
t.Fatalf("determineUpstreamURL returned error: %v", err)
}
if upstreamURL.Host != tt.wantHost {
t.Fatalf("expected host %s, got %s", tt.wantHost, upstreamURL.Host)
}
})
}
}

func TestHandleAgentInvoke(t *testing.T) {
// Set required environment variables
setupEnv()
Expand Down
Loading