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

            
3
#include "source/common/common/assert.h"
4

            
5
#include "absl/container/fixed_array.h"
6

            
7
namespace Envoy {
8
namespace Http {
9
namespace Http2 {
10

            
11
class BufferMetadataSource : public http2::adapter::MetadataSource {
12
public:
13
  explicit BufferMetadataSource(Buffer::OwnedImpl payload)
14
4068
      : payload_(std::move(payload)), original_payload_length_(payload_.length()) {}
15

            
16
3100
  size_t NumFrames(size_t max_frame_size) const override {
17
    // Rounds up, so a trailing partial frame is counted.
18
3100
    return (original_payload_length_ + max_frame_size - 1) / max_frame_size;
19
3100
  }
20

            
21
9643
  std::pair<int64_t, bool> Pack(uint8_t* dest, size_t dest_len) override {
22
9643
    const size_t to_copy = std::min(dest_len, static_cast<size_t>(payload_.length()));
23
9643
    payload_.copyOut(0, to_copy, dest);
24
9643
    payload_.drain(to_copy);
25
9643
    return std::make_pair(static_cast<int64_t>(to_copy), payload_.length() == 0);
26
9643
  }
27

            
28
  void OnFailure() override {}
29

            
30
private:
31
  Buffer::OwnedImpl payload_;
32
  const size_t original_payload_length_;
33
};
34

            
35
264
NewMetadataEncoder::NewMetadataEncoder() {
36
4688
  deflater_.SetIndexingPolicy([](absl::string_view, absl::string_view) { return false; });
37
264
}
38

            
39
std::vector<std::unique_ptr<http2::adapter::MetadataSource>>
40
3957
NewMetadataEncoder::createSources(const MetadataMapVector& metadata_map_vector) {
41
3957
  MetadataSourceVector v;
42
3957
  v.reserve(metadata_map_vector.size());
43
4068
  for (const auto& metadata_map : metadata_map_vector) {
44
4068
    v.push_back(createSource(*metadata_map));
45
4068
  }
46
3957
  return v;
47
3957
}
48

            
49
std::unique_ptr<http2::adapter::MetadataSource>
50
4068
NewMetadataEncoder::createSource(const MetadataMap& metadata_map) {
51
4068
  static const size_t kMaxEncodingChunkSize = 64 * 1024;
52
4068
  spdy::HpackEncoder::Representations r;
53
4068
  r.reserve(metadata_map.size());
54
4688
  for (const auto& header : metadata_map) {
55
4688
    r.push_back({header.first, header.second});
56
4688
  }
57
4068
  ASSERT(r.size() == metadata_map.size());
58
4068
  Buffer::OwnedImpl payload;
59
4068
  auto progressive_encoder = deflater_.EncodeRepresentations(r);
60
8146
  while (progressive_encoder->HasNext()) {
61
4078
    payload.add(progressive_encoder->Next(kMaxEncodingChunkSize));
62
4078
  }
63
4068
  return std::make_unique<BufferMetadataSource>(std::move(payload));
64
4068
}
65

            
66
} // namespace Http2
67
} // namespace Http
68
} // namespace Envoy