Feature/support windows unicode paths (#928)

This commit is contained in:
Greisberger Christophe 2021-07-15 17:57:12 +02:00 committed by GitHub
parent 5e8db234b9
commit 5c1c81e828
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 245 additions and 124 deletions

192
CMakeLists.txt Normal file → Executable file
View File

@ -234,11 +234,50 @@ set(DROGON_SOURCES
lib/src/WebSocketClientImpl.cc
lib/src/WebSocketConnectionImpl.cc
lib/src/WebsocketControllersRouter.cc)
set(private_headers
lib/src/AOPAdvice.h
lib/src/CacheFile.h
lib/src/ConfigLoader.h
lib/src/filesystem.h
lib/src/FiltersFunction.h
lib/src/HttpAppFrameworkImpl.h
lib/src/HttpClientImpl.h
lib/src/HttpControllersRouter.h
lib/src/HttpFileImpl.h
lib/src/HttpFileUploadRequest.h
lib/src/HttpMessageBody.h
lib/src/HttpRequestImpl.h
lib/src/HttpRequestParser.h
lib/src/HttpResponseImpl.h
lib/src/HttpResponseParser.h
lib/src/HttpServer.h
lib/src/HttpSimpleControllersRouter.h
lib/src/HttpUtils.h
lib/src/impl_forwards.h
lib/src/ListenerManager.h
lib/src/PluginsManager.h
lib/src/SessionManager.h
lib/src/SpinLock.h
lib/src/StaticFileRouter.h
lib/src/TaskTimeoutFlag.h
lib/src/WebSocketClientImpl.h
lib/src/WebSocketConnectionImpl.h
lib/src/WebsocketControllersRouter.h)
if (NOT WIN32)
set(DROGON_SOURCES ${DROGON_SOURCES} lib/src/SharedLibManager.cc)
set(DROGON_SOURCES
${DROGON_SOURCES}
lib/src/SharedLibManager.cc)
set(private_headers
${private_headers}
lib/src/SharedLibManager.h)
else (NOT WIN32)
set(DROGON_SOURCES ${DROGON_SOURCES} third_party/mman-win32/mman.c)
set(DROGON_SOURCES
${DROGON_SOURCES}
third_party/mman-win32/mman.c)
set(private_headers
${private_headers}
third_party/mman-win32/mman.h)
endif (NOT WIN32)
if (BUILD_POSTGRESQL)
@ -248,8 +287,12 @@ if (BUILD_POSTGRESQL)
message(STATUS "libpq inc path:" ${PG_INCLUDE_DIRS})
message(STATUS "libpq lib:" ${PG_LIBRARIES})
target_link_libraries(${PROJECT_NAME} PRIVATE pg_lib)
set(DROGON_SOURCES ${DROGON_SOURCES}
set(DROGON_SOURCES
${DROGON_SOURCES}
orm_lib/src/postgresql_impl/PostgreSQLResultImpl.cc)
set(private_headers
${private_headers}
orm_lib/src/postgresql_impl/PostgreSQLResultImpl.h)
if (LIBPQ_BATCH_MODE)
try_compile(libpq_supports_batch ${CMAKE_BINARY_DIR}/cmaketest
${PROJECT_SOURCE_DIR}/cmake/tests/test_libpq_batch_mode.cc
@ -259,12 +302,17 @@ if (BUILD_POSTGRESQL)
if (libpq_supports_batch)
message(STATUS "The libpq supports batch mode")
option(LIBPQ_SUPPORTS_BATCH_MODE "libpq batch mode" ON)
set(DROGON_SOURCES ${DROGON_SOURCES}
set(DROGON_SOURCES
${DROGON_SOURCES}
orm_lib/src/postgresql_impl/PgBatchConnection.cc)
else (libpq_supports_batch)
option(LIBPQ_SUPPORTS_BATCH_MODE "libpq batch mode" OFF)
set(DROGON_SOURCES ${DROGON_SOURCES}
set(DROGON_SOURCES
${DROGON_SOURCES}
orm_lib/src/postgresql_impl/PgConnection.cc)
set(private_headers
${private_headers}
orm_lib/src/postgresql_impl/PgConnection.h)
endif (libpq_supports_batch)
endif (pg_FOUND)
endif (BUILD_POSTGRESQL)
@ -275,9 +323,14 @@ if (BUILD_MYSQL)
if (MySQL_FOUND)
message(STATUS "Ok! We find the mariadb!")
target_link_libraries(${PROJECT_NAME} PRIVATE MySQL_lib)
set(DROGON_SOURCES ${DROGON_SOURCES}
set(DROGON_SOURCES
${DROGON_SOURCES}
orm_lib/src/mysql_impl/MysqlConnection.cc
orm_lib/src/mysql_impl/MysqlResultImpl.cc)
set(private_headers
${private_headers}
orm_lib/src/mysql_impl/MysqlConnection.h
orm_lib/src/mysql_impl/MysqlResultImpl.h)
endif (MySQL_FOUND)
endif (BUILD_MYSQL)
@ -286,9 +339,14 @@ if (BUILD_SQLITE)
find_package(SQLite3)
if (SQLite3_FOUND)
target_link_libraries(${PROJECT_NAME} PRIVATE SQLite3_lib)
set(DROGON_SOURCES ${DROGON_SOURCES}
set(DROGON_SOURCES
${DROGON_SOURCES}
orm_lib/src/sqlite3_impl/Sqlite3Connection.cc
orm_lib/src/sqlite3_impl/Sqlite3ResultImpl.cc)
set(private_headers
${private_headers}
orm_lib/src/sqlite3_impl/Sqlite3Connection.h
orm_lib/src/sqlite3_impl/Sqlite3ResultImpl.h)
endif (SQLite3_FOUND)
endif (BUILD_SQLITE)
@ -300,11 +358,17 @@ if (BUILD_REDIS)
set(DROGON_SOURCES
${DROGON_SOURCES}
nosql_lib/redis/src/RedisClientImpl.cc
nosql_lib/redis/src/RedisConnection.cc
nosql_lib/redis/src/RedisResult.cc
nosql_lib/redis/src/RedisClientLockFree.cc
nosql_lib/redis/src/RedisClientManager.cc
nosql_lib/redis/src/RedisConnection.cc
nosql_lib/redis/src/RedisResult.cc
nosql_lib/redis/src/RedisTransactionImpl.cc)
set(private_headers
${private_headers}
nosql_lib/redis/src/RedisClientImpl.h
nosql_lib/redis/src/RedisClientLockFree.h
nosql_lib/redis/src/RedisConnection.h
nosql_lib/redis/src/RedisTransactionImpl.h)
endif (Hiredis_FOUND)
endif (BUILD_REDIS)
@ -315,6 +379,9 @@ if (NOT Hiredis_FOUND)
lib/src/RedisClientSkipped.cc
lib/src/RedisResultSkipped.cc
lib/src/RedisClientManagerSkipped.cc)
set(private_headers
${private_headers}
lib/src/RedisClientManager.h)
endif (NOT Hiredis_FOUND)
if (BUILD_TESTING)
@ -328,8 +395,14 @@ find_package(OpenSSL)
if (OpenSSL_FOUND)
target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::SSL OpenSSL::Crypto)
else (OpenSSL_FOUND)
set(DROGON_SOURCES ${DROGON_SOURCES} lib/src/ssl_funcs/Md5.cc
set(DROGON_SOURCES
${DROGON_SOURCES}
lib/src/ssl_funcs/Md5.cc
lib/src/ssl_funcs/Sha1.cc)
set(private_headers
${private_headers}
lib/src/ssl_funcs/Md5.h
lib/src/ssl_funcs/Sha1.h)
endif (OpenSSL_FOUND)
execute_process(COMMAND "git" rev-parse HEAD
@ -378,16 +451,57 @@ set(DROGON_SOURCES
orm_lib/src/SqlBinder.cc
orm_lib/src/TransactionImpl.cc
orm_lib/src/RestfulController.cc)
set(DROGON_HEADERS
lib/inc/drogon/Attribute.h
lib/inc/drogon/CacheMap.h
lib/inc/drogon/Cookie.h
lib/inc/drogon/DrClassMap.h
lib/inc/drogon/DrObject.h
lib/inc/drogon/DrTemplate.h
lib/inc/drogon/DrTemplateBase.h
lib/inc/drogon/HttpAppFramework.h
lib/inc/drogon/HttpBinder.h
lib/inc/drogon/HttpClient.h
lib/inc/drogon/HttpController.h
lib/inc/drogon/HttpFilter.h
lib/inc/drogon/HttpRequest.h
lib/inc/drogon/HttpResponse.h
lib/inc/drogon/HttpSimpleController.h
lib/inc/drogon/HttpTypes.h
lib/inc/drogon/HttpViewData.h
lib/inc/drogon/IntranetIpFilter.h
lib/inc/drogon/IOThreadStorage.h
lib/inc/drogon/LocalHostFilter.h
lib/inc/drogon/MultiPart.h
lib/inc/drogon/NotFound.h
lib/inc/drogon/Session.h
lib/inc/drogon/UploadFile.h
lib/inc/drogon/WebSocketClient.h
lib/inc/drogon/WebSocketConnection.h
lib/inc/drogon/WebSocketController.h
lib/inc/drogon/drogon.h
lib/inc/drogon/version.h
lib/inc/drogon/drogon_callbacks.h
lib/inc/drogon/PubSubService.h
lib/inc/drogon/drogon_test.h
${CMAKE_CURRENT_BINARY_DIR}/exports/drogon/exports.h)
set(private_headers
${private_headers}
lib/src/DbClientManager.h
orm_lib/src/DbClientImpl.h
orm_lib/src/DbConnection.h
orm_lib/src/ResultImpl.h
orm_lib/src/TransactionImpl.h)
if (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
set(DROGON_SOURCES
${DROGON_SOURCES}
orm_lib/src/DbClientManager.cc)
else (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
set(DROGON_SOURCES ${DROGON_SOURCES} lib/src/DbClientManagerSkipped.cc)
set(DROGON_SOURCES
${DROGON_SOURCES}
lib/src/DbClientManagerSkipped.cc)
endif (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
target_sources(${PROJECT_NAME} PRIVATE ${DROGON_SOURCES})
set_target_properties(${PROJECT_NAME}
PROPERTIES CXX_STANDARD ${DROGON_CXX_STANDARD})
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD_REQUIRED ON)
@ -467,40 +581,6 @@ install(TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" COMPONENT lib
LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT lib)
set(DROGON_HEADERS
lib/inc/drogon/Attribute.h
lib/inc/drogon/CacheMap.h
lib/inc/drogon/Cookie.h
lib/inc/drogon/DrClassMap.h
lib/inc/drogon/DrObject.h
lib/inc/drogon/DrTemplate.h
lib/inc/drogon/DrTemplateBase.h
lib/inc/drogon/HttpAppFramework.h
lib/inc/drogon/HttpBinder.h
lib/inc/drogon/HttpClient.h
lib/inc/drogon/HttpController.h
lib/inc/drogon/HttpFilter.h
lib/inc/drogon/HttpRequest.h
lib/inc/drogon/HttpResponse.h
lib/inc/drogon/HttpSimpleController.h
lib/inc/drogon/HttpTypes.h
lib/inc/drogon/HttpViewData.h
lib/inc/drogon/IntranetIpFilter.h
lib/inc/drogon/IOThreadStorage.h
lib/inc/drogon/LocalHostFilter.h
lib/inc/drogon/MultiPart.h
lib/inc/drogon/NotFound.h
lib/inc/drogon/Session.h
lib/inc/drogon/UploadFile.h
lib/inc/drogon/WebSocketClient.h
lib/inc/drogon/WebSocketConnection.h
lib/inc/drogon/WebSocketController.h
lib/inc/drogon/drogon.h
lib/inc/drogon/version.h
lib/inc/drogon/drogon_callbacks.h
lib/inc/drogon/PubSubService.h
lib/inc/drogon/drogon_test.h
${CMAKE_CURRENT_BINARY_DIR}/exports/drogon/exports.h)
install(FILES ${DROGON_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon)
set(ORM_HEADERS
@ -521,7 +601,8 @@ set(ORM_HEADERS
orm_lib/inc/drogon/orm/RestfulController.h)
install(FILES ${ORM_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/orm)
set(NOSQL_HEADERS nosql_lib/redis/inc/drogon/nosql/RedisClient.h
set(NOSQL_HEADERS
nosql_lib/redis/inc/drogon/nosql/RedisClient.h
nosql_lib/redis/inc/drogon/nosql/RedisResult.h
nosql_lib/redis/inc/drogon/nosql/RedisException.h)
install(FILES ${NOSQL_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/nosql)
@ -538,12 +619,22 @@ set(DROGON_UTIL_HEADERS
install(FILES ${DROGON_UTIL_HEADERS}
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils)
set(DROGON_PLUGIN_HEADERS lib/inc/drogon/plugins/Plugin.h
set(DROGON_PLUGIN_HEADERS
lib/inc/drogon/plugins/Plugin.h
lib/inc/drogon/plugins/SecureSSLRedirector.h
lib/inc/drogon/plugins/AccessLogger.h)
install(FILES ${DROGON_PLUGIN_HEADERS}
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/plugins)
target_sources(${PROJECT_NAME} PRIVATE
${DROGON_SOURCES}
${private_headers}
${DROGON_HEADERS}
${ORM_HEADERS}
${DROGON_UTIL_HEADERS}
${DROGON_PLUGIN_HEADERS}
${NOSQL_HEADERS})
source_group("Public API"
FILES
${DROGON_HEADERS}
@ -551,6 +642,9 @@ source_group("Public API"
${DROGON_UTIL_HEADERS}
${DROGON_PLUGIN_HEADERS}
${NOSQL_HEADERS})
source_group("Private Headers"
FILES
${private_headers})
# Export the package for use from the build-tree (this registers the build-tree
# with a global cmake-registry) export(PACKAGE Drogon)

View File

@ -55,6 +55,9 @@ add_dependencies(drogon_ctl _drogon_ctl)
if(WIN32)
target_link_libraries(drogon_ctl PRIVATE ws2_32 Rpcrt4)
endif(WIN32)
if(APPLE)
target_link_libraries(drogon_ctl PRIVATE resolv)
endif()
message(STATUS "bin:" ${INSTALL_BIN_DIR})
install(TARGETS drogon_ctl RUNTIME DESTINATION ${INSTALL_BIN_DIR})
if(WIN32)

View File

@ -17,6 +17,7 @@
#include <drogon/exports.h>
#include <trantor/utils/Date.h>
#include <trantor/utils/Funcs.h>
#include <trantor/utils/Utilities.h>
#include <drogon/utils/string_view.h>
#include <memory>
#include <string>
@ -154,38 +155,110 @@ DROGON_EXPORT std::string formattedString(const char *format, ...);
*/
DROGON_EXPORT int createPath(const std::string &path);
/**
* @details Convert a wide string path with arbitrary directory separators
* to a UTF-8 portable path for use with trantor.
*
* This is a helper, mainly for Windows and multi-platform projects.
*
* @note On Windows, backslash directory separators are converted to slash to
* keep portable paths.
*
* @remarks On other OSes, backslashes are not converted to slash, since they
* are valid characters for directory/file names.
*
* @param strPath Wide string path.
*
* @return std::string UTF-8 path, with slash directory separator.
*/
inline std::string fromWidePath(const std::wstring &strPath)
{
return trantor::utils::fromWidePath(strPath);
}
/**
* @details Convert a UTF-8 path with arbitrary directory separator to a wide
* string path.
*
* This is a helper, mainly for Windows and multi-platform projects.
*
* @note On Windows, slash directory separators are converted to backslash.
* Although it accepts both slash and backslash as directory separator in its
* API, it is better to stick to its standard.
* @remarks On other OSes, slashes are not converted to backslashes, since they
* are not interpreted as directory separators and are valid characters for
* directory/file names.
*
* @param strUtf8Path Ascii path considered as being UTF-8.
*
* @return std::wstring path with, on windows, standard backslash directory
* separator to stick to its standard.
*/
inline std::wstring toWidePath(const std::string &strUtf8Path)
{
return trantor::utils::toWidePath(strUtf8Path);
}
/**
* @brief Convert a generic (UTF-8) path with to an OS native path.
* @details This is a helper, mainly for Windows and multi-platform projects.
*
* On Windows, slash directory separators are converted to backslash, and a
* wide string is returned.
*
* On other OSes, returns an UTF-8 string _without_ altering the directory
* separators.
*
* @param strPath Wide string or UTF-8 path.
*
* @return An OS path, suitable for use with the OS API.
*/
#ifdef _WIN32
/**
* @brief Convert a UTF-8 path with arbitrary directory separator to a standard
* Windows UCS2 path.
* @note Although windows accept both slash and backslash as directory
* separator, it is better to stick to its standard.
*
* @param strUtf8Path Ascii path considered as being UTF-8
*
* @return std::wstring path, with windows standard backslash directory
* separator.
*/
DROGON_EXPORT std::wstring toNativePath(const std::string &strPath);
/**
* @brief Convert a UCS2 to an UTF-8 path.
*
* @param strPath Wide char unicode path
*
* @return std::string path in UTF-8 unicode, with standard '/' directory
* separator.
*/
DROGON_EXPORT std::string fromNativePath(std::wstring strPath);
#else // _WIN32
inline std::wstring toNativePath(const std::string &strPath)
{
return trantor::utils::toNativePath(strPath);
}
inline const std::wstring &toNativePath(const std::wstring &strPath)
{
return trantor::utils::toNativePath(strPath);
}
#else // __WIN32
inline const std::string &toNativePath(const std::string &strPath)
{
return strPath;
return trantor::utils::toNativePath(strPath);
}
inline const std::string &fromNativePath(const std::string &strPath)
inline std::string toNativePath(const std::wstring &strPath)
{
return strPath;
return trantor::utils::toNativePath(strPath);
}
#endif // _WIN32
/**
* @brief Convert a OS native path (wide string on Windows) to a generic UTF-8
* path.
* @details This is a helper, mainly for Windows and multi-platform projects.
*
* On Windows, backslash directory separators are converted to slash, and a
* a UTF-8 string is returned, suitable for libraries that supports UTF-8 paths
* like OpenSSL or drogon.
*
* On other OSes, returns an UTF-8 string without altering the directory
* separators (backslashes are *NOT* replaced with slashes, since they
* are valid characters for directory/file names).
*
* @param strPath Wide string or UTF-8 path.
*
* @return A generic path.
*/
inline const std::string &fromNativePath(const std::string &strPath)
{
return trantor::utils::fromNativePath(strPath);
}
// Convert on all systems
inline std::string fromNativePath(const std::wstring &strPath)
{
return trantor::utils::fromNativePath(strPath);
}
/// Replace all occurances of from to to inplace
/**

View File

@ -1053,55 +1053,6 @@ std::string formattedString(const char *format, ...)
return strBuffer;
}
#ifdef _WIN32
std::string utf8_encode(const std::wstring &wstr)
{
if (wstr.empty())
return {};
int nSizeNeeded = ::WideCharToMultiByte(
CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string strTo(nSizeNeeded, 0);
::WideCharToMultiByte(CP_UTF8,
0,
&wstr[0],
(int)wstr.size(),
&strTo[0],
nSizeNeeded,
NULL,
NULL);
return strTo;
}
std::wstring utf8_decode(const std::string &str)
{
if (str.empty())
return {};
int nSizeNeeded =
::MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
std::wstring wstrTo(nSizeNeeded, 0);
::MultiByteToWideChar(
CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], nSizeNeeded);
return wstrTo;
}
std::wstring toNativePath(const std::string &strUtf8Path)
{
// Consider path to be utf-8, to allow using paths with unicode characters
auto wPath{utf8_decode(strUtf8Path)};
// Not needed: normalize path (just replaces '/' with '\')
filesystem::path fsPath(wPath);
// Not needed: normalize path (just replaces '/' with '\')
fsPath.make_preferred();
return fsPath.native();
}
std::string fromNativePath(std::wstring wstrPath)
{
std::replace(wstrPath.begin(), wstrPath.end(), L'\\', L'/');
auto strPath{utf8_encode(wstrPath)};
return strPath;
}
#endif // _WIN32
int createPath(const std::string &path)
{
if (path.empty())

@ -1 +1 @@
Subproject commit d7f700ac7ca0b6c656755142378bc71cd34ecfed
Subproject commit 5c8c12039c0d7c0876f2b3bfb580922427efb4e5