aboutsummaryrefslogtreecommitdiff
path: root/src/httpserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/httpserver.cpp')
-rw-r--r--src/httpserver.cpp106
1 files changed, 54 insertions, 52 deletions
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 0d1cba3fd..592387169 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -7,6 +7,7 @@
#include "chainparamsbase.h"
#include "compat.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "netbase.h"
#include "rpc/protocol.h" // For HTTP status codes
#include "sync.h"
@@ -21,13 +22,13 @@
#include <signal.h>
#include <future>
-#include <event2/event.h>
-#include <event2/http.h>
#include <event2/thread.h>
#include <event2/buffer.h>
#include <event2/util.h>
#include <event2/keyvalq_struct.h>
+#include "support/events.h"
+
#ifdef EVENT__HAVE_NETINET_IN_H
#include <netinet/in.h>
#ifdef _XOPEN_SOURCE_EXTENDED
@@ -39,14 +40,14 @@
static const size_t MAX_HEADERS_SIZE = 8192;
/** HTTP request work item */
-class HTTPWorkItem : public HTTPClosure
+class HTTPWorkItem final : public HTTPClosure
{
public:
HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
req(std::move(_req)), path(_path), func(_func)
{
}
- void operator()()
+ void operator()() override
{
func(req.get(), path);
}
@@ -78,7 +79,7 @@ private:
{
public:
WorkQueue &wq;
- ThreadCounter(WorkQueue &w): wq(w)
+ explicit ThreadCounter(WorkQueue &w): wq(w)
{
std::lock_guard<std::mutex> lock(wq.cs);
wq.numThreads += 1;
@@ -92,7 +93,7 @@ private:
};
public:
- WorkQueue(size_t _maxDepth) : running(true),
+ explicit WorkQueue(size_t _maxDepth) : running(true),
maxDepth(_maxDepth),
numThreads(0)
{
@@ -163,13 +164,13 @@ struct HTTPPathHandler
/** HTTP module state */
//! libevent event loop
-static struct event_base* eventBase = 0;
+static struct event_base* eventBase = nullptr;
//! HTTP server
-struct evhttp* eventHTTP = 0;
+struct evhttp* eventHTTP = nullptr;
//! List of subnets to allow RPC connections from
static std::vector<CSubNet> rpc_allow_subnets;
//! Work queue for handling longer requests off the event loop thread
-static WorkQueue<HTTPClosure>* workQueue = 0;
+static WorkQueue<HTTPClosure>* workQueue = nullptr;
//! Handlers for (sub)paths
std::vector<HTTPPathHandler> pathHandlers;
//! Bound listening sockets
@@ -196,18 +197,16 @@ static bool InitHTTPAllowList()
LookupHost("::1", localv6, false);
rpc_allow_subnets.push_back(CSubNet(localv4, 8)); // always allow IPv4 local subnet
rpc_allow_subnets.push_back(CSubNet(localv6)); // always allow IPv6 localhost
- if (gArgs.IsArgSet("-rpcallowip")) {
- for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) {
- CSubNet subnet;
- LookupSubNet(strAllow.c_str(), subnet);
- if (!subnet.IsValid()) {
- uiInterface.ThreadSafeMessageBox(
- strprintf("Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).", strAllow),
- "", CClientUIInterface::MSG_ERROR);
- return false;
- }
- rpc_allow_subnets.push_back(subnet);
+ for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) {
+ CSubNet subnet;
+ LookupSubNet(strAllow.c_str(), subnet);
+ if (!subnet.IsValid()) {
+ uiInterface.ThreadSafeMessageBox(
+ strprintf("Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).", strAllow),
+ "", CClientUIInterface::MSG_ERROR);
+ return false;
}
+ rpc_allow_subnets.push_back(subnet);
}
std::string strAllowed;
for (const CSubNet& subnet : rpc_allow_subnets)
@@ -293,7 +292,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
static void http_reject_request_cb(struct evhttp_request* req, void*)
{
LogPrint(BCLog::HTTP, "Rejecting request while shutting down\n");
- evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
+ evhttp_send_error(req, HTTP_SERVUNAVAIL, nullptr);
}
/** Event dispatcher thread */
@@ -310,14 +309,14 @@ static bool ThreadHTTP(struct event_base* base, struct evhttp* http)
/** Bind HTTP server to specified addresses */
static bool HTTPBindAddresses(struct evhttp* http)
{
- int defaultPort = GetArg("-rpcport", BaseParams().RPCPort());
+ int defaultPort = gArgs.GetArg("-rpcport", BaseParams().RPCPort());
std::vector<std::pair<std::string, uint16_t> > endpoints;
// Determine what addresses to bind to
- if (!IsArgSet("-rpcallowip")) { // Default to loopback if not allowing external IPs
+ if (!gArgs.IsArgSet("-rpcallowip")) { // Default to loopback if not allowing external IPs
endpoints.push_back(std::make_pair("::1", defaultPort));
endpoints.push_back(std::make_pair("127.0.0.1", defaultPort));
- if (IsArgSet("-rpcbind")) {
+ if (gArgs.IsArgSet("-rpcbind")) {
LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
}
} else if (gArgs.IsArgSet("-rpcbind")) { // Specific bind address
@@ -335,7 +334,7 @@ static bool HTTPBindAddresses(struct evhttp* http)
// Bind addresses
for (std::vector<std::pair<std::string, uint16_t> >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
LogPrint(BCLog::HTTP, "Binding RPC on address %s port %i\n", i->first, i->second);
- evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? NULL : i->first.c_str(), i->second);
+ evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? nullptr : i->first.c_str(), i->second);
if (bind_handle) {
boundSockets.push_back(bind_handle);
} else {
@@ -367,13 +366,10 @@ static void libevent_log_cb(int severity, const char *msg)
bool InitHTTPServer()
{
- struct evhttp* http = 0;
- struct event_base* base = 0;
-
if (!InitHTTPAllowList())
return false;
- if (GetBoolArg("-rpcssl", false)) {
+ if (gArgs.GetBoolArg("-rpcssl", false)) {
uiInterface.ThreadSafeMessageBox(
"SSL mode for RPC (-rpcssl) is no longer supported.",
"", CClientUIInterface::MSG_ERROR);
@@ -395,39 +391,34 @@ bool InitHTTPServer()
evthread_use_pthreads();
#endif
- base = event_base_new(); // XXX RAII
- if (!base) {
- LogPrintf("Couldn't create an event_base: exiting\n");
- return false;
- }
+ raii_event_base base_ctr = obtain_event_base();
/* Create a new evhttp object to handle requests. */
- http = evhttp_new(base); // XXX RAII
+ raii_evhttp http_ctr = obtain_evhttp(base_ctr.get());
+ struct evhttp* http = http_ctr.get();
if (!http) {
LogPrintf("couldn't create evhttp. Exiting.\n");
- event_base_free(base);
return false;
}
- evhttp_set_timeout(http, GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
+ evhttp_set_timeout(http, gArgs.GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
evhttp_set_max_headers_size(http, MAX_HEADERS_SIZE);
evhttp_set_max_body_size(http, MAX_SIZE);
- evhttp_set_gencb(http, http_request_cb, NULL);
+ evhttp_set_gencb(http, http_request_cb, nullptr);
if (!HTTPBindAddresses(http)) {
LogPrintf("Unable to bind any endpoint for RPC server\n");
- evhttp_free(http);
- event_base_free(base);
return false;
}
LogPrint(BCLog::HTTP, "Initialized HTTP server\n");
- int workQueueDepth = std::max((long)GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
+ int workQueueDepth = std::max((long)gArgs.GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
workQueue = new WorkQueue<HTTPClosure>(workQueueDepth);
- eventBase = base;
- eventHTTP = http;
+ // transfer ownership to eventBase/HTTP via .release()
+ eventBase = base_ctr.release();
+ eventHTTP = http_ctr.release();
return true;
}
@@ -451,7 +442,7 @@ std::future<bool> threadResult;
bool StartHTTPServer()
{
LogPrint(BCLog::HTTP, "Starting HTTP server\n");
- int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
+ int rpcThreads = std::max((long)gArgs.GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
std::packaged_task<bool(event_base*, evhttp*)> task(ThreadHTTP);
threadResult = task.get_future();
@@ -473,7 +464,7 @@ void InterruptHTTPServer()
evhttp_del_accept_socket(eventHTTP, socket);
}
// Reject requests on current connections
- evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL);
+ evhttp_set_gencb(eventHTTP, http_reject_request_cb, nullptr);
}
if (workQueue)
workQueue->Interrupt();
@@ -504,11 +495,11 @@ void StopHTTPServer()
}
if (eventHTTP) {
evhttp_free(eventHTTP);
- eventHTTP = 0;
+ eventHTTP = nullptr;
}
if (eventBase) {
event_base_free(eventBase);
- eventBase = 0;
+ eventBase = nullptr;
}
LogPrint(BCLog::HTTP, "Stopped HTTP server\n");
}
@@ -539,7 +530,7 @@ HTTPEvent::~HTTPEvent()
}
void HTTPEvent::trigger(struct timeval* tv)
{
- if (tv == NULL)
+ if (tv == nullptr)
event_active(ev, 0, 0); // immediately trigger event in main thread
else
evtimer_add(ev, tv); // trigger after timeval passed
@@ -582,7 +573,7 @@ std::string HTTPRequest::ReadBody()
* abstraction to consume the evbuffer on the fly in the parsing algorithm.
*/
const char* data = (const char*)evbuffer_pullup(buf, size);
- if (!data) // returns NULL in case of empty buffer
+ if (!data) // returns nullptr in case of empty buffer
return "";
std::string rv(data, size);
evbuffer_drain(buf, size);
@@ -609,10 +600,10 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
assert(evb);
evbuffer_add(evb, strReply.data(), strReply.size());
HTTPEvent* ev = new HTTPEvent(eventBase, true,
- std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
- ev->trigger(0);
+ std::bind(evhttp_send_reply, req, nStatus, (const char*)nullptr, (struct evbuffer *)nullptr));
+ ev->trigger(nullptr);
replySent = true;
- req = 0; // transferred back to main thread
+ req = nullptr; // transferred back to main thread
}
CService HTTPRequest::GetPeer()
@@ -675,3 +666,14 @@ void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
}
}
+std::string urlDecode(const std::string &urlEncoded) {
+ std::string res;
+ if (!urlEncoded.empty()) {
+ char *decoded = evhttp_uridecode(urlEncoded.c_str(), false, nullptr);
+ if (decoded) {
+ res = std::string(decoded);
+ free(decoded);
+ }
+ }
+ return res;
+}