Skip to content

Commit 5a34e65

Browse files
viveknarangsachin-pubmatic
authored andcommitted
Pass Global Privacy Control header to bidders (prebid#1789)
* Feature Request: Ability to pass Sec-GPC header to the bidder endpoints (prebid#1712) * making Sec-GPC value check more strict * minor syntax change * gofmt fixes * updates against draft-code-review:one, more to come soon. * adding a unit test * Adding a test and request header clone update * modified one test and related logic * modifying the last test added with slight more modification of the logic
1 parent 3b9ac64 commit 5a34e65

File tree

7 files changed

+133
-28
lines changed

7 files changed

+133
-28
lines changed

adapters/bidder.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ func (r *RequestData) SetBasicAuth(username string, password string) {
143143
}
144144

145145
type ExtraRequestInfo struct {
146-
PbsEntryPoint metrics.RequestType
146+
PbsEntryPoint metrics.RequestType
147+
GlobalPrivacyControlHeader string
147148
}
148149

149150
type Builder func(openrtb_ext.BidderName, config.Adapter) (Bidder, error)

endpoints/openrtb2/amp_auction.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,16 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h
182182
return
183183
}
184184

185+
secGPC := r.Header.Get("Sec-GPC")
186+
185187
auctionRequest := exchange.AuctionRequest{
186-
BidRequest: req,
187-
Account: *account,
188-
UserSyncs: usersyncs,
189-
RequestType: labels.RType,
190-
StartTime: start,
191-
LegacyLabels: labels,
188+
BidRequest: req,
189+
Account: *account,
190+
UserSyncs: usersyncs,
191+
RequestType: labels.RType,
192+
StartTime: start,
193+
LegacyLabels: labels,
194+
GlobalPrivacyControlHeader: secGPC,
192195
}
193196

194197
response, err := deps.ex.HoldAuction(ctx, auctionRequest, nil)

endpoints/openrtb2/auction.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,17 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http
173173
return
174174
}
175175

176+
secGPC := r.Header.Get("Sec-GPC")
177+
176178
auctionRequest := exchange.AuctionRequest{
177-
BidRequest: req,
178-
Account: *account,
179-
UserSyncs: usersyncs,
180-
RequestType: labels.RType,
181-
StartTime: start,
182-
LegacyLabels: labels,
183-
Warnings: warnings,
179+
BidRequest: req,
180+
Account: *account,
181+
UserSyncs: usersyncs,
182+
RequestType: labels.RType,
183+
StartTime: start,
184+
LegacyLabels: labels,
185+
Warnings: warnings,
186+
GlobalPrivacyControlHeader: secGPC,
184187
}
185188

186189
response, err := deps.ex.HoldAuction(ctx, auctionRequest, nil)

endpoints/openrtb2/video_auction.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,16 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re
274274
return
275275
}
276276

277+
secGPC := r.Header.Get("Sec-GPC")
278+
277279
auctionRequest := exchange.AuctionRequest{
278-
BidRequest: bidReq,
279-
Account: *account,
280-
UserSyncs: usersyncs,
281-
RequestType: labels.RType,
282-
StartTime: start,
283-
LegacyLabels: labels,
280+
BidRequest: bidReq,
281+
Account: *account,
282+
UserSyncs: usersyncs,
283+
RequestType: labels.RType,
284+
StartTime: start,
285+
LegacyLabels: labels,
286+
GlobalPrivacyControlHeader: secGPC,
284287
}
285288

286289
response, err := deps.ex.HoldAuction(ctx, auctionRequest, &debugLog)

exchange/bidder.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,19 @@ func (bidder *bidderAdapter) requestBid(ctx context.Context, request *openrtb2.B
139139
return nil, errs
140140
}
141141

142+
if reqInfo.GlobalPrivacyControlHeader == "1" {
143+
for i := 0; i < len(reqData); i++ {
144+
if reqData[i].Headers != nil {
145+
reqHeader := reqData[i].Headers.Clone()
146+
reqHeader.Add("Sec-GPC", reqInfo.GlobalPrivacyControlHeader)
147+
reqData[i].Headers = reqHeader
148+
} else {
149+
reqData[i].Headers = http.Header{}
150+
reqData[i].Headers.Add("Sec-GPC", reqInfo.GlobalPrivacyControlHeader)
151+
}
152+
}
153+
}
154+
142155
// Make any HTTP requests in parallel.
143156
// If the bidder only needs to make one, save some cycles by just using the current one.
144157
responseChannel := make(chan *httpCallInfo, len(reqData))

exchange/bidder_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,85 @@ func TestRequestBidRemovesSensitiveHeaders(t *testing.T) {
183183
assert.ElementsMatch(t, seatBid.httpCalls, expectedHttpCalls)
184184
}
185185

186+
func TestSetGPCHeader(t *testing.T) {
187+
server := httptest.NewServer(mockHandler(200, "getBody", "responseJson"))
188+
defer server.Close()
189+
190+
requestHeaders := http.Header{}
191+
requestHeaders.Add("Content-Type", "application/json")
192+
193+
bidderImpl := &goodSingleBidder{
194+
httpRequest: &adapters.RequestData{
195+
Method: "POST",
196+
Uri: server.URL,
197+
Body: []byte("requestJson"),
198+
Headers: requestHeaders,
199+
},
200+
bidResponse: &adapters.BidderResponse{
201+
Bids: []*adapters.TypedBid{},
202+
},
203+
}
204+
205+
debugInfo := &config.DebugInfo{Allow: true}
206+
ctx := context.Background()
207+
ctx = context.WithValue(ctx, DebugContextKey, true)
208+
209+
bidder := adaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.DummyMetricsEngine{}, openrtb_ext.BidderAppnexus, debugInfo)
210+
currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0))
211+
seatBid, errs := bidder.requestBid(ctx, &openrtb2.BidRequest{}, "test", 1, currencyConverter.Rates(), &adapters.ExtraRequestInfo{GlobalPrivacyControlHeader: "1"}, true)
212+
213+
expectedHttpCall := []*openrtb_ext.ExtHttpCall{
214+
{
215+
Uri: server.URL,
216+
RequestBody: "requestJson",
217+
RequestHeaders: map[string][]string{"Content-Type": {"application/json"}, "Sec-Gpc": {"1"}},
218+
ResponseBody: "responseJson",
219+
Status: 200,
220+
},
221+
}
222+
223+
assert.Empty(t, errs)
224+
assert.ElementsMatch(t, seatBid.httpCalls, expectedHttpCall)
225+
}
226+
227+
func TestSetGPCHeaderNil(t *testing.T) {
228+
server := httptest.NewServer(mockHandler(200, "getBody", "responseJson"))
229+
defer server.Close()
230+
231+
bidderImpl := &goodSingleBidder{
232+
httpRequest: &adapters.RequestData{
233+
Method: "POST",
234+
Uri: server.URL,
235+
Body: []byte("requestJson"),
236+
Headers: nil,
237+
},
238+
bidResponse: &adapters.BidderResponse{
239+
Bids: []*adapters.TypedBid{},
240+
},
241+
}
242+
243+
debugInfo := &config.DebugInfo{Allow: true}
244+
ctx := context.Background()
245+
ctx = context.WithValue(ctx, DebugContextKey, true)
246+
247+
bidder := adaptBidder(bidderImpl, server.Client(), &config.Configuration{}, &metricsConfig.DummyMetricsEngine{}, openrtb_ext.BidderAppnexus, debugInfo)
248+
currencyConverter := currency.NewRateConverter(&http.Client{}, "", time.Duration(0))
249+
seatBid, errs := bidder.requestBid(ctx, &openrtb2.BidRequest{}, "test", 1, currencyConverter.Rates(), &adapters.ExtraRequestInfo{GlobalPrivacyControlHeader: "1"}, true)
250+
251+
expectedHttpCall := []*openrtb_ext.ExtHttpCall{
252+
{
253+
Uri: server.URL,
254+
RequestBody: "requestJson",
255+
RequestHeaders: map[string][]string{"Sec-Gpc": {"1"}},
256+
ResponseBody: "responseJson",
257+
Status: 200,
258+
},
259+
}
260+
261+
assert.Empty(t, errs)
262+
assert.ElementsMatch(t, seatBid.httpCalls, expectedHttpCall)
263+
}
264+
186265
// TestMultiBidder makes sure all the requests get sent, and the responses processed.
187266
// Because this is done in parallel, it should be run under the race detector.
188267
func TestMultiBidder(t *testing.T) {

exchange/exchange.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,13 @@ func NewExchange(adapters map[openrtb_ext.BidderName]adaptedBidder, cache prebid
126126
// AuctionRequest holds the bid request for the auction
127127
// and all other information needed to process that request
128128
type AuctionRequest struct {
129-
BidRequest *openrtb2.BidRequest
130-
Account config.Account
131-
UserSyncs IdFetcher
132-
RequestType metrics.RequestType
133-
StartTime time.Time
134-
Warnings []error
129+
BidRequest *openrtb2.BidRequest
130+
Account config.Account
131+
UserSyncs IdFetcher
132+
RequestType metrics.RequestType
133+
StartTime time.Time
134+
Warnings []error
135+
GlobalPrivacyControlHeader string
135136

136137
// LegacyLabels is included here for temporary compatability with cleanOpenRTBRequests
137138
// in HoldAuction until we get to factoring it away. Do not use for anything new.
@@ -196,7 +197,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
196197
// Get currency rates conversions for the auction
197198
conversions := e.currencyConverter.Rates()
198199

199-
adapterBids, adapterExtra, anyBidsReturned := e.getAllBids(auctionCtx, bidderRequests, bidAdjustmentFactors, conversions, r.Account.DebugAllow)
200+
adapterBids, adapterExtra, anyBidsReturned := e.getAllBids(auctionCtx, bidderRequests, bidAdjustmentFactors, conversions, r.Account.DebugAllow, r.GlobalPrivacyControlHeader)
200201

201202
var auc *auction
202203
var cacheErrs []error
@@ -411,7 +412,8 @@ func (e *exchange) getAllBids(
411412
bidderRequests []BidderRequest,
412413
bidAdjustments map[string]float64,
413414
conversions currency.Conversions,
414-
accountDebugAllowed bool) (
415+
accountDebugAllowed bool,
416+
globalPrivacyControlHeader string) (
415417
map[openrtb_ext.BidderName]*pbsOrtbSeatBid,
416418
map[openrtb_ext.BidderName]*seatResponseExtra, bool) {
417419
// Set up pointers to the bid results
@@ -443,6 +445,7 @@ func (e *exchange) getAllBids(
443445
}
444446
var reqInfo adapters.ExtraRequestInfo
445447
reqInfo.PbsEntryPoint = bidderRequest.BidderLabels.RType
448+
reqInfo.GlobalPrivacyControlHeader = globalPrivacyControlHeader
446449
bids, err := e.adapterMap[bidderRequest.BidderCoreName].requestBid(ctx, bidderRequest.BidRequest, bidderRequest.BidderName, adjustmentFactor, conversions, &reqInfo, accountDebugAllowed)
447450

448451
// Add in time reporting

0 commit comments

Comments
 (0)