Skip to content

Commit

Permalink
Improve multipart content reader interface
Browse files Browse the repository at this point in the history
  • Loading branch information
yhirose committed Dec 2, 2019
1 parent d910bfc commit 033bc35
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 29 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ svr.Post("/content_receiver",
if (req.is_multipart_form_data()) {
MultipartFiles files;
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) {
auto &file = files.find(name)->second;
file.content.append(data, data_length);
return true;
},
[&](const std::string &name, const MultipartFile &file) {
files.emplace(name, file);
return true;
});
} else {
std::string body;
Expand Down
44 changes: 23 additions & 21 deletions httplib.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,22 +225,22 @@ using MultipartFormDataItems = std::vector<MultipartFormData>;
using ContentReceiver =
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 =
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 {
public:
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)
: reader_(reader), muitlpart_reader_(muitlpart_reader) {}

bool operator()(MultipartContentReceiver receiver, MultipartContentHeader header) const {
return muitlpart_reader_(receiver, header);
bool operator()(MultipartContentHeader header, MultipartContentReceiver receiver) const {
return muitlpart_reader_(header, receiver);
}

bool operator()(ContentReceiver receiver) const {
Expand Down Expand Up @@ -591,13 +591,13 @@ class Server {
bool read_content_with_content_receiver(Stream &strm, bool last_connection,
Request &req, Response &res,
ContentReceiver receiver,
MultipartContentReceiver multipart_receiver,
MultipartContentHeader multipart_header);
MultipartContentHeader multipart_header,
MultipartContentReceiver multipart_receiver);
bool read_content_core(Stream &strm, bool last_connection,
Request &req, Response &res,
ContentReceiver receiver,
MultipartContentReceiver multipart_receiver,
MultipartContentHeader mulitpart_header);
MultipartContentHeader mulitpart_header,
MultipartContentReceiver multipart_receiver);

virtual bool process_and_close_socket(socket_t sock);

Expand Down Expand Up @@ -2796,22 +2796,24 @@ Server::write_content_with_provider(Stream &strm, const Request &req,
inline bool Server::read_content(Stream &strm, bool last_connection,
Request &req, Response &res) {
auto ret = read_content_core(strm, last_connection, req, res,
// Regular
[&](const char *buf, size_t n) {
if (req.body.size() + n > req.body.max_size()) { return false; }
req.body.append(buf, n);
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) {
// TODO: handle elements with a same key
auto it = req.files.find(name);
auto &content = it->second.content;
if (content.size() + n > content.max_size()) { return false; }
content.append(buf, n);
return true;
},
[&](const std::string &name, const MultipartFile &file) {
req.files.emplace(name, file);
return true;
}
);

Expand All @@ -2827,18 +2829,18 @@ inline bool
Server::read_content_with_content_receiver(Stream &strm, bool last_connection,
Request &req, Response &res,
ContentReceiver receiver,
MultipartContentReceiver multipart_receiver,
MultipartContentHeader multipart_header) {
MultipartContentHeader multipart_header,
MultipartContentReceiver multipart_receiver) {
return read_content_core(strm, last_connection, req, res,
receiver, multipart_receiver, multipart_header);
receiver, multipart_header, multipart_receiver);
}

inline bool
Server::read_content_core(Stream &strm, bool last_connection,
Request &req, Response &res,
ContentReceiver receiver,
MultipartContentReceiver multipart_receiver,
MultipartContentHeader mulitpart_header) {
MultipartContentHeader mulitpart_header,
MultipartContentReceiver multipart_receiver) {
detail::MultipartFormDataParser multipart_form_data_parser;
ContentReceiver out;

Expand Down Expand Up @@ -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,
receiver, nullptr, nullptr);
},
[&](MultipartContentReceiver receiver, MultipartContentHeader header) {
[&](MultipartContentHeader header, MultipartContentReceiver receiver) {
return read_content_with_content_receiver(strm, last_connection, req, res,
nullptr, receiver, header);
nullptr, header, receiver);
}
);

Expand Down
8 changes: 4 additions & 4 deletions test/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -761,14 +761,14 @@ class ServerTest : public ::testing::Test {
if (req.is_multipart_form_data()) {
MultipartFiles files;
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) {
auto &file = files.find(name)->second;
file.content.append(data, data_length);
return true;
},
[&](const std::string &name, const MultipartFile &file) {
files.emplace(name, file);
return true;
});

EXPECT_EQ(5u, files.size());
Expand Down

0 comments on commit 033bc35

Please sign in to comment.