Repository navigation
Expand file tree
/
Copy pathqpack_encoder.hpp
More file actions
91 lines (89 loc) · 5 KB
/
Copy pathqpack_encoder.hpp
File metadata and controls
91 lines (89 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Appendix data from RFC 7541, Copyright (c) 2015 IETF Trust and the
// persons identified as authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#if !defined(HTTPSERVER_COMPILATION)
#error "qpack_encoder.hpp is internal to libhttpserver"
#endif
#ifndef SRC_HTTPSERVER_DETAIL_QPACK_ENCODER_HPP_
#define SRC_HTTPSERVER_DETAIL_QPACK_ENCODER_HPP_
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <new>
#include <optional>
#include <span>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <httpserver/detail/qpack_field_section.hpp>
#include <httpserver/detail/qpack_dynamic_table.hpp>
namespace httpserver::detail {
struct qpack_dynamic_bytes_result {
qpack_status status;
std::string value;
std::size_t consumed = 0;
qpack_reference_hold references;
std::uint64_t required_insert_count = 0;
};
class qpack_encoder {
public:
qpack_bytes_result encode(std::span<const qpack_field_view> fields, qpack_section_limits limits, bool huffman = false) const;
qpack_bytes_result encode_section(std::span<const qpack_field> fields, qpack_section_limits limits, bool huffman = false) const;
// Semantic fields do not retain sensitivity; policy must be explicit.
qpack_bytes_result encode_fields(const http::fields& fields, bool never_indexed, qpack_section_limits limits, bool huffman = false) const;
qpack_dynamic_bytes_result encode_dynamic(std::span<const qpack_field_view> fields, qpack_dynamic_table& table,
std::uint64_t base, qpack_section_limits limits, bool huffman = false,
std::optional<std::uint64_t> peer_maximum_capacity = std::nullopt) const;
private:
static std::optional<std::uint64_t> dynamic_reference(qpack_field_view field, const qpack_dynamic_table& table) noexcept;
static qpack_status write_dynamic_field(qpack_field_view field, const qpack_dynamic_table& table, std::uint64_t base,
bool huffman, std::string& wire, std::size_t limit);
template<typename View>
static qpack_bytes_result encode_sequence(std::size_t count, View view, qpack_section_limits limits, bool huffman) {
if (count > limits.max_fields || limits.max_compressed_bytes < 2) return {{qpack_state::limit_exceeded}, {}};
auto remaining = limits.max_expanded_bytes;
for (std::size_t i = 0; i < count; ++i) {
const auto field = view(i);
if (!qpack_admit_field(field.name.size(), field.value.size(), remaining)) return {{qpack_state::limit_exceeded}, {}};
}
try {
// Required Insert Count=0, sign=0, Delta Base=0. Dynamic capacity is fixed at zero.
std::string wire(2, '\0');
for (std::size_t i = 0; i < count; ++i) {
const auto status = write_field(view(i), huffman, wire, limits.max_compressed_bytes);
if (!status.ok()) return {status, {}};
}
const auto size = wire.size();
return {{}, std::move(wire), size};
} catch (const std::bad_alloc&) {
return {{qpack_state::limit_exceeded}, {}};
} catch (const std::length_error&) {
return {{qpack_state::limit_exceeded}, {}};
}
}
static qpack_status append(qpack_bytes_result bytes, std::string& wire);
static qpack_status write_string(std::string_view value, bool huffman, std::string& wire, std::size_t limit,
unsigned prefix = 7, std::uint8_t flag = 0x80, std::uint8_t bits = 0);
static qpack_status write_field(qpack_field_view field, bool huffman, std::string& wire, std::size_t limit);
};
} // namespace httpserver::detail
#endif // SRC_HTTPSERVER_DETAIL_QPACK_ENCODER_HPP_