MCPcopy
hub / github.com/keploy/keploy / ExactBodyMatch

Method ExactBodyMatch

pkg/agent/proxy/integrations/http/match.go:610–713  ·  view source on GitHub ↗

ExactBodyMatch performs exact body matching with noise awareness. First pass: fast string equality. Second pass: noise-aware comparison that skips obfuscated fields identified by Mock.Noise patterns. Three body shapes are handled in the second pass: 1. A mock body that is itself entirely a noise val

(body []byte, schemaMatched []*models.Mock)

Source from the content-addressed store, hash-verified

608// produce byte-identical request bodies at replay.
609// 3. JSON — field-by-field comparison via JSONBodyMatchScore.
610func (h *HTTP) ExactBodyMatch(body []byte, schemaMatched []*models.Mock) (bool, *models.Mock) {
611 // Log all mock names in a single line for better readability
612 mockNames := make([]string, len(schemaMatched))
613 for i, mock := range schemaMatched {
614 mockNames[i] = mock.Name
615 }
616 h.Logger.Debug("mocks under consideration for exact body match", zap.Strings("mock names", mockNames), zap.String("req body", string(body)))
617
618 // First pass: exact string match (fastest path)
619 for _, mock := range schemaMatched {
620 if mock.Spec.HTTPReq.Body == string(body) {
621 h.Logger.Debug("http mock matched",
622 zap.String("mock", mock.Name),
623 zap.Float64("match_percentage", 100.0),
624 zap.String("match_type", "exact_body"))
625 return true, mock
626 }
627 }
628
629 // Second pass: noise-aware match for mocks with obfuscated values.
630 // Pre-compute request-side properties once so we don't re-derive them per
631 // candidate mock: JSON unmarshaling for the JSON-noise path, and the
632 // form-encoded heuristic (which itself runs url.ParseQuery) for the
633 // form-body path.
634 reqBodyStr := string(body)
635 isReqJSON := pkg.IsJSON(body)
636 var reqData interface{}
637 if isReqJSON {
638 if err := json.Unmarshal(body, &reqData); err != nil {
639 isReqJSON = false
640 }
641 }
642 reqIsForm := !isReqJSON && looksLikeFormEncoded(reqBodyStr)
643
644 for _, mock := range schemaMatched {
645 nc := util.NewNoiseChecker(mock.Noise)
646 if nc == nil {
647 continue // no noise patterns → already checked in first pass
648 }
649
650 mockBody := mock.Spec.HTTPReq.Body
651
652 // If the entire body is a single noisy value, auto-match
653 // (schema match already filtered by URL, method, headers)
654 if nc.IsNoisy(mockBody) {
655 h.Logger.Debug("http mock matched",
656 zap.String("mock", mock.Name),
657 zap.Float64("match_percentage", 100.0),
658 zap.Int("noisy_fields_skipped", 1),
659 zap.String("match_type", "exact_body_fully_noisy"))
660 return true, mock
661 }
662
663 // Form-encoded noise-aware comparison. Each "key=value" segment is
664 // tested against the mock's noise patterns; a match wildcards that
665 // segment. The remaining keys must be the same set on both sides
666 // and each non-wildcarded value(s) must be byte-equal.
667 if reqIsForm && looksLikeFormEncoded(mockBody) {

Calls 10

IsNoisyMethod · 0.95
IsJSONFunction · 0.92
NewNoiseCheckerFunction · 0.92
JSONBodyMatchScoreFunction · 0.92
HasExtraNonNoisyKeysFunction · 0.92
looksLikeFormEncodedFunction · 0.85
UnmarshalMethod · 0.80
DebugMethod · 0.65
StringMethod · 0.45