From 2cc4820ab7194f083ffd4e0d987b4685d5e3616c Mon Sep 17 00:00:00 2001 From: Karim Mourra Date: Fri, 4 Apr 2025 16:25:31 -0300 Subject: [PATCH 1/6] replaces unmarshall --- adapters/connatix/connatix.go | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go index 11cf7a146ab..16051a7dcef 100644 --- a/adapters/connatix/connatix.go +++ b/adapters/connatix/connatix.go @@ -105,7 +105,27 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest func validateAndBuildImpExt(imp *openrtb2.Imp) (impExtIncoming, error) { var ext impExtIncoming - if err := jsonutil.Unmarshal(imp.Ext, &ext); err != nil { + + // Use jsonparser to extract only the fields under "bidder" + err := jsonparser.ObjectEach(imp.Ext, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error { + if string(key) != "bidder" { + return nil + } + + // Parse placementId + if placementID, err := jsonparser.GetString(value, "placementId"); err == nil { + ext.Bidder.PlacementId = placementID + } + + // Parse viewabilityPercentage + if viewability, err := jsonparser.GetFloat(value, "viewabilityPercentage"); err == nil { + ext.Bidder.ViewabilityPercentage = viewability + } + + return nil + }) + + if err != nil { return impExtIncoming{}, err } @@ -193,15 +213,9 @@ func splitRequests(imps []openrtb2.Imp, request *openrtb2.BidRequest, uri string } func buildRequestImp(imp *openrtb2.Imp, ext impExtIncoming, displayManagerVer string, reqInfo *adapters.ExtraRequestInfo) error { - if imp.Banner != nil { - bannerCopy := *imp.Banner - - if bannerCopy.W == nil && bannerCopy.H == nil && len(bannerCopy.Format) > 0 { - firstFormat := bannerCopy.Format[0] - bannerCopy.W = &(firstFormat.W) - bannerCopy.H = &(firstFormat.H) - } - imp.Banner = &bannerCopy + if imp.Banner != nil && imp.Banner.W == nil && imp.Banner.H == nil && len(imp.Banner.Format) > 0 { + imp.Banner.W = &imp.Banner.Format[0].W + imp.Banner.H = &imp.Banner.Format[0].H } // Populate imp.displaymanagerver if the SDK failed to do it. From ee29b4411a753ad598d0076f47461ff1d8ce2745 Mon Sep 17 00:00:00 2001 From: Karim Mourra Date: Fri, 4 Apr 2025 18:07:34 -0300 Subject: [PATCH 2/6] modifies url outside of loop --- adapters/connatix/connatix.go | 158 +++++++++++++++++----------------- 1 file changed, 77 insertions(+), 81 deletions(-) diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go index 16051a7dcef..93fd991fa4f 100644 --- a/adapters/connatix/connatix.go +++ b/adapters/connatix/connatix.go @@ -17,15 +17,11 @@ import ( ) const ( - maxImpsPerReq = 1 + maxImpsPerRequest = 1 ) -// Builder builds a new instance of the Connatix adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - bidder := &adapter{ - endpoint: config.Endpoint, - } - return bidder, nil + return &adapter{endpoint: config.Endpoint}, nil } func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { @@ -38,29 +34,32 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E // connatix adapter expects imp.displaymanagerver to be populated in openrtb2 request // but some SDKs will put it in imp.ext.prebid instead displayManagerVer := buildDisplayManagerVer(request) - var errs []error - - validImps := []openrtb2.Imp{} + var validImps []openrtb2.Imp for i := range request.Imp { - impExtIncoming, err := validateAndBuildImpExt(&request.Imp[i]) + imp := &request.Imp[i] + impExt, err := validateAndBuildImpExt(imp) if err != nil { errs = append(errs, err) continue } - if err := buildRequestImp(&request.Imp[i], impExtIncoming, displayManagerVer, reqInfo); err != nil { + if err := buildRequestImp(imp, impExt, displayManagerVer, reqInfo); err != nil { errs = append(errs, err) continue } - validImps = append(validImps, request.Imp[i]) + if imp.Secure == nil { + secure := int8(1) + imp.Secure = &secure + } + + validImps = append(validImps, *imp) } - // Divide imps to several requests - requests, errors := splitRequests(validImps, request, a.endpoint) - return requests, append(errs, errors...) + requests, splitErrs := splitRequests(validImps, request, a.endpoint) + return requests, append(errs, splitErrs...) } func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { @@ -77,7 +76,6 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest return nil, []error{err} } - var errs []error bidderResponse := adapters.NewBidderResponseWithBidsCapacity(1) for _, sb := range connatixResponse.SeatBid { for i := range sb.Bid { @@ -99,25 +97,20 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest } bidderResponse.Currency = "USD" - - return bidderResponse, errs + return bidderResponse, nil } func validateAndBuildImpExt(imp *openrtb2.Imp) (impExtIncoming, error) { var ext impExtIncoming - - // Use jsonparser to extract only the fields under "bidder" - err := jsonparser.ObjectEach(imp.Ext, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error { + err := jsonparser.ObjectEach(imp.Ext, func(key []byte, value []byte, _ jsonparser.ValueType, _ int) error { if string(key) != "bidder" { return nil } - // Parse placementId if placementID, err := jsonparser.GetString(value, "placementId"); err == nil { ext.Bidder.PlacementId = placementID } - // Parse viewabilityPercentage if viewability, err := jsonparser.GetFloat(value, "viewabilityPercentage"); err == nil { ext.Bidder.ViewabilityPercentage = viewability } @@ -132,84 +125,87 @@ func validateAndBuildImpExt(imp *openrtb2.Imp) (impExtIncoming, error) { return ext, nil } -func splitRequests(imps []openrtb2.Imp, request *openrtb2.BidRequest, uri string) ([]*adapters.RequestData, []error) { +func splitRequests(imps []openrtb2.Imp, originalRequest *openrtb2.BidRequest, uri string) ([]*adapters.RequestData, []error) { var errs []error // Initial capacity for future array of requests, memory optimization. // Let's say there are 35 impressions and limit impressions per request equals to 10. // In this case we need to create 4 requests with 10, 10, 10 and 5 impressions. // With this formula initial capacity=(35+10-1)/10 = 4 - initialCapacity := (len(imps) + maxImpsPerReq - 1) / maxImpsPerReq - resArr := make([]*adapters.RequestData, 0, initialCapacity) - startInd := 0 - impsLeft := len(imps) > 0 - - headers := http.Header{} - headers.Add("Content-Type", "application/json") - headers.Add("Accept", "application/json") - - if request.Device != nil { - if len(request.Device.UA) > 0 { - headers.Add("User-Agent", request.Device.UA) - } + //initialCapacity := (len(imps) + maxImpsPerReq - 1) / maxImpsPerReq + //resArr := make([]*adapters.RequestData, 0, initialCapacity) + //startInd := 0 + //impsLeft := len(imps) > 0 - if len(request.Device.IPv6) > 0 { - headers.Add("X-Forwarded-For", request.Device.IPv6) + var requests []*adapters.RequestData + + if len(imps) == 0 { + return nil, nil + } + + baseEndpoint, err := url.Parse(uri) + if err != nil { + return nil, []error{err} + } + + headers := http.Header{ + "Content-Type": {"application/json"}, + "Accept": {"application/json"}, + } + + if originalRequest.Device != nil { + if ua := originalRequest.Device.UA; ua != "" { + headers.Add("User-Agent", ua) } - if len(request.Device.IP) > 0 { - headers.Add("X-Forwarded-For", request.Device.IP) + if ip := originalRequest.Device.IP; ip != "" { + headers.Add("X-Forwarded-For", ip) + } else if ip := originalRequest.Device.IPv6; ip != "" { + headers.Add("X-Forwarded-For", ip) } } - for impsLeft { - endInd := startInd + maxImpsPerReq - if endInd >= len(imps) { - endInd = len(imps) - impsLeft = false + endpoint := *baseEndpoint + if originalRequest.User != nil { + userID := strings.TrimSpace(originalRequest.User.BuyerUID) + if userID != "" { + queryParams := url.Values{} + switch { + case strings.HasPrefix(userID, "1-"): + queryParams.Add("dc", "us-east-2") + case strings.HasPrefix(userID, "2-"): + queryParams.Add("dc", "us-west-2") + case strings.HasPrefix(userID, "3-"): + queryParams.Add("dc", "eu-west-1") + } + endpoint.RawQuery = queryParams.Encode() } - impsForReq := imps[startInd:endInd] - request.Imp = impsForReq + } - reqJSON, err := jsonutil.Marshal(request) - if err != nil { - errs = append(errs, err) - return nil, errs + for start := 0; start < len(imps); start += maxImpsPerRequest { + end := start + maxImpsPerRequest + if end > len(imps) { + end = len(imps) } + impsForRequest := imps[start:end] + requestCopy := *originalRequest + requestCopy.Imp = impsForRequest - endpoint, err := url.Parse(uri) + requestJSON, err := jsonutil.Marshal(&requestCopy) if err != nil { errs = append(errs, err) - return nil, errs - } - - if request.User != nil { - userID := strings.TrimSpace(request.User.BuyerUID) - - if len(userID) > 0 { - queryParams := url.Values{} - - if strings.HasPrefix(userID, "1-") { - queryParams.Add("dc", "us-east-2") - } else if strings.HasPrefix(userID, "2-") { - queryParams.Add("dc", "us-west-2") - } else if strings.HasPrefix(userID, "3-") { - queryParams.Add("dc", "eu-west-1") - } - - endpoint.RawQuery = queryParams.Encode() - } + continue } - resArr = append(resArr, &adapters.RequestData{ + requests = append(requests, &adapters.RequestData{ Method: "POST", Uri: endpoint.String(), - Body: reqJSON, + Body: requestJSON, Headers: headers, - ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + ImpIDs: openrtb_ext.GetImpIDs(impsForRequest), }) - startInd = endInd } - return resArr, errs + + return requests, errs } func buildRequestImp(imp *openrtb2.Imp, ext impExtIncoming, displayManagerVer string, reqInfo *adapters.ExtraRequestInfo) error { @@ -218,8 +214,8 @@ func buildRequestImp(imp *openrtb2.Imp, ext impExtIncoming, displayManagerVer st imp.Banner.H = &imp.Banner.Format[0].H } - // Populate imp.displaymanagerver if the SDK failed to do it. - if len(imp.DisplayManagerVer) == 0 && len(displayManagerVer) > 0 { + // Populate imp.displaymanagerver if the client failed to do it. + if imp.DisplayManagerVer == "" && displayManagerVer != "" { imp.DisplayManagerVer = displayManagerVer } @@ -230,10 +226,11 @@ func buildRequestImp(imp *openrtb2.Imp, ext impExtIncoming, displayManagerVer st if err != nil { return err } + // Update after conversion. All imp elements inside request.Imp are shallow copies // therefore, their non-pointer values are not shared memory and are safe to modify. - imp.BidFloorCur = "USD" imp.BidFloor = convertedValue + imp.BidFloorCur = "USD" } impExt := impExt{ @@ -245,7 +242,6 @@ func buildRequestImp(imp *openrtb2.Imp, ext impExtIncoming, displayManagerVer st var err error imp.Ext, err = json.Marshal(impExt) - return err } From c7d455cfcc3195bab72ec8543b41c0123a9fce5f Mon Sep 17 00:00:00 2001 From: Karim Mourra Date: Fri, 4 Apr 2025 18:33:39 -0300 Subject: [PATCH 3/6] removes secure --- adapters/connatix/connatix.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go index 93fd991fa4f..8cabbb54031 100644 --- a/adapters/connatix/connatix.go +++ b/adapters/connatix/connatix.go @@ -50,11 +50,6 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E continue } - if imp.Secure == nil { - secure := int8(1) - imp.Secure = &secure - } - validImps = append(validImps, *imp) } @@ -157,9 +152,11 @@ func splitRequests(imps []openrtb2.Imp, originalRequest *openrtb2.BidRequest, ur headers.Add("User-Agent", ua) } - if ip := originalRequest.Device.IP; ip != "" { + if ip := originalRequest.Device.IPv6; ip != "" { headers.Add("X-Forwarded-For", ip) - } else if ip := originalRequest.Device.IPv6; ip != "" { + } + + if ip := originalRequest.Device.IP; ip != "" { headers.Add("X-Forwarded-For", ip) } } From f45d1a0556e154d9ae3b5c0ba806f67be374716f Mon Sep 17 00:00:00 2001 From: Karim Mourra Date: Fri, 4 Apr 2025 18:58:52 -0300 Subject: [PATCH 4/6] improves error message --- adapters/connatix/connatix.go | 17 ++++++++++++++--- .../bad-request-invalid-imp-ext.json | 2 +- .../supplemental/multi-imp-request.json | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go index 8cabbb54031..7ee7a0b5498 100644 --- a/adapters/connatix/connatix.go +++ b/adapters/connatix/connatix.go @@ -104,6 +104,11 @@ func validateAndBuildImpExt(imp *openrtb2.Imp) (impExtIncoming, error) { if placementID, err := jsonparser.GetString(value, "placementId"); err == nil { ext.Bidder.PlacementId = placementID + } else { + + return &errortypes.BadInput{ + Message: "Bid request does not contain a valid Placement ID", + } } if viewability, err := jsonparser.GetFloat(value, "viewabilityPercentage"); err == nil { @@ -206,9 +211,15 @@ func splitRequests(imps []openrtb2.Imp, originalRequest *openrtb2.BidRequest, ur } func buildRequestImp(imp *openrtb2.Imp, ext impExtIncoming, displayManagerVer string, reqInfo *adapters.ExtraRequestInfo) error { - if imp.Banner != nil && imp.Banner.W == nil && imp.Banner.H == nil && len(imp.Banner.Format) > 0 { - imp.Banner.W = &imp.Banner.Format[0].W - imp.Banner.H = &imp.Banner.Format[0].H + if imp.Banner != nil { + bannerCopy := *imp.Banner + + if bannerCopy.W == nil && bannerCopy.H == nil && len(bannerCopy.Format) > 0 { + firstFormat := bannerCopy.Format[0] + bannerCopy.W = &(firstFormat.W) + bannerCopy.H = &(firstFormat.H) + } + imp.Banner = &bannerCopy } // Populate imp.displaymanagerver if the client failed to do it. diff --git a/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json b/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json index 9668bcc7b49..1c3aaefe8cb 100644 --- a/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json +++ b/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json @@ -47,7 +47,7 @@ "expectedBidResponses": [], "expectedMakeRequestsErrors": [ { - "value": "cannot unmarshal openrtb_ext.ExtImpConnatix.PlacementId: expects \" or n, but found {", + "value": "Bid request does not contain a valid Placement ID", "comparison": "literal" } ] diff --git a/adapters/connatix/connatixtest/supplemental/multi-imp-request.json b/adapters/connatix/connatixtest/supplemental/multi-imp-request.json index 55deee27612..62f4f5d7da0 100644 --- a/adapters/connatix/connatixtest/supplemental/multi-imp-request.json +++ b/adapters/connatix/connatixtest/supplemental/multi-imp-request.json @@ -302,7 +302,7 @@ ], "expectedMakeRequestsErrors": [ { - "value": "cannot unmarshal openrtb_ext.ExtImpConnatix.PlacementId: expects \" or n, but found 1", + "value": "Bid request does not contain a valid Placement ID", "comparison": "literal" } ] From 51b6d0771b740896dab81b0cedccd2a32bd5e8dc Mon Sep 17 00:00:00 2001 From: Karim Mourra Date: Fri, 4 Apr 2025 19:27:27 -0300 Subject: [PATCH 5/6] removes unnecessary loop --- adapters/connatix/connatix.go | 35 +++++++------------ .../bad-request-invalid-imp-ext.json | 2 +- .../supplemental/multi-imp-request.json | 2 +- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go index 7ee7a0b5498..5d3c0a06add 100644 --- a/adapters/connatix/connatix.go +++ b/adapters/connatix/connatix.go @@ -97,29 +97,24 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest func validateAndBuildImpExt(imp *openrtb2.Imp) (impExtIncoming, error) { var ext impExtIncoming - err := jsonparser.ObjectEach(imp.Ext, func(key []byte, value []byte, _ jsonparser.ValueType, _ int) error { - if string(key) != "bidder" { - return nil - } - - if placementID, err := jsonparser.GetString(value, "placementId"); err == nil { - ext.Bidder.PlacementId = placementID - } else { - return &errortypes.BadInput{ - Message: "Bid request does not contain a valid Placement ID", - } + bidderJSON, _, _, err := jsonparser.Get(imp.Ext, "bidder") + if err != nil { + return impExtIncoming{}, &errortypes.BadInput{ + Message: "Missing 'bidder' object", } + } - if viewability, err := jsonparser.GetFloat(value, "viewabilityPercentage"); err == nil { - ext.Bidder.ViewabilityPercentage = viewability + if placementId, err := jsonparser.GetString(bidderJSON, "placementId"); err == nil { + ext.Bidder.PlacementId = placementId + } else { + return impExtIncoming{}, &errortypes.BadInput{ + Message: "Invalid Placement ID", } + } - return nil - }) - - if err != nil { - return impExtIncoming{}, err + if viewability, err := jsonparser.GetFloat(bidderJSON, "viewabilityPercentage"); err == nil { + ext.Bidder.ViewabilityPercentage = viewability } return ext, nil @@ -131,10 +126,6 @@ func splitRequests(imps []openrtb2.Imp, originalRequest *openrtb2.BidRequest, ur // Let's say there are 35 impressions and limit impressions per request equals to 10. // In this case we need to create 4 requests with 10, 10, 10 and 5 impressions. // With this formula initial capacity=(35+10-1)/10 = 4 - //initialCapacity := (len(imps) + maxImpsPerReq - 1) / maxImpsPerReq - //resArr := make([]*adapters.RequestData, 0, initialCapacity) - //startInd := 0 - //impsLeft := len(imps) > 0 var requests []*adapters.RequestData diff --git a/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json b/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json index 1c3aaefe8cb..c2b272784fe 100644 --- a/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json +++ b/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json @@ -47,7 +47,7 @@ "expectedBidResponses": [], "expectedMakeRequestsErrors": [ { - "value": "Bid request does not contain a valid Placement ID", + "value": "Invalid Placement ID", "comparison": "literal" } ] diff --git a/adapters/connatix/connatixtest/supplemental/multi-imp-request.json b/adapters/connatix/connatixtest/supplemental/multi-imp-request.json index 62f4f5d7da0..75b258b892b 100644 --- a/adapters/connatix/connatixtest/supplemental/multi-imp-request.json +++ b/adapters/connatix/connatixtest/supplemental/multi-imp-request.json @@ -302,7 +302,7 @@ ], "expectedMakeRequestsErrors": [ { - "value": "Bid request does not contain a valid Placement ID", + "value": "Invalid Placement ID", "comparison": "literal" } ] From d03ab4dc72b0c558b421aab7676b2798e7bb1ad1 Mon Sep 17 00:00:00 2001 From: Karim Mourra Date: Fri, 4 Apr 2025 19:50:40 -0300 Subject: [PATCH 6/6] copies imp for better thread safety --- adapters/connatix/connatix.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go index 5d3c0a06add..1205a8ef556 100644 --- a/adapters/connatix/connatix.go +++ b/adapters/connatix/connatix.go @@ -37,20 +37,20 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E var errs []error var validImps []openrtb2.Imp - for i := range request.Imp { - imp := &request.Imp[i] - impExt, err := validateAndBuildImpExt(imp) + for _, imp := range request.Imp { + impCopy := imp + impExt, err := validateAndBuildImpExt(&impCopy) if err != nil { errs = append(errs, err) continue } - if err := buildRequestImp(imp, impExt, displayManagerVer, reqInfo); err != nil { + if err := buildRequestImp(&impCopy, impExt, displayManagerVer, reqInfo); err != nil { errs = append(errs, err) continue } - validImps = append(validImps, *imp) + validImps = append(validImps, impCopy) } requests, splitErrs := splitRequests(validImps, request, a.endpoint)