Skip to content

Commit

Permalink
pull: Use civetweb C API due to packaging issues in Debian
Browse files Browse the repository at this point in the history
  • Loading branch information
gjasny committed Dec 7, 2020
1 parent bb017ec commit 25763e2
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 34 deletions.
2 changes: 0 additions & 2 deletions cmake/civetweb-3rdparty-config.cmake
Expand Up @@ -11,9 +11,7 @@ set_and_check(CIVETWEB_INCLUDE_DIR ${_IMPORT_PREFIX}/include)
set(CIVETWEB_INCLUDE_DIRS "${CIVETWEB_INCLUDE_DIR}")

add_library(civetweb OBJECT
${_IMPORT_PREFIX}/include/CivetServer.h
${_IMPORT_PREFIX}/include/civetweb.h
${_IMPORT_PREFIX}/src/CivetServer.cpp
${_IMPORT_PREFIX}/src/civetweb.c
${_IMPORT_PREFIX}/src/handle_form.inl
${_IMPORT_PREFIX}/src/md5.inl
Expand Down
2 changes: 1 addition & 1 deletion pull/BUILD.bazel
Expand Up @@ -22,7 +22,7 @@ cc_library(
visibility = ["//visibility:public"],
deps = [
"//core",
"@civetweb",
"@civetweb//:libcivetweb",
"@net_zlib_zlib//:z",
],
)
Expand Down
2 changes: 1 addition & 1 deletion pull/CMakeLists.txt
Expand Up @@ -40,7 +40,7 @@ target_link_libraries(pull
${PROJECT_NAME}::core
PRIVATE
Threads::Threads
$<IF:$<BOOL:${USE_THIRDPARTY_LIBRARIES}>,${PROJECT_NAME}::civetweb,civetweb::civetweb-cpp>
$<IF:$<BOOL:${USE_THIRDPARTY_LIBRARIES}>,${PROJECT_NAME}::civetweb,civetweb::civetweb>
$<$<AND:$<BOOL:UNIX>,$<NOT:$<BOOL:APPLE>>>:rt>
$<$<BOOL:${ENABLE_COMPRESSION}>:ZLIB::ZLIB>
)
Expand Down
4 changes: 2 additions & 2 deletions pull/include/prometheus/exposer.h
Expand Up @@ -10,7 +10,7 @@
#include "prometheus/detail/pull_export.h"
#include "prometheus/registry.h"

class CivetServer;
extern "C" struct mg_context;

namespace prometheus {

Expand Down Expand Up @@ -38,7 +38,7 @@ class PROMETHEUS_CPP_PULL_EXPORT Exposer {
private:
detail::Endpoint& GetEndpointForUri(const std::string& uri);

std::unique_ptr<CivetServer> server_;
std::shared_ptr<mg_context> server_;
std::vector<std::unique_ptr<detail::Endpoint>> endpoints_;
};

Expand Down
17 changes: 13 additions & 4 deletions pull/src/basic_auth.cc
@@ -1,6 +1,6 @@
#include "basic_auth.h"

#include "CivetServer.h"
#include "civetweb.h"
#include "detail/base64.h"
#include "prometheus/detail/future_std.h"

Expand All @@ -9,15 +9,24 @@ namespace prometheus {
BasicAuthHandler::BasicAuthHandler(AuthFunc callback, std::string realm)
: callback_(std::move(callback)), realm_(std::move(realm)) {}

bool BasicAuthHandler::authorize(CivetServer* server, mg_connection* conn) {
if (!AuthorizeInner(server, conn)) {
int BasicAuthHandler::authHandler(struct mg_connection* conn, void* cbdata) {
auto* handler = reinterpret_cast<BasicAuthHandler*>(cbdata);
if (!handler) {
return 0; // No handler found
}

return handler->Authorize(conn) ? 1 : 0;
}

bool BasicAuthHandler::Authorize(mg_connection* conn) {
if (!AuthorizeInner(conn)) {
WriteUnauthorizedResponse(conn);
return false;
}
return true;
}

bool BasicAuthHandler::AuthorizeInner(CivetServer*, mg_connection* conn) {
bool BasicAuthHandler::AuthorizeInner(mg_connection* conn) {
const char* authHeader = mg_get_header(conn, "Authorization");

if (authHeader == nullptr) {
Expand Down
23 changes: 17 additions & 6 deletions pull/src/basic_auth.h
Expand Up @@ -4,19 +4,31 @@
#include <string>
#include <unordered_map>

#include "CivetServer.h"
#include "civetweb.h"
#include "prometheus/detail/pull_export.h"

namespace prometheus {

/**
* Handler for HTTP Basic authentication for Endpoints.
*/
class PROMETHEUS_CPP_PULL_EXPORT BasicAuthHandler : public CivetAuthHandler {
class BasicAuthHandler {
public:
using AuthFunc = std::function<bool(const std::string&, const std::string&)>;
explicit BasicAuthHandler(AuthFunc callback, std::string realm);
BasicAuthHandler(AuthFunc callback, std::string realm);

/**
* authHandler(struct mg_connection *, void *cbdata)
*
* Handles the authorization requests.
*
* @param conn - the connection information
* @param cbdata - pointer to the CivetAuthHandler instance.
* @returns 1 if authorized, 0 otherwise
*/
static int authHandler(struct mg_connection* conn, void* cbdata);

private:
/**
* Implements civetweb authorization interface.
*
Expand All @@ -26,10 +38,9 @@ class PROMETHEUS_CPP_PULL_EXPORT BasicAuthHandler : public CivetAuthHandler {
* If handler returns false, or the Auth header is absent,
* rejects the request with 401 Unauthorized.
*/
bool authorize(CivetServer* server, mg_connection* conn) override;
bool Authorize(mg_connection* conn);

private:
bool AuthorizeInner(CivetServer* server, mg_connection* conn);
bool AuthorizeInner(mg_connection* conn);
void WriteUnauthorizedResponse(mg_connection* conn);

AuthFunc callback_;
Expand Down
12 changes: 7 additions & 5 deletions pull/src/endpoint.cc
Expand Up @@ -7,19 +7,20 @@
namespace prometheus {
namespace detail {

Endpoint::Endpoint(CivetServer& server, std::string uri)
Endpoint::Endpoint(mg_context* server, std::string uri)
: server_(server),
uri_(std::move(uri)),
endpoint_registry_(std::make_shared<Registry>()),
metrics_handler_(
detail::make_unique<MetricsHandler>(*endpoint_registry_)) {
RegisterCollectable(endpoint_registry_);
server_.addHandler(uri_, metrics_handler_.get());
mg_set_request_handler(server_, uri_.c_str(), MetricsHandler::requestHandler,
metrics_handler_.get());
}

Endpoint::~Endpoint() {
server_.removeHandler(uri_);
server_.removeAuthHandler(uri_);
mg_set_request_handler(server_, uri_.c_str(), nullptr, nullptr);
mg_set_auth_handler(server_, uri_.c_str(), nullptr, nullptr);
}

void Endpoint::RegisterCollectable(
Expand All @@ -32,7 +33,8 @@ void Endpoint::RegisterAuth(
const std::string& realm) {
auth_handler_ =
detail::make_unique<BasicAuthHandler>(std::move(authCB), realm);
server_.addAuthHandler(uri_, auth_handler_.get());
mg_set_auth_handler(server_, uri_.c_str(), BasicAuthHandler::authHandler,
auth_handler_.get());
}

const std::string& Endpoint::GetURI() const { return uri_; }
Expand Down
6 changes: 3 additions & 3 deletions pull/src/endpoint.h
Expand Up @@ -9,15 +9,15 @@
#include "prometheus/collectable.h"
#include "prometheus/registry.h"

class CivetServer;
extern "C" struct mg_context;

namespace prometheus {
namespace detail {
class MetricsHandler;

class Endpoint {
public:
explicit Endpoint(CivetServer& server, std::string uri);
Endpoint(mg_context* server, std::string uri);
~Endpoint();

void RegisterCollectable(const std::weak_ptr<Collectable>& collectable);
Expand All @@ -28,7 +28,7 @@ class Endpoint {
const std::string& GetURI() const;

private:
CivetServer& server_;
mg_context* server_;
const std::string uri_;
// registry for "meta" metrics about the endpoint itself
std::shared_ptr<Registry> endpoint_registry_;
Expand Down
46 changes: 40 additions & 6 deletions pull/src/exposer.cc
@@ -1,10 +1,12 @@
#include "prometheus/exposer.h"

#include <algorithm>
#include <chrono>
#include <iterator>
#include <stdexcept>
#include <string>
#include <thread>

#include "CivetServer.h"
#include "civetweb.h"
#include "endpoint.h"
#include "handler.h"
#include "prometheus/client_metric.h"
Expand All @@ -17,8 +19,21 @@ Exposer::Exposer(const std::string& bind_address, const std::size_t num_threads)
"num_threads",
std::to_string(num_threads)}) {}

Exposer::Exposer(std::vector<std::string> options)
: server_(detail::make_unique<CivetServer>(std::move(options))) {}
Exposer::Exposer(std::vector<std::string> options) {
// create NULL-terminated option list
std::vector<const char*> pointers;
pointers.reserve(options.size() + 1u);
std::transform(options.begin(), options.end(), std::back_inserter(pointers),
[](const std::string& o) { return o.c_str(); });
pointers.push_back(nullptr);

server_.reset(mg_start(nullptr, this, pointers.data()), mg_stop);
if (!server_) {
throw std::runtime_error(
"null context when constructing civetweb server. "
"Possible problem binding to port.");
}
}

Exposer::~Exposer() = default;

Expand All @@ -36,7 +51,25 @@ void Exposer::RegisterAuth(
}

std::vector<int> Exposer::GetListeningPorts() const {
return server_->getListeningPorts();
std::vector<struct mg_server_port> server_ports(8);
for (;;) {
int size = mg_get_server_ports(server_.get(),
static_cast<int>(server_ports.size()),
server_ports.data());
if (size < static_cast<int>(server_ports.size())) {
server_ports.resize(size < 0 ? 0 : size);
break;
}
server_ports.resize(server_ports.size() * 2);
}

std::vector<int> ports;
ports.reserve(server_ports.size());
std::transform(server_ports.begin(), server_ports.end(),
std::back_inserter(ports),
[](const mg_server_port& sp) { return sp.port; });

return ports;
}

detail::Endpoint& Exposer::GetEndpointForUri(const std::string& uri) {
Expand All @@ -48,7 +81,8 @@ detail::Endpoint& Exposer::GetEndpointForUri(const std::string& uri) {
return *it->get();
}

endpoints_.emplace_back(detail::make_unique<detail::Endpoint>(*server_, uri));
endpoints_.emplace_back(
detail::make_unique<detail::Endpoint>(server_.get(), uri));
return *endpoints_.back().get();
}

Expand Down
15 changes: 14 additions & 1 deletion pull/src/handler.cc
Expand Up @@ -119,7 +119,20 @@ void MetricsHandler::RegisterCollectable(
collectables_.push_back(collectable);
}

bool MetricsHandler::handleGet(CivetServer*, struct mg_connection* conn) {
int MetricsHandler::requestHandler(struct mg_connection* conn, void* cbdata) {
auto* handler = reinterpret_cast<MetricsHandler*>(cbdata);
auto* request_info = mg_get_request_info(conn);

if (handler && request_info) {
if (std::strcmp(request_info->request_method, "GET") == 0) {
return handler->handleGet(conn) ? 1 : 0;
}
}

return 0; // No handler found
}

bool MetricsHandler::handleGet(struct mg_connection* conn) {
auto start_time_of_request = std::chrono::steady_clock::now();

std::vector<MetricFamily> metrics;
Expand Down
8 changes: 5 additions & 3 deletions pull/src/handler.h
Expand Up @@ -4,22 +4,24 @@
#include <mutex>
#include <vector>

#include "CivetServer.h"
#include "civetweb.h"
#include "prometheus/counter.h"
#include "prometheus/registry.h"
#include "prometheus/summary.h"

namespace prometheus {
namespace detail {
class MetricsHandler : public CivetHandler {
class MetricsHandler {
public:
explicit MetricsHandler(Registry& registry);

void RegisterCollectable(const std::weak_ptr<Collectable>& collectable);

bool handleGet(CivetServer* server, struct mg_connection* conn) override;
static int requestHandler(struct mg_connection* conn, void* cbdata);

private:
bool handleGet(struct mg_connection* conn);

std::mutex collectables_mutex_;
std::vector<std::weak_ptr<Collectable>> collectables_;
Family<Counter>& bytes_transferred_family_;
Expand Down

0 comments on commit 25763e2

Please sign in to comment.