Changeset View
Changeset View
Standalone View
Standalone View
src/httpserver.cpp
Show First 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | public: | ||||
} | } | ||||
/** Thread function */ | /** Thread function */ | ||||
void Run() { | void Run() { | ||||
while (true) { | while (true) { | ||||
std::unique_ptr<WorkItem> i; | std::unique_ptr<WorkItem> i; | ||||
{ | { | ||||
WAIT_LOCK(cs, lock); | WAIT_LOCK(cs, lock); | ||||
while (running && queue.empty()) | while (running && queue.empty()) { | ||||
cond.wait(lock); | cond.wait(lock); | ||||
if (!running) break; | } | ||||
if (!running) { | |||||
break; | |||||
} | |||||
i = std::move(queue.front()); | i = std::move(queue.front()); | ||||
queue.pop_front(); | queue.pop_front(); | ||||
} | } | ||||
(*i)(); | (*i)(); | ||||
} | } | ||||
} | } | ||||
/** Interrupt and exit loops */ | /** Interrupt and exit loops */ | ||||
Show All 26 Lines | |||||
static WorkQueue<HTTPClosure> *workQueue = nullptr; | static WorkQueue<HTTPClosure> *workQueue = nullptr; | ||||
//! Handlers for (sub)paths | //! Handlers for (sub)paths | ||||
std::vector<HTTPPathHandler> pathHandlers; | std::vector<HTTPPathHandler> pathHandlers; | ||||
//! Bound listening sockets | //! Bound listening sockets | ||||
std::vector<evhttp_bound_socket *> boundSockets; | std::vector<evhttp_bound_socket *> boundSockets; | ||||
/** Check if a network address is allowed to access the HTTP server */ | /** Check if a network address is allowed to access the HTTP server */ | ||||
static bool ClientAllowed(const CNetAddr &netaddr) { | static bool ClientAllowed(const CNetAddr &netaddr) { | ||||
if (!netaddr.IsValid()) return false; | if (!netaddr.IsValid()) { | ||||
for (const CSubNet &subnet : rpc_allow_subnets) | return false; | ||||
if (subnet.Match(netaddr)) return true; | } | ||||
for (const CSubNet &subnet : rpc_allow_subnets) { | |||||
if (subnet.Match(netaddr)) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | return false; | ||||
} | } | ||||
/** Initialize ACL list for HTTP server */ | /** Initialize ACL list for HTTP server */ | ||||
static bool InitHTTPAllowList() { | static bool InitHTTPAllowList() { | ||||
rpc_allow_subnets.clear(); | rpc_allow_subnets.clear(); | ||||
CNetAddr localv4; | CNetAddr localv4; | ||||
CNetAddr localv6; | CNetAddr localv6; | ||||
▲ Show 20 Lines • Show All 290 Lines • ▼ Show 20 Lines | void InterruptHTTPServer() { | ||||
if (eventHTTP) { | if (eventHTTP) { | ||||
// Unlisten sockets | // Unlisten sockets | ||||
for (evhttp_bound_socket *socket : boundSockets) { | for (evhttp_bound_socket *socket : boundSockets) { | ||||
evhttp_del_accept_socket(eventHTTP, socket); | evhttp_del_accept_socket(eventHTTP, socket); | ||||
} | } | ||||
// Reject requests on current connections | // Reject requests on current connections | ||||
evhttp_set_gencb(eventHTTP, http_reject_request_cb, nullptr); | evhttp_set_gencb(eventHTTP, http_reject_request_cb, nullptr); | ||||
} | } | ||||
if (workQueue) workQueue->Interrupt(); | if (workQueue) { | ||||
workQueue->Interrupt(); | |||||
} | |||||
} | } | ||||
void StopHTTPServer() { | void StopHTTPServer() { | ||||
LogPrint(BCLog::HTTP, "Stopping HTTP server\n"); | LogPrint(BCLog::HTTP, "Stopping HTTP server\n"); | ||||
if (workQueue) { | if (workQueue) { | ||||
LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n"); | LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n"); | ||||
for (auto &thread : g_thread_http_workers) { | for (auto &thread : g_thread_http_workers) { | ||||
thread.join(); | thread.join(); | ||||
Show All 36 Lines | |||||
struct event_base *EventBase() { | struct event_base *EventBase() { | ||||
return eventBase; | return eventBase; | ||||
} | } | ||||
static void httpevent_callback_fn(evutil_socket_t, short, void *data) { | static void httpevent_callback_fn(evutil_socket_t, short, void *data) { | ||||
// Static handler: simply call inner handler | // Static handler: simply call inner handler | ||||
HTTPEvent *self = static_cast<HTTPEvent *>(data); | HTTPEvent *self = static_cast<HTTPEvent *>(data); | ||||
self->handler(); | self->handler(); | ||||
if (self->deleteWhenTriggered) delete self; | if (self->deleteWhenTriggered) { | ||||
delete self; | |||||
} | |||||
} | } | ||||
HTTPEvent::HTTPEvent(struct event_base *base, bool _deleteWhenTriggered, | HTTPEvent::HTTPEvent(struct event_base *base, bool _deleteWhenTriggered, | ||||
const std::function<void()> &_handler) | const std::function<void()> &_handler) | ||||
: deleteWhenTriggered(_deleteWhenTriggered), handler(_handler) { | : deleteWhenTriggered(_deleteWhenTriggered), handler(_handler) { | ||||
ev = event_new(base, -1, 0, httpevent_callback_fn, this); | ev = event_new(base, -1, 0, httpevent_callback_fn, this); | ||||
assert(ev); | assert(ev); | ||||
} | } | ||||
Show All 19 Lines | HTTPRequest::~HTTPRequest() { | ||||
} | } | ||||
// evhttpd cleans up the request, as long as a reply was sent. | // evhttpd cleans up the request, as long as a reply was sent. | ||||
} | } | ||||
std::pair<bool, std::string> HTTPRequest::GetHeader(const std::string &hdr) { | std::pair<bool, std::string> HTTPRequest::GetHeader(const std::string &hdr) { | ||||
const struct evkeyvalq *headers = evhttp_request_get_input_headers(req); | const struct evkeyvalq *headers = evhttp_request_get_input_headers(req); | ||||
assert(headers); | assert(headers); | ||||
const char *val = evhttp_find_header(headers, hdr.c_str()); | const char *val = evhttp_find_header(headers, hdr.c_str()); | ||||
if (val) | if (val) { | ||||
return std::make_pair(true, val); | return std::make_pair(true, val); | ||||
else | } else { | ||||
return std::make_pair(false, ""); | return std::make_pair(false, ""); | ||||
} | } | ||||
} | |||||
std::string HTTPRequest::ReadBody() { | std::string HTTPRequest::ReadBody() { | ||||
struct evbuffer *buf = evhttp_request_get_input_buffer(req); | struct evbuffer *buf = evhttp_request_get_input_buffer(req); | ||||
if (!buf) return ""; | if (!buf) { | ||||
return ""; | |||||
} | |||||
size_t size = evbuffer_get_length(buf); | size_t size = evbuffer_get_length(buf); | ||||
/** | /** | ||||
* Trivial implementation: if this is ever a performance bottleneck, | * Trivial implementation: if this is ever a performance bottleneck, | ||||
* internal copying can be avoided in multi-segment buffers by using | * internal copying can be avoided in multi-segment buffers by using | ||||
* evbuffer_peek and an awkward loop. Though in that case, it'd be even | * evbuffer_peek and an awkward loop. Though in that case, it'd be even | ||||
* better to not copy into an intermediate string but use a stream | * better to not copy into an intermediate string but use a stream | ||||
* abstraction to consume the evbuffer on the fly in the parsing algorithm. | * abstraction to consume the evbuffer on the fly in the parsing algorithm. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, | ||||
LogPrint(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n", | LogPrint(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n", | ||||
prefix, exactMatch); | prefix, exactMatch); | ||||
pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler)); | pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler)); | ||||
} | } | ||||
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch) { | void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch) { | ||||
std::vector<HTTPPathHandler>::iterator i = pathHandlers.begin(); | std::vector<HTTPPathHandler>::iterator i = pathHandlers.begin(); | ||||
std::vector<HTTPPathHandler>::iterator iend = pathHandlers.end(); | std::vector<HTTPPathHandler>::iterator iend = pathHandlers.end(); | ||||
for (; i != iend; ++i) | for (; i != iend; ++i) { | ||||
if (i->prefix == prefix && i->exactMatch == exactMatch) break; | if (i->prefix == prefix && i->exactMatch == exactMatch) { | ||||
break; | |||||
} | |||||
} | |||||
if (i != iend) { | if (i != iend) { | ||||
LogPrint(BCLog::HTTP, | LogPrint(BCLog::HTTP, | ||||
"Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, | "Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, | ||||
exactMatch); | exactMatch); | ||||
pathHandlers.erase(i); | pathHandlers.erase(i); | ||||
} | } | ||||
} | } |