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[]) {
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 << "examples:" << std::endl;
std::cout << " $ file_downloader http://httpbin.org/image/jpeg D:/test.jpg"
<< std::endl;
std::cout << " $ file_downloader https://www.google.com/favicon.ico"
<< " D:/test.ico" << std::endl;
std::cout << "Examples:" << std::endl;
std::cout
<< " $ ./file_downloader http://httpbin.org/image/jpeg ~/test.jpg"
<< std::endl;
std::cout << " $ ./file_downloader https://www.google.com/favicon.ico"
<< " ~/test.ico" << std::endl;
return 1;
}

@ -11,14 +11,19 @@ namespace bfs = boost::filesystem;
int main(int argc, char* argv[]) {
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 << "default url: http://httpbin.org/post" << std::endl;
std::cout << "Default url: http://httpbin.org/post" << std::endl;
std::cout << std::endl;
std::cout << "examples:" << std::endl;
std::cout << " $ form_client E:/github/webcc/data/upload" << std::endl;
std::cout << " $ form_client E:/github/webcc/data/upload "
std::cout << "Examples:" << std::endl;
std::cout << "(Post to httpbin.org)" << std::endl;
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;
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;
}
@ -41,10 +46,10 @@ int main(int argc, char* argv[]) {
webcc::ClientSession session;
try {
auto r = session.Send(webcc::RequestBuilder{}.Post(url).
FormFile("file", upload_dir / "remember.txt").
FormData("json", "{}", "application/json")
());
auto r = session.Send(webcc::RequestBuilder{}
.Post(url)
.FormFile("file", upload_dir / "remember.txt")
.FormData("json", "{}", "application/json")());
std::cout << r->status() << std::endl;

@ -1,5 +1,6 @@
// A server handling multipart form data.
#include <fstream>
#include <iostream>
#include <string>
@ -25,7 +26,13 @@ private:
for (auto& part : request->form_parts()) {
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")();
@ -36,7 +43,7 @@ private:
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cout << "usage: file_upload_server <port>" << std::endl;
std::cout << "usage: form_server <port>" << std::endl;
return 1;
}

@ -130,6 +130,7 @@ protected:
bool ParseHeaderLine(const std::string& line);
// Parse the given length of data.
virtual bool ParseContent(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) {
if (chunked_) {
return ParseChunkedContent(data, length);
if (content_type_.multipart()) {
return ParseMultipartContent(data, length);
} else {
if (content_type_.multipart()) {
return ParseMultipartContent(data, length);
} 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 count = 0;
bool ended = false;
// 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;
}
LOG_INFO("Next boundary found.");
// Next boundary found.
// This part has ended.
if (off > 2) {
@ -269,7 +270,7 @@ bool RequestParser::IsBoundary(const std::string& str, std::size_t off,
*end = true;
}
}
return strncmp(boundary.c_str(), &str[off + 2], boundary.size()) == 0;
}

@ -26,8 +26,6 @@ private:
// asks for data streaming.
bool OnHeadersEnd() override;
bool Stream() const;
bool ParseStartLine(const std::string& line) override;
// 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.
ViewMatcher view_matcher_;
// Form data parsing step.
// Form data parsing steps.
enum Step {
kStart,
kBoundaryParsed,
kHeadersParsed,
kEnded,
};
Step step_ = kStart;
// The current form part being parsed.

Loading…
Cancel
Save