github.com/prebid/prebid-server@v0.275.0/firstpartydata/extmerger.go (about)

     1  package firstpartydata
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/prebid/prebid-server/util/sliceutil"
     9  	jsonpatch "gopkg.in/evanphx/json-patch.v4"
    10  )
    11  
    12  var (
    13  	ErrBadRequest = fmt.Errorf("invalid request ext")
    14  	ErrBadFPD     = fmt.Errorf("invalid first party data ext")
    15  )
    16  
    17  // extMerger tracks a JSON `ext` field within an OpenRTB request. The value of the
    18  // `ext` field is expected to be modified when calling unmarshal on the same object
    19  // and will later be updated when invoking Merge.
    20  type extMerger struct {
    21  	ext      *json.RawMessage // Pointer to the JSON `ext` field.
    22  	snapshot json.RawMessage  // Copy of the original state of the JSON `ext` field.
    23  }
    24  
    25  // Track saves a copy of the JSON `ext` field and stores a reference to the extension
    26  // object for comparison later in the Merge call.
    27  func (e *extMerger) Track(ext *json.RawMessage) {
    28  	e.ext = ext
    29  	e.snapshot = sliceutil.Clone(*ext)
    30  }
    31  
    32  // Merge applies a JSON merge of the stored extension snapshot on top of the current
    33  // JSON of the tracked extension object.
    34  func (e extMerger) Merge() error {
    35  	if e.ext == nil {
    36  		return nil
    37  	}
    38  
    39  	if len(e.snapshot) == 0 {
    40  		return nil
    41  	}
    42  
    43  	if len(*e.ext) == 0 {
    44  		*e.ext = e.snapshot
    45  		return nil
    46  	}
    47  
    48  	merged, err := jsonpatch.MergePatch(e.snapshot, *e.ext)
    49  	if err != nil {
    50  		if errors.Is(err, jsonpatch.ErrBadJSONDoc) {
    51  			return ErrBadRequest
    52  		} else if errors.Is(err, jsonpatch.ErrBadJSONPatch) {
    53  			return ErrBadFPD
    54  		}
    55  		return err
    56  	}
    57  
    58  	*e.ext = merged
    59  	return nil
    60  }