From 1bb4582564aa3eaac7cd7830291b17135332bb15 Mon Sep 17 00:00:00 2001 From: sanjujunnuthula Date: Thu, 10 Sep 2026 19:08:03 +0000 Subject: [PATCH 1/3] chore: ETag is quoted per spec and clean up redundant COA metadata headers Signed-off-by: sanjujunnuthula --- .../vendors/margo/device-agent-vendor.go | 25 +++++++++++++++++++ .../apis/v1alpha1/vendors/margo/helpers.go | 5 +++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go b/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go index 500cf84fb..0a046e19f 100644 --- a/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go +++ b/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go @@ -751,6 +751,19 @@ func (self *DeviceAgentVendor) downloadBundle(request v1alpha2.COARequest) v1alp "Serving bundle for device %s with verified digest %s (%d bytes)", deviceClientId, actualDigest, len(bundleData)) + // Set headers directly in fasthttp context + if fhCtx, ok := request.Context.Value(v1alpha2.COAFastHTTPContextKey).(*fasthttp.RequestCtx); ok { + + fhCtx.Response.Header.Set("Content-Type", "application/vnd.margo.bundle.v1+tar+gzip") + fhCtx.Response.Header.Set("Cache-Control", "public, max-age=31536000, immutable") + fhCtx.Response.Header.Set("ETag", fmt.Sprintf("\"%s\"", actualDigest)) // Quoted ETag + fhCtx.Response.Header.Set("Vary", "Accept-Encoding") + + deviceVendorLogger.InfofCtx(pCtx, "Set response headers directly - ETag: %s", actualDigest) + } else { + deviceVendorLogger.WarnfCtx(pCtx, "Could not access fasthttp context to set headers") + } + // Return with proper headers return createSuccessResponseWithHeaders(span, "application/vnd.margo.bundle.v1+tar+gzip", @@ -900,6 +913,18 @@ func (self *DeviceAgentVendor) downloadDeployment(request v1alpha2.COARequest) v "Serving deployment %s with verified digest %s (%d bytes)", deploymentId, actualDigest, len(yamlContent)) + // Set headers directly in fasthttp context + if fhCtx, ok := request.Context.Value(v1alpha2.COAFastHTTPContextKey).(*fasthttp.RequestCtx); ok { + fhCtx.Response.Header.Set("Content-Type", "application/yaml") + fhCtx.Response.Header.Set("Cache-Control", "public, max-age=31536000, immutable") + fhCtx.Response.Header.Set("ETag", fmt.Sprintf("\"%s\"", actualDigest)) // Quoted ETag + fhCtx.Response.Header.Set("Vary", "Accept-Encoding") + + deviceVendorLogger.InfofCtx(pCtx, "Set response headers directly - ETag: %s", actualDigest) + } else { + deviceVendorLogger.WarnfCtx(pCtx, "Could not access fasthttp context to set headers") + } + // Return with proper headers return createSuccessResponseWithHeaders(span, "application/yaml", diff --git a/api/pkg/apis/v1alpha1/vendors/margo/helpers.go b/api/pkg/apis/v1alpha1/vendors/margo/helpers.go index b143ce3f6..c434b8b44 100644 --- a/api/pkg/apis/v1alpha1/vendors/margo/helpers.go +++ b/api/pkg/apis/v1alpha1/vendors/margo/helpers.go @@ -266,7 +266,7 @@ func createSuccessResponseWithHeaders[T any]( builder := NewResponseBuilder(span). WithContentType(contentType). - WithMetadata(metadata). + // WithMetadata(metadata). WithState(state) if data != nil { @@ -274,6 +274,8 @@ func createSuccessResponseWithHeaders[T any]( if rawBytes, ok := any(*data).([]byte); ok { resp, _ := builder.Build() resp.Body = rawBytes // Assign raw bytes directly + // Ensure Metadata is empty so COA doesn't emit Coa_meta_* headers + resp.Metadata = nil return resp } // Otherwise, pass structured objects (structs/maps) to WithData for standard JSON serialization @@ -281,6 +283,7 @@ func createSuccessResponseWithHeaders[T any]( } resp, _ := builder.Build() + resp.Metadata = nil // Clear metadata return resp } From e7d6a82fa172a1aaae7937ce24688e4f0c5a26d1 Mon Sep 17 00:00:00 2001 From: sanjujunnuthula Date: Fri, 11 Sep 2026 05:35:50 +0000 Subject: [PATCH 2/3] chore: updated helper function Signed-off-by: sanjujunnuthula --- .../vendors/margo/device-agent-vendor.go | 37 ++----------------- .../apis/v1alpha1/vendors/margo/helpers.go | 26 +++++++++++-- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go b/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go index 0a046e19f..a4e2b63da 100644 --- a/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go +++ b/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go @@ -752,27 +752,12 @@ func (self *DeviceAgentVendor) downloadBundle(request v1alpha2.COARequest) v1alp deviceClientId, actualDigest, len(bundleData)) // Set headers directly in fasthttp context - if fhCtx, ok := request.Context.Value(v1alpha2.COAFastHTTPContextKey).(*fasthttp.RequestCtx); ok { - - fhCtx.Response.Header.Set("Content-Type", "application/vnd.margo.bundle.v1+tar+gzip") - fhCtx.Response.Header.Set("Cache-Control", "public, max-age=31536000, immutable") - fhCtx.Response.Header.Set("ETag", fmt.Sprintf("\"%s\"", actualDigest)) // Quoted ETag - fhCtx.Response.Header.Set("Vary", "Accept-Encoding") - - deviceVendorLogger.InfofCtx(pCtx, "Set response headers directly - ETag: %s", actualDigest) - } else { - deviceVendorLogger.WarnfCtx(pCtx, "Could not access fasthttp context to set headers") - } + setFastHTTPResponseHeaders(request.Context, "application/vnd.margo.bundle.v1+tar+gzip", actualDigest) // Return with proper headers return createSuccessResponseWithHeaders(span, "application/vnd.margo.bundle.v1+tar+gzip", - map[string]string{ - "Content-Type": "application/vnd.margo.bundle.v1+tar+gzip", - "Cache-Control": "public, max-age=31536000, immutable", - "ETag": fmt.Sprintf("\"%s\"", actualDigest), // Quoted ETag - "Vary": "Accept-Encoding", - }, + map[string]string{}, v1alpha2.OK, &bundleData, ) @@ -914,26 +899,12 @@ func (self *DeviceAgentVendor) downloadDeployment(request v1alpha2.COARequest) v deploymentId, actualDigest, len(yamlContent)) // Set headers directly in fasthttp context - if fhCtx, ok := request.Context.Value(v1alpha2.COAFastHTTPContextKey).(*fasthttp.RequestCtx); ok { - fhCtx.Response.Header.Set("Content-Type", "application/yaml") - fhCtx.Response.Header.Set("Cache-Control", "public, max-age=31536000, immutable") - fhCtx.Response.Header.Set("ETag", fmt.Sprintf("\"%s\"", actualDigest)) // Quoted ETag - fhCtx.Response.Header.Set("Vary", "Accept-Encoding") - - deviceVendorLogger.InfofCtx(pCtx, "Set response headers directly - ETag: %s", actualDigest) - } else { - deviceVendorLogger.WarnfCtx(pCtx, "Could not access fasthttp context to set headers") - } + setFastHTTPResponseHeaders(request.Context, "application/yaml", actualDigest) // Return with proper headers return createSuccessResponseWithHeaders(span, "application/yaml", - map[string]string{ - "Content-Type": "application/yaml", - "Cache-Control": "public, max-age=31536000, immutable", - "ETag": fmt.Sprintf("\"%s\"", actualDigest), // Quoted ETag - "Vary": "Accept-Encoding", - }, + map[string]string{}, v1alpha2.OK, &yamlContent, ) diff --git a/api/pkg/apis/v1alpha1/vendors/margo/helpers.go b/api/pkg/apis/v1alpha1/vendors/margo/helpers.go index c434b8b44..8520c832b 100644 --- a/api/pkg/apis/v1alpha1/vendors/margo/helpers.go +++ b/api/pkg/apis/v1alpha1/vendors/margo/helpers.go @@ -7,6 +7,7 @@ import ( "time" "github.com/eclipse-symphony/symphony/coa/pkg/logger" + "github.com/valyala/fasthttp" "gopkg.in/yaml.v2" "github.com/eclipse-symphony/symphony/coa/pkg/apis/v1alpha2" @@ -15,6 +16,8 @@ import ( "go.opentelemetry.io/otel/trace" ) +var helperVendorLogger = logger.NewLogger("coa.runtime") + // Helper method for error responses func createErrorResponse(logger logger.Logger, span trace.Span, err error, message string, errorType v1alpha2.State) v1alpha2.COAResponse { logger.InfofCtx(context.Background(), "err: %s, msg: %s", err.Error(), message) @@ -266,7 +269,7 @@ func createSuccessResponseWithHeaders[T any]( builder := NewResponseBuilder(span). WithContentType(contentType). - // WithMetadata(metadata). + WithMetadata(metadata). WithState(state) if data != nil { @@ -274,8 +277,6 @@ func createSuccessResponseWithHeaders[T any]( if rawBytes, ok := any(*data).([]byte); ok { resp, _ := builder.Build() resp.Body = rawBytes // Assign raw bytes directly - // Ensure Metadata is empty so COA doesn't emit Coa_meta_* headers - resp.Metadata = nil return resp } // Otherwise, pass structured objects (structs/maps) to WithData for standard JSON serialization @@ -283,7 +284,6 @@ func createSuccessResponseWithHeaders[T any]( } resp, _ := builder.Build() - resp.Metadata = nil // Clear metadata return resp } @@ -325,3 +325,21 @@ func createSuccessResponseWithHeadersSimple[T any]( return observ_utils.CloseSpanWithCOAResponse(span, coaResponse), nil } + +// setFastHTTPResponseHeaders sets standard cache and artifact headers (ETag, Cache-Control, Content-Type) directly on FastHTTP context +func setFastHTTPResponseHeaders( + ctx context.Context, + contentType string, + digest string, +) { + if fhCtx, ok := ctx.Value(v1alpha2.COAFastHTTPContextKey).(*fasthttp.RequestCtx); ok { + fhCtx.Response.Header.Set("Content-Type", contentType) + fhCtx.Response.Header.Set("Cache-Control", "public, max-age=31536000, immutable") + fhCtx.Response.Header.Set("ETag", fmt.Sprintf("\"%s\"", digest)) // Quoted ETag per spec + fhCtx.Response.Header.Set("Vary", "Accept-Encoding") + + helperVendorLogger.InfofCtx(ctx, "Set response headers directly - ETag: %s", digest) + } else { + helperVendorLogger.WarnfCtx(ctx, "Could not access fasthttp context to set headers") + } +} From b11700aed2c296aa366c621d187a2415c6de2411 Mon Sep 17 00:00:00 2001 From: sanjujunnuthula Date: Fri, 11 Sep 2026 06:06:49 +0000 Subject: [PATCH 3/3] chore: replaced metdata with nil Signed-off-by: sanjujunnuthula --- api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go b/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go index a4e2b63da..3e7d7d004 100644 --- a/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go +++ b/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go @@ -757,7 +757,7 @@ func (self *DeviceAgentVendor) downloadBundle(request v1alpha2.COARequest) v1alp // Return with proper headers return createSuccessResponseWithHeaders(span, "application/vnd.margo.bundle.v1+tar+gzip", - map[string]string{}, + nil, v1alpha2.OK, &bundleData, ) @@ -904,7 +904,7 @@ func (self *DeviceAgentVendor) downloadDeployment(request v1alpha2.COARequest) v // Return with proper headers return createSuccessResponseWithHeaders(span, "application/yaml", - map[string]string{}, + nil, v1alpha2.OK, &yamlContent, )