From 29f58debc9d190bd84f56e736f2ac80320d28ab2 Mon Sep 17 00:00:00 2001 From: ionutboangiu Date: Tue, 7 Nov 2023 11:17:05 -0500 Subject: [PATCH] Clone header before creating exporter HTTP request Behind http.Header is just a map and it's not safe for concurrent use. Before this change, a panic might have occurred when doing asynchronous HTTP exports (applies to both *http_post and *http_json_map exporters). Cloning the header before adding it to the HTTP request has fixed this issue. Slightly improved the test that found this data race. --- ees/httpjsonmap.go | 4 ++-- ees/httppost.go | 5 +++-- ees/httppost_test.go | 24 ++++++++++++++++++++++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/ees/httpjsonmap.go b/ees/httpjsonmap.go index 6bc6a5149..ff4f9b44b 100644 --- a/ees/httpjsonmap.go +++ b/ees/httpjsonmap.go @@ -96,7 +96,7 @@ func (httpEE *HTTPjsonMapEE) GetMetrics() *utils.SafeMapStorage { return httpEE. func (httpEE *HTTPjsonMapEE) PrepareMap(mp *utils.CGREvent) (any, error) { body, err := json.Marshal(mp.Event) return &HTTPPosterRequest{ - Header: httpEE.hdr, + Header: httpEE.hdr.Clone(), Body: body, }, err } @@ -111,7 +111,7 @@ func (httpEE *HTTPjsonMapEE) PrepareOrderMap(mp *utils.OrderedNavigableMap) (any } body, err := json.Marshal(valMp) return &HTTPPosterRequest{ - Header: httpEE.hdr, + Header: httpEE.hdr.Clone(), Body: body, }, err } diff --git a/ees/httppost.go b/ees/httppost.go index d4b7d3f7b..ec4b101a9 100644 --- a/ees/httppost.go +++ b/ees/httppost.go @@ -49,6 +49,7 @@ type HTTPPostEE struct { hdr http.Header } + type HTTPPosterRequest struct { Header http.Header Body any @@ -99,7 +100,7 @@ func (httpPost *HTTPPostEE) PrepareMap(mp *utils.CGREvent) (any, error) { urlVals.Set(k, utils.IfaceAsString(v)) } return &HTTPPosterRequest{ - Header: httpPost.hdr, + Header: httpPost.hdr.Clone(), Body: urlVals, }, nil } @@ -113,7 +114,7 @@ func (httpPost *HTTPPostEE) PrepareOrderMap(mp *utils.OrderedNavigableMap) (any, urlVals.Set(strings.Join(path, utils.NestingSep), nmIt.String()) } return &HTTPPosterRequest{ - Header: httpPost.hdr, + Header: httpPost.hdr.Clone(), Body: urlVals, }, nil } diff --git a/ees/httppost_test.go b/ees/httppost_test.go index 49c930ca9..c4b69cb2c 100644 --- a/ees/httppost_test.go +++ b/ees/httppost_test.go @@ -130,7 +130,7 @@ func TestHttpPostSync(t *testing.T) { t.Error(err) } - vals, err := exp.PrepareMap(&utils.CGREvent{ + req1, err := exp.PrepareMap(&utils.CGREvent{ Event: map[string]any{ "Account": "1001", "Destination": "1002", @@ -139,9 +139,29 @@ func TestHttpPostSync(t *testing.T) { if err != nil { t.Fatal(err) } + req2, err := exp.PrepareMap(&utils.CGREvent{ + Event: map[string]any{ + "Account": "1001", + "Destination": "1003", + }, + }) + if err != nil { + t.Fatal(err) + } + req3, err := exp.PrepareMap(&utils.CGREvent{ + Event: map[string]any{ + "Account": "1003", + "Destination": "1001", + }, + }) + if err != nil { + t.Fatal(err) + } + + requests := []any{req1, req2, req3} for i := 0; i < 3; i++ { - go exp.ExportEvent(vals, "") + go exp.ExportEvent(requests[i], "") } select {