1
#pragma once
2

            
3
#include <memory>
4
#include <string>
5
#include <vector>
6

            
7
#include "envoy/common/pure.h"
8

            
9
#include "source/common/protobuf/protobuf.h"
10

            
11
#include "absl/strings/string_view.h"
12
#include "absl/types/optional.h"
13

            
14
namespace Envoy {
15
namespace ContentParser {
16

            
17
/**
18
 * Represents a metadata action to be written.
19
 *
20
 * Parser implementations must populate namespace_ with a non-empty value.
21
 * If the config has an empty namespace, the parser should apply its default.
22
 */
23
struct MetadataAction {
24
  std::string namespace_; // Must be non-empty (parser applies defaults)
25
  std::string key;
26
  absl::optional<Protobuf::Value> value; // If empty, value extraction failed
27
  bool preserve_existing = false;
28
};
29

            
30
/**
31
 * Result of parsing.
32
 */
33
struct ParseResult {
34
  // Metadata actions to execute immediately (on_present matched)
35
  std::vector<MetadataAction> immediate_actions;
36

            
37
  // Whether all rules have reached their match limits (can stop processing)
38
  bool stop_processing = false;
39

            
40
  // Error message if parsing failed (e.g., invalid JSON). Empty if no error.
41
  absl::optional<std::string> error_message;
42
};
43

            
44
/**
45
 * Content parser interface for extracting metadata from content strings.
46
 *
47
 * Lifecycle and Thread Safety:
48
 * - Parser instances maintain internal state (match counts, error tracking)
49
 * - Callers should create a new parser instance per request/stream
50
 * - Parser instances should not be reused across different requests
51
 *
52
 * Example usage (caller is responsible for applying metadata actions):
53
 *
54
 *   auto parser = factory->createParser();
55
 *   for (chunk : data_chunks) {
56
 *     auto result = parser->parse(chunk);
57
 *     if (result.error_message) {
58
 *       // Optional: log the error
59
 *       LOG_DEBUG("Parse error: {}", *result.error_message);
60
 *     }
61
 *     for (const auto& action : result.immediate_actions) {
62
 *       applyAction(action);  // Caller implements this
63
 *     }
64
 *     if (result.stop_processing) break;
65
 *   }
66
 *   // At end-of-stream, apply deferred actions (on_error/on_missing)
67
 *   for (const auto& action : parser->getAllDeferredActions()) {
68
 *     applyAction(action);
69
 *   }
70
 */
71
class Parser {
72
public:
73
135
  virtual ~Parser() = default;
74

            
75
  /**
76
   * Parse a data string. Call this for each chunk of data.
77
   *
78
   * The parser tracks state internally across multiple parse() calls:
79
   * - Which rules have matched (for on_present)
80
   * - Which rules had selector not found
81
   * - Whether any parse error occurred
82
   *
83
   * @param data a data string to be processed
84
   * @return ParseResult with immediate actions and processing state
85
   */
86
  virtual ParseResult parse(absl::string_view data) PURE;
87

            
88
  /**
89
   * Get all deferred actions for rules that never matched.
90
   *
91
   * Call this once at end-of-stream. The parser uses internally tracked state
92
   * to determine which rules need fallback actions.
93
   *
94
   * @return vector of metadata actions for all rules needing deferred handling
95
   */
96
  virtual std::vector<MetadataAction> getAllDeferredActions() PURE;
97
};
98

            
99
using ParserPtr = std::unique_ptr<Parser>;
100

            
101
} // namespace ContentParser
102
} // namespace Envoy