tdlight/tdnet/td/net/HttpChunkedByteFlow.cpp
levlam 5cbda834bd Update copyright year.
GitOrigin-RevId: 1369d3af1195221f6ddb9462d5f8b74fb5fef20f
2018-01-02 16:45:09 +03:00

85 lines
2.3 KiB
C++

//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/net/HttpChunkedByteFlow.h"
#include "td/utils/find_boundary.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/Status.h"
#include <algorithm>
namespace td {
void HttpChunkedByteFlow::loop() {
bool was_updated = false;
size_t need_size;
while (true) {
if (state_ == ReadChunkLength) {
bool ok = find_boundary(input_->clone(), "\r\n", len_);
if (len_ > 10) {
return finish(Status::Error(PSLICE() << "Too long length in chunked "
<< input_->cut_head(len_).move_as_buffer_slice().as_slice()));
}
if (!ok) {
need_size = input_->size() + 1;
break;
}
auto s_len = input_->cut_head(len_).move_as_buffer_slice();
input_->advance(2);
len_ = hex_to_integer<size_t>(s_len.as_slice());
if (len_ > MAX_CHUNK_SIZE) {
return finish(Status::Error(PSLICE() << "Invalid chunk size " << tag("size", len_)));
}
save_len_ = len_;
state_ = ReadChunkContent;
}
auto size = input_->size();
auto ready = std::min(len_, size);
need_size = std::min(MIN_UPDATE_SIZE, len_ + 2);
if (size < need_size) {
break;
}
total_size_ += ready;
uncommited_size_ += ready;
if (total_size_ > MAX_SIZE) {
return finish(Status::Error(PSLICE() << "Too big query " << tag("size", input_->size())));
}
output_.append(input_->cut_head(ready));
len_ -= ready;
if (uncommited_size_ >= MIN_UPDATE_SIZE) {
uncommited_size_ = 0;
was_updated = true;
}
if (len_ == 0) {
if (input_->size() < 2) {
need_size = 2;
break;
}
input_->cut_head(2);
total_size_ += 2;
if (save_len_ == 0) {
return finish(Status::OK());
}
state_ = ReadChunkLength;
len_ = 0;
}
}
if (was_updated) {
on_output_updated();
}
if (!is_input_active_) {
return finish(Status::Error("Unexpected end of stream"));
}
set_need_size(need_size);
}
constexpr size_t HttpChunkedByteFlow::MIN_UPDATE_SIZE;
} // namespace td