Skip to content

Commit d1dd51d

Browse files
heanlancursoragent
andcommitted
Address Copilot review comments on backend flow handlers
- parseFlowStreamFilter: trim whitespace from each comma-separated value and skip empty elements to avoid passing blank strings to the gRPC filter; extract a splitTrimmed helper. - protoFlowToAPI: guard GetStartTs/GetEndTs for nil before calling AsTime() to avoid a nil-pointer dereference on malformed records. - handler.go errCh select case: add a comment clarifying that !ok means the gRPC goroutine exited cleanly (EOF / ctx cancelled) and buffered flows were already delivered before errCh closed (LIFO defers ensure flowsCh is closed after errCh). Signed-off-by: Anlan He <anlan.he@broadcom.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent e84c9da commit d1dd51d

2 files changed

Lines changed: 26 additions & 6 deletions

File tree

pkg/handlers/flowstream/grpc.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,14 @@ func ipBytesToString(b []byte) string {
187187
func protoFlowToAPI(pb *flowpb.Flow) apisv1.Flow {
188188
f := apisv1.Flow{
189189
ID: pb.GetId(),
190-
StartTs: pb.GetStartTs().AsTime().Format(time.RFC3339Nano),
191-
EndTs: pb.GetEndTs().AsTime().Format(time.RFC3339Nano),
192190
EndReason: apisv1.FlowEndReason(pb.GetEndReason()),
193191
}
192+
if ts := pb.GetStartTs(); ts != nil {
193+
f.StartTs = ts.AsTime().Format(time.RFC3339Nano)
194+
}
195+
if ts := pb.GetEndTs(); ts != nil {
196+
f.EndTs = ts.AsTime().Format(time.RFC3339Nano)
197+
}
194198

195199
if ip := pb.GetIp(); ip != nil {
196200
f.IP = apisv1.FlowIP{

pkg/handlers/flowstream/handler.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,30 @@ func NewSSEHandler(logger logr.Logger, handler FlowStreamSubscriber) *SSEHandler
6363
}
6464
}
6565

66+
// splitTrimmed splits s by comma and trims whitespace from each element,
67+
// omitting any elements that are empty after trimming.
68+
func splitTrimmed(s string) []string {
69+
parts := strings.Split(s, ",")
70+
result := make([]string, 0, len(parts))
71+
for _, p := range parts {
72+
if t := strings.TrimSpace(p); t != "" {
73+
result = append(result, t)
74+
}
75+
}
76+
return result
77+
}
78+
6679
func parseFlowStreamFilter(c *gin.Context) (*FlowStreamFilter, error) {
6780
filter := &FlowStreamFilter{}
6881

6982
if ns := c.Query("namespaces"); ns != "" {
70-
filter.Namespaces = strings.Split(ns, ",")
83+
filter.Namespaces = splitTrimmed(ns)
7184
}
7285
if pods := c.Query("pods"); pods != "" {
73-
filter.PodNames = strings.Split(pods, ",")
86+
filter.PodNames = splitTrimmed(pods)
7487
}
7588
if svcs := c.Query("services"); svcs != "" {
76-
filter.ServiceNames = strings.Split(svcs, ",")
89+
filter.ServiceNames = splitTrimmed(svcs)
7790
}
7891
if selector := c.Query("podLabelSelector"); selector != "" {
7992
filter.PodLabelSelector = selector
@@ -89,7 +102,7 @@ func parseFlowStreamFilter(c *gin.Context) (*FlowStreamFilter, error) {
89102
}
90103
}
91104
if ips := c.Query("ips"); ips != "" {
92-
filter.IPs = strings.Split(ips, ",")
105+
filter.IPs = splitTrimmed(ips)
93106
}
94107
if dir := c.Query("direction"); dir != "" {
95108
switch strings.ToLower(dir) {
@@ -190,6 +203,9 @@ func (h *SSEHandler) StreamFlows(c *gin.Context) {
190203
return true
191204
case streamErr, ok := <-errCh:
192205
if !ok {
206+
// errCh closed means the gRPC goroutine exited cleanly (EOF or
207+
// context cancelled). flowsCh is closed after errCh (LIFO defers),
208+
// so any buffered flows were already delivered. End the SSE stream.
193209
return false
194210
}
195211
errEvent := apisv1.FlowStreamErrorEvent{Message: streamErr.Error()}

0 commit comments

Comments
 (0)