1
#pragma once
2

            
3
#include <memory>
4
#include <stack>
5
#include <string>
6
#include <string_view>
7
#include <vector>
8

            
9
#include "source/common/common/logger.h"
10
#include "source/common/json/json_rpc_parser_config.h"
11
#include "source/common/protobuf/protobuf.h"
12

            
13
#include "absl/container/flat_hash_set.h"
14

            
15
namespace Envoy {
16
namespace Json {
17

            
18
/**
19
 * JsonRpcFieldExtractor extracts specific fields from a JSON-RPC stream into Protobuf metadata.
20
 * It uses the ObjectWriter interface to handle streaming JSON parsing.
21
 */
22
class JsonRpcFieldExtractor : public ProtobufUtil::converter::ObjectWriter,
23
                              public Logger::Loggable<Logger::Id::json_rpc> {
24
public:
25
  JsonRpcFieldExtractor(Protobuf::Struct& metadata, const JsonRpcParserConfig& config);
26
56
  ~JsonRpcFieldExtractor() override = default;
27

            
28
  // ProtobufUtil::converter::ObjectWriter implementation
29
  JsonRpcFieldExtractor* StartObject(absl::string_view name) override;
30
  JsonRpcFieldExtractor* EndObject() override;
31
  JsonRpcFieldExtractor* StartList(absl::string_view name) override;
32
  JsonRpcFieldExtractor* EndList() override;
33
  JsonRpcFieldExtractor* RenderString(absl::string_view name, absl::string_view value) override;
34
  JsonRpcFieldExtractor* RenderInt32(absl::string_view name, int32_t value) override;
35
  JsonRpcFieldExtractor* RenderUint32(absl::string_view name, uint32_t value) override;
36
  JsonRpcFieldExtractor* RenderInt64(absl::string_view name, int64_t value) override;
37
  JsonRpcFieldExtractor* RenderUint64(absl::string_view name, uint64_t value) override;
38
  JsonRpcFieldExtractor* RenderDouble(absl::string_view name, double value) override;
39
  JsonRpcFieldExtractor* RenderFloat(absl::string_view name, float value) override;
40
  JsonRpcFieldExtractor* RenderBool(absl::string_view name, bool value) override;
41
  JsonRpcFieldExtractor* RenderNull(absl::string_view name) override;
42
  JsonRpcFieldExtractor* RenderBytes(absl::string_view name, absl::string_view value) override;
43

            
44
  /**
45
   * @return true if the extractor has found all required fields and can stop parsing early.
46
   */
47
56
  bool shouldStopParsing() const { return can_stop_parsing_; }
48

            
49
  /**
50
   * Finalizes extraction by moving data from temporary storage to the final metadata struct.
51
   */
52
  void finalizeExtraction();
53

            
54
  // Validation getters
55
47
  bool isValidJsonRpc() const { return is_valid_jsonrpc_; }
56
25
  const std::string& getMethod() const { return method_; }
57

            
58
protected:
59
  // Internal state checks for early-stop optimization
60
  void checkEarlyStop();
61

            
62
  // Stores a field in temporary storage
63
  void storeField(const std::string& path, const Protobuf::Value& value);
64

            
65
  // Data migration helpers
66
  void copySelectedFields();
67
  void copyFieldByPath(const std::string& path);
68

            
69
  // Validation
70
  void validateRequiredFields();
71

            
72
  // Path helper
73
  std::string buildFullPath(absl::string_view name) const;
74

            
75
  // Check if it is a valid JSON-RPC request or response.
76
  void checkValidJsonRpc(absl::string_view name,
77
                         absl::optional<absl::string_view> value = absl::nullopt);
78

            
79
  // Protocol-specific interface
80
  virtual bool isNotification(const std::string& method) const = 0;
81
  virtual absl::string_view protocolName() const = 0;
82
  virtual absl::string_view jsonRpcVersion() const = 0;
83
  virtual absl::string_view jsonRpcField() const = 0;
84
  virtual absl::string_view methodField() const = 0;
85
  virtual bool lists_supported() const = 0;
86

            
87
  Protobuf::Struct temp_storage_;   // Store all fields temporarily
88
  Protobuf::Struct& root_metadata_; // Final filtered metadata
89
  const JsonRpcParserConfig& config_;
90

            
91
  // Context stack for building the temporary Protobuf structure
92
  struct NestedContext {
93
    Protobuf::Struct* struct_ptr{nullptr};
94
    Protobuf::ListValue* list_ptr{nullptr};
95
    std::string field_name{};
96
387
    bool is_list() const { return list_ptr != nullptr; }
97
  };
98
  std::stack<NestedContext> context_stack_;
99

            
100
  // Current path tracking (e.g., {"params", "user", "id"})
101
  std::vector<std::string> path_stack_;
102

            
103
  // Field tracking for optimization
104
  absl::flat_hash_set<std::string> collected_fields_;
105
  absl::flat_hash_set<std::string> extracted_fields_;
106

            
107
  // Protocol state
108
  std::string method_;
109
  bool is_valid_jsonrpc_{false};
110
  bool has_jsonrpc_{false};
111
  bool has_method_{false};
112
  bool has_result_{false};
113
  bool has_error_{false};
114

            
115
  // Optimization flag
116
  bool can_stop_parsing_{false};
117

            
118
  // Validation state
119
  std::vector<std::string> missing_required_fields_;
120

            
121
  int depth_{0};
122
  int array_depth_{0};
123

            
124
  // Cache for path building
125
  std::string current_path_cache_;
126
  size_t fields_needed_{0};
127
  size_t fields_collected_count_{0};
128
  bool fields_needed_updated_{false};
129
  bool is_notification_{false};
130
};
131

            
132
} // namespace Json
133
} // namespace Envoy