package proxy import ( "bytes" "io" "strings" "testing" "mitmux/internal/rules" ) func TestApplyBodyRulesRewrites(t *testing.T) { body := io.NopCloser(strings.NewReader(`{"admin":false}`)) rs := []rules.Rule{{Enabled: true, Part: "body", Match: "false", Replace: "true"}} newBody, newLen, applied, err := applyBodyRules(body, rs) if err != nil { t.Fatalf("unexpected error: %v", err) } if !applied { t.Fatal("expected applied=true") } got, _ := io.ReadAll(newBody) want := `{"admin":true}` if string(got) != want { t.Errorf("body = %q, want %q", got, want) } if newLen != int64(len(want)) { t.Errorf("newLength = %d, want %d", newLen, len(want)) } } func TestApplyBodyRulesNilBody(t *testing.T) { newBody, newLen, applied, err := applyBodyRules(nil, []rules.Rule{{Enabled: true, Part: "body"}}) if err != nil { t.Fatalf("unexpected error: %v", err) } if applied || newBody != nil || newLen != 0 { t.Errorf("expected no-op for nil body, got body=%v len=%d applied=%v", newBody, newLen, applied) } } func TestApplyBodyRulesOversizedPassesThroughUnmodified(t *testing.T) { // One byte over the cap: exercises the "too large to safely // rewrite" path, which must reconstruct the ORIGINAL bytes exactly // (not the rule applied, not truncated, not corrupted) since the // whole point is refusing to guess at a partial rewrite. big := bytes.Repeat([]byte("a"), maxCaptureBytes+1) body := io.NopCloser(bytes.NewReader(big)) rs := []rules.Rule{{Enabled: true, Part: "body", Match: "a", Replace: "b"}} newBody, newLen, applied, err := applyBodyRules(body, rs) if err != nil { t.Fatalf("unexpected error: %v", err) } if applied { t.Fatal("expected applied=false for an oversized body") } if newLen != 0 { t.Errorf("expected newLength=0 (caller must not touch Content-Length) for an unapplied rewrite, got %d", newLen) } got, err := io.ReadAll(newBody) if err != nil { t.Fatalf("reading reconstructed body: %v", err) } if !bytes.Equal(got, big) { t.Errorf("reconstructed body does not match original: got %d bytes, want %d bytes, equal=%v", len(got), len(big), bytes.Equal(got, big)) } } func TestApplyBodyRulesExactlyAtCapStillApplies(t *testing.T) { // Exactly at the cap (not over it) should still be treated as // "fits" and get the rule applied - the +1 in the LimitReader is // what distinguishes "at the limit" from "over the limit". body := io.NopCloser(strings.NewReader(strings.Repeat("a", maxCaptureBytes))) rs := []rules.Rule{{Enabled: true, Part: "body", Match: "a", Replace: "b"}} _, _, applied, err := applyBodyRules(body, rs) if err != nil { t.Fatalf("unexpected error: %v", err) } if !applied { t.Error("expected applied=true for a body exactly at the cap") } }