1
#include "source/common/http/http2/metadata_decoder.h"
2

            
3
#include "source/common/common/assert.h"
4
#include "source/common/runtime/runtime_features.h"
5

            
6
#include "absl/container/fixed_array.h"
7
#include "quiche/http2/decoder/decode_buffer.h"
8
#include "quiche/http2/hpack/decoder/hpack_decoder.h"
9
#include "quiche/http2/hpack/decoder/hpack_decoder_listener.h"
10

            
11
namespace Envoy {
12
namespace Http {
13
namespace Http2 {
14
namespace {
15

            
16
class QuicheDecoderListener : public http2::HpackDecoderListener {
17
public:
18
3750
  explicit QuicheDecoderListener(MetadataMap& map) : map_(map) {}
19

            
20
  // HpackDecoderListener
21
  void OnHeaderListStart() override {}
22
4061
  void OnHeader(absl::string_view name, absl::string_view value) override {
23
4061
    map_.emplace(name, value);
24
4061
  }
25
3454
  void OnHeaderListEnd() override {}
26
3
  void OnHeaderErrorDetected(absl::string_view error_message) override {
27
3
    ENVOY_LOG_MISC(error, "Failed to decode payload: {}", error_message);
28
3
    map_.clear();
29
3
  }
30

            
31
private:
32
  MetadataMap& map_;
33
};
34

            
35
} // anonymous namespace
36

            
37
// Since QuicheDecoderListener and http2::HpackDecoder are implementation details, this struct is
38
// defined here rather than the header file.
39
struct MetadataDecoder::HpackDecoderContext {
40
  HpackDecoderContext(MetadataMap& map, size_t max_payload_size_bound)
41
3750
      : listener(map), decoder(&listener, max_payload_size_bound) {}
42
  QuicheDecoderListener listener;
43
  http2::HpackDecoder decoder;
44
};
45

            
46
MetadataDecoder::MetadataDecoder(MetadataCallback cb, uint64_t max_payload_size_bound)
47
296
    : max_payload_size_bound_(max_payload_size_bound) {
48
296
  ASSERT(cb != nullptr);
49
296
  callback_ = std::move(cb);
50

            
51
296
  resetDecoderContext();
52
296
}
53

            
54
296
MetadataDecoder::~MetadataDecoder() = default;
55

            
56
4302
bool MetadataDecoder::receiveMetadata(const uint8_t* data, size_t len) {
57
4302
  ASSERT(data != nullptr && len != 0);
58
4302
  payload_.add(data, len);
59

            
60
4302
  total_payload_size_ += len;
61
4302
  return total_payload_size_ <= max_payload_size_bound_;
62
4302
}
63

            
64
3457
bool MetadataDecoder::onMetadataFrameComplete(bool end_metadata) {
65
3457
  const bool success = decodeMetadataPayload(end_metadata);
66
3457
  if (!success) {
67
3
    return false;
68
3
  }
69

            
70
3454
  if (end_metadata) {
71
3454
    callback_(std::move(metadata_map_));
72
3454
    resetDecoderContext();
73
3454
  }
74
3454
  return true;
75
3457
}
76

            
77
3457
bool MetadataDecoder::decodeMetadataPayload(bool end_metadata) {
78
3457
  Buffer::RawSliceVector slices = payload_.getRawSlices();
79

            
80
  // Data consumed by the decoder so far.
81
3457
  ssize_t payload_size_consumed = 0;
82
4060
  for (const Buffer::RawSlice& slice : slices) {
83
4059
    http2::DecodeBuffer db(static_cast<char*>(slice.mem_), slice.len_);
84
8116
    while (db.HasData()) {
85
4059
      if (!decoder_context_->decoder.DecodeFragment(&db)) {
86
2
        ENVOY_LOG_MISC(error, "Failed to decode payload: {}",
87
2
                       http2::HpackDecodingErrorToString(decoder_context_->decoder.error()));
88
2
        return false;
89
2
      }
90
4059
    }
91
4057
    payload_size_consumed += slice.len_;
92
4057
  }
93
3455
  if (end_metadata) {
94
3455
    const bool result = decoder_context_->decoder.EndDecodingBlock();
95
3455
    if (!result) {
96
1
      ENVOY_LOG_MISC(error, "Failed to decode payload: {}",
97
1
                     http2::HpackDecodingErrorToString(decoder_context_->decoder.error()));
98
1
      return false;
99
1
    }
100
3455
  }
101
3454
  payload_.drain(payload_size_consumed);
102
3454
  return true;
103
3455
}
104

            
105
3750
void MetadataDecoder::resetDecoderContext() {
106
3750
  metadata_map_ = std::make_unique<MetadataMap>();
107
3750
  decoder_context_ = std::make_unique<HpackDecoderContext>(*metadata_map_, max_payload_size_bound_);
108
3750
}
109

            
110
} // namespace Http2
111
} // namespace Http
112
} // namespace Envoy