diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go index bfd8fb3fe60..ebcb5e577b2 100644 --- a/endpoints/openrtb2/amp_auction.go +++ b/endpoints/openrtb2/amp_auction.go @@ -226,7 +226,7 @@ func enforceAMPCache(req *openrtb.BidRequest) (errs []error) { // Ensure Targeting and caching is on if extRequest.Prebid.Targeting == nil || extRequest.Prebid.Cache == nil || extRequest.Prebid.Cache.Bids == nil { - errs = []error{fmt.Errorf("AMP requests require Trageting and Caching to be set")} + errs = []error{fmt.Errorf("AMP requests require Targeting and Caching to be set")} } return diff --git a/pbs_light.go b/pbs_light.go index 148f7caa746..38a7a3b94bd 100644 --- a/pbs_light.go +++ b/pbs_light.go @@ -211,7 +211,8 @@ func (deps *cookieSyncDeps) CookieSync(w http.ResponseWriter, r *http.Request, _ defer r.Body.Close() csReq := &cookieSyncRequest{} - err := json.NewDecoder(r.Body).Decode(&csReq) + csReqRaw := map[string]json.RawMessage{} + err := json.NewDecoder(r.Body).Decode(&csReqRaw) if err != nil { if glog.V(2) { glog.Infof("Failed to parse /cookie_sync request body: %v", err) @@ -219,6 +220,28 @@ func (deps *cookieSyncDeps) CookieSync(w http.ResponseWriter, r *http.Request, _ http.Error(w, "JSON parse failed", http.StatusBadRequest) return } + if UUID, ok := csReqRaw["uuid"]; ok { + err := json.Unmarshal(UUID, &csReq.UUID) + if err != nil { + if glog.V(2) { + glog.Infof("Failed to parse /cookie_sync request body (UUID): %v", err) + } + http.Error(w, "JSON parse failed (uuid)", http.StatusBadRequest) + return + } + } + biddersOmitted := true + if biddersRaw, ok := csReqRaw["bidders"]; ok { + biddersOmitted = false + err := json.Unmarshal(biddersRaw, &csReq.Bidders) + if err != nil { + if glog.V(2) { + glog.Infof("Failed to parse /cookie_sync request body (bidders list): %v", err) + } + http.Error(w, "JSON parse failed (bidders)", http.StatusBadRequest) + return + } + } csResp := cookieSyncResponse{ UUID: csReq.UUID, @@ -231,6 +254,14 @@ func (deps *cookieSyncDeps) CookieSync(w http.ResponseWriter, r *http.Request, _ csResp.Status = "ok" } + // If at the end (After possibly reading stored bidder lists) there still are no bidders, + // and "bidders" is not found in the JSON, sync all bidders + if len(csReq.Bidders) == 0 && biddersOmitted { + for bidder, _ := range deps.syncers { + csReq.Bidders = append(csReq.Bidders, string(bidder)) + } + } + for _, bidder := range csReq.Bidders { if syncer, ok := deps.syncers[openrtb_ext.BidderName(bidder)]; ok { if !userSyncCookie.HasLiveSync(syncer.FamilyName()) { diff --git a/pbs_light_test.go b/pbs_light_test.go index 915e00cab70..70795292406 100644 --- a/pbs_light_test.go +++ b/pbs_light_test.go @@ -43,7 +43,7 @@ func TestCookieSyncNoCookies(t *testing.T) { rr := httptest.NewRecorder() router.ServeHTTP(rr, req) if rr.Code != http.StatusOK { - t.Fatalf("Wrong status: %d", rr.Code) + t.Fatalf("Wrong status: %d (%s)", rr.Code, rr.Body) } csresp := cookieSyncResponse{} @@ -53,7 +53,7 @@ func TestCookieSyncNoCookies(t *testing.T) { } if csresp.UUID != csreq.UUID { - t.Error("UUIDs didn't match") + t.Errorf("UUIDs didn't match (expected: %s found: %s)", csreq.UUID, csresp.UUID) } if csresp.Status != "no_cookie" { @@ -113,10 +113,78 @@ func TestCookieSyncHasCookies(t *testing.T) { } } +func TestCookieSyncNoBidders(t *testing.T) { + endpoint := testableEndpoint() + + router := httprouter.New() + router.POST("/cookie_sync", endpoint) + + // First test a declared empty bidders returns no syncs + csreq := []byte("{\"uuid\": \"abcdefg\", \"bidders\": []}") + csbuf := bytes.NewBuffer(csreq) + + req, _ := http.NewRequest("POST", "/cookie_sync", csbuf) + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + if rr.Code != http.StatusOK { + t.Fatalf("Wrong status: %d (%s)", rr.Code, rr.Body) + } + + csresp := cookieSyncResponse{} + err := json.Unmarshal(rr.Body.Bytes(), &csresp) + if err != nil { + t.Fatalf("Unmarshal response failed: %v", err) + } + + if csresp.UUID != "abcdefg" { + t.Errorf("UUIDs didn't match (expected: abcdefg found: %s)", csresp.UUID) + } + + if csresp.Status != "no_cookie" { + t.Errorf("Expected status = no_cookie; got %s", csresp.Status) + } + + if len(csresp.BidderStatus) != 0 { + t.Errorf("Expected 0 bidder status rows; got %d", len(csresp.BidderStatus)) + } + + // Now test a missing bidders returns all syncs + csreq = []byte("{\"uuid\": \"abcdefg\"}") + csbuf = bytes.NewBuffer(csreq) + + req, _ = http.NewRequest("POST", "/cookie_sync", csbuf) + rr = httptest.NewRecorder() + router.ServeHTTP(rr, req) + if rr.Code != http.StatusOK { + t.Fatalf("Wrong status: %d (%s)", rr.Code, rr.Body) + } + + csresp = cookieSyncResponse{} + err = json.Unmarshal(rr.Body.Bytes(), &csresp) + if err != nil { + t.Fatalf("Unmarshal response failed: %v", err) + } + + if csresp.UUID != "abcdefg" { + t.Errorf("UUIDs didn't match (expected: abcdefg found: %s)", csresp.UUID) + } + + if csresp.Status != "no_cookie" { + t.Errorf("Expected status = no_cookie; got %s", csresp.Status) + } + + if len(csresp.BidderStatus) != 4 { + t.Errorf("Expected %d bidder status rows; got %d", 4, len(csresp.BidderStatus)) + } + +} + func testableEndpoint() httprouter.Handle { knownSyncers := map[openrtb_ext.BidderName]usersyncers.Usersyncer{ - openrtb_ext.BidderAppnexus: usersyncers.NewAppnexusSyncer("someurl.com"), - openrtb_ext.BidderFacebook: usersyncers.NewFacebookSyncer("facebookurl.com"), + openrtb_ext.BidderAppnexus: usersyncers.NewAppnexusSyncer("someurl.com"), + openrtb_ext.BidderFacebook: usersyncers.NewFacebookSyncer("facebookurl.com"), + openrtb_ext.BidderLifestreet: usersyncers.NewLifestreetSyncer("anotherurl.com"), + openrtb_ext.BidderPubmatic: usersyncers.NewPubmaticSyncer("thaturl.com"), } return (&cookieSyncDeps{knownSyncers, &config.Cookie{}, metrics.NewMeter()}).CookieSync }