1
#include <cstddef>
2
#include <cstdint>
3
#include <map>
4
#include <memory>
5
#include <mutex>
6
#include <optional>
7
#include <span>
8
#include <string_view>
9

            
10
#include "source/extensions/dynamic_modules/abi/abi.h"
11

            
12
#include "sdk.h"
13

            
14
namespace Envoy {
15
namespace DynamicModules {
16

            
17
// BodyBuffer implementation
18
template <envoy_dynamic_module_type_http_body_type Type> class BodyBufferImpl : public BodyBuffer {
19
public:
20
  BodyBufferImpl(void* host_plugin_ptr) : host_plugin_ptr_(host_plugin_ptr) {}
21

            
22
  std::vector<BufferView> getChunks() const override {
23
    size_t chunks_size =
24
        envoy_dynamic_module_callback_http_get_body_chunks_size(host_plugin_ptr_, Type);
25
    if (chunks_size == 0) {
26
      return {};
27
    }
28

            
29
    std::vector<BufferView> result_chunks(chunks_size);
30
    envoy_dynamic_module_callback_http_get_body_chunks(
31
        host_plugin_ptr_, Type,
32
        reinterpret_cast<envoy_dynamic_module_type_envoy_buffer*>(result_chunks.data()));
33
    return result_chunks;
34
  }
35

            
36
  size_t getSize() const override {
37
    return envoy_dynamic_module_callback_http_get_body_size(host_plugin_ptr_, Type);
38
  }
39

            
40
  void append(std::string_view data) override {
41
    if (data.empty()) {
42
      return;
43
    }
44
    envoy_dynamic_module_callback_http_append_body(
45
        host_plugin_ptr_, Type, envoy_dynamic_module_type_module_buffer{data.data(), data.size()});
46
  }
47

            
48
  void drain(size_t size) override {
49
    envoy_dynamic_module_callback_http_drain_body(host_plugin_ptr_, Type, size);
50
  }
51

            
52
private:
53
  void* host_plugin_ptr_;
54
};
55

            
56
using ReceivedRequestBody =
57
    BodyBufferImpl<envoy_dynamic_module_type_http_body_type_ReceivedRequestBody>;
58
using BufferedRequestBody =
59
    BodyBufferImpl<envoy_dynamic_module_type_http_body_type_BufferedRequestBody>;
60
using ReceivedResponseBody =
61
    BodyBufferImpl<envoy_dynamic_module_type_http_body_type_ReceivedResponseBody>;
62
using BufferedResponseBody =
63
    BodyBufferImpl<envoy_dynamic_module_type_http_body_type_BufferedResponseBody>;
64

            
65
// HeaderMap implementation
66
template <envoy_dynamic_module_type_http_header_type Type> class HeaderMapImpl : public HeaderMap {
67
public:
68
  HeaderMapImpl(void* host_plugin_ptr) : host_plugin_ptr_(host_plugin_ptr) {}
69

            
70
  std::vector<std::string_view> get(std::string_view key) const override {
71
    size_t value_count = 0;
72
    auto first_value = getSingleHeader(key, 0, &value_count);
73
    if (value_count == 0) {
74
      return {};
75
    }
76

            
77
    std::vector<std::string_view> values;
78
    values.reserve(value_count);
79
    values.push_back(first_value);
80

            
81
    for (size_t i = 1; i < value_count; i++) {
82
      values.push_back(getSingleHeader(key, i, nullptr));
83
    }
84
    return values;
85
  }
86

            
87
  std::string_view getOne(std::string_view key) const override {
88
    return getSingleHeader(key, 0, nullptr);
89
  }
90

            
91
  std::vector<HeaderView> getAll() const override {
92
    size_t header_count =
93
        envoy_dynamic_module_callback_http_get_headers_size(host_plugin_ptr_, Type);
94
    if (header_count == 0) {
95
      return {};
96
    }
97

            
98
    std::vector<HeaderView> result_headers(header_count);
99
    envoy_dynamic_module_callback_http_get_headers(
100
        host_plugin_ptr_, Type,
101
        reinterpret_cast<envoy_dynamic_module_type_envoy_http_header*>(result_headers.data()));
102
    return result_headers;
103
  }
104

            
105
  void set(std::string_view key, std::string_view value) override {
106
    envoy_dynamic_module_callback_http_set_header(
107
        host_plugin_ptr_, Type, envoy_dynamic_module_type_module_buffer{key.data(), key.size()},
108
        envoy_dynamic_module_type_module_buffer{value.data(), value.size()});
109
  }
110

            
111
  void add(std::string_view key, std::string_view value) override {
112
    envoy_dynamic_module_callback_http_add_header(
113
        host_plugin_ptr_, Type, envoy_dynamic_module_type_module_buffer{key.data(), key.size()},
114
        envoy_dynamic_module_type_module_buffer{value.data(), value.size()});
115
  }
116

            
117
  void remove(std::string_view key) override {
118
    envoy_dynamic_module_callback_http_set_header(
119
        host_plugin_ptr_, Type, envoy_dynamic_module_type_module_buffer{key.data(), key.size()},
120
        envoy_dynamic_module_type_module_buffer{nullptr, 0});
121
  }
122

            
123
  size_t size() const override {
124
    return envoy_dynamic_module_callback_http_get_headers_size(host_plugin_ptr_, Type);
125
  }
126

            
127
private:
128
  void* host_plugin_ptr_;
129

            
130
  std::string_view getSingleHeader(std::string_view key, size_t index, size_t* value_count) const {
131
    BufferView value{nullptr, 0};
132

            
133
    bool ret = envoy_dynamic_module_callback_http_get_header(
134
        host_plugin_ptr_, Type, envoy_dynamic_module_type_module_buffer{key.data(), key.size()},
135
        reinterpret_cast<envoy_dynamic_module_type_envoy_buffer*>(&value), index, value_count);
136
    if (!ret || value.data() == nullptr || value.size() == 0) {
137
      return {};
138
    }
139
    return value.toStringView();
140
  }
141
};
142

            
143
using RequestHeaders = HeaderMapImpl<envoy_dynamic_module_type_http_header_type_RequestHeader>;
144
using RequestTrailers = HeaderMapImpl<envoy_dynamic_module_type_http_header_type_RequestTrailer>;
145
using ResponseHeaders = HeaderMapImpl<envoy_dynamic_module_type_http_header_type_ResponseHeader>;
146
using ResponseTrailers = HeaderMapImpl<envoy_dynamic_module_type_http_header_type_ResponseTrailer>;
147

            
148
// Scheduler implementation
149
template <bool IsConfigScheduler> class SchedulerImplBase : public Scheduler {
150
public:
151
  SchedulerImplBase(void* host_ptr) : scheduler_ptr_(newScheduler(host_ptr)) {}
152

            
153
  void schedule(std::function<void()> func) override {
154
    uint64_t task_id = 0;
155

            
156
    // Lock to protect access to tasks_ and next_task_id_ manually
157
    {
158
      std::lock_guard<std::mutex> lock(mutex_);
159
      task_id = next_task_id_++;
160
      tasks_[task_id] = std::move(func);
161
    }
162

            
163
    commitScheduler(scheduler_ptr_, task_id);
164
  }
165

            
166
  void onScheduled(uint64_t task_id) {
167
    std::function<void()> func;
168

            
169
    {
170
      // Lock to protect access to tasks_ manually
171
      std::lock_guard<std::mutex> lock(mutex_);
172
      auto it = tasks_.find(task_id);
173
      if (it != tasks_.end()) {
174
        func = std::move(it->second);
175
        tasks_.erase(it);
176
      }
177
    }
178

            
179
    if (func) {
180
      func();
181
    }
182
  }
183

            
184
  ~SchedulerImplBase() override { deleteScheduler(scheduler_ptr_); }
185

            
186
private:
187
  static void* newScheduler(void* host_ptr) {
188
    if constexpr (IsConfigScheduler) {
189
      return envoy_dynamic_module_callback_http_filter_config_scheduler_new(host_ptr);
190
    } else {
191
      return envoy_dynamic_module_callback_http_filter_scheduler_new(host_ptr);
192
    }
193
  }
194
  static void deleteScheduler(void* scheduler_ptr) {
195
    if constexpr (IsConfigScheduler) {
196
      envoy_dynamic_module_callback_http_filter_config_scheduler_delete(scheduler_ptr);
197
    } else {
198
      envoy_dynamic_module_callback_http_filter_scheduler_delete(scheduler_ptr);
199
    }
200
  }
201
  static void commitScheduler(void* scheduler_ptr, uint64_t task_id) {
202
    if constexpr (IsConfigScheduler) {
203
      envoy_dynamic_module_callback_http_filter_config_scheduler_commit(scheduler_ptr, task_id);
204
    } else {
205
      envoy_dynamic_module_callback_http_filter_scheduler_commit(scheduler_ptr, task_id);
206
    }
207
  }
208

            
209
  void* scheduler_ptr_{};
210

            
211
  std::mutex mutex_;
212
  uint64_t next_task_id_{1}; // 0 is reserved.
213
  std::map<uint64_t, std::function<void()>> tasks_;
214
};
215

            
216
using SchedulerImpl = SchedulerImplBase<false>;
217
using ConfigSchedulerImpl = SchedulerImplBase<true>;
218

            
219
// HttpFilterHandle implementation
220
class HttpFilterHandleImpl : public HttpFilterHandle {
221
public:
222
  HttpFilterHandleImpl(void* host_plugin_ptr)
223
      : host_plugin_ptr_(host_plugin_ptr), request_headers_(host_plugin_ptr),
224
        response_headers_(host_plugin_ptr), request_trailers_(host_plugin_ptr),
225
        response_trailers_(host_plugin_ptr), received_request_body_(host_plugin_ptr),
226
        received_response_body_(host_plugin_ptr), buffered_request_body_(host_plugin_ptr),
227
        buffered_response_body_(host_plugin_ptr) {}
228

            
229
  std::optional<std::string_view> getMetadataString(std::string_view ns,
230
                                                    std::string_view key) override {
231
    BufferView value{nullptr, 0};
232

            
233
    const bool ret = envoy_dynamic_module_callback_http_get_metadata_string(
234
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic,
235
        envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
236
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()},
237
        reinterpret_cast<envoy_dynamic_module_type_envoy_buffer*>(&value));
238

            
239
    if (!ret || value.data() == nullptr || value.size() == 0) {
240
      return {};
241
    }
242
    return value.toStringView();
243
  }
244

            
245
  std::optional<double> getMetadataNumber(std::string_view ns, std::string_view key) override {
246
    double value = 0.0;
247
    const bool ret = envoy_dynamic_module_callback_http_get_metadata_number(
248
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic,
249
        envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
250
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()}, &value);
251

            
252
    if (!ret) {
253
      return {};
254
    }
255
    return value;
256
  }
257

            
258
  std::optional<bool> getMetadataBool(std::string_view ns, std::string_view key) override {
259
    bool value = false;
260
    const bool ret = envoy_dynamic_module_callback_http_get_metadata_bool(
261
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic,
262
        envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
263
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()}, &value);
264

            
265
    if (!ret) {
266
      return {};
267
    }
268
    return value;
269
  }
270

            
271
  std::vector<std::string_view> getMetadataKeys(std::string_view ns) override {
272
    size_t count = envoy_dynamic_module_callback_http_get_metadata_keys_count(
273
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic,
274
        envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()});
275
    if (count == 0) {
276
      return {};
277
    }
278
    std::vector<envoy_dynamic_module_type_envoy_buffer> buffers(count);
279
    const bool ret = envoy_dynamic_module_callback_http_get_metadata_keys(
280
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic,
281
        envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()}, buffers.data());
282
    if (!ret) {
283
      return {};
284
    }
285
    std::vector<std::string_view> keys;
286
    keys.reserve(count);
287
    for (size_t i = 0; i < count; i++) {
288
      keys.emplace_back(buffers[i].ptr, buffers[i].length);
289
    }
290
    return keys;
291
  }
292

            
293
  std::vector<std::string_view> getMetadataNamespaces() override {
294
    size_t count = envoy_dynamic_module_callback_http_get_metadata_namespaces_count(
295
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic);
296
    if (count == 0) {
297
      return {};
298
    }
299
    std::vector<envoy_dynamic_module_type_envoy_buffer> buffers(count);
300
    const bool ret = envoy_dynamic_module_callback_http_get_metadata_namespaces(
301
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic, buffers.data());
302
    if (!ret) {
303
      return {};
304
    }
305
    std::vector<std::string_view> namespaces;
306
    namespaces.reserve(count);
307
    for (size_t i = 0; i < count; i++) {
308
      namespaces.emplace_back(buffers[i].ptr, buffers[i].length);
309
    }
310
    return namespaces;
311
  }
312

            
313
  void setMetadata(std::string_view ns, std::string_view key, std::string_view value) override {
314
    envoy_dynamic_module_callback_http_set_dynamic_metadata_string(
315
        host_plugin_ptr_, envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
316
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()},
317
        envoy_dynamic_module_type_module_buffer{value.data(), value.size()});
318
  }
319

            
320
  void setMetadata(std::string_view ns, std::string_view key, double value) override {
321
    envoy_dynamic_module_callback_http_set_dynamic_metadata_number(
322
        host_plugin_ptr_, envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
323
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()}, value);
324
  }
325

            
326
  void setMetadata(std::string_view ns, std::string_view key, bool value) override {
327
    envoy_dynamic_module_callback_http_set_dynamic_metadata_bool(
328
        host_plugin_ptr_, envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
329
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()}, value);
330
  }
331

            
332
  bool addMetadataList(std::string_view ns, std::string_view key, double value) override {
333
    return envoy_dynamic_module_callback_http_add_dynamic_metadata_list_number(
334
        host_plugin_ptr_, envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
335
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()}, value);
336
  }
337

            
338
  bool addMetadataList(std::string_view ns, std::string_view key, std::string_view value) override {
339
    return envoy_dynamic_module_callback_http_add_dynamic_metadata_list_string(
340
        host_plugin_ptr_, envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
341
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()},
342
        envoy_dynamic_module_type_module_buffer{value.data(), value.size()});
343
  }
344

            
345
  bool addMetadataList(std::string_view ns, std::string_view key, bool value) override {
346
    return envoy_dynamic_module_callback_http_add_dynamic_metadata_list_bool(
347
        host_plugin_ptr_, envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
348
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()}, value);
349
  }
350

            
351
  std::optional<size_t> getMetadataListSize(std::string_view ns, std::string_view key) override {
352
    size_t result = 0;
353
    const bool ret = envoy_dynamic_module_callback_http_get_metadata_list_size(
354
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic,
355
        envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
356
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()}, &result);
357
    if (!ret) {
358
      return {};
359
    }
360
    return result;
361
  }
362

            
363
  std::optional<double> getMetadataListNumber(std::string_view ns, std::string_view key,
364
                                              size_t index) override {
365
    double value = 0.0;
366
    const bool ret = envoy_dynamic_module_callback_http_get_metadata_list_number(
367
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic,
368
        envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
369
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()}, index, &value);
370
    if (!ret) {
371
      return {};
372
    }
373
    return value;
374
  }
375

            
376
  std::optional<std::string_view> getMetadataListString(std::string_view ns, std::string_view key,
377
                                                        size_t index) override {
378
    BufferView value{nullptr, 0};
379
    const bool ret = envoy_dynamic_module_callback_http_get_metadata_list_string(
380
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic,
381
        envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
382
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()}, index,
383
        reinterpret_cast<envoy_dynamic_module_type_envoy_buffer*>(&value));
384
    if (!ret || value.data() == nullptr) {
385
      return {};
386
    }
387
    return value.toStringView();
388
  }
389

            
390
  std::optional<bool> getMetadataListBool(std::string_view ns, std::string_view key,
391
                                          size_t index) override {
392
    bool value = false;
393
    const bool ret = envoy_dynamic_module_callback_http_get_metadata_list_bool(
394
        host_plugin_ptr_, envoy_dynamic_module_type_metadata_source_Dynamic,
395
        envoy_dynamic_module_type_module_buffer{ns.data(), ns.size()},
396
        envoy_dynamic_module_type_module_buffer{key.data(), key.size()}, index, &value);
397
    if (!ret) {
398
      return {};
399
    }
400
    return value;
401
  }
402

            
403
  std::optional<std::string_view> getFilterState(std::string_view key) override {
404
    BufferView value{nullptr, 0};
405

            
406
    const bool ret = envoy_dynamic_module_callback_http_get_filter_state_bytes(
407
        host_plugin_ptr_, envoy_dynamic_module_type_module_buffer{key.data(), key.size()},
408
        reinterpret_cast<envoy_dynamic_module_type_envoy_buffer*>(&value));
409

            
410
    if (!ret || value.data() == nullptr || value.size() == 0) {
411
      return {};
412
    }
413
    return value.toStringView();
414
  }
415

            
416
  void setFilterState(std::string_view key, std::string_view value) override {
417
    envoy_dynamic_module_callback_http_set_filter_state_bytes(
418
        host_plugin_ptr_, envoy_dynamic_module_type_module_buffer{key.data(), key.size()},
419
        envoy_dynamic_module_type_module_buffer{value.data(), value.size()});
420
  }
421

            
422
  std::optional<std::string_view> getAttributeString(AttributeID id) override {
423
    BufferView value{nullptr, 0};
424

            
425
    const bool ret = envoy_dynamic_module_callback_http_filter_get_attribute_string(
426
        host_plugin_ptr_, static_cast<envoy_dynamic_module_type_attribute_id>(id),
427
        reinterpret_cast<envoy_dynamic_module_type_envoy_buffer*>(&value));
428

            
429
    if (!ret || value.data() == nullptr || value.size() == 0) {
430
      return {};
431
    }
432
    return value.toStringView();
433
  }
434

            
435
  std::optional<uint64_t> getAttributeNumber(AttributeID id) override {
436
    uint64_t value = 0;
437
    const bool ret = envoy_dynamic_module_callback_http_filter_get_attribute_int(
438
        host_plugin_ptr_, static_cast<envoy_dynamic_module_type_attribute_id>(id), &value);
439

            
440
    if (!ret) {
441
      return {};
442
    }
443
    return value;
444
  }
445

            
446
  std::optional<bool> getAttributeBool(AttributeID id) override {
447
    bool value = false;
448
    const bool ret = envoy_dynamic_module_callback_http_filter_get_attribute_bool(
449
        host_plugin_ptr_, static_cast<envoy_dynamic_module_type_attribute_id>(id), &value);
450

            
451
    if (!ret) {
452
      return {};
453
    }
454
    return value;
455
  }
456

            
457
  void sendLocalResponse(uint32_t status, std::span<const HeaderView> headers,
458
                         std::string_view body, std::string_view detail) override {
459
    envoy_dynamic_module_callback_http_send_response(
460
        host_plugin_ptr_, status,
461
        const_cast<envoy_dynamic_module_type_module_http_header*>(
462
            reinterpret_cast<const envoy_dynamic_module_type_module_http_header*>(headers.data())),
463
        headers.size(), envoy_dynamic_module_type_module_buffer{body.data(), body.size()},
464
        envoy_dynamic_module_type_module_buffer{detail.data(), detail.size()});
465
  }
466

            
467
  void sendResponseHeaders(std::span<const HeaderView> headers, bool end_stream) override {
468
    envoy_dynamic_module_callback_http_send_response_headers(
469
        host_plugin_ptr_,
470
        const_cast<envoy_dynamic_module_type_module_http_header*>(
471
            reinterpret_cast<const envoy_dynamic_module_type_module_http_header*>(headers.data())),
472
        headers.size(), end_stream);
473
  }
474

            
475
  void sendResponseData(std::string_view body, bool end_stream) override {
476
    envoy_dynamic_module_callback_http_send_response_data(
477
        host_plugin_ptr_, envoy_dynamic_module_type_module_buffer{body.data(), body.size()},
478
        end_stream);
479
  }
480

            
481
  void sendResponseTrailers(std::span<const HeaderView> trailers) override {
482
    envoy_dynamic_module_callback_http_send_response_trailers(
483
        host_plugin_ptr_,
484
        const_cast<envoy_dynamic_module_type_module_http_header*>(
485
            reinterpret_cast<const envoy_dynamic_module_type_module_http_header*>(trailers.data())),
486
        trailers.size());
487
  }
488

            
489
  void addCustomFlag(std::string_view flag) override {
490
    envoy_dynamic_module_callback_http_add_custom_flag(
491
        host_plugin_ptr_, envoy_dynamic_module_type_module_buffer{flag.data(), flag.size()});
492
  }
493

            
494
  void continueRequest() override {
495
    envoy_dynamic_module_callback_http_filter_continue_decoding(host_plugin_ptr_);
496
  }
497

            
498
  void continueResponse() override {
499
    envoy_dynamic_module_callback_http_filter_continue_encoding(host_plugin_ptr_);
500
  }
501

            
502
  void clearRouteCache() override {
503
    envoy_dynamic_module_callback_http_clear_route_cache(host_plugin_ptr_);
504
  }
505

            
506
  HeaderMap& requestHeaders() override { return request_headers_; }
507

            
508
  BodyBuffer& bufferedRequestBody() override { return buffered_request_body_; }
509

            
510
  BodyBuffer& receivedRequestBody() override { return received_request_body_; }
511

            
512
  HeaderMap& requestTrailers() override { return request_trailers_; }
513

            
514
  HeaderMap& responseHeaders() override { return response_headers_; }
515

            
516
  BodyBuffer& bufferedResponseBody() override { return buffered_response_body_; }
517

            
518
  BodyBuffer& receivedResponseBody() override { return received_response_body_; }
519

            
520
  bool receivedBufferedRequestBody() override {
521
    return envoy_dynamic_module_callback_http_received_buffered_request_body(host_plugin_ptr_);
522
  }
523

            
524
  bool receivedBufferedResponseBody() override {
525
    return envoy_dynamic_module_callback_http_received_buffered_response_body(host_plugin_ptr_);
526
  }
527

            
528
  HeaderMap& responseTrailers() override { return response_trailers_; }
529

            
530
  const RouteSpecificConfig* getMostSpecificConfig() override {
531
    const void* config_ptr =
532
        envoy_dynamic_module_callback_get_most_specific_route_config(host_plugin_ptr_);
533
    if (config_ptr == nullptr) {
534
      return nullptr;
535
    }
536
    return static_cast<const RouteSpecificConfig*>(config_ptr);
537
  }
538

            
539
  std::shared_ptr<Scheduler> getScheduler() override {
540
    if (!scheduler_) {
541
      scheduler_ = std::make_shared<SchedulerImpl>(host_plugin_ptr_);
542
    }
543
    return scheduler_;
544
  }
545

            
546
  std::pair<HttpCalloutInitResult, uint64_t> httpCallout(std::string_view cluster,
547
                                                         std::span<const HeaderView> headers,
548
                                                         std::string_view body, uint64_t timeout_ms,
549
                                                         HttpCalloutCallback& cb) override {
550
    uint64_t callout_id_out = 0;
551
    auto result = envoy_dynamic_module_callback_http_filter_http_callout(
552
        host_plugin_ptr_, &callout_id_out,
553
        envoy_dynamic_module_type_module_buffer{cluster.data(), cluster.size()},
554
        const_cast<envoy_dynamic_module_type_module_http_header*>(
555
            reinterpret_cast<const envoy_dynamic_module_type_module_http_header*>(headers.data())),
556
        headers.size(), envoy_dynamic_module_type_module_buffer{body.data(), body.size()},
557
        timeout_ms);
558

            
559
    if (result == envoy_dynamic_module_type_http_callout_init_result_Success) {
560
      callout_callbacks_[callout_id_out] = &cb;
561
    }
562

            
563
    return {static_cast<HttpCalloutInitResult>(result), callout_id_out};
564
  }
565

            
566
  std::pair<HttpCalloutInitResult, uint64_t>
567
  startHttpStream(std::string_view cluster, std::span<const HeaderView> headers,
568
                  std::string_view body, bool end_of_stream, uint64_t timeout_ms,
569
                  HttpStreamCallback& cb) override {
570
    uint64_t stream_id_out = 0;
571
    auto result = envoy_dynamic_module_callback_http_filter_start_http_stream(
572
        host_plugin_ptr_, &stream_id_out,
573
        envoy_dynamic_module_type_module_buffer{cluster.data(), cluster.size()},
574
        const_cast<envoy_dynamic_module_type_module_http_header*>(
575
            reinterpret_cast<const envoy_dynamic_module_type_module_http_header*>(headers.data())),
576
        headers.size(), envoy_dynamic_module_type_module_buffer{body.data(), body.size()},
577
        end_of_stream, timeout_ms);
578

            
579
    if (result == envoy_dynamic_module_type_http_callout_init_result_Success) {
580
      stream_callbacks_[stream_id_out] = &cb;
581
    }
582

            
583
    return {static_cast<HttpCalloutInitResult>(result), stream_id_out};
584
  }
585

            
586
  bool sendHttpStreamData(uint64_t stream_id, std::string_view body, bool end_of_stream) override {
587
    return envoy_dynamic_module_callback_http_stream_send_data(
588
        host_plugin_ptr_, stream_id,
589
        envoy_dynamic_module_type_module_buffer{body.data(), body.size()}, end_of_stream);
590
  }
591

            
592
  bool sendHttpStreamTrailers(uint64_t stream_id, std::span<const HeaderView> trailers) override {
593
    return envoy_dynamic_module_callback_http_stream_send_trailers(
594
        host_plugin_ptr_, stream_id,
595
        const_cast<envoy_dynamic_module_type_module_http_header*>(
596
            reinterpret_cast<const envoy_dynamic_module_type_module_http_header*>(trailers.data())),
597
        trailers.size());
598
  }
599

            
600
  void resetHttpStream(uint64_t stream_id) override {
601
    envoy_dynamic_module_callback_http_filter_reset_http_stream(host_plugin_ptr_, stream_id);
602
  }
603

            
604
  void setDownstreamWatermarkCallbacks(DownstreamWatermarkCallbacks& callbacks) override {
605
    downstream_watermark_callbacks_ = &callbacks;
606
  }
607

            
608
  void clearDownstreamWatermarkCallbacks() override { downstream_watermark_callbacks_ = nullptr; }
609

            
610
  MetricsResult recordHistogramValue(MetricID id, uint64_t value,
611
                                     std::span<const BufferView> tags_values) override {
612
    return static_cast<MetricsResult>(
613
        envoy_dynamic_module_callback_http_filter_record_histogram_value(
614
            host_plugin_ptr_, id,
615
            const_cast<envoy_dynamic_module_type_module_buffer*>(
616
                reinterpret_cast<const envoy_dynamic_module_type_module_buffer*>(
617
                    tags_values.data())),
618
            tags_values.size(), value));
619
  }
620

            
621
  MetricsResult setGaugeValue(MetricID id, uint64_t value,
622
                              std::span<const BufferView> tags_values) override {
623
    return static_cast<MetricsResult>(envoy_dynamic_module_callback_http_filter_set_gauge(
624
        host_plugin_ptr_, id,
625
        const_cast<envoy_dynamic_module_type_module_buffer*>(
626
            reinterpret_cast<const envoy_dynamic_module_type_module_buffer*>(tags_values.data())),
627
        tags_values.size(), value));
628
  }
629

            
630
  MetricsResult incrementGaugeValue(MetricID id, uint64_t value,
631
                                    std::span<const BufferView> tags_values) override {
632
    return static_cast<MetricsResult>(envoy_dynamic_module_callback_http_filter_increment_gauge(
633
        host_plugin_ptr_, id,
634
        const_cast<envoy_dynamic_module_type_module_buffer*>(
635
            reinterpret_cast<const envoy_dynamic_module_type_module_buffer*>(tags_values.data())),
636
        tags_values.size(), value));
637
  }
638

            
639
  MetricsResult decrementGaugeValue(MetricID id, uint64_t value,
640
                                    std::span<const BufferView> tags_values) override {
641
    return static_cast<MetricsResult>(envoy_dynamic_module_callback_http_filter_decrement_gauge(
642
        host_plugin_ptr_, id,
643
        const_cast<envoy_dynamic_module_type_module_buffer*>(
644
            reinterpret_cast<const envoy_dynamic_module_type_module_buffer*>(tags_values.data())),
645
        tags_values.size(), value));
646
  }
647

            
648
  MetricsResult incrementCounterValue(MetricID id, uint64_t value,
649
                                      std::span<const BufferView> tags_values) override {
650
    return static_cast<MetricsResult>(envoy_dynamic_module_callback_http_filter_increment_counter(
651
        host_plugin_ptr_, id,
652
        const_cast<envoy_dynamic_module_type_module_buffer*>(
653
            reinterpret_cast<const envoy_dynamic_module_type_module_buffer*>(tags_values.data())),
654
        tags_values.size(), value));
655
  }
656
  bool logEnabled(LogLevel level) override {
657
    return envoy_dynamic_module_callback_log_enabled(
658
        static_cast<envoy_dynamic_module_type_log_level>(level));
659
  }
660
  void log(LogLevel level, std::string_view message) override {
661
    return envoy_dynamic_module_callback_log(
662
        static_cast<envoy_dynamic_module_type_log_level>(level),
663
        envoy_dynamic_module_type_module_buffer{message.data(), message.size()});
664
  }
665

            
666
  void* host_plugin_ptr_;
667
  RequestHeaders request_headers_;
668
  ResponseHeaders response_headers_;
669
  RequestTrailers request_trailers_;
670
  ResponseTrailers response_trailers_;
671

            
672
  ReceivedRequestBody received_request_body_;
673
  ReceivedResponseBody received_response_body_;
674
  BufferedRequestBody buffered_request_body_;
675
  BufferedResponseBody buffered_response_body_;
676

            
677
  std::shared_ptr<SchedulerImpl> scheduler_;
678

            
679
  std::map<uint64_t, HttpCalloutCallback*> callout_callbacks_;
680
  std::map<uint64_t, HttpStreamCallback*> stream_callbacks_;
681

            
682
  DownstreamWatermarkCallbacks* downstream_watermark_callbacks_ = nullptr;
683

            
684
  std::unique_ptr<HttpFilter> plugin_;
685
  bool stream_complete_ = false;
686
  bool local_reply_sent_ = false;
687
};
688

            
689
// HttpFilterConfigHandle implementation
690
class HttpFilterConfigHandleImpl : public HttpFilterConfigHandle {
691
public:
692
  HttpFilterConfigHandleImpl(void* host_config_ptr) : host_config_ptr_(host_config_ptr) {}
693

            
694
  std::pair<MetricID, MetricsResult>
695
  defineHistogram(std::string_view name, std::span<const BufferView> tags_keys) override {
696
    size_t metric_id = 0;
697
    auto result = static_cast<MetricsResult>(
698
        envoy_dynamic_module_callback_http_filter_config_define_histogram(
699
            host_config_ptr_, envoy_dynamic_module_type_module_buffer{name.data(), name.size()},
700
            const_cast<envoy_dynamic_module_type_module_buffer*>(
701
                reinterpret_cast<const envoy_dynamic_module_type_module_buffer*>(tags_keys.data())),
702
            tags_keys.size(), &metric_id));
703
    return {metric_id, result};
704
  }
705

            
706
  std::pair<MetricID, MetricsResult> defineGauge(std::string_view name,
707
                                                 std::span<const BufferView> tags_keys) override {
708
    size_t metric_id = 0;
709
    auto result =
710
        static_cast<MetricsResult>(envoy_dynamic_module_callback_http_filter_config_define_gauge(
711
            host_config_ptr_, envoy_dynamic_module_type_module_buffer{name.data(), name.size()},
712
            const_cast<envoy_dynamic_module_type_module_buffer*>(
713
                reinterpret_cast<const envoy_dynamic_module_type_module_buffer*>(tags_keys.data())),
714
            tags_keys.size(), &metric_id));
715
    return {metric_id, result};
716
  }
717

            
718
  std::pair<MetricID, MetricsResult> defineCounter(std::string_view name,
719
                                                   std::span<const BufferView> tags_keys) override {
720
    size_t metric_id = 0;
721
    auto result =
722
        static_cast<MetricsResult>(envoy_dynamic_module_callback_http_filter_config_define_counter(
723
            host_config_ptr_, envoy_dynamic_module_type_module_buffer{name.data(), name.size()},
724
            const_cast<envoy_dynamic_module_type_module_buffer*>(
725
                reinterpret_cast<const envoy_dynamic_module_type_module_buffer*>(tags_keys.data())),
726
            tags_keys.size(), &metric_id));
727
    return {metric_id, result};
728
  }
729
  bool logEnabled(LogLevel level) override {
730
    return envoy_dynamic_module_callback_log_enabled(
731
        static_cast<envoy_dynamic_module_type_log_level>(level));
732
  }
733
  void log(LogLevel level, std::string_view message) override {
734
    return envoy_dynamic_module_callback_log(
735
        static_cast<envoy_dynamic_module_type_log_level>(level),
736
        envoy_dynamic_module_type_module_buffer{message.data(), message.size()});
737
  }
738

            
739
  std::pair<HttpCalloutInitResult, uint64_t> httpCallout(std::string_view cluster,
740
                                                         std::span<const HeaderView> headers,
741
                                                         std::string_view body, uint64_t timeout_ms,
742
                                                         HttpCalloutCallback& cb) override {
743
    uint64_t callout_id_out = 0;
744
    auto result = envoy_dynamic_module_callback_http_filter_config_http_callout(
745
        host_config_ptr_, &callout_id_out,
746
        envoy_dynamic_module_type_module_buffer{cluster.data(), cluster.size()},
747
        const_cast<envoy_dynamic_module_type_module_http_header*>(
748
            reinterpret_cast<const envoy_dynamic_module_type_module_http_header*>(headers.data())),
749
        headers.size(), envoy_dynamic_module_type_module_buffer{body.data(), body.size()},
750
        timeout_ms);
751

            
752
    if (result == envoy_dynamic_module_type_http_callout_init_result_Success) {
753
      callout_callbacks_[callout_id_out] = &cb;
754
    }
755
    return {static_cast<HttpCalloutInitResult>(result), callout_id_out};
756
  }
757

            
758
  std::pair<HttpCalloutInitResult, uint64_t>
759
  startHttpStream(std::string_view cluster, std::span<const HeaderView> headers,
760
                  std::string_view body, bool end_of_stream, uint64_t timeout_ms,
761
                  HttpStreamCallback& cb) override {
762
    uint64_t stream_id_out = 0;
763
    auto result = envoy_dynamic_module_callback_http_filter_config_start_http_stream(
764
        host_config_ptr_, &stream_id_out,
765
        envoy_dynamic_module_type_module_buffer{cluster.data(), cluster.size()},
766
        const_cast<envoy_dynamic_module_type_module_http_header*>(
767
            reinterpret_cast<const envoy_dynamic_module_type_module_http_header*>(headers.data())),
768
        headers.size(), envoy_dynamic_module_type_module_buffer{body.data(), body.size()},
769
        end_of_stream, timeout_ms);
770

            
771
    if (result == envoy_dynamic_module_type_http_callout_init_result_Success) {
772
      stream_callbacks_[stream_id_out] = &cb;
773
    }
774
    return {static_cast<HttpCalloutInitResult>(result), stream_id_out};
775
  }
776

            
777
  bool sendHttpStreamData(uint64_t stream_id, std::string_view body, bool end_of_stream) override {
778
    return envoy_dynamic_module_callback_http_filter_config_stream_send_data(
779
        host_config_ptr_, stream_id,
780
        envoy_dynamic_module_type_module_buffer{body.data(), body.size()}, end_of_stream);
781
  }
782

            
783
  bool sendHttpStreamTrailers(uint64_t stream_id, std::span<const HeaderView> trailers) override {
784
    return envoy_dynamic_module_callback_http_filter_config_stream_send_trailers(
785
        host_config_ptr_, stream_id,
786
        const_cast<envoy_dynamic_module_type_module_http_header*>(
787
            reinterpret_cast<const envoy_dynamic_module_type_module_http_header*>(trailers.data())),
788
        trailers.size());
789
  }
790

            
791
  void resetHttpStream(uint64_t stream_id) override {
792
    envoy_dynamic_module_callback_http_filter_config_reset_http_stream(host_config_ptr_, stream_id);
793
  }
794

            
795
  std::shared_ptr<Scheduler> getScheduler() override {
796
    if (!scheduler_) {
797
      scheduler_ = std::make_shared<ConfigSchedulerImpl>(host_config_ptr_);
798
    }
799
    return scheduler_;
800
  }
801

            
802
  // Use map because we expect the number of concurrent callouts/streams to be
803
  // very small.
804
  std::map<uint64_t, HttpCalloutCallback*> callout_callbacks_;
805
  std::map<uint64_t, HttpStreamCallback*> stream_callbacks_;
806
  std::shared_ptr<ConfigSchedulerImpl> scheduler_;
807

            
808
private:
809
  void* host_config_ptr_;
810
};
811

            
812
class DummyLoggerHandle {
813
public:
814
  bool logEnabled(LogLevel level) {
815
    return envoy_dynamic_module_callback_log_enabled(
816
        static_cast<envoy_dynamic_module_type_log_level>(level));
817
  }
818
  void log(LogLevel level, std::string_view message) {
819
    return envoy_dynamic_module_callback_log(
820
        static_cast<envoy_dynamic_module_type_log_level>(level),
821
        envoy_dynamic_module_type_module_buffer{message.data(), message.size()});
822
  }
823
};
824

            
825
DummyLoggerHandle& dummyLoggerHandle() {
826
  static auto handle = new DummyLoggerHandle();
827
  return *handle;
828
}
829

            
830
template <class T> T* unwrapPointer(const void* ptr) {
831
  return const_cast<T*>(reinterpret_cast<const T*>(ptr));
832
}
833

            
834
template <class T> void* wrapPointer(const T* ptr) {
835
  return reinterpret_cast<void*>(const_cast<T*>(ptr));
836
}
837

            
838
struct HttpFilterFactoryWrapper {
839
  std::unique_ptr<HttpFilterConfigHandleImpl> config_handle_;
840
  std::unique_ptr<HttpFilterFactory> factory_;
841
};
842

            
843
// Extern C exports
844
extern "C" {
845

            
846
envoy_dynamic_module_type_abi_version_module_ptr envoy_dynamic_module_on_program_init(void) {
847
  return envoy_dynamic_modules_abi_version;
848
}
849

            
850
envoy_dynamic_module_type_http_filter_config_module_ptr
851
envoy_dynamic_module_on_http_filter_config_new(
852
    envoy_dynamic_module_type_http_filter_config_envoy_ptr filter_config_envoy_ptr,
853
    envoy_dynamic_module_type_envoy_buffer name, envoy_dynamic_module_type_envoy_buffer config) {
854
  auto config_handle = std::make_unique<HttpFilterConfigHandleImpl>(filter_config_envoy_ptr);
855
  std::string_view name_view(name.ptr, name.length);
856
  std::string_view config_view(config.ptr, config.length);
857

            
858
  auto config_factory = HttpFilterConfigFactoryRegistry::getRegistry().find(name_view);
859
  if (config_factory == HttpFilterConfigFactoryRegistry::getRegistry().end()) {
860
    DYM_LOG((*config_handle), LogLevel::Warn, "Plugin config factory not found for name: {}",
861
            name_view);
862
    return nullptr;
863
  }
864

            
865
  auto plugin_factory = config_factory->second->create(*config_handle, config_view);
866
  if (!plugin_factory) {
867
    DYM_LOG((*config_handle), LogLevel::Warn, "Failed to create plugin factory for name: {}",
868
            name_view);
869
    return nullptr;
870
  }
871

            
872
  auto factory = std::make_unique<HttpFilterFactoryWrapper>();
873
  factory->config_handle_ = std::move(config_handle);
874
  factory->factory_ = std::move(plugin_factory);
875

            
876
  return wrapPointer(factory.release());
877
}
878

            
879
void envoy_dynamic_module_on_http_filter_config_destroy(
880
    envoy_dynamic_module_type_http_filter_config_module_ptr filter_config_ptr) {
881
  auto* factory_wrapper = unwrapPointer<HttpFilterFactoryWrapper>(filter_config_ptr);
882
  delete factory_wrapper;
883
}
884

            
885
envoy_dynamic_module_type_http_filter_per_route_config_module_ptr
886
envoy_dynamic_module_on_http_filter_per_route_config_new(
887
    envoy_dynamic_module_type_envoy_buffer name, envoy_dynamic_module_type_envoy_buffer config) {
888
  std::string_view name_view(name.ptr, name.length);
889
  std::string_view config_view(config.ptr, config.length);
890

            
891
  auto config_factory = HttpFilterConfigFactoryRegistry::getRegistry().find(name_view);
892
  if (config_factory == HttpFilterConfigFactoryRegistry::getRegistry().end()) {
893
    DYM_LOG(dummyLoggerHandle(), LogLevel::Warn,
894
            "Plugin per-route config factory not found for name: {}", name_view);
895
    return nullptr;
896
  }
897

            
898
  auto parsed_config = config_factory->second->createPerRoute(config_view);
899
  if (!parsed_config) {
900
    DYM_LOG(dummyLoggerHandle(), LogLevel::Warn,
901
            "Failed to create plugin per-route config for name: {}", name_view);
902
    return nullptr;
903
  }
904

            
905
  return wrapPointer(parsed_config.release());
906
}
907

            
908
void envoy_dynamic_module_on_http_filter_per_route_config_destroy(
909
    envoy_dynamic_module_type_http_filter_per_route_config_module_ptr filter_config_ptr) {
910
  auto* config = unwrapPointer<RouteSpecificConfig>(filter_config_ptr);
911
  delete config;
912
}
913

            
914
envoy_dynamic_module_type_http_filter_module_ptr envoy_dynamic_module_on_http_filter_new(
915
    envoy_dynamic_module_type_http_filter_config_module_ptr filter_config_ptr,
916
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr) {
917
  auto* factory_wrapper = unwrapPointer<HttpFilterFactoryWrapper>(filter_config_ptr);
918
  if (!factory_wrapper) {
919
    return nullptr;
920
  }
921

            
922
  auto plugin_handle = std::make_unique<HttpFilterHandleImpl>(filter_envoy_ptr);
923
  auto plugin = factory_wrapper->factory_->create(*plugin_handle);
924
  if (plugin == nullptr) {
925
    DYM_LOG((*plugin_handle), LogLevel::Warn, "Failed to create plugin instance");
926
    return nullptr;
927
  }
928
  // So the plugin_ field will never be null as long as the plugin handle is alive.
929
  plugin_handle->plugin_ = std::move(plugin);
930

            
931
  return wrapPointer(plugin_handle.release());
932
}
933

            
934
void envoy_dynamic_module_on_http_filter_destroy(
935
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr) {
936
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
937
  if (plugin_handle == nullptr) {
938
    return;
939
  }
940
  plugin_handle->plugin_->onDestroy();
941
  delete plugin_handle;
942
}
943

            
944
envoy_dynamic_module_type_on_http_filter_request_headers_status
945
envoy_dynamic_module_on_http_filter_request_headers(
946
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
947
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, bool end_of_stream) {
948
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
949

            
950
  if (plugin_handle == nullptr) {
951
    return envoy_dynamic_module_type_on_http_filter_request_headers_status_Continue;
952
  }
953
  auto status =
954
      plugin_handle->plugin_->onRequestHeaders(plugin_handle->request_headers_, end_of_stream);
955

            
956
  return static_cast<envoy_dynamic_module_type_on_http_filter_request_headers_status>(status);
957
}
958

            
959
envoy_dynamic_module_type_on_http_filter_request_body_status
960
envoy_dynamic_module_on_http_filter_request_body(
961
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
962
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, bool end_of_stream) {
963
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
964
  if (plugin_handle == nullptr) {
965
    return envoy_dynamic_module_type_on_http_filter_request_body_status_Continue;
966
  }
967

            
968
  auto status =
969
      plugin_handle->plugin_->onRequestBody(plugin_handle->received_request_body_, end_of_stream);
970
  return static_cast<envoy_dynamic_module_type_on_http_filter_request_body_status>(status);
971
}
972

            
973
envoy_dynamic_module_type_on_http_filter_request_trailers_status
974
envoy_dynamic_module_on_http_filter_request_trailers(
975
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
976
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr) {
977
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
978
  if (plugin_handle == nullptr) {
979
    return envoy_dynamic_module_type_on_http_filter_request_trailers_status_Continue;
980
  }
981

            
982
  auto status = plugin_handle->plugin_->onRequestTrailers(plugin_handle->request_trailers_);
983
  return static_cast<envoy_dynamic_module_type_on_http_filter_request_trailers_status>(status);
984
}
985

            
986
envoy_dynamic_module_type_on_http_filter_response_headers_status
987
envoy_dynamic_module_on_http_filter_response_headers(
988
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
989
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, bool end_of_stream) {
990
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
991
  if (plugin_handle == nullptr || plugin_handle->local_reply_sent_) {
992
    return envoy_dynamic_module_type_on_http_filter_response_headers_status_Continue;
993
  }
994

            
995
  auto status =
996
      plugin_handle->plugin_->onResponseHeaders(plugin_handle->response_headers_, end_of_stream);
997
  return static_cast<envoy_dynamic_module_type_on_http_filter_response_headers_status>(status);
998
}
999

            
envoy_dynamic_module_type_on_http_filter_response_body_status
envoy_dynamic_module_on_http_filter_response_body(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, bool end_of_stream) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (plugin_handle == nullptr || plugin_handle->local_reply_sent_) {
    return envoy_dynamic_module_type_on_http_filter_response_body_status_Continue;
  }
  auto status =
      plugin_handle->plugin_->onResponseBody(plugin_handle->received_response_body_, end_of_stream);
  return static_cast<envoy_dynamic_module_type_on_http_filter_response_body_status>(status);
}
envoy_dynamic_module_type_on_http_filter_response_trailers_status
envoy_dynamic_module_on_http_filter_response_trailers(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (plugin_handle == nullptr || plugin_handle->local_reply_sent_) {
    return envoy_dynamic_module_type_on_http_filter_response_trailers_status_Continue;
  }
  auto status = plugin_handle->plugin_->onResponseTrailers(plugin_handle->response_trailers_);
  return static_cast<envoy_dynamic_module_type_on_http_filter_response_trailers_status>(status);
}
void envoy_dynamic_module_on_http_filter_stream_complete(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (plugin_handle == nullptr) {
    return;
  }
  plugin_handle->stream_complete_ = true;
  plugin_handle->plugin_->onStreamComplete();
}
void envoy_dynamic_module_on_http_filter_scheduled(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, uint64_t event_id) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (!plugin_handle || !plugin_handle->scheduler_ || plugin_handle->stream_complete_) {
    return;
  }
  plugin_handle->scheduler_->onScheduled(event_id);
}
void envoy_dynamic_module_on_http_filter_http_callout_done(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, uint64_t callout_id,
    envoy_dynamic_module_type_http_callout_result result,
    envoy_dynamic_module_type_envoy_http_header* headers, size_t headers_size,
    envoy_dynamic_module_type_envoy_buffer* body_chunks, size_t body_chunks_size) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (!plugin_handle || plugin_handle->stream_complete_) {
    return;
  }
  auto* typed_headers = reinterpret_cast<HeaderView*>(headers);
  auto* typed_body_chunks = reinterpret_cast<BufferView*>(body_chunks);
  auto it = plugin_handle->callout_callbacks_.find(callout_id);
  if (it != plugin_handle->callout_callbacks_.end()) {
    auto callback = it->second;
    plugin_handle->callout_callbacks_.erase(it);
    callback->onHttpCalloutDone(static_cast<HttpCalloutResult>(result),
                                {typed_headers, headers_size},
                                {typed_body_chunks, body_chunks_size});
  }
}
void envoy_dynamic_module_on_http_filter_http_stream_headers(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, uint64_t stream_id,
    envoy_dynamic_module_type_envoy_http_header* headers, size_t headers_size, bool end_stream) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (!plugin_handle || plugin_handle->stream_complete_) {
    return;
  }
  auto it = plugin_handle->stream_callbacks_.find(stream_id);
  if (it != plugin_handle->stream_callbacks_.end()) {
    auto* typed_headers = reinterpret_cast<HeaderView*>(headers);
    it->second->onHttpStreamHeaders(stream_id, {typed_headers, headers_size}, end_stream);
  }
}
void envoy_dynamic_module_on_http_filter_http_stream_data(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, uint64_t stream_id,
    const envoy_dynamic_module_type_envoy_buffer* chunks, size_t chunks_size, bool end_stream) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (!plugin_handle || plugin_handle->stream_complete_) {
    return;
  }
  auto it = plugin_handle->stream_callbacks_.find(stream_id);
  if (it != plugin_handle->stream_callbacks_.end()) {
    auto* typed_chunks =
        reinterpret_cast<BufferView*>(const_cast<envoy_dynamic_module_type_envoy_buffer*>(chunks));
    it->second->onHttpStreamData(stream_id, {typed_chunks, chunks_size}, end_stream);
  }
}
void envoy_dynamic_module_on_http_filter_http_stream_trailers(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, uint64_t stream_id,
    envoy_dynamic_module_type_envoy_http_header* trailers, size_t trailers_size) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (!plugin_handle || plugin_handle->stream_complete_) {
    return;
  }
  auto it = plugin_handle->stream_callbacks_.find(stream_id);
  if (it != plugin_handle->stream_callbacks_.end()) {
    auto* typed_trailers = reinterpret_cast<HeaderView*>(trailers);
    it->second->onHttpStreamTrailers(stream_id, {typed_trailers, trailers_size});
  }
}
void envoy_dynamic_module_on_http_filter_http_stream_complete(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, uint64_t stream_id) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (!plugin_handle || plugin_handle->stream_complete_) {
    return;
  }
  auto it = plugin_handle->stream_callbacks_.find(stream_id);
  if (it != plugin_handle->stream_callbacks_.end()) {
    auto* cb = it->second;
    plugin_handle->stream_callbacks_.erase(it);
    cb->onHttpStreamComplete(stream_id);
  }
}
void envoy_dynamic_module_on_http_filter_http_stream_reset(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, uint64_t stream_id,
    envoy_dynamic_module_type_http_stream_reset_reason reason) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (!plugin_handle || plugin_handle->stream_complete_) {
    return;
  }
  auto it = plugin_handle->stream_callbacks_.find(stream_id);
  if (it != plugin_handle->stream_callbacks_.end()) {
    auto* cb = it->second;
    plugin_handle->stream_callbacks_.erase(it);
    cb->onHttpStreamReset(stream_id, static_cast<HttpStreamResetReason>(reason));
  }
}
void envoy_dynamic_module_on_http_filter_downstream_above_write_buffer_high_watermark(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (!plugin_handle || plugin_handle->stream_complete_) {
    return;
  }
  if (plugin_handle->downstream_watermark_callbacks_) {
    plugin_handle->downstream_watermark_callbacks_->onAboveWriteBufferHighWatermark();
  }
}
void envoy_dynamic_module_on_http_filter_downstream_below_write_buffer_low_watermark(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr) {
  auto* plugin_handle = unwrapPointer<HttpFilterHandleImpl>(filter_module_ptr);
  if (!plugin_handle || plugin_handle->stream_complete_) {
    return;
  }
  if (plugin_handle->downstream_watermark_callbacks_) {
    plugin_handle->downstream_watermark_callbacks_->onBelowWriteBufferLowWatermark();
  }
}
envoy_dynamic_module_type_on_http_filter_local_reply_status
envoy_dynamic_module_on_http_filter_local_reply(
    envoy_dynamic_module_type_http_filter_envoy_ptr filter_envoy_ptr,
    envoy_dynamic_module_type_http_filter_module_ptr filter_module_ptr, uint32_t response_code,
    envoy_dynamic_module_type_envoy_buffer details, bool reset_imminent) {
  return envoy_dynamic_module_type_on_http_filter_local_reply_status_Continue;
}
void envoy_dynamic_module_on_http_filter_config_http_callout_done(
    envoy_dynamic_module_type_http_filter_config_envoy_ptr filter_config_envoy_ptr,
    envoy_dynamic_module_type_http_filter_config_module_ptr filter_config_ptr, uint64_t callout_id,
    envoy_dynamic_module_type_http_callout_result result,
    envoy_dynamic_module_type_envoy_http_header* headers, size_t headers_size,
    envoy_dynamic_module_type_envoy_buffer* body_chunks, size_t body_chunks_size) {
  auto* factory_wrapper = unwrapPointer<HttpFilterFactoryWrapper>(filter_config_ptr);
  if (!factory_wrapper) {
    return;
  }
  auto* config_handle =
      static_cast<HttpFilterConfigHandleImpl*>(factory_wrapper->config_handle_.get());
  if (!config_handle) {
    return;
  }
  auto* typed_headers = reinterpret_cast<HeaderView*>(headers);
  auto* typed_body_chunks = reinterpret_cast<BufferView*>(body_chunks);
  auto it = config_handle->callout_callbacks_.find(callout_id);
  if (it != config_handle->callout_callbacks_.end()) {
    auto* cb = it->second;
    config_handle->callout_callbacks_.erase(it);
    cb->onHttpCalloutDone(static_cast<HttpCalloutResult>(result), {typed_headers, headers_size},
                          {typed_body_chunks, body_chunks_size});
  }
}
void envoy_dynamic_module_on_http_filter_config_http_stream_headers(
    envoy_dynamic_module_type_http_filter_config_envoy_ptr filter_config_envoy_ptr,
    envoy_dynamic_module_type_http_filter_config_module_ptr filter_config_ptr, uint64_t stream_id,
    envoy_dynamic_module_type_envoy_http_header* headers, size_t headers_size, bool end_stream) {
  auto* factory_wrapper = unwrapPointer<HttpFilterFactoryWrapper>(filter_config_ptr);
  if (!factory_wrapper) {
    return;
  }
  auto* config_handle =
      static_cast<HttpFilterConfigHandleImpl*>(factory_wrapper->config_handle_.get());
  if (!config_handle) {
    return;
  }
  auto it = config_handle->stream_callbacks_.find(stream_id);
  if (it != config_handle->stream_callbacks_.end()) {
    auto* typed_headers = reinterpret_cast<HeaderView*>(headers);
    it->second->onHttpStreamHeaders(stream_id, {typed_headers, headers_size}, end_stream);
  }
}
void envoy_dynamic_module_on_http_filter_config_http_stream_data(
    envoy_dynamic_module_type_http_filter_config_envoy_ptr filter_config_envoy_ptr,
    envoy_dynamic_module_type_http_filter_config_module_ptr filter_config_ptr, uint64_t stream_id,
    const envoy_dynamic_module_type_envoy_buffer* chunks, size_t chunks_size, bool end_stream) {
  auto* factory_wrapper = unwrapPointer<HttpFilterFactoryWrapper>(filter_config_ptr);
  if (!factory_wrapper) {
    return;
  }
  auto* config_handle =
      static_cast<HttpFilterConfigHandleImpl*>(factory_wrapper->config_handle_.get());
  if (!config_handle) {
    return;
  }
  auto it = config_handle->stream_callbacks_.find(stream_id);
  if (it != config_handle->stream_callbacks_.end()) {
    auto* typed_chunks =
        reinterpret_cast<BufferView*>(const_cast<envoy_dynamic_module_type_envoy_buffer*>(chunks));
    it->second->onHttpStreamData(stream_id, {typed_chunks, chunks_size}, end_stream);
  }
}
void envoy_dynamic_module_on_http_filter_config_http_stream_trailers(
    envoy_dynamic_module_type_http_filter_config_envoy_ptr filter_config_envoy_ptr,
    envoy_dynamic_module_type_http_filter_config_module_ptr filter_config_ptr, uint64_t stream_id,
    envoy_dynamic_module_type_envoy_http_header* trailers, size_t trailers_size) {
  auto* factory_wrapper = unwrapPointer<HttpFilterFactoryWrapper>(filter_config_ptr);
  if (!factory_wrapper) {
    return;
  }
  auto* config_handle =
      static_cast<HttpFilterConfigHandleImpl*>(factory_wrapper->config_handle_.get());
  if (!config_handle) {
    return;
  }
  auto it = config_handle->stream_callbacks_.find(stream_id);
  if (it != config_handle->stream_callbacks_.end()) {
    auto* typed_trailers = reinterpret_cast<HeaderView*>(trailers);
    it->second->onHttpStreamTrailers(stream_id, {typed_trailers, trailers_size});
  }
}
void envoy_dynamic_module_on_http_filter_config_http_stream_complete(
    envoy_dynamic_module_type_http_filter_config_envoy_ptr filter_config_envoy_ptr,
    envoy_dynamic_module_type_http_filter_config_module_ptr filter_config_ptr, uint64_t stream_id) {
  auto* factory_wrapper = unwrapPointer<HttpFilterFactoryWrapper>(filter_config_ptr);
  if (!factory_wrapper) {
    return;
  }
  auto* config_handle =
      static_cast<HttpFilterConfigHandleImpl*>(factory_wrapper->config_handle_.get());
  if (!config_handle) {
    return;
  }
  auto it = config_handle->stream_callbacks_.find(stream_id);
  if (it != config_handle->stream_callbacks_.end()) {
    auto* cb = it->second;
    config_handle->stream_callbacks_.erase(it);
    cb->onHttpStreamComplete(stream_id);
  }
}
void envoy_dynamic_module_on_http_filter_config_http_stream_reset(
    envoy_dynamic_module_type_http_filter_config_envoy_ptr filter_config_envoy_ptr,
    envoy_dynamic_module_type_http_filter_config_module_ptr filter_config_ptr, uint64_t stream_id,
    envoy_dynamic_module_type_http_stream_reset_reason reason) {
  auto* factory_wrapper = unwrapPointer<HttpFilterFactoryWrapper>(filter_config_ptr);
  if (!factory_wrapper) {
    return;
  }
  auto* config_handle =
      static_cast<HttpFilterConfigHandleImpl*>(factory_wrapper->config_handle_.get());
  if (!config_handle) {
    return;
  }
  auto it = config_handle->stream_callbacks_.find(stream_id);
  if (it != config_handle->stream_callbacks_.end()) {
    auto* cb = it->second;
    config_handle->stream_callbacks_.erase(it);
    cb->onHttpStreamReset(stream_id, static_cast<HttpStreamResetReason>(reason));
  }
}
void envoy_dynamic_module_on_http_filter_config_scheduled(
    envoy_dynamic_module_type_http_filter_config_envoy_ptr,
    envoy_dynamic_module_type_http_filter_config_module_ptr filter_config_ptr, uint64_t event_id) {
  auto* factory_wrapper = unwrapPointer<HttpFilterFactoryWrapper>(filter_config_ptr);
  if (factory_wrapper == nullptr || factory_wrapper->config_handle_ == nullptr ||
      factory_wrapper->config_handle_->scheduler_ == nullptr) {
    return;
  }
  factory_wrapper->config_handle_->scheduler_->onScheduled(event_id);
}
}
} // namespace DynamicModules
} // namespace Envoy