1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
8 #include "rgw_frontend.h"
9 #include "rgw_client_io_filters.h"
10 #include "rgw_dmclock_sync_scheduler.h"
12 #define dout_subsys ceph_subsys_rgw
14 namespace dmc
= rgw::dmclock
;
16 RGWCivetWebFrontend::RGWCivetWebFrontend(RGWProcessEnv
& env
,
17 RGWFrontendConfig
*conf
,
18 dmc::SchedulerCtx
& sched_ctx
)
24 auto sched_t
= dmc::get_scheduler_t(cct());
26 case dmc::scheduler_t::none
: [[fallthrough
]];
27 case dmc::scheduler_t::throttler
:
29 case dmc::scheduler_t::dmclock
:
30 // TODO: keep track of server ready state and use that here civetweb
31 // internally tracks in the ctx the threads used and free, while it is
32 // expected with the current implementation that the threads waiting on the
33 // queue would still show up in the "used" queue, it might be a useful thing
34 // to make decisions on in the future. Also while reconfiguring we should
35 // probably set this to false
36 auto server_ready_f
= []() -> bool { return true; };
38 scheduler
.reset(new dmc::SyncScheduler(cct(),
39 std::ref(sched_ctx
.get_dmc_client_counters()),
40 *sched_ctx
.get_dmc_client_config(),
42 std::ref(dmc::SyncScheduler::handle_request_cb
),
43 dmc::AtLimit::Reject
));
48 static int civetweb_callback(struct mg_connection
* conn
)
50 const struct mg_request_info
* const req_info
= mg_get_request_info(conn
);
51 return static_cast<RGWCivetWebFrontend
*>(req_info
->user_data
)->process(conn
);
54 int RGWCivetWebFrontend::process(struct mg_connection
* const conn
)
56 /* Hold a read lock over access to env.store for reconfiguration. */
57 std::shared_lock lock
{env
.mutex
};
59 RGWCivetWeb
cw_client(conn
);
60 auto real_client_io
= rgw::io::add_reordering(
61 rgw::io::add_buffering(dout_context
,
62 rgw::io::add_chunking(
63 rgw::io::add_conlen_controlling(
65 RGWRestfulIO
client_io(dout_context
, &real_client_io
);
67 RGWRequest
req(env
.store
->getRados()->get_new_req_id());
69 ceph::coarse_real_clock::duration latency
{};
70 //assert (scheduler != nullptr);
71 int ret
= process_request(env
.store
, env
.rest
, &req
, env
.uri_prefix
,
72 *env
.auth_registry
, &client_io
, env
.olog
,
73 null_yield
, scheduler
.get(), nullptr, &latency
, &http_ret
);
75 /* We don't really care about return code. */
76 dout(20) << "process_request() returned " << ret
<< dendl
;
80 /* Mark as processed. */
87 int RGWCivetWebFrontend::run()
89 auto& conf_map
= conf
->get_config_map();
91 set_conf_default(conf_map
, "num_threads",
92 std::to_string(g_conf()->rgw_thread_pool_size
));
93 set_conf_default(conf_map
, "decode_url", "no");
94 set_conf_default(conf_map
, "enable_keep_alive", "yes");
95 set_conf_default(conf_map
, "validate_http_method", "no");
96 set_conf_default(conf_map
, "canonicalize_url_path", "no");
97 set_conf_default(conf_map
, "enable_auth_domain_check", "no");
98 set_conf_default(conf_map
, "allow_unicode_in_urls", "yes");
99 set_conf_default(conf_map
, "request_timeout_ms", "65000");
101 std::string listening_ports
;
102 // support multiple port= entries
103 auto range
= conf_map
.equal_range("port");
104 for (auto p
= range
.first
; p
!= range
.second
; ++p
) {
105 std::string port_str
= p
->second
;
106 // support port= entries with multiple values
107 std::replace(port_str
.begin(), port_str
.end(), '+', ',');
108 if (!listening_ports
.empty()) {
109 listening_ports
.append(1, ',');
111 listening_ports
.append(port_str
);
113 if (listening_ports
.empty()) {
114 listening_ports
= "80";
116 conf_map
.emplace("listening_ports", std::move(listening_ports
));
118 /* Set run_as_user. This will cause civetweb to invoke setuid() and setgid()
119 * based on pw_uid and pw_gid obtained from pw_name. */
120 std::string uid_string
= g_ceph_context
->get_set_uid_string();
121 if (! uid_string
.empty()) {
122 conf_map
.emplace("run_as_user", std::move(uid_string
));
125 /* Prepare options for CivetWeb. */
126 const std::set
<std::string_view
> rgw_opts
= { "port", "prefix" };
128 std::vector
<const char*> options
;
130 for (const auto& pair
: conf_map
) {
131 if (! rgw_opts
.count(pair
.first
)) {
132 /* CivetWeb doesn't understand configurables of the glue layer between
133 * it and RadosGW. We need to strip them out. Otherwise CivetWeb would
134 * signalise an error. */
135 options
.push_back(pair
.first
.c_str());
136 options
.push_back(pair
.second
.c_str());
138 dout(20) << "civetweb config: " << pair
.first
139 << ": " << pair
.second
<< dendl
;
143 options
.push_back(nullptr);
144 /* Initialize the CivetWeb right now. */
145 struct mg_callbacks cb
;
146 // FIPS zeroization audit 20191115: this memset is not security related.
147 memset((void *)&cb
, 0, sizeof(cb
));
148 cb
.begin_request
= civetweb_callback
;
149 cb
.log_message
= rgw_civetweb_log_callback
;
150 cb
.log_access
= rgw_civetweb_log_access_callback
;
151 ctx
= mg_start(&cb
, this, options
.data());
153 return ! ctx
? -EIO
: 0;
154 } /* RGWCivetWebFrontend::run */