diff --git a/examples/file_downloader.cc b/examples/file_downloader.cc index d6ab77a..26e91ba 100644 --- a/examples/file_downloader.cc +++ b/examples/file_downloader.cc @@ -8,13 +8,14 @@ int main(int argc, char* argv[]) { if (argc != 3) { - std::cout << "usage: file_downloader " << std::endl; + std::cout << "Usage: file_downloader " << 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; } diff --git a/examples/form_client.cc b/examples/form_client.cc index d76b8cd..412b5c2 100644 --- a/examples/form_client.cc +++ b/examples/form_client.cc @@ -11,14 +11,19 @@ namespace bfs = boost::filesystem; int main(int argc, char* argv[]) { if (argc < 2) { - std::cout << "usage: form_client [url]" << std::endl; + std::cout << "Usage: form_client [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; diff --git a/examples/form_server.cc b/examples/form_server.cc index e484be7..6f646df 100644 --- a/examples/form_server.cc +++ b/examples/form_server.cc @@ -1,5 +1,6 @@ // A server handling multipart form data. +#include #include #include @@ -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 " << std::endl; + std::cout << "usage: form_server " << std::endl; return 1; } diff --git a/webcc/parser.h b/webcc/parser.h index 9e87b14..973065e 100644 --- a/webcc/parser.h +++ b/webcc/parser.h @@ -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); diff --git a/webcc/request_parser.cc b/webcc/request_parser.cc index 28fbcf7..0585b98 100644 --- a/webcc/request_parser.cc +++ b/webcc/request_parser.cc @@ -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; } diff --git a/webcc/request_parser.h b/webcc/request_parser.h index e61e630..603366f 100644 --- a/webcc/request_parser.h +++ b/webcc/request_parser.h @@ -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.