// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
+#include <set>
+#include <string>
+
+#include <boost/utility/string_ref.hpp>
+
#include "rgw_frontend.h"
#include "rgw_client_io_decoimpl.h"
#define dout_subsys ceph_subsys_rgw
-static int civetweb_callback(struct mg_connection* conn) {
- struct mg_request_info* req_info = mg_get_request_info(conn);
- RGWMongooseEnv* pe = static_cast<RGWMongooseEnv *>(req_info->user_data);
-
- {
- // hold a read lock over access to pe->store for reconfiguration
- RWLock::RLocker lock(pe->mutex);
+static int civetweb_callback(struct mg_connection* conn)
+{
+ struct mg_request_info* const req_info = mg_get_request_info(conn);
+ return static_cast<RGWCivetWebFrontend *>(req_info->user_data)->process(conn);
+}
- RGWRados* store = pe->store;
- RGWREST* rest = pe->rest;
- OpsLogSocket* olog = pe->olog;
+int RGWCivetWebFrontend::process(struct mg_connection* const conn)
+{
+ /* Hold a read lock over access to env.store for reconfiguration. */
+ RWLock::RLocker lock(env.mutex);
- RGWRequest req(store->get_new_req_id());
- RGWCivetWeb real_client_io(conn, pe->port);
- RGWStreamIOLegacyWrapper client_io(&real_client_io);
+ RGWRequest req(env.store->get_new_req_id());
+ RGWCivetWeb real_client_io(conn, env.port);
+ RGWStreamIOLegacyWrapper client_io(&real_client_io);
- int ret = process_request(pe->store, rest, &req, &client_io, olog);
- if (ret < 0) {
- /* we don't really care about return code */
- dout(20) << "process_request() returned " << ret << dendl;
- }
+ int ret = process_request(env.store, env.rest, &req, &client_io, env.olog);
+ if (ret < 0) {
+ /* We don't really care about return code. */
+ dout(20) << "process_request() returned " << ret << dendl;
}
-// Mark as processed
+ /* Mark as processed. */
return 1;
}
-int RGWCivetWebFrontend::run() {
- char thread_pool_buf[32];
- snprintf(thread_pool_buf, sizeof(thread_pool_buf), "%d",
- (int)g_conf->rgw_thread_pool_size);
- string port_str;
- map<string, string> conf_map = conf->get_config_map();
- conf->get_val("port", "80", &port_str);
- conf_map.erase("port");
- conf_map.erase("prefix");
- conf_map["listening_ports"] = port_str;
- set_conf_default(conf_map, "enable_keep_alive", "yes");
- set_conf_default(conf_map, "num_threads", thread_pool_buf);
+int RGWCivetWebFrontend::run()
+{
+ auto& conf_map = conf->get_config_map();
+
+ set_conf_default(conf_map, "num_threads",
+ std::to_string(g_conf->rgw_thread_pool_size));
set_conf_default(conf_map, "decode_url", "no");
+ set_conf_default(conf_map, "enable_keep_alive", "yes");
+ conf_map["listening_ports"] = conf->get_val("port", "80");
- // Set run_as_user. This will cause civetweb to invoke setuid() and setgid()
- // based on pw_uid and pw_gid obtained from pw_name.
- string uid_string = g_ceph_context->get_set_uid_string();
- if (!uid_string.empty()) {
- conf_map.erase("run_as_user");
- conf_map["run_as_user"] = uid_string;
+ /* Set run_as_user. This will cause civetweb to invoke setuid() and setgid()
+ * based on pw_uid and pw_gid obtained from pw_name. */
+ std::string uid_string = g_ceph_context->get_set_uid_string();
+ if (! uid_string.empty()) {
+ conf_map["run_as_user"] = std::move(uid_string);
}
- const char *options[conf_map.size() * 2 + 1];
- int i = 0;
- for (map<string, string>::iterator iter = conf_map.begin();
- iter != conf_map.end(); ++iter) {
- options[i] = iter->first.c_str();
- options[i + 1] = iter->second.c_str();
- dout(20)<< "civetweb config: " << options[i] << ": "
- << (options[i + 1] ? options[i + 1] : "<null>") << dendl;
- i += 2;
+ /* Prepare options for CivetWeb. */
+ const std::set<boost::string_ref> rgw_opts = { "port", "prefix" };
+ const std::size_t CW_NUM_OPTS = 2 * (conf_map.size() - rgw_opts.size()) + 1;
+ const char *options[CW_NUM_OPTS];
+ std::size_t i = 0;
+
+ for (const auto& pair : conf_map) {
+ if (! rgw_opts.count(pair.first)) {
+ /* CivetWeb doesn't understand configurables of the glue layer between
+ * it and RadosGW. We need to strip them out. Otherwise CivetWeb would
+ * signalise an error. */
+ options[i + 0] = pair.first.c_str();
+ options[i + 1] = pair.second.c_str();
+
+ dout(20) << "civetweb config: " << options[i] << ": "
+ << (options[i + 1] ? options[i + 1] : "<null>") << dendl;
+ i += 2;
+ }
}
- options[i] = NULL;
+ options[i] = nullptr;
+ /* Initialize the CivetWeb right now. */
struct mg_callbacks cb;
memset((void *)&cb, 0, sizeof(cb));
cb.begin_request = civetweb_callback;
cb.log_message = rgw_civetweb_log_callback;
cb.log_access = rgw_civetweb_log_access_callback;
- ctx = mg_start(&cb, &env, (const char **)&options);
-
- if (!ctx) {
- return -EIO;
- }
+ ctx = mg_start(&cb, this, (const char **)&options);
- return 0;
+ return ! ctx ? -EIO : 0;
} /* RGWCivetWebFrontend::run */
#ifndef RGW_FRONTEND_H
#define RGW_FRONTEND_H
+#include <map>
+#include <string>
+
#include "rgw_request.h"
#include "rgw_process.h"
#include "rgw_realm_reloader.h"
#define dout_subsys ceph_subsys_rgw
class RGWFrontendConfig {
- string config;
- map<string, string> config_map;
- int parse_config(const string& config, map<string, string>& config_map);
- string framework;
+ std::string config;
+ std::map<std::string, std::string> config_map;
+ std::string framework;
+
+ int parse_config(const std::string& config,
+ std::map<std::string, std::string>& config_map);
+
public:
- RGWFrontendConfig(const string& _conf) : config(_conf) {}
+ RGWFrontendConfig(const std::string& config)
+ : config(config) {
+ }
+
int init() {
- int ret = parse_config(config, config_map);
- if (ret < 0)
- return ret;
- return 0;
+ const int ret = parse_config(config, config_map);
+ return ret < 0 ? ret : 0;
+ }
+
+ bool get_val(const std::string& key,
+ const std::string& def_val,
+ std::string* out);
+ bool get_val(const std::string& key, int def_val, int *out);
+
+ std::string get_val(const std::string& key,
+ const std::string& def_val) {
+ std::string out;
+ get_val(key, def_val, &out);
+ return out;
}
- bool get_val(const string& key, const string& def_val, string *out);
- bool get_val(const string& key, int def_val, int *out);
- map<string, string>& get_config_map() { return config_map; }
+ std::map<std::string, std::string>& get_config_map() {
+ return config_map;
+ }
- string get_framework() { return framework; }
+ std::string get_framework() const {
+ return framework;
+ }
};
class RGWFrontend {
virtual void join() = 0;
virtual void pause_for_new_config() = 0;
- virtual void unpause_with_new_config(RGWRados *store) = 0;
+ virtual void unpause_with_new_config(RGWRados* store) = 0;
};
+
struct RGWMongooseEnv : public RGWProcessEnv {
// every request holds a read lock, so we need to prioritize write locks to
// avoid starving pause_for_new_config()
static constexpr bool prioritize_write = true;
RWLock mutex;
+
RGWMongooseEnv(const RGWProcessEnv &env)
: RGWProcessEnv(env),
- mutex("RGWCivetWebFrontend", false, true, prioritize_write) {}
+ mutex("RGWCivetWebFrontend", false, true, prioritize_write) {
+ }
};
+
class RGWCivetWebFrontend : public RGWFrontend {
RGWFrontendConfig* conf;
struct mg_context* ctx;
RGWMongooseEnv env;
- void set_conf_default(map<string, string>& m, const string& key,
- const string& def_val) {
- if (m.find(key) == m.end()) {
+ void set_conf_default(std::map<std::string, std::string>& m,
+ const std::string& key,
+ const std::string& def_val) {
+ if (m.find(key) == std::end(m)) {
m[key] = def_val;
}
}
public:
- RGWCivetWebFrontend(RGWProcessEnv& pe, RGWFrontendConfig* _conf)
- : conf(_conf), ctx(nullptr), env(pe) {
+ RGWCivetWebFrontend(RGWProcessEnv& env,
+ RGWFrontendConfig* conf)
+ : conf(conf),
+ ctx(nullptr),
+ env(env) {
}
- int init() {
+ int init() override {
return 0;
}
- int run();
+ int run() override;
- void stop() {
+ int process(struct mg_connection* conn);
+
+ void stop() override {
if (ctx) {
mg_stop(ctx);
}
}
- void join() {
+ void join() override {
+ return;
}
void pause_for_new_config() override {