yalantinglibs/include/ylt/standalone/cinatra/multipart.hpp

118 lines
3.1 KiB
C++

#pragma once
#include "define.h"
namespace cinatra {
template <typename T>
class multipart_reader_t {
public:
multipart_reader_t(T *conn)
: conn_(conn),
head_buf_(conn_->head_buf_),
chunked_buf_(conn_->chunked_buf_) {}
async_simple::coro::Lazy<part_head_t> read_part_head() {
if (head_buf_.size() > 0) {
const char *data_ptr = asio::buffer_cast<const char *>(head_buf_.data());
chunked_buf_.sputn(data_ptr, head_buf_.size());
head_buf_.consume(head_buf_.size());
}
part_head_t result{};
std::error_code ec{};
size_t last_size = chunked_buf_.size();
size_t size;
auto get_part_name = [](std::string_view data, std::string_view name,
size_t start) {
start += name.length();
size_t end = data.find("\"", start);
return data.substr(start, end - start);
};
constexpr std::string_view name = "name=\"";
constexpr std::string_view filename = "filename=\"";
while (true) {
if (std::tie(ec, size) =
co_await conn_->async_read_until(chunked_buf_, CRCF);
ec) {
result.ec = ec;
conn_->close();
co_return result;
}
const char *data_ptr =
asio::buffer_cast<const char *>(chunked_buf_.data());
chunked_buf_.consume(size);
if (*data_ptr == '-') {
continue;
}
std::string_view data{data_ptr, size};
if (size == 2) { // got the head end: \r\n\r\n
break;
}
if (size_t pos = data.find("name"); pos != std::string_view::npos) {
result.name = get_part_name(data, name, pos);
if (size_t pos = data.find("filename"); pos != std::string_view::npos) {
result.filename = get_part_name(data, filename, pos);
}
continue;
}
}
co_return result;
}
async_simple::coro::Lazy<chunked_result> read_part_body(
std::string_view boundary) {
chunked_result result{};
std::error_code ec{};
size_t size = 0;
if (std::tie(ec, size) =
co_await conn_->async_read_until(chunked_buf_, boundary);
ec) {
result.ec = ec;
conn_->close();
co_return result;
}
const char *data_ptr = asio::buffer_cast<const char *>(chunked_buf_.data());
chunked_buf_.consume(size);
result.data = std::string_view{
data_ptr, size - boundary.size() - 4}; //-- boundary \r\n
if (std::tie(ec, size) =
co_await conn_->async_read_until(chunked_buf_, CRCF);
ec) {
result = {};
result.ec = ec;
conn_->close();
co_return result;
}
data_ptr = asio::buffer_cast<const char *>(chunked_buf_.data());
std::string data{data_ptr, size};
if (size > 2) {
constexpr std::string_view complete_flag = "--\r\n";
if (data == complete_flag) {
result.eof = true;
}
}
chunked_buf_.consume(size);
co_return result;
}
private:
T *conn_;
asio::streambuf &head_buf_;
asio::streambuf &chunked_buf_;
};
template <typename T>
multipart_reader_t(T *con) -> multipart_reader_t<T>;
} // namespace cinatra