improve the parsing of form data

master
Chunting Gu 5 years ago
parent 63abc5bbda
commit abd30ab69d

@ -8,13 +8,14 @@
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
if (argc != 3) { if (argc != 3) {
std::cout << "usage: file_downloader <url> <path>" << std::endl; std::cout << "Usage: file_downloader <url> <path>" << std::endl;
std::cout << std::endl; std::cout << std::endl;
std::cout << "examples:" << std::endl; std::cout << "Examples:" << std::endl;
std::cout << " $ file_downloader http://httpbin.org/image/jpeg D:/test.jpg" std::cout
<< " $ ./file_downloader http://httpbin.org/image/jpeg ~/test.jpg"
<< std::endl; << std::endl;
std::cout << " $ file_downloader https://www.google.com/favicon.ico" std::cout << " $ ./file_downloader https://www.google.com/favicon.ico"
<< " D:/test.ico" << std::endl; << " ~/test.ico" << std::endl;
return 1; return 1;
} }

@ -11,14 +11,19 @@ namespace bfs = boost::filesystem;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
if (argc < 2) { if (argc < 2) {
std::cout << "usage: form_client <upload_dir> [url]" << std::endl; std::cout << "Usage: form_client <upload_dir> [url]" << std::endl;
std::cout << std::endl; std::cout << std::endl;
std::cout << "default url: http://httpbin.org/post" << std::endl; std::cout << "Default url: http://httpbin.org/post" << std::endl;
std::cout << std::endl; std::cout << std::endl;
std::cout << "examples:" << std::endl; std::cout << "Examples:" << std::endl;
std::cout << " $ form_client E:/github/webcc/data/upload" << std::endl; std::cout << "(Post to httpbin.org)" << std::endl;
std::cout << " $ form_client E:/github/webcc/data/upload " std::cout << " $ ./form_client path/to/webcc/data/upload" << std::endl;
std::cout << " $ ./form_client path/to/webcc/data/upload "
<< "http://httpbin.org/post" << std::endl; << "http://httpbin.org/post" << std::endl;
std::cout << "(Post the example 'form_server')" << std::endl;
std::cout << " $ ./form_client path/to/webcc/data/upload "
"http://localhost:8080/upload"
<< std::endl;
return 1; return 1;
} }
@ -41,10 +46,10 @@ int main(int argc, char* argv[]) {
webcc::ClientSession session; webcc::ClientSession session;
try { try {
auto r = session.Send(webcc::RequestBuilder{}.Post(url). auto r = session.Send(webcc::RequestBuilder{}
FormFile("file", upload_dir / "remember.txt"). .Post(url)
FormData("json", "{}", "application/json") .FormFile("file", upload_dir / "remember.txt")
()); .FormData("json", "{}", "application/json")());
std::cout << r->status() << std::endl; std::cout << r->status() << std::endl;

@ -1,5 +1,6 @@
// A server handling multipart form data. // A server handling multipart form data.
#include <fstream>
#include <iostream> #include <iostream>
#include <string> #include <string>
@ -25,7 +26,13 @@ private:
for (auto& part : request->form_parts()) { for (auto& part : request->form_parts()) {
std::cout << "name: " << part->name() << std::endl; std::cout << "name: " << part->name() << std::endl;
std::cout << "data: " << std::endl << part->data() << std::endl;
if (part->file_name().empty()) {
std::cout << "data: " << part->data() << std::endl;
} else {
// Save part->data() as binary to file.
// ...
}
} }
return webcc::ResponseBuilder{}.Created().Body("OK")(); return webcc::ResponseBuilder{}.Created().Body("OK")();
@ -36,7 +43,7 @@ private:
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
if (argc < 2) { if (argc < 2) {
std::cout << "usage: file_upload_server <port>" << std::endl; std::cout << "usage: form_server <port>" << std::endl;
return 1; return 1;
} }

@ -130,6 +130,7 @@ protected:
bool ParseHeaderLine(const std::string& line); bool ParseHeaderLine(const std::string& line);
// Parse the given length of data.
virtual bool ParseContent(const char* data, std::size_t length); virtual bool ParseContent(const char* data, std::size_t length);
bool ParseFixedContent(const char* data, std::size_t length); bool ParseFixedContent(const char* data, std::size_t length);

@ -50,14 +50,10 @@ bool RequestParser::ParseStartLine(const std::string& line) {
} }
bool RequestParser::ParseContent(const char* data, std::size_t length) { bool RequestParser::ParseContent(const char* data, std::size_t length) {
if (chunked_) {
return ParseChunkedContent(data, length);
} else {
if (content_type_.multipart()) { if (content_type_.multipart()) {
return ParseMultipartContent(data, length); return ParseMultipartContent(data, length);
} else { } else {
return ParseFixedContent(data, length); return Parser::ParseContent(data, length);
}
} }
} }
@ -115,13 +111,18 @@ bool RequestParser::ParseMultipartContent(const char* data,
std::size_t off = 0; std::size_t off = 0;
std::size_t count = 0; std::size_t count = 0;
bool ended = false; bool ended = false;
// TODO: Remember last CRLF position. // TODO: Remember last CRLF position.
if (!GetNextBoundaryLine(&off, &count, &ended)) {
// Wait until next boundary. bool next_boundary_found = GetNextBoundaryLine(&off, &count, &ended);
if (!next_boundary_found) {
part_->AppendData(pending_data_);
pending_data_.clear();
break; break;
} }
LOG_INFO("Next boundary found."); // Next boundary found.
// This part has ended. // This part has ended.
if (off > 2) { if (off > 2) {

@ -26,8 +26,6 @@ private:
// asks for data streaming. // asks for data streaming.
bool OnHeadersEnd() override; bool OnHeadersEnd() override;
bool Stream() const;
bool ParseStartLine(const std::string& line) override; bool ParseStartLine(const std::string& line) override;
// Override to handle multipart form data which is request only. // Override to handle multipart form data which is request only.
@ -51,13 +49,14 @@ private:
// received. The parsing will stop and fail if no view can be matched. // received. The parsing will stop and fail if no view can be matched.
ViewMatcher view_matcher_; ViewMatcher view_matcher_;
// Form data parsing step. // Form data parsing steps.
enum Step { enum Step {
kStart, kStart,
kBoundaryParsed, kBoundaryParsed,
kHeadersParsed, kHeadersParsed,
kEnded, kEnded,
}; };
Step step_ = kStart; Step step_ = kStart;
// The current form part being parsed. // The current form part being parsed.

Loading…
Cancel
Save