pull: Use internal base64 decoding function to avoid dependency (#417)

This commit is contained in:
Gregor Jasny
2020-11-23 23:44:04 +01:00
committed by GitHub
parent 27c3d670c6
commit bb017ec15a
16 changed files with 187 additions and 60 deletions
+1 -1
View File
@@ -34,6 +34,6 @@ esac
case "${BUILDSYSTEM_ARG}" in
cmake)
"${VCPKG_INSTALLATION_ROOT}/vcpkg" install benchmark civetweb cppcodec curl gtest zlib
"${VCPKG_INSTALLATION_ROOT}/vcpkg" install benchmark civetweb curl gtest zlib
;;
esac
+1 -1
View File
@@ -1,4 +1,4 @@
if [%1] == [cmake] (
%VCPKG_INSTALLATION_ROOT%/vcpkg install benchmark civetweb cppcodec curl gtest zlib || EXIT /B 1
%VCPKG_INSTALLATION_ROOT%/vcpkg install benchmark civetweb curl gtest zlib || EXIT /B 1
)
-3
View File
@@ -4,6 +4,3 @@
[submodule "civetweb"]
path = 3rdparty/civetweb
url = https://github.com/civetweb/civetweb.git
[submodule "3rdparty/cppcodec"]
path = 3rdparty/cppcodec
url = https://github.com/tplgy/cppcodec.git
Submodule 3rdparty/cppcodec deleted from 302dc28f8f
-6
View File
@@ -1,6 +0,0 @@
cc_library(
name = "cppcodec",
hdrs = glob(["cppcodec/**/*.hpp"]),
includes = ["."],
visibility = ["//visibility:public"],
)
-11
View File
@@ -45,17 +45,6 @@ def prometheus_cpp_repositories():
],
)
maybe(
http_archive,
name = "com_github_tplgy_cppcodec",
sha256 = "0edaea2a9d9709d456aa99a1c3e17812ed130f9ef2b5c2d152c230a5cbc5c482",
strip_prefix = "cppcodec-0.2",
urls = [
"https://github.com/tplgy/cppcodec/archive/v0.2.tar.gz",
],
build_file = "@com_github_jupp0r_prometheus_cpp//bazel:cppcodec.BUILD",
)
maybe(
http_archive,
name = "net_zlib_zlib",
-8
View File
@@ -1,8 +0,0 @@
find_path(CPPCODEC_INCLUDE_DIR base64_rfc4648.hpp PATH_SUFFIXES include/cppcodec)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cppcodec DEFAULT_MSG CPPCODEC_INCLUDE_DIR)
if(cppcodec_FOUND)
set(CPPCODEC_INCLUDE_DIRS "${CPPCODEC_INCLUDE_DIR}")
endif()
-14
View File
@@ -1,14 +0,0 @@
get_filename_component(_IMPORT_PREFIX "${PROJECT_SOURCE_DIR}/3rdparty/cppcodec/" ABSOLUTE)
macro(set_and_check _var _file)
set(${_var} "${_file}")
if(NOT EXISTS "${_file}")
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
endif()
endmacro()
set_and_check(CPPCODEC_INCLUDE_DIR ${_IMPORT_PREFIX})
set(CPPCODEC_INCLUDE_DIRS "${CPPCODEC_INCLUDE_DIR}")
add_library(cppcodec INTERFACE)
target_include_directories(cppcodec INTERFACE "$<BUILD_INTERFACE:${CPPCODEC_INCLUDE_DIR}>")
+12 -1
View File
@@ -23,7 +23,18 @@ cc_library(
deps = [
"//core",
"@civetweb",
"@com_github_tplgy_cppcodec//:cppcodec",
"@net_zlib_zlib//:z",
],
)
cc_library(
name = "pull_internal_headers",
hdrs = glob(
["src/detail/*.h"],
),
strip_include_prefix = "src",
visibility = ["//pull/tests:__subpackages__"],
deps = [
"//core",
],
)
+6 -9
View File
@@ -5,15 +5,8 @@ if(USE_THIRDPARTY_LIBRARIES)
TARGETS civetweb
EXPORT ${PROJECT_NAME}-targets
)
find_package(cppcodec-3rdparty CONFIG REQUIRED)
add_library(${PROJECT_NAME}::cppcodec ALIAS cppcodec)
install(
TARGETS cppcodec
EXPORT ${PROJECT_NAME}-targets
)
else()
find_package(civetweb CONFIG REQUIRED)
find_package(cppcodec REQUIRED)
# work-around https://github.com/civetweb/civetweb/pull/918
if(WIN32 AND NOT TARGET WINSOCK::WINSOCK)
@@ -36,6 +29,8 @@ add_library(pull
src/handler.h
src/metrics_collector.cc
src/metrics_collector.h
src/detail/base64.h
)
add_library(${PROJECT_NAME}::pull ALIAS pull)
@@ -46,7 +41,6 @@ target_link_libraries(pull
PRIVATE
Threads::Threads
$<IF:$<BOOL:${USE_THIRDPARTY_LIBRARIES}>,${PROJECT_NAME}::civetweb,civetweb::civetweb-cpp>
$<$<BOOL:${USE_THIRDPARTY_LIBRARIES}>:${PROJECT_NAME}::cppcodec>
$<$<AND:$<BOOL:UNIX>,$<NOT:$<BOOL:APPLE>>>:rt>
$<$<BOOL:${ENABLE_COMPRESSION}>:ZLIB::ZLIB>
)
@@ -56,7 +50,6 @@ target_include_directories(pull
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
PRIVATE
${CPPCODEC_INCLUDE_DIRS} # needed as long as upstream cppcodec installs no config file with imported target
${CIVETWEB_INCLUDE_DIRS}
)
@@ -93,5 +86,9 @@ install(
)
if(ENABLE_TESTING)
add_library(pull_internal_headers INTERFACE)
add_library(${PROJECT_NAME}::pull_internal_headers ALIAS pull_internal_headers)
target_include_directories(pull_internal_headers INTERFACE src)
add_subdirectory(tests)
endif()
+2 -5
View File
@@ -1,14 +1,11 @@
#include "basic_auth.h"
#include <cppcodec/base64_rfc4648.hpp>
#include "CivetServer.h"
#include "detail/base64.h"
#include "prometheus/detail/future_std.h"
namespace prometheus {
using base64 = cppcodec::base64_rfc4648;
BasicAuthHandler::BasicAuthHandler(AuthFunc callback, std::string realm)
: callback_(std::move(callback)), realm_(std::move(realm)) {}
@@ -42,7 +39,7 @@ bool BasicAuthHandler::AuthorizeInner(CivetServer*, mg_connection* conn) {
std::string decoded;
try {
decoded = base64::decode<std::string>(b64Auth.data(), b64Auth.size());
decoded = detail::base64_decode(b64Auth);
} catch (...) {
return false;
}
+88
View File
@@ -0,0 +1,88 @@
#pragma once
#include <cstdint>
#include <stdexcept>
#include <string>
namespace prometheus {
namespace detail {
/*
Copyright (C) 2019-2020 by Martin Vorbrodt <martin@vorbrodt.blog>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
https://github.com/mvorbrodt/blog/blob/master/src/base64.hpp
*/
inline std::string base64_decode(const std::string& input) {
const char kPadCharacter = '=';
if (input.length() % 4) {
throw std::runtime_error("Invalid base64 length!");
}
std::size_t padding = 0;
if (!input.empty()) {
if (input[input.length() - 1] == kPadCharacter) padding++;
if (input[input.length() - 2] == kPadCharacter) padding++;
}
std::string decoded;
decoded.reserve(((input.length() / 4) * 3) - padding);
std::uint32_t temp = 0;
auto it = input.begin();
while (it < input.end()) {
for (std::size_t i = 0; i < 4; ++i) {
temp <<= 6;
if (*it >= 0x41 && *it <= 0x5A) {
temp |= *it - 0x41;
} else if (*it >= 0x61 && *it <= 0x7A) {
temp |= *it - 0x47;
} else if (*it >= 0x30 && *it <= 0x39) {
temp |= *it + 0x04;
} else if (*it == 0x2B) {
temp |= 0x3E;
} else if (*it == 0x2F) {
temp |= 0x3F;
} else if (*it == kPadCharacter) {
switch (input.end() - it) {
case 1:
decoded.push_back((temp >> 16) & 0x000000FF);
decoded.push_back((temp >> 8) & 0x000000FF);
return decoded;
case 2:
decoded.push_back((temp >> 10) & 0x000000FF);
return decoded;
default:
throw std::runtime_error("Invalid padding in base64!");
}
} else {
throw std::runtime_error("Invalid character in base64!");
}
++it;
}
decoded.push_back((temp >> 16) & 0x000000FF);
decoded.push_back((temp >> 8) & 0x000000FF);
decoded.push_back((temp)&0x000000FF);
}
return decoded;
}
} // namespace detail
} // namespace prometheus
+1
View File
@@ -1,2 +1,3 @@
add_subdirectory(integration)
add_subdirectory(internal)
add_subdirectory(unit)
+13
View File
@@ -0,0 +1,13 @@
cc_test(
name = "internal",
srcs = glob([
"*.cc",
"*.h",
]),
copts = ["-Iexternal/googletest/include"],
linkstatic = True,
deps = [
"//pull:pull_internal_headers",
"@com_google_googletest//:gtest_main",
],
)
+14
View File
@@ -0,0 +1,14 @@
add_executable(prometheus_pull_internal_test
base64_test.cc
)
target_link_libraries(prometheus_pull_internal_test
PRIVATE
${PROJECT_NAME}::pull_internal_headers
GTest::gmock_main
)
add_test(
NAME prometheus_pull_internal_test
COMMAND prometheus_pull_internal_test
)
+49
View File
@@ -0,0 +1,49 @@
#include "detail/base64.h"
#include <gtest/gtest.h>
#include <string>
namespace prometheus {
namespace {
struct TestVector {
const std::string decoded;
const std::string encoded;
};
const TestVector testVector[] = {
{"", ""},
{"f", "Zg=="},
{"fo", "Zm8="},
{"foo", "Zm9v"},
{"foob", "Zm9vYg=="},
{"fooba", "Zm9vYmE="},
{"foobar", "Zm9vYmFy"},
};
const unsigned nVectors = sizeof(testVector) / sizeof(testVector[0]);
using namespace testing;
TEST(Base64Test, decodeTest) {
for (unsigned i = 0; i < nVectors; ++i) {
std::string decoded = detail::base64_decode(testVector[i].encoded);
EXPECT_EQ(testVector[i].decoded, decoded);
}
}
TEST(Base64Test, rejectInvalidSymbols) {
EXPECT_ANY_THROW(detail::base64_decode("...."));
}
TEST(Base64Test, rejectInvalidInputSize) {
EXPECT_ANY_THROW(detail::base64_decode("ABC"));
}
TEST(Base64Test, rejectInvalidPadding) {
EXPECT_ANY_THROW(detail::base64_decode("A==="));
}
} // namespace
} // namespace prometheus