diff --git a/.github/actions/retry-action/action.yml b/.github/actions/retry-action/action.yml index 5db8b62341..74b649439a 100644 --- a/.github/actions/retry-action/action.yml +++ b/.github/actions/retry-action/action.yml @@ -1,5 +1,5 @@ name: Retry Step -description: 'Retry a step on failure or timeout' +description: "Retry a step on failure or timeout" inputs: timeout_minutes: description: Minutes to wait before attempt times out. Must only specify either minutes or seconds @@ -50,5 +50,5 @@ outputs: exit_error: description: The final error returned by the command runs: - using: 'node16' - main: 'dist/index.js' \ No newline at end of file + using: "node20" + main: "dist/index.js" diff --git a/.github/actions/retry-action/package.json b/.github/actions/retry-action/package.json index f1c309fba3..10f8caf933 100644 --- a/.github/actions/retry-action/package.json +++ b/.github/actions/retry-action/package.json @@ -35,7 +35,7 @@ "@types/babel-generator": "^6.25.7", "@types/jest": "^28.1.6", "@types/milliseconds": "0.0.30", - "@types/node": "^16.11.7", + "@types/node": "^20.11.24", "@typescript-eslint/eslint-plugin": "^5.32.0", "@typescript-eslint/parser": "^5.32.0", "@vercel/ncc": "^0.38.1", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b20eeda0b..e737844a89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,29 +15,29 @@ concurrency: jobs: android-arm64-v8a-ndk-latest-cmake: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - uses: nttld/setup-ndk@v1 - with: - ndk-version: r25c - add-to-path: true - - run: cmake -S$GITHUB_WORKSPACE -B$HOME/android-build -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-21 -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_LATEST_HOME/build/cmake/android.toolchain.cmake && cmake --build $HOME/android-build --target all + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: nttld/setup-ndk@v1 + with: + ndk-version: r25c + add-to-path: true + - run: cmake -S$GITHUB_WORKSPACE -B$HOME/android-build -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-21 -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_LATEST_HOME/build/cmake/android.toolchain.cmake && cmake --build $HOME/android-build --target all android-arm64-v8a-ndk-cmake: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - uses: nttld/setup-ndk@v1 - with: - ndk-version: r25c - add-to-path: true - - run: cmake -S$GITHUB_WORKSPACE -B$HOME/android-build -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-21 -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake && cmake --build $HOME/android-build --target all + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: nttld/setup-ndk@v1 + with: + ndk-version: r25c + add-to-path: true + - run: cmake -S$GITHUB_WORKSPACE -B$HOME/android-build -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-21 -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake && cmake --build $HOME/android-build --target all android-armeabi-v7a-ndk-cmake: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: nttld/setup-ndk@v1 with: ndk-version: r25c @@ -47,14 +47,14 @@ jobs: linux-gcc-make-armv7l: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update && sudo apt -y install g++-arm-linux-gnueabihf - run: ./configure --config=X-Linux-gcc-arm --everything --omit=ApacheConnector,CppParser,Crypto,Data/MySQL,Data/PostgreSQL,Data/ODBC,JWT,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,SevenZip && make all -s -j4 linux-gcc-make: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev redis-server libmysqlclient-dev - run: ./configure --everything --omit=PDF && make all -s -j4 && sudo make install - uses: ./.github/actions/retry-action @@ -70,7 +70,7 @@ jobs: linux-gcc-make-cxx20: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev redis-server libmysqlclient-dev - run: ./configure --config=Linux-c++20 --everything --omit=PDF && make all -s -j4 && sudo make install - uses: ./.github/actions/retry-action @@ -86,7 +86,15 @@ jobs: linux-gcc-make-asan: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + # ASLR (https://en.wikipedia.org/wiki/Address_space_layout_randomization) + # causes sanitizer to fail. + # vm.mmap_rnd_bits needs to be set to 28 to make it work. + # (https://github.com/google/sanitizers/issues/1716) + - run: sysctl vm.legacy_va_layout + - run: sysctl kernel.randomize_va_space + - run: sudo sysctl vm.mmap_rnd_bits + - run: sudo sysctl -w vm.mmap_rnd_bits=28 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev redis-server - run: ./configure --everything --no-samples --omit=PDF && make all -s -j4 SANITIZEFLAGS=-fsanitize=address && sudo make install - uses: ./.github/actions/retry-action @@ -102,7 +110,15 @@ jobs: linux-gcc-make-asan-no-soo: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + # ASLR (https://en.wikipedia.org/wiki/Address_space_layout_randomization) + # causes sanitizer to fail. + # vm.mmap_rnd_bits needs to be set to 28 to make it work. + # (https://github.com/google/sanitizers/issues/1716) + - run: sysctl vm.legacy_va_layout + - run: sysctl kernel.randomize_va_space + - run: sudo sysctl vm.mmap_rnd_bits + - run: sudo sysctl -w vm.mmap_rnd_bits=28 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev redis-server - run: ./configure --everything --no-samples --omit=PDF --no-soo && make all -s -j4 SANITIZEFLAGS=-fsanitize=address && sudo make install - uses: ./.github/actions/retry-action @@ -118,7 +134,7 @@ jobs: linux-gcc-make-ubsan: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev redis-server - run: ./configure --everything --no-samples --omit=PDF && make all -s -j4 SANITIZEFLAGS=-fsanitize=undefined && sudo make install - uses: ./.github/actions/retry-action @@ -134,7 +150,15 @@ jobs: linux-gcc-make-tsan: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + # ASLR (https://en.wikipedia.org/wiki/Address_space_layout_randomization) + # causes sanitizer to fail. + # vm.mmap_rnd_bits needs to be set to 28 to make it work. + # (https://github.com/google/sanitizers/issues/1716) + - run: sysctl vm.legacy_va_layout + - run: sysctl kernel.randomize_va_space + - run: sudo sysctl vm.mmap_rnd_bits + - run: sudo sysctl -w vm.mmap_rnd_bits=28 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev redis-server - run: ./configure --everything --no-samples --omit=CppParser,Encodings,Data/MySQL,Data/ODBC,Data/PostgreSQL,MongoDB,PageCompiler,PDF,PocoDoc,ProGen,Redis,SevenZip && make all -s -j4 SANITIZEFLAGS=-fsanitize=thread && sudo make install - uses: ./.github/actions/retry-action @@ -143,13 +167,12 @@ jobs: max_attempts: 3 retry_on: any command: >- - sudo -s - ./ci/runtests.sh TSAN + sudo -s ./ci/runtests.sh TSAN linux-gcc-cmake: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update && sudo apt -y install cmake ninja-build libssl-dev unixodbc-dev libmysqlclient-dev redis-server - run: cmake -S. -Bcmake-build -GNinja -DENABLE_PDF=OFF -DENABLE_TESTS=ON && cmake --build cmake-build --target all - uses: ./.github/actions/retry-action @@ -166,25 +189,25 @@ jobs: linux-emscripten-cmake: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update && sudo apt -y install cmake ninja-build emscripten - run: emcmake cmake -H. -B cmake-build -DENABLE_ACTIVERECORD_COMPILER=OFF -DENABLE_PAGECOMPILER=OFF -DENABLE_PAGECOMPILER_FILE2PAGE=off && emmake cmake --build cmake-build --target all -j4 -# TODO: How to run unit tests in emscripten? -# - uses: ./.github/actions/retry-action -# with: -# timeout_minutes: 90 -# max_attempts: 3 -# retry_on: any -# command: >- -# cd cmake-build && -# sudo -s -# PWD=`pwd` -# ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(PostgreSQL)|(MongoDB)" + # TODO: How to run unit tests in emscripten? + # - uses: ./.github/actions/retry-action + # with: + # timeout_minutes: 90 + # max_attempts: 3 + # retry_on: any + # command: >- + # cd cmake-build && + # sudo -s + # PWD=`pwd` + # ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(PostgreSQL)|(MongoDB)" linux-gcc-make-cross-armhf: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: >- sudo apt-get -y update && sudo apt-get -y install crossbuild-essential-armhf @@ -200,7 +223,7 @@ jobs: macos-clang-make: runs-on: macos-12 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: brew install openssl@1.1 mysql-client unixodbc libpq - run: >- ./configure --everything --no-prefix --omit=PDF @@ -228,9 +251,10 @@ jobs: ./ci/runtests.sh macos-clang-make-visibility-hidden: + # macos-12 runs on Intel CPU runs-on: macos-12 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: brew install openssl@1.1 mysql-client unixodbc libpq - run: >- ./configure --everything --no-prefix --cflags="-fvisibility=hidden" --omit=PDF @@ -258,9 +282,10 @@ jobs: ./ci/runtests.sh macos-clang-cmake-openssl: - runs-on: macos-12 + # macos-14 runs on Apple Silicon + runs-on: macos-14 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: brew install openssl@1.1 mysql-client unixodbc libpq - run: cmake -S. -Bcmake-build -DENABLE_PDF=OFF -DENABLE_TESTS=ON -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1 -DMYSQL_ROOT_DIR=/usr/local/opt/mysql-client && cmake --build cmake-build --target all - uses: ./.github/actions/retry-action @@ -283,9 +308,9 @@ jobs: ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(PostgreSQL)|(MongoDB)|(Redis)" macos-clang-cmake-openssl3: - runs-on: macos-12 + runs-on: macos-14 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: brew install openssl@3 mysql-client unixodbc libpq - run: cmake -S. -Bcmake-build -DENABLE_PDF=OFF -DENABLE_TESTS=ON -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@3 -DMYSQL_ROOT_DIR=/usr/local/opt/mysql-client && cmake --build cmake-build --target all - uses: ./.github/actions/retry-action @@ -308,9 +333,9 @@ jobs: ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(PostgreSQL)|(MongoDB)|(Redis)" macos-clang-cmake-openssl3-visibility-hidden: - runs-on: macos-12 + runs-on: macos-14 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: brew install openssl@3 mysql-client unixodbc libpq - run: cmake -S. -Bcmake-build -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DENABLE_ENCODINGS_COMPILER=ON -DENABLE_PDF=ON -DENABLE_SEVENZIP=ON -DENABLE_CPPPARSER=ON -DENABLE_TESTS=ON -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@3 -DMYSQL_ROOT_DIR=/usr/local/opt/mysql-client && cmake --build cmake-build --target all - uses: ./.github/actions/retry-action @@ -333,9 +358,9 @@ jobs: ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(PostgreSQL)|(MongoDB)|(Redis)" macos-clang-make-openssl3-tsan: - runs-on: macos-12 + runs-on: macos-14 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: brew install openssl@3 - run: >- ./configure --everything --no-prefix --no-samples --omit=CppParser,Encodings,Data/MySQL,Data/ODBC,Data/PostgreSQL,MongoDB,PageCompiler,PDF,PocoDoc,ProGen,Redis,SevenZip @@ -365,7 +390,7 @@ jobs: macos-clang-make-openssl3-ubsan: runs-on: macos-12 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: brew install openssl@3 mysql-client unixodbc libpq - run: >- ./configure --everything --no-prefix --no-samples --omit=PDF @@ -395,7 +420,7 @@ jobs: macos-clang-make-openssl3-asan: runs-on: macos-12 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: brew install openssl@3 mysql-client unixodbc libpq - run: >- ./configure --everything --no-prefix --no-samples --omit=PDF @@ -422,63 +447,63 @@ jobs: EXCLUDE_TESTS="Redis Data/MySQL Data/ODBC Data/PostgreSQL MongoDB PDF" ./ci/runtests.sh -# windows-2019-msvc-cmake: -# runs-on: windows-2019 -# env: -# CPPUNIT_IGNORE: >- -# class CppUnit::TestCaller.testFind, -# class CppUnit::TestCaller.testSendToReceiveFrom, -# class CppUnit::TestCaller.testPing, -# class CppUnit::TestCaller.testBigPing, -# class CppUnit::TestCaller.testMTU, -# class CppUnit::TestCaller.testProxy, -# class CppUnit::TestCaller.testProxy, -# class CppUnit::TestCaller.testPollClosedServer -# steps: -# - uses: actions/checkout@v3 -# - run: cmake -S. -Bcmake-build -DENABLE_NETSSL_WIN=ON -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_JWT=OFF -DENABLE_DATA=ON -DENABLE_DATA_ODBC=ON -DENABLE_DATA_MYSQL=OFF -DENABLE_DATA_POSTGRESQL=OFF -DENABLE_TESTS=ON -# - run: cmake --build cmake-build --config Release -# - uses: ./.github/actions/retry-action -# with: -# timeout_minutes: 90 -# max_attempts: 3 -# retry_on: any -# command: >- -# cd cmake-build; -# ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(Redis)|(MongoDB)" -C Release - -# windows-2019-msvc-buildwin-x64: -# runs-on: windows-2019 -# env: -# CPPUNIT_IGNORE: >- -# class CppUnit::TestCaller.testFind, -# class CppUnit::TestCaller.testSendToReceiveFrom, -# class CppUnit::TestCaller.testPing, -# class CppUnit::TestCaller.testBigPing, -# class CppUnit::TestCaller.testMTU, -# class CppUnit::TestCaller.testProxy, -# class CppUnit::TestCaller.testProxy -# steps: -# - uses: actions/checkout@v3 -# - uses: ./.github/actions/retry-action -# with: -# timeout_minutes: 90 -# max_attempts: 3 -# retry_on: any -# command: .\buildwin.ps1 -poco_base . -vs 160 -action build -linkmode all -config release -platform x64 -samples -tests -omit "Crypto,NetSSL_OpenSSL,Data/MySQL,Data/PostgreSQL,JWT" - -# windows-2019-msvc-buildwin-win32: -# runs-on: windows-2019 -# env: -# CPPUNIT_IGNORE: class CppUnit::TestCaller.testFind,class CppUnit::TestCaller.testSendToReceiveFrom,class CppUnit::TestCaller.testPing,class CppUnit::TestCaller.testBigPing,class CppUnit::TestCaller.testMTU,class CppUnit::TestCaller.testProxy,class CppUnit::TestCaller.testProxy -# steps: -# - uses: actions/checkout@v3 -# - uses: ./.github/actions/retry-action -# with: -# timeout_minutes: 90 -# max_attempts: 3 -# retry_on: any -# command: .\buildwin.ps1 -poco_base . -vs 160 -action build -linkmode all -config release -platform Win32 -samples -tests -omit "Crypto,NetSSL_OpenSSL,Data/MySQL,Data/PostgreSQL,JWT" + # windows-2019-msvc-cmake: + # runs-on: windows-2019 + # env: + # CPPUNIT_IGNORE: >- + # class CppUnit::TestCaller.testFind, + # class CppUnit::TestCaller.testSendToReceiveFrom, + # class CppUnit::TestCaller.testPing, + # class CppUnit::TestCaller.testBigPing, + # class CppUnit::TestCaller.testMTU, + # class CppUnit::TestCaller.testProxy, + # class CppUnit::TestCaller.testProxy, + # class CppUnit::TestCaller.testPollClosedServer + # steps: + # - uses: actions/checkout@v4 + # - run: cmake -S. -Bcmake-build -DENABLE_NETSSL_WIN=ON -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_JWT=OFF -DENABLE_DATA=ON -DENABLE_DATA_ODBC=ON -DENABLE_DATA_MYSQL=OFF -DENABLE_DATA_POSTGRESQL=OFF -DENABLE_TESTS=ON + # - run: cmake --build cmake-build --config Release + # - uses: ./.github/actions/retry-action + # with: + # timeout_minutes: 90 + # max_attempts: 3 + # retry_on: any + # command: >- + # cd cmake-build; + # ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(Redis)|(MongoDB)" -C Release + + # windows-2019-msvc-buildwin-x64: + # runs-on: windows-2019 + # env: + # CPPUNIT_IGNORE: >- + # class CppUnit::TestCaller.testFind, + # class CppUnit::TestCaller.testSendToReceiveFrom, + # class CppUnit::TestCaller.testPing, + # class CppUnit::TestCaller.testBigPing, + # class CppUnit::TestCaller.testMTU, + # class CppUnit::TestCaller.testProxy, + # class CppUnit::TestCaller.testProxy + # steps: + # - uses: actions/checkout@v4 + # - uses: ./.github/actions/retry-action + # with: + # timeout_minutes: 90 + # max_attempts: 3 + # retry_on: any + # command: .\buildwin.ps1 -poco_base . -vs 160 -action build -linkmode all -config release -platform x64 -samples -tests -omit "Crypto,NetSSL_OpenSSL,Data/MySQL,Data/PostgreSQL,JWT" + + # windows-2019-msvc-buildwin-win32: + # runs-on: windows-2019 + # env: + # CPPUNIT_IGNORE: class CppUnit::TestCaller.testFind,class CppUnit::TestCaller.testSendToReceiveFrom,class CppUnit::TestCaller.testPing,class CppUnit::TestCaller.testBigPing,class CppUnit::TestCaller.testMTU,class CppUnit::TestCaller.testProxy,class CppUnit::TestCaller.testProxy + # steps: + # - uses: actions/checkout@v4 + # - uses: ./.github/actions/retry-action + # with: + # timeout_minutes: 90 + # max_attempts: 3 + # retry_on: any + # command: .\buildwin.ps1 -poco_base . -vs 160 -action build -linkmode all -config release -platform Win32 -samples -tests -omit "Crypto,NetSSL_OpenSSL,Data/MySQL,Data/PostgreSQL,JWT" windows-2022-msvc-buildwin-x64: runs-on: windows-2022 @@ -492,7 +517,7 @@ jobs: class CppUnit::TestCaller.testProxy, class CppUnit::TestCaller.testProxy steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: ./.github/actions/retry-action with: timeout_minutes: 90 @@ -500,25 +525,25 @@ jobs: retry_on: any command: .\buildwin.ps1 -poco_base . -vs 170 -action build -linkmode all -config release -platform x64 -samples -tests -omit "Crypto,NetSSL_OpenSSL,Data/MySQL,Data/PostgreSQL,JWT" -# windows-2022-msvc-buildwin-win32: -# runs-on: windows-2022 -# env: -# CPPUNIT_IGNORE: >- -# class CppUnit::TestCaller.testFind, -# class CppUnit::TestCaller.testSendToReceiveFrom, -# class CppUnit::TestCaller.testPing, -# class CppUnit::TestCaller.testBigPing, -# class CppUnit::TestCaller.testMTU, -# class CppUnit::TestCaller.testProxy, -# class CppUnit::TestCaller.testProxy -# steps: -# - uses: actions/checkout@v3 -# - uses: ./.github/actions/retry-action -# with: -# timeout_minutes: 90 -# max_attempts: 3 -# retry_on: any -# command: .\buildwin.ps1 -poco_base . -vs 170 -action build -linkmode all -config release -platform Win32 -samples -tests -omit "Crypto,NetSSL_OpenSSL,Data/MySQL,Data/PostgreSQL,JWT" + # windows-2022-msvc-buildwin-win32: + # runs-on: windows-2022 + # env: + # CPPUNIT_IGNORE: >- + # class CppUnit::TestCaller.testFind, + # class CppUnit::TestCaller.testSendToReceiveFrom, + # class CppUnit::TestCaller.testPing, + # class CppUnit::TestCaller.testBigPing, + # class CppUnit::TestCaller.testMTU, + # class CppUnit::TestCaller.testProxy, + # class CppUnit::TestCaller.testProxy + # steps: + # - uses: actions/checkout@v4 + # - uses: ./.github/actions/retry-action + # with: + # timeout_minutes: 90 + # max_attempts: 3 + # retry_on: any + # command: .\buildwin.ps1 -poco_base . -vs 170 -action build -linkmode all -config release -platform Win32 -samples -tests -omit "Crypto,NetSSL_OpenSSL,Data/MySQL,Data/PostgreSQL,JWT" windows-2022-msvc-cmake: runs-on: windows-2022 @@ -532,8 +557,8 @@ jobs: class CppUnit::TestCaller.testProxy, class CppUnit::TestCaller.testProxy steps: - - uses: actions/checkout@v3 - - run: cmake -S. -Bcmake-build -DENABLE_NETSSL_WIN=ON -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_JWT=OFF -DENABLE_DATA=ON -DENABLE_DATA_ODBC=ON -DENABLE_DATA_MYSQL=OFF -DENABLE_DATA_POSTGRESQL=OFF -DENABLE_DNSSD=OFF -DENABLE_TESTS=ON + - uses: actions/checkout@v4 + - run: cmake -S. -Bcmake-build -DENABLE_NETSSL_WIN=ON -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_JWT=OFF -DENABLE_DATA=ON -DENABLE_DATA_ODBC=ON -DENABLE_DATA_MYSQL=OFF -DENABLE_DATA_POSTGRESQL=OFF -DENABLE_TESTS=ON - run: cmake --build cmake-build --config Release - uses: ./.github/actions/retry-action with: @@ -544,30 +569,30 @@ jobs: cd cmake-build; ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(Redis)|(MongoDB)" -C Release -# missing asan dll path -# windows-2022-msvc-cmake-asan: -# runs-on: windows-2022 -# env: -# CPPUNIT_IGNORE: >- -# class CppUnit::TestCaller.testFind, -# class CppUnit::TestCaller.testSendToReceiveFrom, -# class CppUnit::TestCaller.testPing, -# class CppUnit::TestCaller.testBigPing, -# class CppUnit::TestCaller.testMTU, -# class CppUnit::TestCaller.testProxy, -# class CppUnit::TestCaller.testProxy -# steps: -# - uses: actions/checkout@v3 -# - run: cmake -S. -Bcmake-build -DPOCO_SANITIZE_ASAN=ON -DENABLE_NETSSL_WIN=ON -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_JWT=OFF -DENABLE_DATA=ON -DENABLE_DATA_ODBC=ON -DENABLE_DATA_MYSQL=OFF -DENABLE_DATA_POSTGRESQL=OFF -DENABLE_TESTS=ON -# - run: cmake --build cmake-build --config Debug -# - uses: ./.github/actions/retry-action -# with: -# timeout_minutes: 90 -# max_attempts: 3 -# retry_on: any -# command: >- -# cd cmake-build; -# ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(Redis)|(MongoDB)" -C Debug + # missing asan dll path + # windows-2022-msvc-cmake-asan: + # runs-on: windows-2022 + # env: + # CPPUNIT_IGNORE: >- + # class CppUnit::TestCaller.testFind, + # class CppUnit::TestCaller.testSendToReceiveFrom, + # class CppUnit::TestCaller.testPing, + # class CppUnit::TestCaller.testBigPing, + # class CppUnit::TestCaller.testMTU, + # class CppUnit::TestCaller.testProxy, + # class CppUnit::TestCaller.testProxy + # steps: + # - uses: actions/checkout@v4 + # - run: cmake -S. -Bcmake-build -DPOCO_SANITIZE_ASAN=ON -DENABLE_NETSSL_WIN=ON -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_JWT=OFF -DENABLE_DATA=ON -DENABLE_DATA_ODBC=ON -DENABLE_DATA_MYSQL=OFF -DENABLE_DATA_POSTGRESQL=OFF -DENABLE_TESTS=ON + # - run: cmake --build cmake-build --config Debug + # - uses: ./.github/actions/retry-action + # with: + # timeout_minutes: 90 + # max_attempts: 3 + # retry_on: any + # command: >- + # cd cmake-build; + # ctest --output-on-failure -E "(DataMySQL)|(DataODBC)|(Redis)|(MongoDB)" -C Debug linux-gcc-make-mysql: runs-on: ubuntu-22.04 @@ -582,7 +607,7 @@ jobs: ports: - 3306:3306 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev mysql-client - run: ./configure --everything --no-samples --omit=ActiveRecord,ApacheConnector,CppParser,Crypto,Data/PostgreSQL,Data/SQLite,Data/ODBC,Encodings,JSON,JWT,MongoDB,Net,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,Prometheus,Redis,SevenZip,Util,XML,Zip && make all -s -j4 && sudo make install - uses: ./.github/actions/retry-action @@ -595,7 +620,7 @@ jobs: EXCLUDE_TESTS="ActiveRecord ApacheConnector CppParser CppUnit Crypto Data Data/PostgreSQL Data/ODBC Data/SQLite Encodings Foundation JSON JWT MongoDB Net NetSSL_OpenSSL NetSSL_Win PDF PageCompiler PocoDoc ProGen Prometheus Redis SevenZip Util XML Zip" ./ci/runtests.sh -# TODO tests sometimes failing on testTransaction and testReconnect + # TODO tests sometimes failing on testTransaction and testReconnect linux-gcc-make-postgres: runs-on: ubuntu-22.04 services: @@ -606,7 +631,7 @@ jobs: ports: - 5432:5432 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev odbc-postgresql - run: ./configure --everything --no-samples --omit=ActiveRecord,ApacheConnector,CppParser,Crypto,Data/MySQL,Data/ODBC,Data/SQLite,Encodings,JSON,JWT,MongoDB,Net,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,Prometheus,Redis,SevenZip,Util,XML,Zip && make all -s -j4 && sudo make install - uses: ./.github/actions/retry-action @@ -622,7 +647,7 @@ jobs: linux-gcc-make-redis: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev - run: | curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg @@ -643,7 +668,7 @@ jobs: linux-gcc-make-mongodb: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: supercharge/mongodb-github-action@1.10.0 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev libmysqlclient-dev - run: ./configure --everything --no-samples --omit=ActiveRecord,ApacheConnector,CppParser,Crypto,Data/ODBC,Data/MySQL,Data/SQLite,Data/PostgreSQL,Encodings,JSON,JWT,Net,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,Prometheus,Redis,SevenZip,Util,XML,Zip && make all -s -j4 && sudo make install @@ -690,7 +715,7 @@ jobs: ports: - 1433:1433 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev alien libaio1 gnupg2 curl # libmysqlclient-dev mysql-client odbc-postgresql - run: ./configure --everything --no-samples --omit=ActiveRecord,ApacheConnector,CppParser,Crypto,Data/MySQL,Data/PostgreSQL,Data/SQLite,Encodings,JSON,JWT,MongoDB,Net,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,Prometheus,Redis,SevenZip,Util,XML,Zip && make all -s -j4 && sudo make install # - name: Setup MySQL ODBC connector @@ -712,10 +737,10 @@ jobs: # sudo /usr/lib/oracle/21/client64/bin/odbc_update_ini.sh / "/usr/lib/oracle/21/client64/lib" "" "" "/etc/odbc.ini" - name: Setup SQL Server ODBC connector run: | - curl https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc - curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list - sudo apt-get update - sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 + curl https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc + curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 - uses: ./.github/actions/retry-action with: timeout_minutes: 90 @@ -739,7 +764,7 @@ jobs: ports: - 3306:3306 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: sudo apt -y update - run: ./configure --everything --no-samples --no-sqlparser --omit=ActiveRecord,ApacheConnector,CppParser,Crypto,Data/PostgreSQL,Data/MySQL,Data/ODBC,Encodings,JSON,JWT,MongoDB,Net,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,Prometheus,Redis,SevenZip,Util,XML,Zip && make all -s -j4 && sudo make install - uses: ./.github/actions/retry-action diff --git a/Data/ODBC/src/ConnectionHandle.cpp b/Data/ODBC/src/ConnectionHandle.cpp index 4d1ce7cbbd..a313b54190 100644 --- a/Data/ODBC/src/ConnectionHandle.cpp +++ b/Data/ODBC/src/ConnectionHandle.cpp @@ -97,7 +97,7 @@ void ConnectionHandle::setTimeouts(SQLULEN loginTimeout, SQLULEN timeout) { try { - setTimeout(timeout); + setTimeout(static_cast(timeout)); } catch(const NotSupportedException&) {} } @@ -145,7 +145,7 @@ bool ConnectionHandle::connect(const std::string& connectString, SQLULEN loginTi // for Oracle) flat out refuse to set login timeout and return error - that's why these calls // are wrapped in try/catch and silently ignore errors. if (getTimeout() != timeout) - setTimeout(timeout); + setTimeout(static_cast(timeout)); if (getLoginTimeout() != loginTimeout) setLoginTimeout(loginTimeout); } diff --git a/Data/ODBC/src/SessionImpl.cpp b/Data/ODBC/src/SessionImpl.cpp index dac7d082e4..222a41b8f3 100644 --- a/Data/ODBC/src/SessionImpl.cpp +++ b/Data/ODBC/src/SessionImpl.cpp @@ -248,7 +248,7 @@ inline Poco::Any SessionImpl::getCursorUse(const std::string&) const void SessionImpl::setConnectionTimeout(std::size_t timeout) { SQLULEN value = static_cast(timeout); - _db.setTimeout(value); + _db.setTimeout(static_cast(value)); } diff --git a/Data/ODBC/src/Unicode_UNIXODBC.cpp b/Data/ODBC/src/Unicode_UNIXODBC.cpp index 1f671fed50..f5810b0c7c 100644 --- a/Data/ODBC/src/Unicode_UNIXODBC.cpp +++ b/Data/ODBC/src/Unicode_UNIXODBC.cpp @@ -14,6 +14,7 @@ #include "Poco/Data/ODBC/ODBC.h" #include "Poco/Data/ODBC/Unicode_UNIXODBC.h" +#include "Poco/Data/ODBC/Utility.h" #include "Poco/TextConverter.h" #include "Poco/UTF8Encoding.h" #include "Poco/UTF16Encoding.h" @@ -73,6 +74,12 @@ SQLRETURN SQLColAttribute(SQLHSTMT hstmt, SQLSMALLINT* pcbCharAttr, NumAttrPtrType pNumAttr) { + SQLSMALLINT cbCharAttr = 0; + if (!pcbCharAttr) pcbCharAttr = &cbCharAttr; + + SQLSMALLINT cbCharAttr; + if (!pcbCharAttr) pcbCharAttr = &cbCharAttr; + if (isString(pCharAttr, cbCharAttrMax)) { Buffer buffer(stringLength(pCharAttr, cbCharAttrMax)); @@ -85,7 +92,9 @@ SQLRETURN SQLColAttribute(SQLHSTMT hstmt, pcbCharAttr, pNumAttr); - makeUTF8(buffer, *pcbCharAttr, pCharAttr, cbCharAttrMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbCharAttr, pCharAttr, cbCharAttrMax); + return rc; } @@ -107,6 +116,11 @@ SQLRETURN SQLColAttributes(SQLHSTMT hstmt, SQLSMALLINT* pcbDesc, SQLLEN* pfDesc) { + SQLSMALLINT cbDesc = 0; + if (!pcbDesc) pcbDesc = &cbDesc; + SQLLEN fDesc = 0; + if (!pfDesc) pfDesc = &fDesc; + return SQLColAttribute(hstmt, icol, fDescType, @@ -151,6 +165,17 @@ SQLRETURN SQLDescribeCol(SQLHSTMT hstmt, SQLSMALLINT* pibScale, SQLSMALLINT* pfNullable) { + SQLSMALLINT cbColName = 0; + if (!pcbColName) pcbColName = &cbColName; + SQLSMALLINT fSqlType = 0; + if (!pfSqlType) pfSqlType = &fSqlType; + SQLULEN cbColDef = 0; + if (!pcbColDef) pcbColDef = &cbColDef; + SQLSMALLINT ibScale = 0; + if (!pibScale) pibScale = &ibScale; + SQLSMALLINT fNullable = 0; + if (!pfNullable) pfNullable = &fNullable; + Buffer buffer(cbColNameMax); SQLRETURN rc = SQLDescribeColW(hstmt, icol, @@ -162,7 +187,9 @@ SQLRETURN SQLDescribeCol(SQLHSTMT hstmt, pibScale, pfNullable); - makeUTF8(buffer, *pcbColName * sizeof(SQLWCHAR), szColName, cbColNameMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbColName * sizeof(SQLWCHAR), szColName, cbColNameMax); + return rc; } @@ -198,6 +225,9 @@ SQLRETURN SQLGetConnectAttr(SQLHDBC hdbc, SQLINTEGER cbValueMax, SQLINTEGER* pcbValue) { + SQLINTEGER cbValue = 0; + if (!pcbValue) pcbValue = &cbValue; + if (isString(rgbValue, cbValueMax)) { Buffer buffer(stringLength(rgbValue, cbValueMax)); @@ -208,7 +238,8 @@ SQLRETURN SQLGetConnectAttr(SQLHDBC hdbc, (SQLINTEGER) buffer.sizeBytes(), pcbValue); - makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax); return rc; } @@ -263,6 +294,9 @@ SQLRETURN SQLGetDescField(SQLHDESC hdesc, SQLINTEGER cbValueMax, SQLINTEGER* pcbValue) { + SQLINTEGER cbValue = 0; + if (!pcbValue) pcbValue = &cbValue; + if (isString(rgbValue, cbValueMax)) { Buffer buffer(stringLength(rgbValue, cbValueMax)); @@ -274,7 +308,8 @@ SQLRETURN SQLGetDescField(SQLHDESC hdesc, (SQLINTEGER) buffer.sizeBytes(), pcbValue); - makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax); return rc; } @@ -312,6 +347,9 @@ SQLRETURN SQLGetDiagField(SQLSMALLINT fHandleType, SQLSMALLINT cbDiagInfoMax, SQLSMALLINT* pcbDiagInfo) { + SQLSMALLINT cbDiagInfo = 0; + if (!pcbDiagInfo) pcbDiagInfo = &cbDiagInfo; + if (isString(rgbDiagInfo, cbDiagInfoMax)) { Buffer buffer(stringLength(rgbDiagInfo, cbDiagInfoMax)); @@ -324,7 +362,8 @@ SQLRETURN SQLGetDiagField(SQLSMALLINT fHandleType, (SQLSMALLINT) buffer.sizeBytes(), pcbDiagInfo); - makeUTF8(buffer, *pcbDiagInfo, rgbDiagInfo, cbDiagInfoMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbDiagInfo, rgbDiagInfo, cbDiagInfoMax); return rc; } @@ -348,6 +387,11 @@ SQLRETURN SQLGetDiagRec(SQLSMALLINT fHandleType, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT* pcbErrorMsg) { + SQLINTEGER fNativeError = 0; + if (!pfNativeError) pfNativeError = &fNativeError; + SQLSMALLINT cbErrorMsg = 0; + if (!pcbErrorMsg) pcbErrorMsg = &cbErrorMsg; + const SQLINTEGER stateLen = SQL_SQLSTATE_SIZE + 1; Buffer bufState(stateLen); Buffer bufErr(cbErrorMsgMax); @@ -361,8 +405,11 @@ SQLRETURN SQLGetDiagRec(SQLSMALLINT fHandleType, (SQLSMALLINT) bufErr.size(), pcbErrorMsg); - makeUTF8(bufState, stateLen * sizeof(SQLWCHAR), szSqlState, stateLen); - makeUTF8(bufErr, *pcbErrorMsg * sizeof(SQLWCHAR), szErrorMsg, cbErrorMsgMax); + if (!Utility::isError(rc)) + { + makeUTF8(bufState, stateLen * sizeof(SQLWCHAR), szSqlState, stateLen); + makeUTF8(bufErr, *pcbErrorMsg * sizeof(SQLWCHAR), szErrorMsg, cbErrorMsgMax); + } return rc; } @@ -433,6 +480,9 @@ SQLRETURN SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER cbValueMax, SQLINTEGER* pcbValue) { + SQLINTEGER cbValue = 0; + if (!pcbValue) pcbValue = &cbValue; + if (isString(rgbValue, cbValueMax)) { Buffer buffer(stringLength(rgbValue, cbValueMax)); @@ -476,6 +526,9 @@ SQLRETURN SQLGetInfo(SQLHDBC hdbc, SQLSMALLINT cbInfoValueMax, SQLSMALLINT* pcbInfoValue) { + SQLSMALLINT cbInfoValue = 0; + if (!pcbInfoValue) pcbInfoValue = &cbInfoValue; + if (cbInfoValueMax) { Buffer buffer(cbInfoValueMax); @@ -486,7 +539,8 @@ SQLRETURN SQLGetInfo(SQLHDBC hdbc, (SQLSMALLINT) buffer.sizeBytes(), pcbInfoValue); - makeUTF8(buffer, *pcbInfoValue, rgbInfoValue, cbInfoValueMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbInfoValue, rgbInfoValue, cbInfoValueMax); return rc; } @@ -561,6 +615,10 @@ SQLRETURN SQLDataSources(SQLHENV henv, SQLSMALLINT cbDescMax, SQLSMALLINT* pcbDesc) { + SQLSMALLINT cbDSN = 0, cbDesc = 0; + if (!pcbDSN) pcbDSN = &cbDSN; + if (!pcbDesc) pcbDesc = &cbDesc; + Buffer bufDSN(cbDSNMax); Buffer bufDesc(cbDescMax); @@ -573,8 +631,11 @@ SQLRETURN SQLDataSources(SQLHENV henv, (SQLSMALLINT) bufDesc.size(), pcbDesc); - makeUTF8(bufDSN, *pcbDSN * sizeof(SQLWCHAR), szDSN, cbDSNMax); - makeUTF8(bufDesc, *pcbDesc * sizeof(SQLWCHAR), szDesc, cbDescMax); + if (!Utility::isError(rc)) + { + makeUTF8(bufDSN, *pcbDSN * sizeof(SQLWCHAR), szDSN, cbDSNMax); + makeUTF8(bufDesc, *pcbDesc * sizeof(SQLWCHAR), szDesc, cbDescMax); + } return rc; } @@ -589,6 +650,9 @@ SQLRETURN SQLDriverConnect(SQLHDBC hdbc, SQLSMALLINT* pcbConnStrOut, SQLUSMALLINT fDriverCompletion) { + SQLSMALLINT cbConnStrOut = 0; + if (!pcbConnStrOut) pcbConnStrOut = &cbConnStrOut; + SQLSMALLINT len = cbConnStrIn; if (SQL_NTS == len) len = (SQLSMALLINT) std::strlen((const char*) szConnStrIn) + 1; @@ -606,7 +670,8 @@ SQLRETURN SQLDriverConnect(SQLHDBC hdbc, pcbConnStrOut, fDriverCompletion); - makeUTF8(out, *pcbConnStrOut * sizeof(SQLWCHAR), pcbConnStrOut, cbConnStrOutMax); + if (!Utility::isError(rc)) + makeUTF8(out, *pcbConnStrOut * sizeof(SQLWCHAR), pcbConnStrOut, cbConnStrOutMax); return rc; } @@ -619,6 +684,9 @@ SQLRETURN SQLBrowseConnect(SQLHDBC hdbc, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT* pcbConnStrOut) { + SQLSMALLINT cbConnStrOut = 0; + if (!pcbConnStrOut) pcbConnStrOut = &cbConnStrOut; + std::string str; makeUTF16(szConnStrIn, cbConnStrIn, str); @@ -631,7 +699,8 @@ SQLRETURN SQLBrowseConnect(SQLHDBC hdbc, (SQLSMALLINT) bufConnStrOut.size(), pcbConnStrOut); - makeUTF8(bufConnStrOut, *pcbConnStrOut * sizeof(SQLWCHAR), szConnStrOut, cbConnStrOutMax); + if (!Utility::isError(rc)) + makeUTF8(bufConnStrOut, *pcbConnStrOut * sizeof(SQLWCHAR), szConnStrOut, cbConnStrOutMax); return rc; } @@ -676,6 +745,9 @@ SQLRETURN SQLNativeSql(SQLHDBC hdbc, SQLINTEGER cbSqlStrMax, SQLINTEGER* pcbSqlStr) { + SQLINTEGER cbSqlStr = 0; + if (!pcbSqlStr) pcbSqlStr = &cbSqlStr; + std::string str; makeUTF16(szSqlStrIn, cbSqlStrIn, str); @@ -688,7 +760,8 @@ SQLRETURN SQLNativeSql(SQLHDBC hdbc, (SQLINTEGER) bufSQLOut.size(), pcbSqlStr); - makeUTF8(bufSQLOut, *pcbSqlStr * sizeof(SQLWCHAR), szSqlStr, cbSqlStrMax); + if (!Utility::isError(rc)) + makeUTF8(bufSQLOut, *pcbSqlStr * sizeof(SQLWCHAR), szSqlStr, cbSqlStrMax); return rc; } @@ -753,6 +826,10 @@ SQLRETURN SQLDrivers(SQLHENV henv, SQLSMALLINT cbDrvrAttrMax, SQLSMALLINT* pcbDrvrAttr) { + SQLSMALLINT cbDriverDesc = 0, cbDrvrAttr = 0; + if (!pcbDriverDesc) pcbDriverDesc = &cbDriverDesc; + if (!pcbDrvrAttr) pcbDrvrAttr = &cbDrvrAttr; + Buffer bufDriverDesc(cbDriverDescMax); Buffer bufDriverAttr(cbDrvrAttrMax); @@ -765,8 +842,11 @@ SQLRETURN SQLDrivers(SQLHENV henv, (SQLSMALLINT) bufDriverAttr.size(), pcbDrvrAttr); - makeUTF8(bufDriverDesc, *pcbDriverDesc * sizeof(SQLWCHAR), szDriverDesc, cbDriverDescMax); - makeUTF8(bufDriverAttr, *pcbDrvrAttr * sizeof(SQLWCHAR), szDriverAttributes, cbDrvrAttrMax); + if (!Utility::isError(rc)) + { + makeUTF8(bufDriverDesc, *pcbDriverDesc * sizeof(SQLWCHAR), szDriverDesc, cbDriverDescMax); + makeUTF8(bufDriverAttr, *pcbDrvrAttr * sizeof(SQLWCHAR), szDriverAttributes, cbDrvrAttrMax); + } return rc; } diff --git a/Data/ODBC/src/Unicode_WIN32.cpp b/Data/ODBC/src/Unicode_WIN32.cpp index ed472115a5..cbc57331ac 100644 --- a/Data/ODBC/src/Unicode_WIN32.cpp +++ b/Data/ODBC/src/Unicode_WIN32.cpp @@ -49,7 +49,9 @@ SQLRETURN SQLColAttribute(SQLHSTMT hstmt, pcbCharAttr, pNumAttr); - makeUTF8(buffer, *pcbCharAttr, pCharAttr, cbCharAttrMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbCharAttr, pCharAttr, cbCharAttrMax); + return rc; } @@ -129,7 +131,9 @@ SQLRETURN SQLDescribeCol(SQLHSTMT hstmt, pibScale, pfNullable); - makeUTF8(buffer, *pcbColName * sizeof(wchar_t), szColName, cbColNameMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbColName * sizeof(wchar_t), szColName, cbColNameMax); + return rc; } @@ -167,6 +171,9 @@ SQLRETURN SQLGetConnectAttr(SQLHDBC hdbc, SQLINTEGER cbValueMax, SQLINTEGER* pcbValue) { + SQLINTEGER cbValue = 0; + if (!pcbValue) pcbValue = &cbValue; + if (isString(rgbValue, cbValueMax)) { Buffer buffer(stringLength(rgbValue, cbValueMax)); @@ -177,7 +184,9 @@ SQLRETURN SQLGetConnectAttr(SQLHDBC hdbc, (SQLINTEGER) buffer.sizeBytes(), pcbValue); - makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax); + return rc; } @@ -234,6 +243,9 @@ SQLRETURN SQLGetDescField(SQLHDESC hdesc, SQLINTEGER cbValueMax, SQLINTEGER* pcbValue) { + SQLINTEGER cbValue = 0; + if (!pcbValue) pcbValue = &cbValue; + if (isString(rgbValue, cbValueMax)) { Buffer buffer(stringLength(rgbValue, cbValueMax)); @@ -245,7 +257,9 @@ SQLRETURN SQLGetDescField(SQLHDESC hdesc, (SQLINTEGER) buffer.sizeBytes(), pcbValue); - makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbValue, rgbValue, cbValueMax); + return rc; } @@ -294,7 +308,8 @@ SQLRETURN SQLGetDiagField(SQLSMALLINT fHandleType, (SQLSMALLINT) buffer.sizeBytes(), pcbDiagInfo); - makeUTF8(buffer, *pcbDiagInfo, rgbDiagInfo, cbDiagInfoMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbDiagInfo, rgbDiagInfo, cbDiagInfoMax); return rc; } @@ -317,6 +332,12 @@ SQLRETURN SQLGetDiagRec(SQLSMALLINT fHandleType, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT* pcbErrorMsg) { + SQLINTEGER nativeError = 0; + SQLSMALLINT cbErrorMsg = 0; + + if (!pfNativeError) pfNativeError = &nativeError; + if (!pcbErrorMsg) pcbErrorMsg = &cbErrorMsg; + const SQLINTEGER stateLen = SQL_SQLSTATE_SIZE + 1; Buffer bufState(stateLen); Buffer bufErr(cbErrorMsgMax); @@ -330,8 +351,11 @@ SQLRETURN SQLGetDiagRec(SQLSMALLINT fHandleType, (SQLSMALLINT) bufErr.size(), pcbErrorMsg); - makeUTF8(bufState, stateLen * sizeof(wchar_t), szSqlState, stateLen); - makeUTF8(bufErr, *pcbErrorMsg * sizeof(wchar_t), szErrorMsg, cbErrorMsgMax); + if (!Utility::isError(rc)) + { + makeUTF8(bufState, stateLen * sizeof(wchar_t), szSqlState, stateLen); + makeUTF8(bufErr, *pcbErrorMsg * sizeof(wchar_t), szErrorMsg, cbErrorMsgMax); + } return rc; } @@ -410,6 +434,9 @@ SQLRETURN SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER cbValueMax, SQLINTEGER* pcbValue) { + SQLINTEGER cbValue = 0; + if (!pcbValue) pcbValue = &cbValue; + if (isString(rgbValue, cbValueMax)) { Buffer buffer(stringLength(rgbValue, cbValueMax)); @@ -457,6 +484,9 @@ SQLRETURN SQLGetInfo(SQLHDBC hdbc, SQLSMALLINT cbInfoValueMax, SQLSMALLINT* pcbInfoValue) { + SQLSMALLINT cbValue = 0; + if (!pcbInfoValue) pcbInfoValue = &cbValue; + if (cbInfoValueMax) { Buffer buffer(cbInfoValueMax); @@ -467,7 +497,8 @@ SQLRETURN SQLGetInfo(SQLHDBC hdbc, (SQLSMALLINT) buffer.sizeBytes(), pcbInfoValue); - makeUTF8(buffer, *pcbInfoValue, rgbInfoValue, cbInfoValueMax); + if (!Utility::isError(rc)) + makeUTF8(buffer, *pcbInfoValue, rgbInfoValue, cbInfoValueMax); return rc; } @@ -558,8 +589,11 @@ SQLRETURN SQLDataSources(SQLHENV henv, (SQLSMALLINT) bufDesc.size(), pcbDesc); - makeUTF8(bufDSN, *pcbDSN * sizeof(wchar_t), szDSN, cbDSNMax); - makeUTF8(bufDesc, *pcbDesc * sizeof(wchar_t), szDesc, cbDescMax); + if (!Utility::isError(rc)) + { + makeUTF8(bufDSN, *pcbDSN * sizeof(wchar_t), szDSN, cbDSNMax); + makeUTF8(bufDesc, *pcbDesc * sizeof(wchar_t), szDesc, cbDescMax); + } return rc; } @@ -617,7 +651,8 @@ SQLRETURN SQLBrowseConnect(SQLHDBC hdbc, (SQLSMALLINT) bufConnStrOut.size(), pcbConnStrOut); - makeUTF8(bufConnStrOut, *pcbConnStrOut * sizeof(wchar_t), szConnStrOut, cbConnStrOutMax); + if (!Utility::isError(rc)) + makeUTF8(bufConnStrOut, *pcbConnStrOut * sizeof(wchar_t), szConnStrOut, cbConnStrOutMax); return rc; } @@ -674,7 +709,8 @@ SQLRETURN SQLNativeSql(SQLHDBC hdbc, (SQLINTEGER) bufSQLOut.size(), pcbSqlStr); - makeUTF8(bufSQLOut, *pcbSqlStr * sizeof(wchar_t), szSqlStr, cbSqlStrMax); + if (!Utility::isError(rc)) + makeUTF8(bufSQLOut, *pcbSqlStr * sizeof(wchar_t), szSqlStr, cbSqlStrMax); return rc; } @@ -751,8 +787,11 @@ SQLRETURN SQLDrivers(SQLHENV henv, (SQLSMALLINT) bufDriverAttr.size(), pcbDrvrAttr); - makeUTF8(bufDriverDesc, *pcbDriverDesc * sizeof(wchar_t), szDriverDesc, cbDriverDescMax); - makeUTF8(bufDriverAttr, *pcbDrvrAttr * sizeof(wchar_t), szDriverAttributes, cbDrvrAttrMax); + if (!Utility::isError(rc)) + { + makeUTF8(bufDriverDesc, *pcbDriverDesc * sizeof(wchar_t), szDriverDesc, cbDriverDescMax); + makeUTF8(bufDriverAttr, *pcbDrvrAttr * sizeof(wchar_t), szDriverAttributes, cbDrvrAttrMax); + } return rc; } diff --git a/Foundation/include/Poco/FileStream.h b/Foundation/include/Poco/FileStream.h index 768364bbd6..abe47b163c 100644 --- a/Foundation/include/Poco/FileStream.h +++ b/Foundation/include/Poco/FileStream.h @@ -72,6 +72,9 @@ class Foundation_API FileIOS: public virtual std::ios Poco::UInt64 size() const; /// Returns file size + void flushToDisk(); + /// Forces buffered data to be written to the disk + protected: FileStreamBuf _buf; }; diff --git a/Foundation/include/Poco/FileStream_POSIX.h b/Foundation/include/Poco/FileStream_POSIX.h index 8e7ef8fb29..5788d3f3fc 100644 --- a/Foundation/include/Poco/FileStream_POSIX.h +++ b/Foundation/include/Poco/FileStream_POSIX.h @@ -52,6 +52,9 @@ class Foundation_API FileStreamBuf: public BufferedBidirectionalStreamBuf std::streampos seekpos(std::streampos pos, std::ios::openmode mode = std::ios::in | std::ios::out); /// Change to specified position, according to mode. + void flushToDisk(); + /// Forces buffered data to be written to the disk + NativeHandle nativeHandle() const; /// Returns native file descriptor handle diff --git a/Foundation/include/Poco/FileStream_WIN32.h b/Foundation/include/Poco/FileStream_WIN32.h index d26f1ffed0..09f787c9b6 100644 --- a/Foundation/include/Poco/FileStream_WIN32.h +++ b/Foundation/include/Poco/FileStream_WIN32.h @@ -51,6 +51,9 @@ class Foundation_API FileStreamBuf: public BufferedBidirectionalStreamBuf std::streampos seekpos(std::streampos pos, std::ios::openmode mode = std::ios::in | std::ios::out); /// change to specified position, according to mode + void flushToDisk(); + /// Forces buffered data to be written to the disk + NativeHandle nativeHandle() const; /// Returns native file descriptor handle diff --git a/Foundation/include/Poco/LogFile.h b/Foundation/include/Poco/LogFile.h index 3e1ec21f4e..cbd200b224 100644 --- a/Foundation/include/Poco/LogFile.h +++ b/Foundation/include/Poco/LogFile.h @@ -17,21 +17,14 @@ #ifndef Foundation_LogFile_INCLUDED #define Foundation_LogFile_INCLUDED - #include "Poco/Foundation.h" - - -#if defined(POCO_OS_FAMILY_WINDOWS) -#include "Poco/LogFile_WIN32U.h" -#else -#include "Poco/LogFile_STD.h" -#endif - +#include "Poco/Timestamp.h" +#include "Poco/FileStream.h" namespace Poco { -class Foundation_API LogFile: public LogFileImpl +class Foundation_API LogFile /// This class is used by FileChannel to work /// with a log file. { @@ -55,34 +48,13 @@ class Foundation_API LogFile: public LogFileImpl const std::string& path() const; /// Returns the path given in the constructor. -}; - - -// -// inlines -// -inline void LogFile::write(const std::string& text, bool flush) -{ - writeImpl(text, flush); -} - -inline UInt64 LogFile::size() const -{ - return sizeImpl(); -} - - -inline Timestamp LogFile::creationDate() const -{ - return creationDateImpl(); -} - - -inline const std::string& LogFile::path() const -{ - return pathImpl(); -} +private: + std::string _path; + mutable Poco::FileOutputStream _str; + Timestamp _creationDate; + UInt64 _size; +}; } // namespace Poco diff --git a/Foundation/include/Poco/LogFile_STD.h b/Foundation/include/Poco/LogFile_STD.h deleted file mode 100644 index a178cb0bab..0000000000 --- a/Foundation/include/Poco/LogFile_STD.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// LogFile_STD.h -// -// Library: Foundation -// Package: Logging -// Module: LogFile -// -// Definition of the LogFileImpl class using iostreams. -// -// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// SPDX-License-Identifier: BSL-1.0 -// - - -#ifndef Foundation_LogFile_STD_INCLUDED -#define Foundation_LogFile_STD_INCLUDED - - -#include "Poco/Foundation.h" -#include "Poco/Timestamp.h" -#include "Poco/FileStream.h" - - -namespace Poco { - - -class Foundation_API LogFileImpl - /// The implementation of LogFile for non-Windows platforms. - /// The native filesystem APIs are used for - /// total control over locking behavior. -{ -public: - LogFileImpl(const std::string& path); - ~LogFileImpl(); - void writeImpl(const std::string& text, bool flush); - UInt64 sizeImpl() const; - Timestamp creationDateImpl() const; - const std::string& pathImpl() const; - -private: - std::string _path; - mutable Poco::FileOutputStream _str; - Timestamp _creationDate; - UInt64 _size; -}; - - -} // namespace Poco - - -#endif // Foundation_LogFile_STD_INCLUDED diff --git a/Foundation/include/Poco/LogFile_WIN32U.h b/Foundation/include/Poco/LogFile_WIN32U.h deleted file mode 100644 index ed558a7da7..0000000000 --- a/Foundation/include/Poco/LogFile_WIN32U.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// LogFile_WIN32U.h -// -// Library: Foundation -// Package: Logging -// Module: LogFile -// -// Definition of the LogFileImpl class using the Windows file APIs. -// -// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// SPDX-License-Identifier: BSL-1.0 -// - - -#ifndef Foundation_LogFile_WIN32U_INCLUDED -#define Foundation_LogFile_WIN32U_INCLUDED - - -#include "Poco/Foundation.h" -#include "Poco/Timestamp.h" -#include "Poco/UnWindows.h" - - -namespace Poco { - - -class Foundation_API LogFileImpl - /// The implementation of LogFile for Windows. - /// The native filesystem APIs are used for - /// total control over locking behavior. -{ -public: - LogFileImpl(const std::string& path); - ~LogFileImpl(); - void writeImpl(const std::string& text, bool flush); - UInt64 sizeImpl() const; - Timestamp creationDateImpl() const; - const std::string& pathImpl() const; - -private: - void createFile(); - - std::string _path; - HANDLE _hFile; - Timestamp _creationDate; -}; - - -} // namespace Poco - - -#endif // Foundation_LogFile_WIN32U_INCLUDED diff --git a/Foundation/include/Poco/MemoryStream.h b/Foundation/include/Poco/MemoryStream.h index 1db3a2c236..a537307674 100644 --- a/Foundation/include/Poco/MemoryStream.h +++ b/Foundation/include/Poco/MemoryStream.h @@ -140,6 +140,12 @@ class BasicMemoryStreamBuf: public std::basic_streambuf return newoff; } + + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) + { + const off_type off = pos; + return seekoff(off, std::ios::beg, which); + } virtual int sync() { diff --git a/Foundation/src/DateTimeFormat.cpp b/Foundation/src/DateTimeFormat.cpp index da25d6e8c8..27057143a0 100644 --- a/Foundation/src/DateTimeFormat.cpp +++ b/Foundation/src/DateTimeFormat.cpp @@ -67,7 +67,7 @@ const std::string DateTimeFormat::RFC850_REGEX( const std::string DateTimeFormat::RFC1036_FORMAT("%W, %e %b %y %H:%M:%S %Z"); const std::string DateTimeFormat::RFC1036_REGEX( - "(((Monday)|(Tuesday)|(Wednesday)|(Thursday)|(Friday)|(Saturday)|(Sun)), *)?" + "(((Monday)|(Tuesday)|(Wednesday)|(Thursday)|(Friday)|(Saturday)|(Sunday)), *)?" "\\d\\d? +" "((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec)) +" "\\d\\d(\\d\\d)? +\\d\\d:\\d\\d(:\\d\\d)? " diff --git a/Foundation/src/FileChannel.cpp b/Foundation/src/FileChannel.cpp index 1e5cbcf46a..81ae42471a 100644 --- a/Foundation/src/FileChannel.cpp +++ b/Foundation/src/FileChannel.cpp @@ -42,7 +42,7 @@ const std::string FileChannel::PROP_ROTATEONOPEN = "rotateOnOpen"; FileChannel::FileChannel(): _times("utc"), _compress(false), - _flush(true), + _flush(false), _rotateOnOpen(false), _pFile(nullptr), _pRotateStrategy(new NullRotateStrategy()), @@ -56,7 +56,7 @@ FileChannel::FileChannel(const std::string& path): _path(path), _times("utc"), _compress(false), - _flush(true), + _flush(false), _rotateOnOpen(false), _pFile(nullptr), _pRotateStrategy(new NullRotateStrategy()), diff --git a/Foundation/src/FileStream.cpp b/Foundation/src/FileStream.cpp index 28b49eb246..54dd62c3f2 100644 --- a/Foundation/src/FileStream.cpp +++ b/Foundation/src/FileStream.cpp @@ -56,10 +56,18 @@ FileIOS::NativeHandle FileIOS::nativeHandle() const } -Poco::UInt64 FileIOS::size() const { +Poco::UInt64 FileIOS::size() const +{ return _buf.size(); } + +void FileIOS::flushToDisk() +{ + _buf.flushToDisk(); +} + + FileInputStream::FileInputStream(): std::istream(&_buf) { diff --git a/Foundation/src/FileStream_POSIX.cpp b/Foundation/src/FileStream_POSIX.cpp index fb4b967076..c62d9c6d9c 100644 --- a/Foundation/src/FileStream_POSIX.cpp +++ b/Foundation/src/FileStream_POSIX.cpp @@ -169,6 +169,17 @@ std::streampos FileStreamBuf::seekpos(std::streampos pos, std::ios::openmode mod } +void FileStreamBuf::flushToDisk() +{ + if (getMode() & std::ios::out) + { + sync(); + if (fsync(_fd) != 0) + File::handleLastError(_path); + } +} + + FileStreamBuf::NativeHandle FileStreamBuf::nativeHandle() const { return _fd; diff --git a/Foundation/src/FileStream_WIN32.cpp b/Foundation/src/FileStream_WIN32.cpp index 5e1986c99a..e79c54706b 100644 --- a/Foundation/src/FileStream_WIN32.cpp +++ b/Foundation/src/FileStream_WIN32.cpp @@ -199,6 +199,17 @@ std::streampos FileStreamBuf::seekpos(std::streampos pos, std::ios::openmode mod } +void FileStreamBuf::flushToDisk() +{ + if (getMode() & std::ios::out) + { + sync(); + if (FlushFileBuffers(_handle) == 0) + File::handleLastError(_path); + } +} + + FileStreamBuf::NativeHandle FileStreamBuf::nativeHandle() const { return _handle; diff --git a/Foundation/src/LogFile.cpp b/Foundation/src/LogFile.cpp index 5380110fda..be3b12a605 100644 --- a/Foundation/src/LogFile.cpp +++ b/Foundation/src/LogFile.cpp @@ -13,25 +13,98 @@ #include "Poco/LogFile.h" +#include "Poco/File.h" +#include "Poco/Exception.h" + +namespace Poco { + + +LogFile::LogFile(const std::string& path): + _path(path), + _str(_path, std::ios::app), + _size(static_cast(_str.tellp())) +{ + // There seems to be a strange "optimization" in the Windows NTFS + // filesystem that causes it to reuse directory entries of deleted + // files. Example: + // 1. create a file named "test.dat" + // note the file's creation date + // 2. delete the file "test.dat" + // 3. wait a few seconds + // 4. create a file named "test.dat" + // the new file will have the same creation + // date as the old one. + // We work around this bug by taking the file's + // modification date as a reference when the + // file is empty. + if (_size == 0) + _creationDate = File(path).getLastModified(); + else + _creationDate = File(path).created(); +} +LogFile::~LogFile() +{ +} + + +void LogFile::write(const std::string& text, bool flush) +{ + std::streampos pos = _str.tellp(); + #if defined(POCO_OS_FAMILY_WINDOWS) -#include "LogFile_WIN32U.cpp" + // Replace \n with \r\n + std::string logText; + logText.reserve(text.size() + 16); // keep some reserve for \n -> \r\n + char prevChar = 0; + for (char c: text) + { + if (c == '\n' && prevChar != '\r') + logText += POCO_DEFAULT_NEWLINE_CHARS; + else + logText += c; + + prevChar = c; + } + _str << logText; #else -#include "LogFile_STD.cpp" + _str << text; #endif + _str << POCO_DEFAULT_NEWLINE_CHARS; -namespace Poco { + if (flush) + _str.flushToDisk(); + else + _str.flush(); + + if (!_str.good()) + { + _str.clear(); + _str.seekp(pos); + throw WriteFileException(_path); + } + + _size = static_cast(_str.tellp()); +} -LogFile::LogFile(const std::string& path): LogFileImpl(path) +UInt64 LogFile::size() const { + return _size; } -LogFile::~LogFile() +Timestamp LogFile::creationDate() const +{ + return _creationDate; +} + + +const std::string& LogFile::path() const { + return _path; } diff --git a/Foundation/src/LogFile_STD.cpp b/Foundation/src/LogFile_STD.cpp deleted file mode 100644 index e5c6587425..0000000000 --- a/Foundation/src/LogFile_STD.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// -// LogFile_STD.cpp -// -// Library: Foundation -// Package: Logging -// Module: LogFile -// -// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// SPDX-License-Identifier: BSL-1.0 -// - - -#include "Poco/LogFile_STD.h" -#include "Poco/File.h" -#include "Poco/Exception.h" - -#include - -namespace Poco { - - -LogFileImpl::LogFileImpl(const std::string& path): - _path(path), - _str(_path, std::ios::app), - _size(static_cast(_str.tellp())) -{ - if (_size == 0) - _creationDate = File(path).getLastModified(); - else - _creationDate = File(path).created(); -} - - -LogFileImpl::~LogFileImpl() -{ -} - - -void LogFileImpl::writeImpl(const std::string& text, bool flush) -{ - std::streampos pos = _str.tellp(); - - _str << text << '\n'; - - // Flush the stream buffer to file to match the implementation on Windows - _str.flush(); - - if (!_str.good()) - { - _str.clear(); - _str.seekp(pos); - throw WriteFileException(_path); - } - - if (flush) - { - // Sync the file to disk as it is done on Windows - if (fsync(_str.nativeHandle()) != 0) - throw WriteFileException(_path); - } - - _size = static_cast(_str.tellp()); -} - - -UInt64 LogFileImpl::sizeImpl() const -{ - return _size; -} - - -Timestamp LogFileImpl::creationDateImpl() const -{ - return _creationDate; -} - - -const std::string& LogFileImpl::pathImpl() const -{ - return _path; -} - - -} // namespace Poco diff --git a/Foundation/src/LogFile_WIN32U.cpp b/Foundation/src/LogFile_WIN32U.cpp deleted file mode 100644 index 2930310727..0000000000 --- a/Foundation/src/LogFile_WIN32U.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// -// LogFile_WIN32U.cpp -// -// Library: Foundation -// Package: Logging -// Module: LogFile -// -// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// SPDX-License-Identifier: BSL-1.0 -// - - -#include "Poco/LogFile_WIN32U.h" -#include "Poco/File.h" -#include "Poco/Exception.h" -#include "Poco/UnicodeConverter.h" - -// TODO: LogStream shall use FileOutputStream for all implementations (see LogStream_STD) -// TODO: Implement flushToDisk function in FileOutputStream. - -namespace Poco { - - -LogFileImpl::LogFileImpl(const std::string& path): _path(path), _hFile(INVALID_HANDLE_VALUE) -{ - File file(path); - if (file.exists()) - { - if (0 == sizeImpl()) - _creationDate = file.getLastModified(); - else - _creationDate = file.created(); - } -} - - -LogFileImpl::~LogFileImpl() -{ - CloseHandle(_hFile); -} - - -void LogFileImpl::writeImpl(const std::string& text, bool flush) -{ - if (INVALID_HANDLE_VALUE == _hFile) createFile(); - - std::string logText; - logText.reserve(text.size() + 16); // keep some reserve for \n -> \r\n and terminating \r\n - for (char c: text) - { - if (c == '\n') - logText += "\r\n"; - else - logText += c; - } - logText += "\r\n"; - - DWORD bytesWritten; - BOOL res = WriteFile(_hFile, logText.data(), static_cast(logText.size()), &bytesWritten, NULL); - if (!res) throw WriteFileException(_path); - if (flush) - { - res = FlushFileBuffers(_hFile); - if (!res) throw WriteFileException(_path); - } -} - - -UInt64 LogFileImpl::sizeImpl() const -{ - if (INVALID_HANDLE_VALUE == _hFile) - { - File file(_path); - if (file.exists()) return file.getSize(); - else return 0; - } - - LARGE_INTEGER li; - li.HighPart = 0; - li.LowPart = SetFilePointer(_hFile, 0, &li.HighPart, FILE_CURRENT); - return li.QuadPart; -} - - -Timestamp LogFileImpl::creationDateImpl() const -{ - return _creationDate; -} - - -const std::string& LogFileImpl::pathImpl() const -{ - return _path; -} - - -void LogFileImpl::createFile() -{ - std::wstring upath; - FileImpl::convertPath(_path, upath); - - _hFile = CreateFileW(upath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (_hFile == INVALID_HANDLE_VALUE) throw OpenFileException(_path); - SetFilePointer(_hFile, 0, 0, FILE_END); - // There seems to be a strange "optimization" in the Windows NTFS - // filesystem that causes it to reuse directory entries of deleted - // files. Example: - // 1. create a file named "test.dat" - // note the file's creation date - // 2. delete the file "test.dat" - // 3. wait a few seconds - // 4. create a file named "test.dat" - // the new file will have the same creation - // date as the old one. - // We work around this bug by taking the file's - // modification date as a reference when the - // file is empty. - if (sizeImpl() == 0) - _creationDate = File(_path).getLastModified(); - else - _creationDate = File(_path).created(); -} - - -} // namespace Poco diff --git a/Foundation/src/URI.cpp b/Foundation/src/URI.cpp index e64629fb21..bc7582b489 100644 --- a/Foundation/src/URI.cpp +++ b/Foundation/src/URI.cpp @@ -857,7 +857,8 @@ void URI::parseHostAndPort(std::string::const_iterator& it, const std::string::c } else _port = 0; _host = host; - toLowerInPlace(_host); + if (_host.size() && _host[0] != '%') + toLowerInPlace(_host); } diff --git a/Foundation/testsuite/src/MemoryStreamTest.cpp b/Foundation/testsuite/src/MemoryStreamTest.cpp index f3c6ff30cc..529f4c7f1a 100644 --- a/Foundation/testsuite/src/MemoryStreamTest.cpp +++ b/Foundation/testsuite/src/MemoryStreamTest.cpp @@ -143,6 +143,14 @@ void MemoryStreamTest::testInputSeek() assertTrue (istr.good()); assertTrue (9 == istr.tellg()); + + istr.seekg(5); + assertTrue (istr.good()); + assertTrue (5 == istr.tellg()); + istr >> c; + assertTrue (c == '6'); + + { Poco::MemoryInputStream istr2(buffer.begin(), buffer.size()); istr2.seekg(10, std::ios_base::beg); @@ -337,6 +345,12 @@ void MemoryStreamTest::testOutputSeek() assertTrue (ostr.good()); assertTrue (9 == ostr.tellp()); + + ostr.seekp(5); + assertTrue (ostr.good()); + assertTrue (5 == ostr.tellp()); + + { Poco::MemoryOutputStream ostr2(buffer.begin(), buffer.size()); ostr2.seekp(10, std::ios_base::beg); diff --git a/Foundation/testsuite/src/URITest.cpp b/Foundation/testsuite/src/URITest.cpp index e835b377b7..4008bdbeee 100644 --- a/Foundation/testsuite/src/URITest.cpp +++ b/Foundation/testsuite/src/URITest.cpp @@ -798,6 +798,15 @@ void URITest::testOther() assertTrue (uri.getRawFragment() == "foo%2Fbar"); assertTrue (uri.toString() == "http://google.com/search?q=hello+world#foo%2Fbar"); assertTrue (uri.getPathEtc() == "/search?q=hello+world#foo%2Fbar"); + + uri = "http://ServerSocket.com/index.html"; + assertTrue (uri.toString() == "http://serversocket.com/index.html"); + + uri = "http+unix://%2Ftmp%2FServerSocket/index.html"; + assertTrue (uri.toString() == "http+unix://%2Ftmp%2FServerSocket/index.html"); + std::string decoded; + uri.decode("http+unix://%2Ftmp%2FServerSocket/index.html", decoded); + assertTrue (decoded == "http+unix:///tmp/ServerSocket/index.html"); } diff --git a/Net/include/Poco/Net/DatagramSocket.h b/Net/include/Poco/Net/DatagramSocket.h index cd5fa113e7..8c3d69aaf4 100644 --- a/Net/include/Poco/Net/DatagramSocket.h +++ b/Net/include/Poco/Net/DatagramSocket.h @@ -129,7 +129,7 @@ class Net_API DatagramSocket: public Socket /// If reuseAddress is true, sets the SO_REUSEADDR /// socket option. /// - /// Calls to connect cannot() come before calls to bind(). + /// Calls to connect() cannot come before calls to bind(). void bind(const SocketAddress& address, bool reuseAddress, bool reusePort); /// Bind a local address to the socket. @@ -143,7 +143,7 @@ class Net_API DatagramSocket: public Socket /// If reusePort is true, sets the SO_REUSEPORT /// socket option. /// - /// Calls to connect cannot() come before calls to bind(). + /// Calls to connect() cannot come before calls to bind(). void bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only = false); /// Bind a local address to the socket. @@ -160,7 +160,7 @@ class Net_API DatagramSocket: public Socket /// Sets the IPV6_V6ONLY socket option in accordance with /// the supplied ipV6Only value. /// - /// Calls to connect cannot() come before calls to bind(). + /// Calls to connect() cannot come before calls to bind(). int sendBytes(const void* buffer, int length, int flags = 0); /// Sends the contents of the given buffer through diff --git a/Net/include/Poco/Net/Socket.h b/Net/include/Poco/Net/Socket.h index 331657aebc..2817150413 100644 --- a/Net/include/Poco/Net/Socket.h +++ b/Net/include/Poco/Net/Socket.h @@ -216,7 +216,7 @@ class Net_API Socket /// as the system is free to adjust the value. void setReceiveTimeout(const Poco::Timespan& timeout); - /// Sets the send timeout for the socket. + /// Sets the receive timeout for the socket. /// /// On systems that do not support SO_RCVTIMEO, a /// workaround using poll() is provided. diff --git a/Net/src/SocketImpl.cpp b/Net/src/SocketImpl.cpp index 68310f9300..34cad7d074 100644 --- a/Net/src/SocketImpl.cpp +++ b/Net/src/SocketImpl.cpp @@ -147,7 +147,7 @@ SocketImpl* SocketImpl::acceptConnection(SocketAddress& clientAddr) return new StreamSocketImpl(sd); } error(); // will throw - return 0; + return nullptr; } @@ -527,7 +527,7 @@ int SocketImpl::sendTo(const SocketBufVec& buffers, const SocketAddress& address msgHdr.msg_namelen = address.length(); msgHdr.msg_iov = const_cast(&buffers[0]); msgHdr.msg_iovlen = buffers.size(); - msgHdr.msg_control = 0; + msgHdr.msg_control = nullptr; msgHdr.msg_controllen = 0; msgHdr.msg_flags = flags; rc = sendmsg(_sockfd, &msgHdr, flags); @@ -613,7 +613,7 @@ int SocketImpl::receiveFrom(SocketBufVec& buffers, struct sockaddr** pSA, poco_s msgHdr.msg_namelen = **ppSALen; msgHdr.msg_iov = &buffers[0]; msgHdr.msg_iovlen = buffers.size(); - msgHdr.msg_control = 0; + msgHdr.msg_control = nullptr; msgHdr.msg_controllen = 0; msgHdr.msg_flags = flags; rc = recvmsg(_sockfd, &msgHdr, flags); @@ -652,7 +652,7 @@ int SocketImpl::available() if (result && (type() == SOCKET_TYPE_DATAGRAM)) { std::vector buf(result); - result = recvfrom(sockfd(), &buf[0], result, MSG_PEEK, NULL, NULL); + result = recvfrom(sockfd(), &buf[0], result, MSG_PEEK, nullptr, nullptr); } #endif return result; @@ -1114,7 +1114,7 @@ void SocketImpl::setReusePort(bool flag) int value = flag ? 1 : 0; setOption(SOL_SOCKET, SO_REUSEPORT, value); } - catch (IOException&) + catch (const IOException&) { // ignore error, since not all implementations // support SO_REUSEPORT, even if the macro diff --git a/NetSSL_OpenSSL/include/Poco/Net/SecureStreamSocket.h b/NetSSL_OpenSSL/include/Poco/Net/SecureStreamSocket.h index 016757beaf..4e228b6a40 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/SecureStreamSocket.h +++ b/NetSSL_OpenSSL/include/Poco/Net/SecureStreamSocket.h @@ -132,7 +132,7 @@ class NetSSL_API SecureStreamSocket: public StreamSocket /// a SecureStreamSocketImpl, otherwise an InvalidArgumentException /// will be thrown. - virtual ~SecureStreamSocket(); + ~SecureStreamSocket() override; /// Destroys the StreamSocket. SecureStreamSocket& operator = (const Socket& socket); diff --git a/NetSSL_OpenSSL/include/Poco/Net/SecureStreamSocketImpl.h b/NetSSL_OpenSSL/include/Poco/Net/SecureStreamSocketImpl.h index 8114b036f3..1327a67cd0 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/SecureStreamSocketImpl.h +++ b/NetSSL_OpenSSL/include/Poco/Net/SecureStreamSocketImpl.h @@ -39,12 +39,12 @@ class NetSSL_API SecureStreamSocketImpl: public StreamSocketImpl SecureStreamSocketImpl(StreamSocketImpl* pStreamSocket, Context::Ptr pContext); /// Creates the SecureStreamSocketImpl. - SocketImpl* acceptConnection(SocketAddress& clientAddr); + SocketImpl* acceptConnection(SocketAddress& clientAddr) override; /// Not supported by a SecureStreamSocket. /// /// Throws a Poco::InvalidAccessException. - void connect(const SocketAddress& address); + void connect(const SocketAddress& address) override; /// Initializes the socket and establishes a connection to /// the TCP server at the given address. /// @@ -52,57 +52,57 @@ class NetSSL_API SecureStreamSocketImpl: public StreamSocketImpl /// connection is established. Instead, incoming and outgoing /// packets are restricted to the specified address. - void connect(const SocketAddress& address, const Poco::Timespan& timeout); + void connect(const SocketAddress& address, const Poco::Timespan& timeout) override; /// Initializes the socket, sets the socket timeout and /// establishes a connection to the TCP server at the given address. - void connectNB(const SocketAddress& address); + void connectNB(const SocketAddress& address) override; /// Initializes the socket and establishes a connection to /// the TCP server at the given address. Prior to opening the /// connection the socket is set to nonblocking mode. - void bind(const SocketAddress& address, bool reuseAddress = false); + void bind(const SocketAddress& address, bool reuseAddress = false) override; /// Not supported by a SecureStreamSocket. /// /// Throws a Poco::InvalidAccessException. - void listen(int backlog = 64); + void listen(int backlog = 64) override; /// Not supported by a SecureStreamSocket. /// /// Throws a Poco::InvalidAccessException. - void close(); + void close() override; /// Close the socket. - int sendBytes(const void* buffer, int length, int flags = 0); + int sendBytes(const void* buffer, int length, int flags = 0) override; /// Sends the contents of the given buffer through /// the socket. Any specified flags are ignored. /// /// Returns the number of bytes sent, which may be /// less than the number of bytes specified. - int receiveBytes(void* buffer, int length, int flags = 0); + int receiveBytes(void* buffer, int length, int flags = 0) override; /// Receives data from the socket and stores it /// in buffer. Up to length bytes are received. /// /// Returns the number of bytes received. - int sendTo(const void* buffer, int length, const SocketAddress& address, int flags = 0); + int sendTo(const void* buffer, int length, const SocketAddress& address, int flags = 0) override; /// Not supported by a SecureStreamSocket. /// /// Throws a Poco::InvalidAccessException. - int receiveFrom(void* buffer, int length, SocketAddress& address, int flags = 0); + int receiveFrom(void* buffer, int length, SocketAddress& address, int flags = 0) override; /// Not supported by a SecureStreamSocket. /// /// Throws a Poco::InvalidAccessException. - void sendUrgent(unsigned char data); + void sendUrgent(unsigned char data) override; /// Not supported by a SecureStreamSocket. /// /// Throws a Poco::InvalidAccessException. - int available(); + int available() override; /// Returns the number of bytes available that can be read /// without causing the socket to block. /// @@ -110,26 +110,26 @@ class NetSSL_API SecureStreamSocketImpl: public StreamSocketImpl /// can be read from the currently buffered SSL record, /// before a new record is read from the underlying socket. - void shutdownReceive(); + void shutdownReceive() override; /// Shuts down the receiving part of the socket connection. /// /// Since SSL does not support a half shutdown, this does /// nothing. - void shutdownSend(); + void shutdownSend() override; /// Shuts down the receiving part of the socket connection. /// /// Since SSL does not support a half shutdown, this does /// nothing. - void shutdown(); + void shutdown() override; /// Shuts down the SSL connection. void abort(); /// Aborts the connection by closing the underlying /// TCP connection. No orderly SSL shutdown is performed. - bool secure() const; + bool secure() const override; /// Returns true iff the socket's connection is secure /// (using SSL or TLS). @@ -203,7 +203,7 @@ class NetSSL_API SecureStreamSocketImpl: public StreamSocketImpl void connectSSL(); /// Performs a SSL client-side handshake on an already connected TCP socket. - ~SecureStreamSocketImpl(); + ~SecureStreamSocketImpl() override; /// Destroys the SecureStreamSocketImpl. static int lastError(); diff --git a/NetSSL_OpenSSL/src/SecureSocketImpl.cpp b/NetSSL_OpenSSL/src/SecureSocketImpl.cpp index 911c0dea0a..55c163f142 100644 --- a/NetSSL_OpenSSL/src/SecureSocketImpl.cpp +++ b/NetSSL_OpenSSL/src/SecureSocketImpl.cpp @@ -22,10 +22,7 @@ #include "Poco/Net/SecureStreamSocketImpl.h" #include "Poco/Net/StreamSocketImpl.h" #include "Poco/Net/StreamSocket.h" -#include "Poco/Net/NetException.h" -#include "Poco/Net/DNS.h" #include "Poco/NumberFormatter.h" -#include "Poco/NumberParser.h" #include "Poco/Format.h" #include #include @@ -38,16 +35,12 @@ using Poco::NumberFormatter; using Poco::Timespan; -// workaround for C++-incompatible macro -#define POCO_BIO_set_nbio_accept(b,n) BIO_ctrl(b,BIO_C_SET_ACCEPT,1,(void*)((n)?"a":NULL)) - - namespace Poco { namespace Net { SecureSocketImpl::SecureSocketImpl(Poco::AutoPtr pSocketImpl, Context::Ptr pContext): - _pSSL(0), + _pSSL(nullptr), _pSocket(pSocketImpl), _pContext(pContext), _needHandshake(false) @@ -86,14 +79,14 @@ void SecureSocketImpl::acceptSSL() { poco_assert (!_pSSL); - BIO* pBIO = BIO_new(BIO_s_socket()); + BIO* pBIO = ::BIO_new(BIO_s_socket()); if (!pBIO) throw SSLException("Cannot create BIO object"); BIO_set_fd(pBIO, static_cast(_pSocket->sockfd()), BIO_NOCLOSE); - _pSSL = SSL_new(_pContext->sslContext()); + _pSSL = ::SSL_new(_pContext->sslContext()); if (!_pSSL) { - BIO_free(pBIO); + ::BIO_free(pBIO); throw SSLException("Cannot create SSL object"); } @@ -105,15 +98,15 @@ void SecureSocketImpl::acceptSSL() * tickets. */ if (1 != SSL_set_num_tickets(_pSSL, 0)) { - BIO_free(pBIO); + ::BIO_free(pBIO); throw SSLException("Cannot create SSL object"); } //Otherwise we can perform two-way shutdown. Client must call SSL_read() before the final SSL_shutdown(). #endif - SSL_set_bio(_pSSL, pBIO, pBIO); - SSL_set_accept_state(_pSSL); - SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), this); + ::SSL_set_bio(_pSSL, pBIO, pBIO); + ::SSL_set_accept_state(_pSSL); + ::SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), this); _needHandshake = true; } @@ -162,18 +155,18 @@ void SecureSocketImpl::connectSSL(bool performHandshake) poco_assert (!_pSSL); poco_assert (_pSocket->initialized()); - BIO* pBIO = BIO_new(BIO_s_socket()); + ::BIO* pBIO = ::BIO_new(BIO_s_socket()); if (!pBIO) throw SSLException("Cannot create SSL BIO object"); BIO_set_fd(pBIO, static_cast(_pSocket->sockfd()), BIO_NOCLOSE); - _pSSL = SSL_new(_pContext->sslContext()); + _pSSL = ::SSL_new(_pContext->sslContext()); if (!_pSSL) { - BIO_free(pBIO); + ::BIO_free(pBIO); throw SSLException("Cannot create SSL object"); } - SSL_set_bio(_pSSL, pBIO, pBIO); - SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), this); + ::SSL_set_bio(_pSSL, pBIO, pBIO); + ::SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), this); if (!_peerHostName.empty()) { @@ -189,27 +182,27 @@ void SecureSocketImpl::connectSSL(bool performHandshake) if (_pSession && _pSession->isResumable()) { - SSL_set_session(_pSSL, _pSession->sslSession()); + ::SSL_set_session(_pSSL, _pSession->sslSession()); } try { if (performHandshake && _pSocket->getBlocking()) { - int ret = SSL_connect(_pSSL); + int ret = ::SSL_connect(_pSSL); handleError(ret); verifyPeerCertificate(); } else { - SSL_set_connect_state(_pSSL); + ::SSL_set_connect_state(_pSSL); _needHandshake = true; } } catch (...) { - SSL_free(_pSSL); - _pSSL = 0; + ::SSL_free(_pSSL); + _pSSL = nullptr; throw; } } @@ -259,11 +252,11 @@ void SecureSocketImpl::shutdown() { if (_pSSL) { - // Don't shut down the socket more than once. - int shutdownState = SSL_get_shutdown(_pSSL); - bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN; - if (!shutdownSent) - { + // Don't shut down the socket more than once. + int shutdownState = ::SSL_get_shutdown(_pSSL); + bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN; + if (!shutdownSent) + { // A proper clean shutdown would require us to // retry the shutdown if we get a zero return // value, until SSL_shutdown() returns 1. @@ -274,7 +267,7 @@ void SecureSocketImpl::shutdown() #if OPENSSL_VERSION_NUMBER >= 0x30000000L int rc = 0; if (!_bidirectShutdown) - rc = SSL_shutdown(_pSSL); + rc = ::SSL_shutdown(_pSSL); else { Poco::Timespan recvTimeout = _pSocket->getReceiveTimeout(); @@ -282,11 +275,11 @@ void SecureSocketImpl::shutdown() Poco::Timestamp tsNow; do { - rc = SSL_shutdown(_pSSL); + rc = ::SSL_shutdown(_pSSL); if (rc == 1) break; if (rc < 0) { - int err = SSL_get_error(_pSSL, rc); + int err = ::SSL_get_error(_pSSL, rc); if (err == SSL_ERROR_WANT_READ) _pSocket->poll(pollTimeout, Poco::Net::Socket::SELECT_READ); else if (err == SSL_ERROR_WANT_WRITE) @@ -294,7 +287,7 @@ void SecureSocketImpl::shutdown() else { int socketError = SocketImpl::lastError(); - long lastError = ERR_get_error(); + long lastError = ::ERR_get_error(); if ((err == SSL_ERROR_SSL) && (socketError == 0) && (lastError == 0x0A000123)) rc = 0; break; @@ -304,7 +297,7 @@ void SecureSocketImpl::shutdown() } while (!tsNow.isElapsed(recvTimeout.totalMicroseconds())); } #else - int rc = SSL_shutdown(_pSSL); + int rc = ::SSL_shutdown(_pSSL); #endif if (rc < 0) handleError(rc); if (_pSocket->getBlocking()) @@ -361,11 +354,17 @@ int SecureSocketImpl::sendBytes(const void* buffer, int length, int flags) else return rc; } - do + const auto sendTimeout = _pSocket->getSendTimeout(); + Poco::Timestamp tsStart; + while (true) { - rc = SSL_write(_pSSL, buffer, length); - } - while (mustRetry(rc)); + rc = ::SSL_write(_pSSL, buffer, length); + if (!mustRetry(rc)) + break; + + if (tsStart.isElapsed(sendTimeout.totalMicroseconds())) + throw Poco::TimeoutException(); + }; if (rc <= 0) { rc = handleError(rc); @@ -389,11 +388,18 @@ int SecureSocketImpl::receiveBytes(void* buffer, int length, int flags) else return rc; } - do + + const auto recvTimeout = _pSocket->getReceiveTimeout(); + Poco::Timestamp tsStart; + while (true) { - rc = SSL_read(_pSSL, buffer, length); - } - while (mustRetry(rc)); + rc = ::SSL_read(_pSSL, buffer, length); + if (!mustRetry(rc)) + break; + + if (tsStart.isElapsed(recvTimeout.totalMicroseconds())) + throw Poco::TimeoutException(); + }; _bidirectShutdown = false; if (rc <= 0) { @@ -407,7 +413,7 @@ int SecureSocketImpl::available() const { poco_check_ptr (_pSSL); - return SSL_pending(_pSSL); + return ::SSL_pending(_pSSL); } @@ -417,11 +423,17 @@ int SecureSocketImpl::completeHandshake() poco_check_ptr (_pSSL); int rc; - do + const auto recvTimeout = _pSocket->getReceiveTimeout(); + Poco::Timestamp tsStart; + while (true) { - rc = SSL_do_handshake(_pSSL); - } - while (mustRetry(rc)); + rc = ::SSL_do_handshake(_pSSL); + if (!mustRetry(rc)) + break; + + if (tsStart.isElapsed(recvTimeout.totalMicroseconds())) + throw Poco::TimeoutException(); + }; if (rc <= 0) { return handleError(rc); @@ -460,7 +472,7 @@ long SecureSocketImpl::verifyPeerCertificateImpl(const std::string& hostName) return X509_V_OK; } - X509* pCert = SSL_get_peer_certificate(_pSSL); + ::X509* pCert = ::SSL_get_peer_certificate(_pSSL); if (pCert) { X509Certificate cert(pCert); @@ -477,7 +489,7 @@ bool SecureSocketImpl::isLocalHost(const std::string& hostName) SocketAddress addr(hostName, 0); return addr.host().isLoopback(); } - catch (Poco::Exception&) + catch (const Poco::Exception&) { return false; } @@ -487,9 +499,9 @@ bool SecureSocketImpl::isLocalHost(const std::string& hostName) X509* SecureSocketImpl::peerCertificate() const { if (_pSSL) - return SSL_get_peer_certificate(_pSSL); + return ::SSL_get_peer_certificate(_pSSL); else - return 0; + return nullptr; } @@ -497,26 +509,24 @@ bool SecureSocketImpl::mustRetry(int rc) { if (rc <= 0) { - int sslError = SSL_get_error(_pSSL, rc); + static const Poco::Timespan pollTimeout(0, 100000); + + int sslError = ::SSL_get_error(_pSSL, rc); int socketError = _pSocket->lastError(); switch (sslError) { case SSL_ERROR_WANT_READ: if (_pSocket->getBlocking()) { - if (_pSocket->poll(_pSocket->getReceiveTimeout(), Poco::Net::Socket::SELECT_READ)) - return true; - else - throw Poco::TimeoutException(); + _pSocket->poll(pollTimeout, Poco::Net::Socket::SELECT_READ); + return true; } break; case SSL_ERROR_WANT_WRITE: if (_pSocket->getBlocking()) { - if (_pSocket->poll(_pSocket->getSendTimeout(), Poco::Net::Socket::SELECT_WRITE)) - return true; - else - throw Poco::TimeoutException(); + _pSocket->poll(pollTimeout, Poco::Net::Socket::SELECT_WRITE); + return true; } break; case SSL_ERROR_SYSCALL: @@ -533,7 +543,7 @@ int SecureSocketImpl::handleError(int rc) { if (rc > 0) return rc; - int sslError = SSL_get_error(_pSSL, rc); + int sslError = ::SSL_get_error(_pSSL, rc); int socketError = SocketImpl::lastError(); switch (sslError) @@ -569,12 +579,12 @@ int SecureSocketImpl::handleError(int rc) // fallthrough default: { - long lastError = ERR_get_error(); + long lastError = ::ERR_get_error(); std::string msg; if (lastError) { char buffer[256]; - ERR_error_string_n(lastError, buffer, sizeof(buffer)); + ::ERR_error_string_n(lastError, buffer, sizeof(buffer)); msg = buffer; } // SSL_GET_ERROR(3ossl): @@ -627,9 +637,9 @@ void SecureSocketImpl::reset() close(); if (_pSSL) { - SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), nullptr); - SSL_free(_pSSL); - _pSSL = 0; + ::SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), nullptr); + ::SSL_free(_pSSL); + _pSSL = nullptr; } } @@ -655,7 +665,7 @@ void SecureSocketImpl::useSession(Session::Ptr pSession) bool SecureSocketImpl::sessionWasReused() { if (_pSSL) - return SSL_session_reused(_pSSL) != 0; + return ::SSL_session_reused(_pSSL) != 0; else return false; } @@ -663,7 +673,7 @@ bool SecureSocketImpl::sessionWasReused() int SecureSocketImpl::onSessionCreated(SSL* pSSL, SSL_SESSION* pSession) { - void* pEx = SSL_get_ex_data(pSSL, SSLManager::instance().socketIndex()); + void* pEx = ::SSL_get_ex_data(pSSL, SSLManager::instance().socketIndex()); if (pEx) { SecureSocketImpl* pThis = reinterpret_cast(pEx); diff --git a/NetSSL_OpenSSL/testsuite/src/HTTPSStreamFactoryTest.cpp b/NetSSL_OpenSSL/testsuite/src/HTTPSStreamFactoryTest.cpp index ab2003c50b..b707febcf1 100644 --- a/NetSSL_OpenSSL/testsuite/src/HTTPSStreamFactoryTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/HTTPSStreamFactoryTest.cpp @@ -103,7 +103,7 @@ void HTTPSStreamFactoryTest::testError() uri.setPort(server.port()); try { - std::istream* pStr = factory.open(uri); + factory.open(uri); fail("not found - must throw"); } catch (HTTPException& exc) diff --git a/NetSSL_OpenSSL/testsuite/src/WebSocketTest.cpp b/NetSSL_OpenSSL/testsuite/src/WebSocketTest.cpp index eeb47c4234..284c332977 100644 --- a/NetSSL_OpenSSL/testsuite/src/WebSocketTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/WebSocketTest.cpp @@ -23,7 +23,6 @@ #include "Poco/Net/SecureServerSocket.h" #include "Poco/Net/NetException.h" #include "Poco/Thread.h" -#include using Poco::Net::HTTPSClientSession; using Poco::Net::HTTPRequest; @@ -55,13 +54,14 @@ namespace do { n = ws.receiveFrame(pBuffer.get(), static_cast(_bufSize), flags); + Poco::Thread::current()->sleep(handleDelay.totalMilliseconds()); if (n == 0) break; ws.sendFrame(pBuffer.get(), n, flags); } while ((flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE); } - catch (WebSocketException& exc) + catch (const WebSocketException& exc) { switch (exc.code()) { @@ -79,10 +79,17 @@ namespace } } + public: + + static Poco::Timespan handleDelay; + private: std::size_t _bufSize; }; + Poco::Timespan WebSocketRequestHandler::handleDelay {0}; + + class WebSocketRequestHandlerFactory: public Poco::Net::HTTPRequestHandlerFactory { public: @@ -90,7 +97,7 @@ namespace { } - Poco::Net::HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request) + Poco::Net::HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request) override { return new WebSocketRequestHandler(_bufSize); } @@ -111,6 +118,46 @@ WebSocketTest::~WebSocketTest() } +void WebSocketTest::testWebSocketTimeout() +{ + Poco::Net::SecureServerSocket ss(0); + Poco::Net::HTTPServer server(new WebSocketRequestHandlerFactory, ss, new Poco::Net::HTTPServerParams); + server.start(); + + Poco::Thread::sleep(200); + + HTTPSClientSession cs("127.0.0.1", ss.address().port()); + HTTPRequest request(HTTPRequest::HTTP_GET, "/ws"); + HTTPResponse response; + WebSocket ws(cs, request, response); + ws.setSendTimeout( Poco::Timespan(2, 0)); + ws.setReceiveTimeout( Poco::Timespan(2, 0)); + + Poco::Timestamp sendStart; + char buffer[1024] = {}; + int flags; + try + { + // Server will take long to process and cause WS timeout + WebSocketRequestHandler::handleDelay.assign(3, 0); + + std::string payload("x"); + ws.sendFrame(payload.data(), (int) payload.size()); + ws.receiveFrame(buffer, sizeof(buffer), flags); + + failmsg("Data exchange shall time out."); + } + catch (const Poco::TimeoutException& te) + { + assertTrue(sendStart.elapsed() < Poco::Timespan(4, 0).totalMicroseconds()); + } + + ws.shutdown(); + ws.receiveFrame(buffer, sizeof(buffer), flags); + server.stop(); +} + + void WebSocketTest::testWebSocket() { Poco::Net::SecureServerSocket ss(0); @@ -227,6 +274,7 @@ CppUnit::Test* WebSocketTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("WebSocketTest"); CppUnit_addTest(pSuite, WebSocketTest, testWebSocket); + CppUnit_addTest(pSuite, WebSocketTest, testWebSocketTimeout); CppUnit_addTest(pSuite, WebSocketTest, testWebSocketLarge); return pSuite; diff --git a/NetSSL_OpenSSL/testsuite/src/WebSocketTest.h b/NetSSL_OpenSSL/testsuite/src/WebSocketTest.h index 87d943da7c..f8ea9131c6 100644 --- a/NetSSL_OpenSSL/testsuite/src/WebSocketTest.h +++ b/NetSSL_OpenSSL/testsuite/src/WebSocketTest.h @@ -22,13 +22,14 @@ class WebSocketTest: public CppUnit::TestCase { public: WebSocketTest(const std::string& name); - ~WebSocketTest(); + ~WebSocketTest() override; + void testWebSocketTimeout(); void testWebSocket(); void testWebSocketLarge(); - void setUp(); - void tearDown(); + void setUp() override; + void tearDown() override; static CppUnit::Test* suite(); diff --git a/Util/include/Poco/Util/Timer.h b/Util/include/Poco/Util/Timer.h index d41a88ead5..b6bd14a854 100644 --- a/Util/include/Poco/Util/Timer.h +++ b/Util/include/Poco/Util/Timer.h @@ -159,6 +159,9 @@ class Util_API Timer: protected Poco::Runnable /// If task execution takes longer than the given interval, /// further executions are delayed. + bool idle() const; + /// Returns true if the task queue is empty, otherwise false. + template static TimerTask::Ptr func(const Fn& fn) /// Helper function template to use a functor or lambda @@ -188,6 +191,15 @@ class Util_API Timer: protected Poco::Runnable }; +// +// inlines +// +inline bool Timer::idle() const +{ + return _queue.empty(); +} + + } } // namespace Poco::Util diff --git a/Util/testsuite/src/TimerTest.cpp b/Util/testsuite/src/TimerTest.cpp index b5551bdb3f..f3ba220f48 100644 --- a/Util/testsuite/src/TimerTest.cpp +++ b/Util/testsuite/src/TimerTest.cpp @@ -314,6 +314,28 @@ void TimerTest::testFunc() } +void TimerTest::testIdle() +{ + Timer timer; + + assertTrue (timer.idle()); + + Timestamp time; + time += 1000000; + + TimerTask::Ptr pTask = new TimerTaskAdapter(*this, &TimerTest::onTimer); + + timer.schedule(pTask, time); + + assertFalse (timer.idle()); + + _event.wait(); + assertTrue (pTask->lastExecution() >= time); + + assertTrue (timer.idle()); +} + + void TimerTest::setUp() { } @@ -346,6 +368,7 @@ CppUnit::Test* TimerTest::suite() CppUnit_addTest(pSuite, TimerTest, testCancelAllWaitStop); CppUnit_addTest(pSuite, TimerTest, testMultiCancelAllWaitStop); CppUnit_addTest(pSuite, TimerTest, testFunc); + CppUnit_addTest(pSuite, TimerTest, testIdle); return pSuite; } diff --git a/Util/testsuite/src/TimerTest.h b/Util/testsuite/src/TimerTest.h index b88366fd7d..825c5b9b42 100644 --- a/Util/testsuite/src/TimerTest.h +++ b/Util/testsuite/src/TimerTest.h @@ -37,6 +37,7 @@ class TimerTest: public CppUnit::TestCase void testCancelAllWaitStop(); void testMultiCancelAllWaitStop(); void testFunc(); + void testIdle(); void setUp(); void tearDown(); diff --git a/XML/include/Poco/XML/expat.h b/XML/include/Poco/XML/expat.h index 95464b0dd1..c2770be389 100644 --- a/XML/include/Poco/XML/expat.h +++ b/XML/include/Poco/XML/expat.h @@ -18,6 +18,7 @@ Copyright (c) 2022 Thijs Schreijer Copyright (c) 2023 Hanno Böck Copyright (c) 2023 Sony Corporation / Snild Dolkow + Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -1042,7 +1043,7 @@ typedef struct { XMLPARSEAPI(const XML_Feature *) XML_GetFeatureList(void); -#if XML_GE == 1 +#if defined(XML_DTD) || (defined(XML_GE) && XML_GE == 1) /* Added in Expat 2.4.0 for XML_DTD defined and * added in Expat 2.6.0 for XML_GE == 1. */ XMLPARSEAPI(XML_Bool) @@ -1065,7 +1066,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled); */ #define XML_MAJOR_VERSION 2 #define XML_MINOR_VERSION 6 -#define XML_MICRO_VERSION 0 +#define XML_MICRO_VERSION 2 #ifdef __cplusplus } diff --git a/XML/src/internal.h b/XML/src/internal.h index a82c68b4b2..a27eb20bcc 100644 --- a/XML/src/internal.h +++ b/XML/src/internal.h @@ -28,10 +28,11 @@ Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein - Copyright (c) 2016-2023 Sebastian Pipping + Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo - Copyright (c) 2023 Sony Corporation / Snild Dolkow + Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow + Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -155,14 +156,20 @@ extern "C" { void _INTERNAL_trim_to_complete_utf8_characters(const char *from, const char **fromLimRef); -#if XML_GE == 1 +#if defined(XML_GE) && XML_GE == 1 unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser); unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser); const char *unsignedCharToPrintable(unsigned char c); #endif -extern XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c -extern unsigned int g_parseAttempts; // used for testing only +extern +#if ! defined(XML_TESTING) + const +#endif + XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c +#if defined(XML_TESTING) +extern unsigned int g_bytesScanned; // used for testing only +#endif #ifdef __cplusplus } diff --git a/XML/src/xmlparse.cpp b/XML/src/xmlparse.cpp index 8791b8efe3..e9cf7a46a4 100644 --- a/XML/src/xmlparse.cpp +++ b/XML/src/xmlparse.cpp @@ -1,4 +1,4 @@ -/* 628e24d4966bedbd4800f6ed128d06d29703765b4bce12d3b7f099f90f842fc9 (2.6.0+) +/* 2a14271ad4d35e82bde8ba210b4edb7998794bcbae54deab114046a300f9639a (2.6.2+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -38,7 +38,7 @@ Copyright (c) 2022 Jann Horn Copyright (c) 2022 Sean McBride Copyright (c) 2023 Owain Davies - Copyright (c) 2023 Sony Corporation / Snild Dolkow + Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -217,7 +217,7 @@ typedef char ICHAR; #endif /* Round up n to be a multiple of sz, where sz is a power of 2. */ -#define ROUND_UP(n, sz) (((n) + ((sz)-1)) & ~((sz)-1)) +#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) /* Do safe (NULL-aware) pointer arithmetic */ #define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0) @@ -255,7 +255,7 @@ static void copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key); it odd, since odd numbers are always relative prime to a power of 2. */ #define SECOND_HASH(hash, mask, power) \ - ((((hash) & ~(mask)) >> ((power)-1)) & ((mask) >> 2)) + ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2)) #define PROBE_STEP(hash, mask, power) \ ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1)) @@ -636,8 +636,14 @@ static unsigned long getDebugLevel(const char *variableName, ? 0 \ : ((*((pool)->ptr)++ = c), 1)) -XML_Bool g_reparseDeferralEnabledDefault = XML_TRUE; // write ONLY in runtests.c -unsigned int g_parseAttempts = 0; // used for testing only +#if ! defined(XML_TESTING) +const +#endif + XML_Bool g_reparseDeferralEnabledDefault + = XML_TRUE; // write ONLY in runtests.c +#if defined(XML_TESTING) +unsigned int g_bytesScanned = 0; // used for testing only +#endif struct XML_ParserStruct { /* The first member must be m_userData so that the XML_GetUserData @@ -1035,7 +1041,9 @@ callProcessor(XML_Parser parser, const char *start, const char *end, return XML_ERROR_NONE; } } - g_parseAttempts += 1; +#if defined(XML_TESTING) + g_bytesScanned += (unsigned)have_now; +#endif const enum XML_Error ret = parser->m_processor(parser, start, end, endPtr); if (ret == XML_ERROR_NONE) { // if we consumed nothing, remember what we had on this parse attempt. @@ -6250,7 +6258,7 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc, dtd->keepProcessing = dtd->standalone; goto endEntityValue; } - if (entity->open) { + if (entity->open || (entity == parser->m_declEntity)) { if (enc == parser->m_encoding) parser->m_eventPtr = entityTextPtr; result = XML_ERROR_RECURSIVE_ENTITY_REF; @@ -7797,6 +7805,8 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { static float accountingGetCurrentAmplification(XML_Parser rootParser) { + // 1.........1.........12 => 22 + const size_t lenOfShortestInclude = sizeof("") - 1; const XmlBigCount countBytesOutput = rootParser->m_accounting.countBytesDirect + rootParser->m_accounting.countBytesIndirect; @@ -7804,7 +7814,9 @@ accountingGetCurrentAmplification(XML_Parser rootParser) { = rootParser->m_accounting.countBytesDirect ? (countBytesOutput / (float)(rootParser->m_accounting.countBytesDirect)) - : 1.0f; + : ((lenOfShortestInclude + + rootParser->m_accounting.countBytesIndirect) + / (float)lenOfShortestInclude); assert(! rootParser->m_parentParser); return amplificationFactor; }