From df96f969bc183536f276a2847b2433d2f14d4945 Mon Sep 17 00:00:00 2001 From: Chunting Gu Date: Thu, 27 May 2021 11:15:08 +0800 Subject: [PATCH] add a cmake option to switch between std and boost filesystem --- CMakeLists.txt | 28 +++++++-- autotest/client_autotest/client_autotest.cc | 33 +++++------ examples/book_client/book_client.cc | 11 ++-- examples/book_client/book_client.h | 9 ++- examples/book_client/main.cc | 9 +-- examples/book_server/main.cc | 15 ++--- examples/book_server/views.cc | 20 +++---- examples/book_server/views.h | 11 ++-- examples/form_client.cc | 9 +-- examples/form_urlencoded_client.cc | 2 - webcc/body.cc | 18 +++--- webcc/body.h | 19 +++--- webcc/common.cc | 4 +- webcc/common.h | 8 +-- webcc/config.h.example | 3 + webcc/config.h.in | 3 + webcc/fs.h | 65 +++++++++++++++++++++ webcc/globals.h | 2 + webcc/logger.cc | 22 +++---- webcc/logger.h | 4 +- webcc/parser.cc | 7 +-- webcc/parser.h | 8 +-- webcc/request_builder.cc | 6 +- webcc/request_builder.h | 37 ++++++------ webcc/response_builder.cc | 4 +- webcc/response_builder.h | 6 +- webcc/response_parser.cc | 20 +++---- webcc/server.cc | 14 ++--- webcc/server.h | 7 +-- webcc/utility.cc | 12 ++-- webcc/utility.h | 6 +- 31 files changed, 227 insertions(+), 195 deletions(-) create mode 100644 webcc/fs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 620d5c8..3a1810b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,11 +25,13 @@ option(BUILD_UNITTEST "Build unit test?" OFF) option(BUILD_EXAMPLES "Build examples?" ON) option(BUILD_QT_EXAMPLES "Build Qt application examples?" OFF) -set(WEBCC_ENABLE_LOG 1 CACHE STRING "Enable logging? (1:Yes, 0:No)") -set(WEBCC_ENABLE_SSL 0 CACHE STRING "Enable SSL/HTTPS (need OpenSSL)? (1:Yes, 0:No)") -set(WEBCC_ENABLE_GZIP 0 CACHE STRING "Enable gzip compression (need Zlib)? (1:Yes, 0:No)") +set(WEBCC_ENABLE_LOG 1 CACHE STRING "Enable logging? (1:Yes, 0:No)") +set(WEBCC_ENABLE_SSL 0 CACHE STRING "Enable SSL/HTTPS (need OpenSSL)? (1:Yes, 0:No)") +set(WEBCC_ENABLE_GZIP 0 CACHE STRING "Enable gzip compression (need Zlib)? (1:Yes, 0:No)") -set(WEBCC_LOG_LEVEL 2 CACHE STRING "Log level (0:VERB, 1:INFO, 2:USER, 3:WARN or 4:ERRO)") +set(WEBCC_LOG_LEVEL 2 CACHE STRING "Log level (0:VERB, 1:INFO, 2:USER, 3:WARN or 4:ERRO)") + +set(WEBCC_USE_STD_FILESYSTEM 1 CACHE STRING "Use C++17 filesystem? (1:Yes, 0:No)") if(BUILD_UNITTEST) enable_testing() @@ -42,16 +44,30 @@ if(WIN32) endif() # C++ standard requirements. -set(CMAKE_CXX_STANDARD 11) + +if(WEBCC_USE_STD_FILESYSTEM) + set(CMAKE_CXX_STANDARD 17) +else() + set(CMAKE_CXX_STANDARD 11) +endif() + set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # Boost + +set(BOOST_COMPONENTS system date_time) + +if(NOT WEBCC_USE_STD_FILESYSTEM) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} filesystem) +endif() + set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) -find_package(Boost 1.66.0 REQUIRED COMPONENTS system date_time filesystem) +find_package(Boost 1.66.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) if(Boost_FOUND) message(STATUS "Boost version: ${Boost_VERSION}") + message(STATUS "Boost libraries: ${Boost_LIBRARIES}") include_directories(${Boost_INCLUDE_DIRS}) endif() diff --git a/autotest/client_autotest/client_autotest.cc b/autotest/client_autotest/client_autotest.cc index 923a066..dadfe83 100644 --- a/autotest/client_autotest/client_autotest.cc +++ b/autotest/client_autotest/client_autotest.cc @@ -2,18 +2,15 @@ #include #include "boost/algorithm/string.hpp" -#include "boost/filesystem/fstream.hpp" -#include "boost/filesystem/operations.hpp" #include "gtest/gtest.h" #include "json/json.h" #include "webcc/client_session.h" +#include "webcc/fs.h" #include "webcc/string.h" -namespace bfs = boost::filesystem; - // ----------------------------------------------------------------------------- // JSON helper functions (based on jsoncpp). @@ -181,15 +178,15 @@ TEST(ClientTest, Get_Jpeg_Stream) { EXPECT_TRUE(!file_body->path().empty()); // Backup the path of the temp file. - const bfs::path ori_path = file_body->path(); + const webcc::fs::path ori_path = file_body->path(); - const bfs::path new_path("./wolf.jpeg"); + const webcc::fs::path new_path("./wolf.jpeg"); bool moved = file_body->Move(new_path); EXPECT_TRUE(moved); - EXPECT_TRUE(bfs::exists(new_path)); + EXPECT_TRUE(webcc::fs::exists(new_path)); // The file in the original path should not exist any more. - EXPECT_TRUE(!bfs::exists(ori_path)); + EXPECT_TRUE(!webcc::fs::exists(ori_path)); // After move, the original path should be reset. EXPECT_TRUE(file_body->path().empty()); @@ -205,7 +202,7 @@ TEST(ClientTest, Get_Jpeg_Stream_NoMove) { webcc::ClientSession session; try { - bfs::path ori_path; + webcc::fs::path ori_path; { auto r = session.Send(webcc::RequestBuilder{}. @@ -223,7 +220,7 @@ TEST(ClientTest, Get_Jpeg_Stream_NoMove) { } // The temp file should be deleted. - EXPECT_TRUE(!bfs::exists(ori_path)); + EXPECT_TRUE(!webcc::fs::exists(ori_path)); } catch (const webcc::Error& error) { std::cerr << error << std::endl; @@ -298,22 +295,22 @@ TEST(ClientTest, Post) { } } -static bfs::path GenerateTempFile(const std::string& data) { +static webcc::fs::path GenerateTempFile(const std::string& data) { try { - bfs::path path = bfs::temp_directory_path() / webcc::RandomString(10); + webcc::fs::path path = webcc::fs::temp_directory_path() / webcc::RandomString(10); - bfs::ofstream ofs; + webcc::fs::ofstream ofs; ofs.open(path, std::ios::binary); if (ofs.fail()) { - return bfs::path{}; + return webcc::fs::path{}; } ofs << data; return path; - } catch (const bfs::filesystem_error&) { - return bfs::path{}; + } catch (const webcc::fs::filesystem_error&) { + return webcc::fs::path{}; } } @@ -344,8 +341,8 @@ TEST(ClientTest, Post_FileBody) { } // Remove the temp file. - boost::system::error_code ec; - bfs::remove(path, ec); + webcc::fs::error_code ec; + webcc::fs::remove(path, ec); } #if WEBCC_ENABLE_GZIP diff --git a/examples/book_client/book_client.cc b/examples/book_client/book_client.cc index c286235..b71caff 100644 --- a/examples/book_client/book_client.cc +++ b/examples/book_client/book_client.cc @@ -3,14 +3,11 @@ #include #include "boost/algorithm/string.hpp" -#include "boost/filesystem/operations.hpp" #include "json/json.h" #include "book_json.h" -namespace bfs = boost::filesystem; - BookClient::BookClient(const std::string& url, int timeout) : url_(url), session_(timeout) { // Default Content-Type for requests with a body. @@ -127,7 +124,7 @@ bool BookClient::Delete(const std::string& id) { } } -bool BookClient::GetPhoto(const std::string& id, const bfs::path& path) { +bool BookClient::GetPhoto(const std::string& id, const webcc::fs::path& path) { try { auto r = session_.Send(WEBCC_GET(url_). Path("books").Path(id).Path("photo")(), @@ -147,7 +144,7 @@ bool BookClient::GetPhoto(const std::string& id, const bfs::path& path) { } } -bool BookClient::SetPhoto(const std::string& id, const bfs::path& path) { +bool BookClient::SetPhoto(const std::string& id, const webcc::fs::path& path) { try { if (!CheckPhoto(path)) { return false; @@ -169,12 +166,12 @@ bool BookClient::SetPhoto(const std::string& id, const bfs::path& path) { } } -bool BookClient::CheckPhoto(const bfs::path& photo) { +bool BookClient::CheckPhoto(const webcc::fs::path& photo) { if (photo.empty()) { return false; } - if (!bfs::is_regular_file(photo) || !bfs::exists(photo)) { + if (!webcc::fs::is_regular_file(photo) || !webcc::fs::exists(photo)) { return false; } diff --git a/examples/book_client/book_client.h b/examples/book_client/book_client.h index a152839..e9fcc68 100644 --- a/examples/book_client/book_client.h +++ b/examples/book_client/book_client.h @@ -4,11 +4,10 @@ #include #include -#include "boost/filesystem/path.hpp" - #include "json/json-forwards.h" #include "webcc/client_session.h" +#include "webcc/fs.h" #include "book.h" @@ -29,13 +28,13 @@ public: bool Delete(const std::string& id); // Get photo, save to the given path. - bool GetPhoto(const std::string& id, const boost::filesystem::path& path); + bool GetPhoto(const std::string& id, const webcc::fs::path& path); // Set photo using the file of the given path. - bool SetPhoto(const std::string& id, const boost::filesystem::path& path); + bool SetPhoto(const std::string& id, const webcc::fs::path& path); private: - bool CheckPhoto(const boost::filesystem::path& photo); + bool CheckPhoto(const webcc::fs::path& photo); // Check HTTP response status. bool CheckStatus(webcc::ResponsePtr response, int expected_status); diff --git a/examples/book_client/main.cc b/examples/book_client/main.cc index 4c90aed..5d2b622 100644 --- a/examples/book_client/main.cc +++ b/examples/book_client/main.cc @@ -1,13 +1,10 @@ #include -#include "boost/filesystem/operations.hpp" - +#include "webcc/fs.h" #include "webcc/logger.h" #include "book_client.h" -namespace bfs = boost::filesystem; - // ----------------------------------------------------------------------------- void PrintSeparator() { @@ -39,8 +36,8 @@ int main(int argc, char* argv[]) { std::string url = argv[1]; - bfs::path photo_dir = argv[2]; - if (!bfs::is_directory(photo_dir) || !bfs::exists(photo_dir)) { + webcc::fs::path photo_dir = argv[2]; + if (!webcc::fs::is_directory(photo_dir) || !webcc::fs::exists(photo_dir)) { std::cerr << "Invalid photo dir!" << std::endl; return 1; } diff --git a/examples/book_server/main.cc b/examples/book_server/main.cc index 9d06dc9..fe07d0a 100644 --- a/examples/book_server/main.cc +++ b/examples/book_server/main.cc @@ -1,14 +1,11 @@ #include -#include "boost/filesystem/operations.hpp" - +#include "webcc/fs.h" #include "webcc/logger.h" #include "webcc/server.h" #include "views.h" -namespace bfs = boost::filesystem; - int main(int argc, char* argv[]) { if (argc < 3) { std::cout << "usage: book_server " << std::endl; @@ -21,16 +18,16 @@ int main(int argc, char* argv[]) { std::uint16_t port = static_cast(std::atoi(argv[1])); - bfs::path upload_dir = argv[2]; - if (!bfs::is_directory(upload_dir) || !bfs::exists(upload_dir)) { + webcc::fs::path upload_dir = argv[2]; + if (!webcc::fs::is_directory(upload_dir) || !webcc::fs::exists(upload_dir)) { std::cerr << "Invalid upload dir!" << std::endl; return 1; } // Add a sub-dir for book photos. - bfs::path photo_dir = upload_dir / "books"; - if (!bfs::exists(photo_dir)) { - bfs::create_directory(photo_dir); + webcc::fs::path photo_dir = upload_dir / "books"; + if (!webcc::fs::exists(photo_dir)) { + webcc::fs::create_directory(photo_dir); } std::cout << "Book photos will be saved to: " << photo_dir << std::endl; diff --git a/examples/book_server/views.cc b/examples/book_server/views.cc index cc59b01..7e72c32 100644 --- a/examples/book_server/views.cc +++ b/examples/book_server/views.cc @@ -1,7 +1,5 @@ #include "views.h" -#include "boost/filesystem/operations.hpp" - #include "json/json.h" #include "webcc/response_builder.h" @@ -10,8 +8,6 @@ #include "book_db.h" #include "book_json.h" -namespace bfs = boost::filesystem; - // ----------------------------------------------------------------------------- static BookDB g_book_db; @@ -57,7 +53,7 @@ webcc::ResponsePtr BookListView::Post(webcc::RequestPtr request) { // ----------------------------------------------------------------------------- -BookDetailView::BookDetailView(bfs::path photo_dir) +BookDetailView::BookDetailView(webcc::fs::path photo_dir) : photo_dir_(std::move(photo_dir)) { } @@ -125,8 +121,8 @@ webcc::ResponsePtr BookDetailView::Delete(webcc::RequestPtr request) { // Delete the photo from file system. if (!photo_name.empty()) { - boost::system::error_code ec; - bfs::remove(photo_dir_ / photo_name, ec); + webcc::fs::error_code ec; + webcc::fs::remove(photo_dir_ / photo_name, ec); } return webcc::ResponseBuilder{}.OK()(); @@ -134,7 +130,7 @@ webcc::ResponsePtr BookDetailView::Delete(webcc::RequestPtr request) { // ----------------------------------------------------------------------------- -BookPhotoView::BookPhotoView(bfs::path photo_dir) +BookPhotoView::BookPhotoView(webcc::fs::path photo_dir) : photo_dir_(std::move(photo_dir)) { } @@ -164,8 +160,8 @@ webcc::ResponsePtr BookPhotoView::Get(webcc::RequestPtr request) { return webcc::ResponseBuilder{}.NotFound()(); } - bfs::path photo_path = photo_dir_ / book.photo; - if (!bfs::exists(photo_path)) { + webcc::fs::path photo_path = photo_dir_ / book.photo; + if (!webcc::fs::exists(photo_path)) { return webcc::ResponseBuilder{}.NotFound()(); } @@ -219,8 +215,8 @@ webcc::ResponsePtr BookPhotoView::Delete(webcc::RequestPtr request) { } // Error handling is simplified. - boost::system::error_code ec; - bfs::remove(photo_dir_ / book.photo, ec); + webcc::fs::error_code ec; + webcc::fs::remove(photo_dir_ / book.photo, ec); return webcc::ResponseBuilder{}.OK()(); } diff --git a/examples/book_server/views.h b/examples/book_server/views.h index f7f81f5..78f2a40 100644 --- a/examples/book_server/views.h +++ b/examples/book_server/views.h @@ -1,8 +1,7 @@ #ifndef VIEWS_H_ #define VIEWS_H_ -#include "boost/filesystem/path.hpp" - +#include "webcc/fs.h" #include "webcc/view.h" // ----------------------------------------------------------------------------- @@ -25,7 +24,7 @@ private: // URL: /books/{id} class BookDetailView : public webcc::View { public: - explicit BookDetailView(boost::filesystem::path photo_dir); + explicit BookDetailView(webcc::fs::path photo_dir); webcc::ResponsePtr Handle(webcc::RequestPtr request) override; @@ -40,7 +39,7 @@ private: webcc::ResponsePtr Delete(webcc::RequestPtr request); private: - boost::filesystem::path photo_dir_; + webcc::fs::path photo_dir_; }; // ----------------------------------------------------------------------------- @@ -48,7 +47,7 @@ private: // URL: /books/{id}/photo class BookPhotoView : public webcc::View { public: - explicit BookPhotoView(boost::filesystem::path photo_dir); + explicit BookPhotoView(webcc::fs::path photo_dir); webcc::ResponsePtr Handle(webcc::RequestPtr request) override; @@ -68,7 +67,7 @@ private: webcc::ResponsePtr Delete(webcc::RequestPtr request); private: - boost::filesystem::path photo_dir_; + webcc::fs::path photo_dir_; }; #endif // VIEWS_H_ diff --git a/examples/form_client.cc b/examples/form_client.cc index 412b5c2..614a0c6 100644 --- a/examples/form_client.cc +++ b/examples/form_client.cc @@ -2,13 +2,10 @@ #include -#include "boost/filesystem/operations.hpp" - #include "webcc/client_session.h" +#include "webcc/fs.h" #include "webcc/logger.h" -namespace bfs = boost::filesystem; - int main(int argc, char* argv[]) { if (argc < 2) { std::cout << "Usage: form_client [url]" << std::endl; @@ -29,7 +26,7 @@ int main(int argc, char* argv[]) { WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); - const bfs::path upload_dir(argv[1]); + const webcc::fs::path upload_dir(argv[1]); std::string url; if (argc == 3) { @@ -38,7 +35,7 @@ int main(int argc, char* argv[]) { url = "http://httpbin.org/post"; } - if (!bfs::is_directory(upload_dir) || !bfs::exists(upload_dir)) { + if (!webcc::fs::is_directory(upload_dir) || !webcc::fs::exists(upload_dir)) { std::cerr << "Invalid upload dir!" << std::endl; return 1; } diff --git a/examples/form_urlencoded_client.cc b/examples/form_urlencoded_client.cc index 1edd9a1..bc095f7 100644 --- a/examples/form_urlencoded_client.cc +++ b/examples/form_urlencoded_client.cc @@ -5,8 +5,6 @@ #include "webcc/client_session.h" #include "webcc/logger.h" -namespace bfs = boost::filesystem; - int main(int argc, char* argv[]) { WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); diff --git a/webcc/body.cc b/webcc/body.cc index 8f13c6a..baca6b0 100644 --- a/webcc/body.cc +++ b/webcc/body.cc @@ -1,7 +1,5 @@ #include "webcc/body.h" -#include "boost/filesystem/operations.hpp" - #include "webcc/logger.h" #include "webcc/utility.h" @@ -9,8 +7,6 @@ #include "webcc/gzip.h" #endif -namespace bfs = boost::filesystem; - namespace webcc { // ----------------------------------------------------------------------------- @@ -157,7 +153,7 @@ void FormBody::Free(std::size_t index) { // ----------------------------------------------------------------------------- -FileBody::FileBody(const bfs::path& path, std::size_t chunk_size) +FileBody::FileBody(const fs::path& path, std::size_t chunk_size) : path_(path), chunk_size_(chunk_size), auto_delete_(false), size_(0) { size_ = utility::TellSize(path_); if (size_ == kInvalidLength) { @@ -165,15 +161,15 @@ FileBody::FileBody(const bfs::path& path, std::size_t chunk_size) } } -FileBody::FileBody(const bfs::path& path, bool auto_delete) +FileBody::FileBody(const fs::path& path, bool auto_delete) : path_(path), chunk_size_(0), auto_delete_(auto_delete), size_(0) { // Don't need to tell file size. } FileBody::~FileBody() { if (auto_delete_ && !path_.empty()) { - boost::system::error_code ec; - bfs::remove(path_, ec); + fs::error_code ec; + fs::remove(path_, ec); if (ec) { LOG_ERRO("Failed to remove file (%s).", ec.message().c_str()); } @@ -209,7 +205,7 @@ void FileBody::Dump(std::ostream& os, const std::string& prefix) const { os << prefix << "" << std::endl; } -bool FileBody::Move(const bfs::path& new_path) { +bool FileBody::Move(const fs::path& new_path) { if (path_ == new_path) { return false; } @@ -218,8 +214,8 @@ bool FileBody::Move(const bfs::path& new_path) { ifstream_.close(); } - boost::system::error_code ec; - bfs::rename(path_, new_path, ec); + fs::error_code ec; + fs::rename(path_, new_path, ec); if (ec) { LOG_ERRO("Failed to rename file (%s).", ec.message().c_str()); diff --git a/webcc/body.h b/webcc/body.h index c87528d..446ec35 100644 --- a/webcc/body.h +++ b/webcc/body.h @@ -1,15 +1,12 @@ #ifndef WEBCC_BODY_H_ #define WEBCC_BODY_H_ -#include #include #include #include -#include "boost/filesystem/fstream.hpp" -#include "boost/filesystem/path.hpp" - #include "webcc/common.h" +#include "webcc/fs.h" namespace webcc { @@ -154,14 +151,14 @@ private: class FileBody : public Body { public: // For message to be sent out. - FileBody(const boost::filesystem::path& path, std::size_t chunk_size); + FileBody(const fs::path& path, std::size_t chunk_size); // For message received. // No |chunk_size| is needed since you don't iterate the payload of a // received message. // If |auto_delete| is true, the file will be deleted on destructor unless it // is moved to another path (see Move()). - FileBody(const boost::filesystem::path& path, bool auto_delete = false); + FileBody(const fs::path& path, bool auto_delete = false); ~FileBody() override; @@ -175,7 +172,7 @@ public: void Dump(std::ostream& os, const std::string& prefix) const override; - const boost::filesystem::path& path() const { + const fs::path& path() const { return path_; } @@ -188,17 +185,17 @@ public: // If |new_path| resolves to an existing non-directory file, it is removed. // If |new_path| resolves to an existing directory, it is removed if empty // on ISO/IEC 9945 but is an error on Windows. - // See boost::filesystem::rename() for more details. - bool Move(const boost::filesystem::path& new_path); + // See fs::rename() for more details. + bool Move(const fs::path& new_path); private: - boost::filesystem::path path_; + fs::path path_; std::size_t chunk_size_; bool auto_delete_; std::size_t size_; // File size in bytes - boost::filesystem::ifstream ifstream_; + fs::ifstream ifstream_; std::string chunk_; }; diff --git a/webcc/common.cc b/webcc/common.cc index 527d487..570c995 100644 --- a/webcc/common.cc +++ b/webcc/common.cc @@ -8,8 +8,6 @@ #include "webcc/string.h" #include "webcc/utility.h" -namespace bfs = boost::filesystem; - namespace webcc { // ----------------------------------------------------------------------------- @@ -194,7 +192,7 @@ FormPartPtr FormPart::New(const std::string& name, std::string&& data, return form_part; } -FormPartPtr FormPart::NewFile(const std::string& name, const bfs::path& path, +FormPartPtr FormPart::NewFile(const std::string& name, const fs::path& path, const std::string& media_type) { auto form_part = std::make_shared(); diff --git a/webcc/common.h b/webcc/common.h index c60d5a1..5a85905 100644 --- a/webcc/common.h +++ b/webcc/common.h @@ -6,8 +6,7 @@ #include #include -#include "boost/filesystem/path.hpp" - +#include "webcc/fs.h" #include "webcc/globals.h" namespace webcc { @@ -158,8 +157,7 @@ public: // Construct a file part. // The file name will be extracted from path. // The media type, if not provided, will be inferred from file extension. - static FormPartPtr NewFile(const std::string& name, - const boost::filesystem::path& path, + static FormPartPtr NewFile(const std::string& name, const fs::path& path, const std::string& media_type = ""); // API: SERVER @@ -230,7 +228,7 @@ private: std::string name_; // The path of the file to post. - boost::filesystem::path path_; + fs::path path_; // The original local file name. // E.g., "baby.jpg". diff --git a/webcc/config.h.example b/webcc/config.h.example index 287847e..14ff92c 100644 --- a/webcc/config.h.example +++ b/webcc/config.h.example @@ -17,4 +17,7 @@ // Set 1/0 to enable/disable GZIP compression. #define WEBCC_ENABLE_GZIP 0 +// Set 1 to use C++17 filesystem or 0 to use Boost filesystem. +#define WEBCC_USE_STD_FILESYSTEM 1 + #endif // WEBCC_CONFIG_H_ diff --git a/webcc/config.h.in b/webcc/config.h.in index 3b84c81..7d3974c 100644 --- a/webcc/config.h.in +++ b/webcc/config.h.in @@ -19,4 +19,7 @@ // Set 1/0 to enable/disable GZIP compression. #define WEBCC_ENABLE_GZIP @WEBCC_ENABLE_GZIP@ +// Set 1 to use C++17 filesystem or 0 to use Boost filesystem. +#define WEBCC_USE_STD_FILESYSTEM @WEBCC_USE_STD_FILESYSTEM@ + #endif // WEBCC_CONFIG_H_ diff --git a/webcc/fs.h b/webcc/fs.h new file mode 100644 index 0000000..71decfb --- /dev/null +++ b/webcc/fs.h @@ -0,0 +1,65 @@ +#ifndef WEBCC_FS_H_ +#define WEBCC_FS_H_ + +// Use std or boost filesystem according to config. + +#include "webcc/config.h" // for WEBCC_USE_STD_FILESYSTEM + +#if WEBCC_USE_STD_FILESYSTEM +#include +#include +#else +#include "boost/filesystem/fstream.hpp" +#include "boost/filesystem/operations.hpp" +#include "boost/filesystem/path.hpp" +#endif // WEBCC_USE_STD_FILESYSTEM + +namespace webcc { +namespace fs { + +#if WEBCC_USE_STD_FILESYSTEM + +// types +using std::error_code; +using std::ifstream; +using std::ofstream; +using std::filesystem::path; +using std::filesystem::filesystem_error; + +// functions +using std::filesystem::rename; +using std::filesystem::remove; +using std::filesystem::exists; +using std::filesystem::is_directory; +using std::filesystem::is_regular_file; +using std::filesystem::create_directory; +using std::filesystem::create_directories; +using std::filesystem::current_path; +using std::filesystem::temp_directory_path; + +#else + +// types +using boost::system::error_code; +using boost::filesystem::ifstream; +using boost::filesystem::ofstream; +using boost::filesystem::path; +using boost::filesystem::filesystem_error; + +// functions +using boost::filesystem::rename; +using boost::filesystem::remove; +using boost::filesystem::exists; +using boost::filesystem::is_directory; +using boost::filesystem::is_regular_file; +using boost::filesystem::create_directory; +using boost::filesystem::create_directories; +using boost::filesystem::current_path; +using boost::filesystem::temp_directory_path; + +#endif // WEBCC_USE_STD_FILESYSTEM + +} // namespace fs +} // namespace webcc + +#endif // WEBCC_FS_H_ diff --git a/webcc/globals.h b/webcc/globals.h index afa554b..5421c65 100644 --- a/webcc/globals.h +++ b/webcc/globals.h @@ -126,6 +126,8 @@ namespace media_types { const char* const kApplicationJson = "application/json"; const char* const kApplicationSoapXml = "application/soap+xml"; +const char* const kApplicationFormUrlEncoded = + "application/x-www-form-urlencoded"; const char* const kTextPlain = "text/plain"; const char* const kTextXml = "text/xml"; diff --git a/webcc/logger.cc b/webcc/logger.cc index 22bbf85..715636a 100644 --- a/webcc/logger.cc +++ b/webcc/logger.cc @@ -18,11 +18,7 @@ // For getting thread ID. #include #include -#endif - -#include "boost/filesystem/operations.hpp" - -namespace bfs = boost::filesystem; +#endif // defined(_WIN32) || defined(_WIN64) namespace webcc { @@ -36,7 +32,7 @@ static const char* kLevelNames[] = { // ----------------------------------------------------------------------------- -static FILE* FOpen(const bfs::path& path, bool overwrite) { +static FILE* FOpen(const fs::path& path, bool overwrite) { #if (defined(_WIN32) || defined(_WIN64)) return _wfopen(path.wstring().c_str(), overwrite ? L"w+" : L"a+"); #else @@ -53,7 +49,7 @@ struct Logger { } } - void Init(const bfs::path& path, int _modes) { + void Init(const fs::path& path, int _modes) { modes = _modes; // Create log file only if necessary. @@ -155,14 +151,14 @@ static std::string GetThreadID() { return thread_id; } -static bfs::path InitLogPath(const bfs::path& dir) { +static fs::path InitLogPath(const fs::path& dir) { if (dir.empty()) { - return bfs::current_path() / WEBCC_LOG_FILE_NAME; + return fs::current_path() / WEBCC_LOG_FILE_NAME; } - boost::system::error_code ec; - if (!bfs::exists(dir, ec) || !bfs::is_directory(dir, ec)) { - if (!bfs::create_directories(dir, ec) || ec) { + fs::error_code ec; + if (!fs::exists(dir, ec) || !fs::is_directory(dir, ec)) { + if (!fs::create_directories(dir, ec) || ec) { return {}; } } @@ -170,7 +166,7 @@ static bfs::path InitLogPath(const bfs::path& dir) { return (dir / WEBCC_LOG_FILE_NAME); } -void LogInit(const bfs::path& dir, int modes) { +void LogInit(const fs::path& dir, int modes) { // Suppose this is called from the main thread. g_main_thread_id = DoGetThreadID(); diff --git a/webcc/logger.h b/webcc/logger.h index d106233..d236144 100644 --- a/webcc/logger.h +++ b/webcc/logger.h @@ -9,7 +9,7 @@ #include // for strrchr() #include -#include "boost/filesystem/path.hpp" +#include "webcc/fs.h" // Log levels. // VERB is similar to DEBUG commonly used by other projects. @@ -44,7 +44,7 @@ const int LOG_FILE_OVERWRITE = LOG_FILE | LOG_OVERWRITE; // Initialize logger. // If |dir| is empty, log file will be generated in current directory. -void LogInit(const boost::filesystem::path& dir, int modes); +void LogInit(const fs::path& dir, int modes); void Log(int level, const char* file, int line, const char* format, ...); diff --git a/webcc/parser.cc b/webcc/parser.cc index ec4b6b5..524d136 100644 --- a/webcc/parser.cc +++ b/webcc/parser.cc @@ -1,7 +1,6 @@ #include "webcc/parser.h" #include "boost/algorithm/string.hpp" -#include "boost/filesystem/operations.hpp" #include "webcc/logger.h" #include "webcc/message.h" @@ -12,8 +11,6 @@ #include "webcc/gzip.h" #endif -namespace bfs = boost::filesystem; - namespace webcc { // ----------------------------------------------------------------------------- @@ -70,7 +67,7 @@ bool StringBodyHandler::Finish() { bool FileBodyHandler::OpenFile() { try { - temp_path_ = bfs::temp_directory_path(); + temp_path_ = fs::temp_directory_path(); // Generate a random string as file name. // A replacement of boost::filesystem::unique_path(). @@ -79,7 +76,7 @@ bool FileBodyHandler::OpenFile() { LOG_VERB("Generate a temp path for streaming: %s", temp_path_.string().c_str()); - } catch (const bfs::filesystem_error&) { + } catch (const fs::filesystem_error&) { LOG_ERRO("Failed to generate temp path for streaming"); return false; } diff --git a/webcc/parser.h b/webcc/parser.h index ca9bd01..926ac46 100644 --- a/webcc/parser.h +++ b/webcc/parser.h @@ -4,10 +4,8 @@ #include #include -#include "boost/filesystem/fstream.hpp" -#include "boost/filesystem/path.hpp" - #include "webcc/common.h" +#include "webcc/fs.h" #include "webcc/globals.h" namespace webcc { @@ -84,8 +82,8 @@ public: private: std::size_t streamed_size_ = 0; - boost::filesystem::ofstream ofstream_; - boost::filesystem::path temp_path_; + fs::ofstream ofstream_; + fs::path temp_path_; }; // ----------------------------------------------------------------------------- diff --git a/webcc/request_builder.cc b/webcc/request_builder.cc index b091ef3..be484e5 100644 --- a/webcc/request_builder.cc +++ b/webcc/request_builder.cc @@ -9,8 +9,6 @@ #include "webcc/gzip.h" #endif -namespace bfs = boost::filesystem; - namespace webcc { RequestPtr RequestBuilder::operator()() { @@ -67,7 +65,7 @@ RequestBuilder& RequestBuilder::AcceptGzip(bool gzip) { #endif // WEBCC_ENABLE_GZIP -RequestBuilder& RequestBuilder::File(const bfs::path& path, +RequestBuilder& RequestBuilder::File(const fs::path& path, bool infer_media_type, std::size_t chunk_size) { body_.reset(new FileBody{ path, chunk_size }); @@ -80,7 +78,7 @@ RequestBuilder& RequestBuilder::File(const bfs::path& path, } RequestBuilder& RequestBuilder::FormFile(const std::string& name, - const bfs::path& path, + const fs::path& path, const std::string& media_type) { assert(!name.empty()); return Form(FormPart::NewFile(name, path, media_type)); diff --git a/webcc/request_builder.h b/webcc/request_builder.h index 609c518..11ceb5c 100644 --- a/webcc/request_builder.h +++ b/webcc/request_builder.h @@ -4,26 +4,29 @@ #include #include -#include "boost/filesystem/path.hpp" - +#include "webcc/fs.h" #include "webcc/request.h" #include "webcc/url.h" // ----------------------------------------------------------------------------- // Handy macros for creating a RequestBuilder. -#define WEBCC_GET(url) webcc::RequestBuilder{}.Get(url, false) -#define WEBCC_GET_ENC(url) webcc::RequestBuilder{}.Get(url, true) -#define WEBCC_HEAD(url) webcc::RequestBuilder{}.Head(url, false) -#define WEBCC_HEAD_ENC(url) webcc::RequestBuilder{}.Head(url, true) -#define WEBCC_POST(url) webcc::RequestBuilder{}.Post(url, false) -#define WEBCC_POST_ENC(url) webcc::RequestBuilder{}.Post(url, true) -#define WEBCC_PUT(url) webcc::RequestBuilder{}.Put(url, false) -#define WEBCC_PUT_ENC(url) webcc::RequestBuilder{}.Put(url, true) -#define WEBCC_DELETE(url) webcc::RequestBuilder{}.Delete(url, false) -#define WEBCC_DELETE_ENC(url) webcc::RequestBuilder{}.Delete(url, true) -#define WEBCC_PATCH(url) webcc::RequestBuilder{}.Patch(url, false) -#define WEBCC_PATCH_ENC(url) webcc::RequestBuilder{}.Patch(url, true) +#define WEBCC_RB webcc::RequestBuilder{} + +// clang-format off +#define WEBCC_GET(url) WEBCC_RB.Get(url, false) +#define WEBCC_GET_ENC(url) WEBCC_RB.Get(url, true) +#define WEBCC_HEAD(url) WEBCC_RB.Head(url, false) +#define WEBCC_HEAD_ENC(url) WEBCC_RB.Head(url, true) +#define WEBCC_POST(url) WEBCC_RB.Post(url, false) +#define WEBCC_POST_ENC(url) WEBCC_RB.Post(url, true) +#define WEBCC_PUT(url) WEBCC_RB.Put(url, false) +#define WEBCC_PUT_ENC(url) WEBCC_RB.Put(url, true) +#define WEBCC_DELETE(url) WEBCC_RB.Delete(url, false) +#define WEBCC_DELETE_ENC(url) WEBCC_RB.Delete(url, true) +#define WEBCC_PATCH(url) WEBCC_RB.Patch(url, false) +#define WEBCC_PATCH_ENC(url) WEBCC_RB.Patch(url, true) +// clang-format on // ----------------------------------------------------------------------------- @@ -143,8 +146,7 @@ public: // Use the file content as body. // NOTE: Error::kFileError might be thrown. - RequestBuilder& File(const boost::filesystem::path& path, - bool infer_media_type = true, + RequestBuilder& File(const fs::path& path, bool infer_media_type = true, std::size_t chunk_size = 1024); // Add a form part. @@ -154,8 +156,7 @@ public: } // Add a form part of file. - RequestBuilder& FormFile(const std::string& name, - const boost::filesystem::path& path, + RequestBuilder& FormFile(const std::string& name, const fs::path& path, const std::string& media_type = ""); // Add a form part of string data. diff --git a/webcc/response_builder.cc b/webcc/response_builder.cc index bbedf1b..3b488be 100644 --- a/webcc/response_builder.cc +++ b/webcc/response_builder.cc @@ -8,8 +8,6 @@ #include "webcc/gzip.h" #endif -namespace bfs = boost::filesystem; - namespace webcc { ResponsePtr ResponseBuilder::operator()() { @@ -45,7 +43,7 @@ ResponsePtr ResponseBuilder::operator()() { return response; } -ResponseBuilder& ResponseBuilder::File(const bfs::path& path, +ResponseBuilder& ResponseBuilder::File(const fs::path& path, bool infer_media_type, std::size_t chunk_size) { body_.reset(new FileBody{ path, chunk_size }); diff --git a/webcc/response_builder.h b/webcc/response_builder.h index 955b8d6..5bacfc5 100644 --- a/webcc/response_builder.h +++ b/webcc/response_builder.h @@ -4,8 +4,7 @@ #include #include -#include "boost/filesystem/path.hpp" - +#include "webcc/fs.h" #include "webcc/request.h" #include "webcc/response.h" @@ -96,8 +95,7 @@ public: // Use the file content as body. // NOTE: Error::kFileError might be thrown. - ResponseBuilder& File(const boost::filesystem::path& path, - bool infer_media_type = true, + ResponseBuilder& File(const fs::path& path, bool infer_media_type = true, std::size_t chunk_size = 1024); ResponseBuilder& Header(const std::string& key, const std::string& value) { diff --git a/webcc/response_parser.cc b/webcc/response_parser.cc index a317d3a..fe418d2 100644 --- a/webcc/response_parser.cc +++ b/webcc/response_parser.cc @@ -9,16 +9,16 @@ namespace webcc { // ----------------------------------------------------------------------------- -namespace { - -void SplitStartLine(const std::string& line, std::vector* parts) { - const char SPACE = ' '; - +// Split HTTP response status line to three parts. +// Don't use the general split function because the reason part might also +// contain spaces. +static void SplitStatusLine(const std::string& line, + std::vector* parts) { std::size_t off = 0; std::size_t pos = 0; for (std::size_t i = 0; i < 2; ++i) { - pos = line.find(SPACE, off); + pos = line.find(' ', off); if (pos == std::string::npos) { break; } @@ -26,7 +26,9 @@ void SplitStartLine(const std::string& line, std::vector* parts) { parts->push_back(line.substr(off, pos - off)); off = pos + 1; - for (; off < line.size() && line[off] == SPACE; ++off) { + // Skip spaces + while (off < line.size() && line[off] == ' ') { + ++off; } } @@ -35,8 +37,6 @@ void SplitStartLine(const std::string& line, std::vector* parts) { } } -} // namespace - // ----------------------------------------------------------------------------- void ResponseParser::Init(Response* response, bool stream) { @@ -48,7 +48,7 @@ void ResponseParser::Init(Response* response, bool stream) { bool ResponseParser::ParseStartLine(const std::string& line) { std::vector parts; - SplitStartLine(line, &parts); + SplitStatusLine(line, &parts); if (parts.size() < 2) { LOG_ERRO("Invalid HTTP response status line: %s", line.c_str()); diff --git a/webcc/server.cc b/webcc/server.cc index 6ccd156..e00f1f3 100644 --- a/webcc/server.cc +++ b/webcc/server.cc @@ -4,22 +4,18 @@ #include #include -#include "boost/filesystem/operations.hpp" - #include "webcc/body.h" #include "webcc/logger.h" #include "webcc/request.h" #include "webcc/response.h" #include "webcc/utility.h" -namespace bfs = boost::filesystem; - using tcp = boost::asio::ip::tcp; namespace webcc { Server::Server(boost::asio::ip::tcp protocol, std::uint16_t port, - const bfs::path& doc_root) + const fs::path& doc_root) : protocol_(protocol), port_(port), doc_root_(doc_root), @@ -304,10 +300,10 @@ bool Server::MatchViewOrStatic(const std::string& method, // Try to match a static file. if (method == methods::kGet && !doc_root_.empty()) { - bfs::path path = doc_root_ / url; + fs::path path = doc_root_ / url; - boost::system::error_code ec; - if (!bfs::is_directory(path, ec) && bfs::exists(path, ec)) { + fs::error_code ec; + if (!fs::is_directory(path, ec) && fs::exists(path, ec)) { return true; } } @@ -323,7 +319,7 @@ ResponsePtr Server::ServeStatic(RequestPtr request) { return {}; } - bfs::path path = doc_root_ / request->url().path(); + fs::path path = doc_root_ / request->url().path(); try { // NOTE: FileBody might throw Error::kFileError. diff --git a/webcc/server.h b/webcc/server.h index 5615a1e..46f807e 100644 --- a/webcc/server.h +++ b/webcc/server.h @@ -5,14 +5,13 @@ #include #include -#include "boost/filesystem/path.hpp" - #include "boost/asio/io_context.hpp" #include "boost/asio/ip/tcp.hpp" #include "boost/asio/signal_set.hpp" #include "webcc/connection.h" #include "webcc/connection_pool.h" +#include "webcc/fs.h" #include "webcc/queue.h" #include "webcc/router.h" #include "webcc/url.h" @@ -22,7 +21,7 @@ namespace webcc { class Server : public Router { public: Server(boost::asio::ip::tcp protocol, std::uint16_t port, - const boost::filesystem::path& doc_root = {}); + const fs::path& doc_root = {}); Server(const Server&) = delete; Server& operator=(const Server&) = delete; @@ -108,7 +107,7 @@ private: std::uint16_t port_ = 0; // The directory with the static files to be served. - boost::filesystem::path doc_root_; + fs::path doc_root_; // The size of the buffer for reading request. std::size_t buffer_size_ = kBufferSize; diff --git a/webcc/utility.cc b/webcc/utility.cc index 833d78f..e42864d 100644 --- a/webcc/utility.cc +++ b/webcc/utility.cc @@ -7,13 +7,9 @@ #include #include -#include "boost/filesystem/fstream.hpp" - #include "webcc/string.h" #include "webcc/version.h" -namespace bfs = boost::filesystem; - namespace webcc { namespace utility { @@ -32,18 +28,18 @@ std::string HttpDate() { return date.str(); } -std::size_t TellSize(const bfs::path& path) { +std::size_t TellSize(const fs::path& path) { // Flag "ate": seek to the end of stream immediately after open. - bfs::ifstream stream{ path, std::ios::binary | std::ios::ate }; + fs::ifstream stream{ path, std::ios::binary | std::ios::ate }; if (stream.fail()) { return kInvalidLength; } return static_cast(stream.tellg()); } -bool ReadFile(const bfs::path& path, std::string* output) { +bool ReadFile(const fs::path& path, std::string* output) { // Flag "ate": seek to the end of stream immediately after open. - bfs::ifstream stream{ path, std::ios::binary | std::ios::ate }; + fs::ifstream stream{ path, std::ios::binary | std::ios::ate }; if (stream.fail()) { return false; } diff --git a/webcc/utility.h b/webcc/utility.h index f4851b8..528c454 100644 --- a/webcc/utility.h +++ b/webcc/utility.h @@ -5,8 +5,8 @@ #include #include "boost/asio/ip/tcp.hpp" -#include "boost/filesystem/path.hpp" +#include "webcc/fs.h" #include "webcc/globals.h" namespace webcc { @@ -22,10 +22,10 @@ std::string HttpDate(); // Tell the size in bytes of the given file. // Return kInvalidLength (-1) on failure. -std::size_t TellSize(const boost::filesystem::path& path); +std::size_t TellSize(const fs::path& path); // Read entire file into string. -bool ReadFile(const boost::filesystem::path& path, std::string* output); +bool ReadFile(const fs::path& path, std::string* output); // Dump the string data line by line to achieve more readability. // Also limit the maximum size of the data to be dumped.