Improve multipart content reader interface

This commit is contained in:
yhirose 2019-12-02 07:11:12 -05:00
parent d910bfc303
commit 033bc35723
3 changed files with 31 additions and 29 deletions

View File

@ -121,14 +121,14 @@ svr.Post("/content_receiver",
if (req.is_multipart_form_data()) { if (req.is_multipart_form_data()) {
MultipartFiles files; MultipartFiles files;
content_reader( content_reader(
[&](const std::string &name, const MultipartFile &file) {
files.emplace(name, file);
return true;
},
[&](const std::string &name, const char *data, size_t data_length) { [&](const std::string &name, const char *data, size_t data_length) {
auto &file = files.find(name)->second; auto &file = files.find(name)->second;
file.content.append(data, data_length); file.content.append(data, data_length);
return true; return true;
},
[&](const std::string &name, const MultipartFile &file) {
files.emplace(name, file);
return true;
}); });
} else { } else {
std::string body; std::string body;

View File

@ -225,22 +225,22 @@ using MultipartFormDataItems = std::vector<MultipartFormData>;
using ContentReceiver = using ContentReceiver =
std::function<bool(const char *data, size_t data_length)>; std::function<bool(const char *data, size_t data_length)>;
using MultipartContentReceiver =
std::function<bool(const std::string& name, const char *data, size_t data_length)>;
using MultipartContentHeader = using MultipartContentHeader =
std::function<bool(const std::string &name, const MultipartFile &file)>; std::function<bool(const std::string &name, const MultipartFile &file)>;
using MultipartContentReceiver =
std::function<bool(const std::string& name, const char *data, size_t data_length)>;
class ContentReader { class ContentReader {
public: public:
using Reader = std::function<bool(ContentReceiver receiver)>; using Reader = std::function<bool(ContentReceiver receiver)>;
using MultipartReader = std::function<bool(MultipartContentReceiver receiver, MultipartContentHeader header)>; using MultipartReader = std::function<bool(MultipartContentHeader header, MultipartContentReceiver receiver)>;
ContentReader(Reader reader, MultipartReader muitlpart_reader) ContentReader(Reader reader, MultipartReader muitlpart_reader)
: reader_(reader), muitlpart_reader_(muitlpart_reader) {} : reader_(reader), muitlpart_reader_(muitlpart_reader) {}
bool operator()(MultipartContentReceiver receiver, MultipartContentHeader header) const { bool operator()(MultipartContentHeader header, MultipartContentReceiver receiver) const {
return muitlpart_reader_(receiver, header); return muitlpart_reader_(header, receiver);
} }
bool operator()(ContentReceiver receiver) const { bool operator()(ContentReceiver receiver) const {
@ -591,13 +591,13 @@ private:
bool read_content_with_content_receiver(Stream &strm, bool last_connection, bool read_content_with_content_receiver(Stream &strm, bool last_connection,
Request &req, Response &res, Request &req, Response &res,
ContentReceiver receiver, ContentReceiver receiver,
MultipartContentReceiver multipart_receiver, MultipartContentHeader multipart_header,
MultipartContentHeader multipart_header); MultipartContentReceiver multipart_receiver);
bool read_content_core(Stream &strm, bool last_connection, bool read_content_core(Stream &strm, bool last_connection,
Request &req, Response &res, Request &req, Response &res,
ContentReceiver receiver, ContentReceiver receiver,
MultipartContentReceiver multipart_receiver, MultipartContentHeader mulitpart_header,
MultipartContentHeader mulitpart_header); MultipartContentReceiver multipart_receiver);
virtual bool process_and_close_socket(socket_t sock); virtual bool process_and_close_socket(socket_t sock);
@ -2796,11 +2796,17 @@ Server::write_content_with_provider(Stream &strm, const Request &req,
inline bool Server::read_content(Stream &strm, bool last_connection, inline bool Server::read_content(Stream &strm, bool last_connection,
Request &req, Response &res) { Request &req, Response &res) {
auto ret = read_content_core(strm, last_connection, req, res, auto ret = read_content_core(strm, last_connection, req, res,
// Regular
[&](const char *buf, size_t n) { [&](const char *buf, size_t n) {
if (req.body.size() + n > req.body.max_size()) { return false; } if (req.body.size() + n > req.body.max_size()) { return false; }
req.body.append(buf, n); req.body.append(buf, n);
return true; return true;
}, },
// Multipart
[&](const std::string &name, const MultipartFile &file) {
req.files.emplace(name, file);
return true;
},
[&](const std::string &name, const char *buf, size_t n) { [&](const std::string &name, const char *buf, size_t n) {
// TODO: handle elements with a same key // TODO: handle elements with a same key
auto it = req.files.find(name); auto it = req.files.find(name);
@ -2808,10 +2814,6 @@ inline bool Server::read_content(Stream &strm, bool last_connection,
if (content.size() + n > content.max_size()) { return false; } if (content.size() + n > content.max_size()) { return false; }
content.append(buf, n); content.append(buf, n);
return true; return true;
},
[&](const std::string &name, const MultipartFile &file) {
req.files.emplace(name, file);
return true;
} }
); );
@ -2827,18 +2829,18 @@ inline bool
Server::read_content_with_content_receiver(Stream &strm, bool last_connection, Server::read_content_with_content_receiver(Stream &strm, bool last_connection,
Request &req, Response &res, Request &req, Response &res,
ContentReceiver receiver, ContentReceiver receiver,
MultipartContentReceiver multipart_receiver, MultipartContentHeader multipart_header,
MultipartContentHeader multipart_header) { MultipartContentReceiver multipart_receiver) {
return read_content_core(strm, last_connection, req, res, return read_content_core(strm, last_connection, req, res,
receiver, multipart_receiver, multipart_header); receiver, multipart_header, multipart_receiver);
} }
inline bool inline bool
Server::read_content_core(Stream &strm, bool last_connection, Server::read_content_core(Stream &strm, bool last_connection,
Request &req, Response &res, Request &req, Response &res,
ContentReceiver receiver, ContentReceiver receiver,
MultipartContentReceiver multipart_receiver, MultipartContentHeader mulitpart_header,
MultipartContentHeader mulitpart_header) { MultipartContentReceiver multipart_receiver) {
detail::MultipartFormDataParser multipart_form_data_parser; detail::MultipartFormDataParser multipart_form_data_parser;
ContentReceiver out; ContentReceiver out;
@ -3001,9 +3003,9 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm,
return read_content_with_content_receiver(strm, last_connection, req, res, return read_content_with_content_receiver(strm, last_connection, req, res,
receiver, nullptr, nullptr); receiver, nullptr, nullptr);
}, },
[&](MultipartContentReceiver receiver, MultipartContentHeader header) { [&](MultipartContentHeader header, MultipartContentReceiver receiver) {
return read_content_with_content_receiver(strm, last_connection, req, res, return read_content_with_content_receiver(strm, last_connection, req, res,
nullptr, receiver, header); nullptr, header, receiver);
} }
); );

View File

@ -761,14 +761,14 @@ protected:
if (req.is_multipart_form_data()) { if (req.is_multipart_form_data()) {
MultipartFiles files; MultipartFiles files;
content_reader( content_reader(
[&](const std::string &name, const MultipartFile &file) {
files.emplace(name, file);
return true;
},
[&](const std::string &name, const char *data, size_t data_length) { [&](const std::string &name, const char *data, size_t data_length) {
auto &file = files.find(name)->second; auto &file = files.find(name)->second;
file.content.append(data, data_length); file.content.append(data, data_length);
return true; return true;
},
[&](const std::string &name, const MultipartFile &file) {
files.emplace(name, file);
return true;
}); });
EXPECT_EQ(5u, files.size()); EXPECT_EQ(5u, files.size());