Skip to content

Commit 4e8ae35

Browse files
FlorianReimoldbjuulpBjarne Juul Pasgaard
authored
Added Memory Mapped Files, Tests, fixed Path Vulnerability and much more (#58)
- Performance improvements for FTP Downloads through memory-mapped file (Thanks to @bjuulp) - Added googletest as submodule - Added unit tests for fineftp-server. The tests require C++17 to compile and `curl` to be present in the `PATH` when executing them - New CMake Options for Enabling / Disabling different components (See Readme.md) - Binary downloads for Windows are now built with VS 2017 / v140 toolset - Fixed a race condition on Windows that caused files not being fully flushed after fineftp-server reported the finished data upload (Thanks to @bjuulp) - Reordered internal asio::strand implementation in order to prevent race conditions that haven't been detected, yet. (Thanks to @bjuulp) - Fixed a vulnerability that enabled an attacker to access files above the root directory (reported by #52) - Fixed many clang-tidy warnings - The `APPE` (= append-to-file) command now creates a new file if it didn't exist already (this is the correct behavior according to RFC 959 - Updated the asio submodule to 1.28.2 --------- Co-authored-by: Bjarne Juul Pasgaard <[email protected]> Co-authored-by: Bjarne Juul Pasgaard <[email protected]>
1 parent c12589a commit 4e8ae35

37 files changed

+3517
-274
lines changed

.clang-tidy

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,31 @@
44
# -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling
55
# This warns about memcpy and wants us to use memcpy_s, which is not available in our gcc setup.
66
#
7+
# -cppcoreguidelines-avoid-const-or-ref-data-members
8+
# I seriously don't understand why I shouldn't make a member variable const,
9+
# if I want to prevent people from changing it. I actually consider it good
10+
# style to do that
11+
#
712
# -cppcoreguidelines-pro-type-vararg
813
# This forbids using functions like printf, snprintf etc. We would like to use those either way.
914
#
1015
# -misc-no-recursion
1116
# Recursion with functions can be an elegant way of solving recursive problems
1217
#
18+
# -misc-include-cleaner
19+
# I would love to keep this option, but it would force me to include all
20+
# Win32 headers by hand instead of just including Windows.h. It would also force
21+
# me to copy the entire content of <asio/asio.hpp> into all of my cpp files and
22+
# there is no way that this would improve my code.
23+
#
24+
# -performance-avoid-endl
25+
# std::endl seems to be a good idea often, as it also flushes the stream buffer
26+
#
27+
# -bugprone-unused-return-value
28+
# asio returns error codes as parameter AND return value. The paraemter is
29+
# necessary to get teh error-code at all, but the return value is absolutely
30+
# useless in that case.
31+
#
1332
# These checks have been disabled to keep compatibility with C++14:
1433
# -modernize-concat-nested-namespaces
1534
# -modernize-use-nodiscard
@@ -23,9 +42,13 @@ Checks: "-*,
2342
-bugprone-easily-swappable-parameters,
2443
-bugprone-implicit-widening-of-multiplication-result,
2544
-bugprone-narrowing-conversions,
45+
-bugprone-unused-return-value,
2646
2747
cppcoreguidelines-*,
48+
-cppcoreguidelines-avoid-const-or-ref-data-members,
49+
-cppcoreguidelines-avoid-do-while,
2850
-cppcoreguidelines-avoid-magic-numbers,
51+
-cppcoreguidelines-avoid-non-const-global-variables,
2952
-cppcoreguidelines-macro-usage,
3053
-cppcoreguidelines-narrowing-conversions,
3154
-cppcoreguidelines-non-private-member-variables-in-classes,
@@ -35,19 +58,22 @@ Checks: "-*,
3558
-cppcoreguidelines-pro-type-reinterpret-cast,
3659
3760
misc-*,
61+
-misc-include-cleaner,
3862
-misc-non-private-member-variables-in-classes,
3963
-misc-no-recursion,
4064
4165
modernize-*,
42-
-modernize-pass-by-value,
43-
-modernize-use-trailing-return-type,
44-
-modernize-use-auto,
66+
-modernize-avoid-bind,
4567
-modernize-concat-nested-namespaces,
68+
-modernize-pass-by-value,
69+
-modernize-raw-string-literal,
4670
-modernize-return-braced-init-list,
71+
-modernize-use-auto,
4772
-modernize-use-nodiscard,
48-
-modernize-avoid-bind,
73+
-modernize-use-trailing-return-type,
4974
5075
performance-*,
76+
-performance-avoid-endl
5177
5278
readability-*,
5379
-readability-braces-around-statements,

.github/workflows/build-macos.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,20 @@ jobs:
2424
submodules: 'true'
2525
fetch-depth: 0
2626

27-
2827
- name: Configure CMake
2928
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
3029
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
31-
run: cmake -B ${{github.workspace}}/_build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
30+
run: |
31+
cmake -B ${{github.workspace}}/_build \
32+
-DFINEFTP_SERVER_BUILD_TESTS=ON \
33+
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
34+
shell: bash
3235

3336
- name: Build
3437
# Build your program with the given configuration
3538
run: cmake --build ${{github.workspace}}/_build --config ${{env.BUILD_TYPE}}
39+
40+
- name: Run Tests
41+
run: ctest -C Release -V
42+
working-directory: ${{ github.workspace }}/_build
3643

.github/workflows/build-ubuntu.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,18 @@ jobs:
5050
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
5151
run: |
5252
cmake -B ${{github.workspace}}/_build \
53+
-DFINEFTP_SERVER_BUILD_TESTS=ON \
5354
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
5455
-DBUILD_SHARED_LIBS=${{ env.build_shared_libs }}
5556
5657
- name: Build
5758
# Build your program with the given configuration
5859
run: cmake --build ${{github.workspace}}/_build --config ${{env.BUILD_TYPE}}
5960

61+
- name: Run Tests
62+
run: ctest -C Release -V
63+
working-directory: ${{ github.workspace }}/_build
64+
6065
- name: Read Project Version from CMakeCache
6166
run: |
6267
cmake_project_version_string=$(cat "${{github.workspace}}/_build/CMakeCache.txt" | grep "^CMAKE_PROJECT_VERSION:")

.github/workflows/build-windows.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ env:
99
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
1010
INSTALL_PREFIX: _install
1111
PROJECT_NAME: fineftp-server
12-
VS_TOOLSET: v140
13-
VS_NAME: vs2015
12+
VS_TOOLSET: v141
13+
VS_NAME: vs2017
1414

1515
jobs:
1616
build-windows:
@@ -59,6 +59,7 @@ jobs:
5959
-G "Visual Studio 16 2019" ^
6060
-A ${{ matrix.build_arch }} ^
6161
-T ${{ env.VS_TOOLSET }} ^
62+
-DFINEFTP_SERVER_BUILD_TESTS=ON ^
6263
-DCMAKE_INSTALL_PREFIX=${{env.INSTALL_PREFIX}} ^
6364
-DBUILD_SHARED_LIBS=${{ env.build_shared_libs }}
6465
@@ -73,6 +74,10 @@ jobs:
7374
run: |
7475
cmake --build ${{github.workspace}}/_build --config Debug --parallel
7576
cmake --build ${{github.workspace}}/_build --config Debug --target INSTALL
77+
78+
- name: Run Tests
79+
run: ctest -C Release -V
80+
working-directory: ${{ github.workspace }}/_build
7681

7782
- name: Read Project Version from CMakeCache
7883
run: |

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ ipch
77
*.user
88
*.opendb
99
*.db
10+
*.vscode
1011
/_build
1112
/samples/integration_test/_build
1213
/_install
1314
/.vs
1415
/CMakeLists.txt.user
1516

1617
# Common build directories in CMake projects
17-
build*
18+
/build*
1819

1920
# Temporary Vim files
2021
*.swp

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "thirdparty/asio"]
22
path = thirdparty/asio
33
url = https://github.com/chriskohlhoff/asio.git
4+
[submodule "thirdparty/googletest"]
5+
path = thirdparty/googletest
6+
url = https://github.com/google/googletest.git

CMakeLists.txt

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
cmake_minimum_required(VERSION 3.5.1)
22

3+
include(CMakeDependentOption)
4+
35
# Project call
46
include("${CMAKE_CURRENT_LIST_DIR}/fineftp-server/version.cmake")
57
project(fineftp VERSION ${FINEFTP_SERVER_VERSION_MAJOR}.${FINEFTP_SERVER_VERSION_MINOR}.${FINEFTP_SERVER_VERSION_PATCH})
@@ -12,23 +14,57 @@ message(STATUS "Prefix Path: ${CMAKE_PREFIX_PATH}")
1214

1315
# CMake Options
1416
option(FINEFTP_SERVER_BUILD_SAMPLES
15-
"Build project samples"
17+
"Build project samples."
1618
ON)
19+
option(FINEFTP_SERVER_BUILD_TESTS
20+
"Build the the fineftp-server tests. Requires C++17. For executing the tests, curl must be available from the PATH."
21+
OFF)
1722

18-
# Module path for finding asio
19-
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
23+
option(FINEFTP_SERVER_USE_BUILTIN_ASIO
24+
"Use the builtin asio submodule. If set to OFF, asio must be available from somewhere else (e.g. system libs)."
25+
ON)
26+
cmake_dependent_option(FINEFTP_SERVER_USE_BUILTIN_GTEST
27+
"Use the builtin GoogleTest submodule. Only needed if FINEFTP_SERVER_BUILD_TESTS is ON. If set to OFF, GoogleTest must be available from somewhere else (e.g. system libs)."
28+
ON # Default value if dependency is met
29+
"FINEFTP_SERVER_BUILD_TESTS" # Dependency
30+
OFF) # Default value if dependency is not met
2031

2132
# Set Debug postfix
2233
set(CMAKE_DEBUG_POSTFIX d)
2334
set(CMAKE_MINSIZEREL_POSTFIX minsize)
2435
set(CMAKE_RELWITHDEBINFO_POSTFIX reldbg)
2536

37+
# Use builtin asio
38+
if (FINEFTP_SERVER_USE_BUILTIN_ASIO)
39+
include("${CMAKE_CURRENT_LIST_DIR}/thirdparty/build-asio.cmake")
40+
endif()
41+
42+
# Use builtin gtest
43+
if (FINEFTP_SERVER_USE_BUILTIN_GTEST)
44+
include("${CMAKE_CURRENT_LIST_DIR}/thirdparty/build-gtest.cmake")
45+
endif()
46+
47+
# For tests we need to make sure that all shared libraries and executables are
48+
# put into the same directory. Otherwise the tests will fail on windows.
49+
if(FINEFTP_SERVER_BUILD_TESTS AND BUILD_SHARED_LIBS AND FINEFTP_SERVER_USE_BUILTIN_GTEST)
50+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
51+
endif()
52+
2653
# Add main fineftp::server library
2754
add_subdirectory(fineftp-server)
2855

56+
# Add the fineftp::server dummy module
57+
# Module path for finding asio
58+
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/fineftp-module)
59+
2960
if (FINEFTP_SERVER_BUILD_SAMPLES)
3061
add_subdirectory(samples/fineftp_example)
3162
endif()
3263

64+
if (FINEFTP_SERVER_BUILD_TESTS)
65+
enable_testing()
66+
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/tests/fineftp_test")
67+
endif()
68+
3369
# Make this package available for packing with CPack
3470
include("${CMAKE_CURRENT_LIST_DIR}/cpack_config.cmake")

README.md

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
FineFTP is a minimal FTP server library for Windows and Unix flavors. The project is CMake based and only depends on asio, which is integrated as git submodule. No boost is required.
66

7-
You can easily embed this library into your own project in order to create an embedded FTP Server. It was developed and tested on Windows 10 (Visual Studio 2015 / 2019, MinGW) and Ubuntu 16.04 - 21.10 (gcc 5.4.0 - 11.2.0).
7+
You can easily embed this library into your own project in order to create an embedded FTP Server. It was developed and tested on Windows 10 (Visual Studio 2015 and newer, MinGW) and Ubuntu 18.04 - 22.04 (gcc 7.4.0 - 11.2.0). It should also run fine on macOS.
88

99
## Features
1010

@@ -74,6 +74,63 @@ There is an example project provided that will create an FTP Server at `C:\` (Wi
7474

7575
5. Start `fineftp_example` / `fineftp_example.exe` and connect with your favorite FTP Client (e.g. FileZilla) on port 2121 *(This port is used so you don't need root privileges to start the FTP server)*
7676

77+
## CMake Options
78+
79+
You can set the following CMake Options to control how fineFTP Server is built:
80+
81+
**Option** | **Type** | **Default** | **Explanation** |
82+
|--------------------------------|----------|-------------|-----------------------------------------------------------------------------------------------------------------|
83+
| `FINEFTP_SERVER_BUILD_SAMPLES` | `BOOL` | `ON` | Build the fineFTP Server sample project. |
84+
| `FINEFTP_SERVER_BUILD_TESTS` | `BOOL` | `OFF` | Build the the fineftp-server tests. Requires C++17. For executing the tests, `curl` must be available from the `PATH`. |
85+
| `FINEFTP_SERVER_USE_BUILTIN_ASIO`| `BOOL`| `ON` | Use the builtin asio submodule. If set to `OFF`, asio must be available from somewhere else (e.g. system libs). |
86+
| `FINEFTP_SERVER_USE_BUILTIN_GTEST`| `BOOL`| `ON` <br>_(when building tests)_ | Use the builtin GoogleTest submodule. Only needed if `FINEFTP_SERVER_BUILD_TESTS` is `ON`. If set to `OFF`, GoogleTest must be available from somewhere else (e.g. system libs). |
87+
| `BUILD_SHARED_LIBS` | `BOOL` | | Not a fineFTP Server option, but use this to control whether you want to have a static or shared library. |
88+
89+
## How to integrate in your project
90+
91+
### Option 1: Integrate as binaries
92+
93+
1. Download the latest release from the releases page or compile the binaries yourself.
94+
95+
2. Add the fineFTP Server directory to your `CMAKE_PREFIX_PATH`:
96+
97+
```shell
98+
cmake your_command_line -DCMAKE_PREFIX_PATH=path/to/fineftp/install/dir
99+
```
100+
101+
### Option 2: Integrate as source
102+
103+
1. Make the fineFTP Server directory available in your project. You can either add it as a git submodule, or use CMake FetchContent to download it.
104+
105+
2. Add it to your CMake Project:
106+
107+
- **Either** by adding the top-level CMakeLists.txt to your project
108+
109+
```cmake
110+
add_subdirectory(path/to/fineftp-server)
111+
```
112+
113+
This which will inherit some behavior:
114+
115+
- You can use the CMake options described below
116+
- You will get the asio version shipped with fineFTP
117+
- The debug / minsize / relwithdebinfo postfix will be set automatically
118+
119+
120+
- **Or** if you want to get a very clean version, which doesn't set any unnecessary options, include the `fineftp-server/server` subdirectory:
121+
122+
```cmake
123+
add_subdirectory(path/to/fineftp-server/server)
124+
```
125+
126+
You have to provide the required asio target on your own.
127+
128+
### Link against fineFTP Server
129+
130+
```cmake
131+
find_package(fineftp REQUIRED)
132+
target_link_libraries(your_target PRIVATE fineftp::server)
133+
```
77134
78135
## Contribute
79136
File renamed without changes.

fineftp-server/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ set(sources
3838
src/win_str_convert.h
3939
)
4040

41+
if (WIN32)
42+
list(APPEND sources src/win32/file_man.cpp)
43+
list(APPEND sources src/win32/file_man.h)
44+
set(platform_include src/win32)
45+
else()
46+
list(APPEND sources src/unix/file_man.cpp)
47+
list(APPEND sources src/unix/file_man.h)
48+
set(platform_include src/unix)
49+
endif()
4150

4251
add_library (${PROJECT_NAME}
4352
${includes}
@@ -92,6 +101,7 @@ target_include_directories(${PROJECT_NAME}
92101
$<INSTALL_INTERFACE:include>
93102
PRIVATE
94103
src/
104+
${platform_include}
95105
)
96106

97107
set_target_properties(${PROJECT_NAME} PROPERTIES

0 commit comments

Comments
 (0)