24#include <seastar/http/chunk_parsers.hh>
25#include <seastar/core/iostream.hh>
26#include <seastar/core/temporary_buffer.hh>
27#include <seastar/http/common.hh>
28#include <seastar/util/log.hh>
29#include <seastar/http/exception.hh>
43 size_t _remaining_bytes = 0;
46 : _inp(inp), _remaining_bytes(length) {
50 if (_remaining_bytes == 0) {
51 return make_ready_future<temporary_buffer<char>>();
54 _remaining_bytes -= tmp_buf.
size();
60 uint64_t
skip_bytes = std::min(n, _remaining_bytes);
68 return make_ready_future<>();
78 enum class parsing_state
84 http_chunk_size_and_ext_parser _size_and_ext_parser;
85 http_chunk_trailer_parser _trailer_parser;
88 size_t _current_chunk_bytes_read = 0;
89 size_t _current_chunk_length;
90 parsing_state _ps = parsing_state::size_and_ext;
91 bool _end_of_request =
false;
93 std::unordered_map<sstring, sstring>& _chunk_extensions;
94 std::unordered_map<sstring, sstring>& _trailing_headers;
97 chunk_parser(std::unordered_map<sstring, sstring>& chunk_extensions, std::unordered_map<sstring, sstring>& trailing_headers)
98 : _chunk_extensions(chunk_extensions), _trailing_headers(trailing_headers) {
99 _size_and_ext_parser.init();
102 _current_chunk_bytes_read += _buf.
size();
103 return std::move(_buf);
107 if (_buf.
size() || _end_of_request || data.
empty()) {
110 return make_ready_future<consumption_result_type>(
stop_consuming(std::move(data)));
114 case parsing_state::size_and_ext:
116 if (res.has_value()) {
117 if (_size_and_ext_parser.failed()) {
118 return make_exception_future<consumption_result_type>(bad_request_exception(
"Can't parse chunk size and extensions"));
121 auto parsed_extensions = _size_and_ext_parser.get_parsed_extensions();
122 _chunk_extensions.merge(parsed_extensions);
123 for (
auto& key_val : parsed_extensions) {
124 _chunk_extensions[key_val.first] += sstring(
",") + key_val.second;
128 auto size_string = _size_and_ext_parser.get_size();
129 if (size_string.size() > 16) {
130 return make_exception_future<consumption_result_type>(
bad_chunk_exception(
"Chunk length too big"));
132 _current_chunk_bytes_read = 0;
133 _current_chunk_length = strtol(size_string.c_str(),
nullptr, 16);
135 if (_current_chunk_length == 0) {
136 _ps = parsing_state::trailer_part;
137 _trailer_parser.init();
139 _ps = parsing_state::body;
144 return this->operator()(std::move(res.value()));
149 case parsing_state::body:
151 if (_current_chunk_bytes_read < _current_chunk_length) {
152 size_t to_read = std::min(_current_chunk_length - _current_chunk_bytes_read, data.
size());
154 _buf = data.
share(0, to_read);
157 return make_ready_future<consumption_result_type>(
stop_consuming(std::move(data)));
161 if (_current_chunk_bytes_read == _current_chunk_length) {
163 if (data.
get()[0] !=
'\r') {
164 return make_exception_future<consumption_result_type>(
bad_chunk_exception(
"The actual chunk length exceeds the specified length"));
166 _current_chunk_bytes_read++;
173 if (_current_chunk_bytes_read == _current_chunk_length + 1) {
175 if (data.
get()[0] !=
'\n') {
176 return make_exception_future<consumption_result_type>(
bad_chunk_exception(
"The actual chunk length exceeds the specified length"));
178 _ps = parsing_state::size_and_ext;
179 _size_and_ext_parser.init();
186 return this->operator()(std::move(data));
187 case parsing_state::trailer_part:
189 if (res.has_value()) {
190 if (_trailer_parser.failed()) {
191 return make_exception_future<consumption_result_type>(bad_request_exception(
"Can't parse chunked request trailer"));
194 _trailing_headers = _trailer_parser.get_parsed_headers();
195 _end_of_request =
true;
196 return make_ready_future<consumption_result_type>(
stop_consuming(std::move(*res)));
202 __builtin_unreachable();
209 chunked_source_impl(
input_stream<char>& inp, std::unordered_map<sstring, sstring>& chunk_extensions, std::unordered_map<sstring, sstring>& trailing_headers)
210 : _inp(inp), _chunk(chunk_extensions, trailing_headers) {
214 return _inp.consume(_chunk).
then([
this] ()
mutable {
219 virtual future<> close()
override {
220 return make_ready_future<>();
Definition: iostream.hh:237
Definition: iostream.hh:61
A representation of a possibly not-yet-computed value.
Definition: future.hh:1240
Result then(Func &&func) noexcept
Schedule a block of code to run when the future is ready.
Definition: future.hh:1425
Definition: exception.hh:110
Definition: content_source.hh:76
Definition: content_source.hh:41
Definition: iostream.hh:228
Definition: iostream.hh:217
bool empty() const noexcept
Checks whether the buffer is empty.
Definition: temporary_buffer.hh:152
temporary_buffer share()
Definition: temporary_buffer.hh:160
void trim_front(size_t pos) noexcept
Definition: temporary_buffer.hh:186
size_t size() const noexcept
Gets the buffer size.
Definition: temporary_buffer.hh:130
const CharType * get() const noexcept
Gets a pointer to the beginning of the buffer.
Definition: temporary_buffer.hh:125
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
Definition: iostream.hh:214