19 #include <sys/types.h> 23 #include <event2/event.h> 24 #include <event2/http.h> 25 #include <event2/thread.h> 26 #include <event2/buffer.h> 27 #include <event2/util.h> 28 #include <event2/keyvalq_struct.h> 30 #ifdef EVENT__HAVE_NETINET_IN_H 31 #include <netinet/in.h> 32 #ifdef _XOPEN_SOURCE_EXTENDED 33 #include <arpa/inet.h> 37 #include <boost/algorithm/string/case_conv.hpp> 38 #include <boost/foreach.hpp> 39 #include <boost/scoped_ptr.hpp> 57 boost::scoped_ptr<HTTPRequest>
req;
67 template <
typename WorkItem>
87 boost::lock_guard<boost::mutex> lock(
wq.
cs);
92 boost::lock_guard<boost::mutex> lock(
wq.
cs);
109 while (!
queue.empty()) {
110 delete queue.front();
117 boost::unique_lock<boost::mutex> lock(
cs);
121 queue.push_back(item);
132 boost::unique_lock<boost::mutex> lock(
cs);
147 boost::unique_lock<boost::mutex> lock(
cs);
154 boost::unique_lock<boost::mutex> lock(
cs);
163 boost::unique_lock<boost::mutex> lock(
cs);
201 if (subnet.
Match(netaddr))
217 const std::vector<std::string>& vAllow =
mapMultiArgs[
"-rpcallowip"];
218 BOOST_FOREACH (std::string strAllow, vAllow) {
223 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),
230 std::string strAllowed;
232 strAllowed += subnet.
ToString() +
" ";
233 LogPrint(
"http",
"Allowing HTTP connections from: %s\n", strAllowed);
261 std::unique_ptr<HTTPRequest> hreq(
new HTTPRequest(req));
263 LogPrint(
"http",
"Received a %s request for %s from %s\n",
264 RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());
274 hreq->WriteReply(HTTP_BADMETHOD);
279 std::string strURI = hreq->GetURI();
281 std::vector<HTTPPathHandler>::const_iterator i =
pathHandlers.begin();
282 std::vector<HTTPPathHandler>::const_iterator iend =
pathHandlers.end();
283 for (; i != iend; ++i) {
286 match = (strURI == i->prefix);
288 match = (strURI.substr(0, i->prefix.size()) == i->prefix);
290 path = strURI.substr(i->prefix.size());
297 std::unique_ptr<HTTPWorkItem> item(
new HTTPWorkItem(hreq.release(), path, i->handler));
302 item->req->WriteReply(HTTP_INTERNAL,
"Work queue depth exceeded");
304 hreq->WriteReply(HTTP_NOTFOUND);
311 LogPrint(
"http",
"Rejecting request while shutting down\n");
312 evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
319 LogPrint(
"http",
"Entering http event loop\n");
320 event_base_dispatch(
base);
322 LogPrint(
"http",
"Exited http event loop\n");
329 std::vector<std::pair<std::string, uint16_t> > endpoints;
332 if (!
mapArgs.count(
"-rpcallowip")) {
333 endpoints.push_back(std::make_pair(
"::1", defaultPort));
334 endpoints.push_back(std::make_pair(
"127.0.0.1", defaultPort));
335 if (
mapArgs.count(
"-rpcbind")) {
336 LogPrintf(
"WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
338 }
else if (
mapArgs.count(
"-rpcbind")) {
339 const std::vector<std::string>& vbind =
mapMultiArgs[
"-rpcbind"];
340 for (std::vector<std::string>::const_iterator i = vbind.begin(); i != vbind.end(); ++i) {
341 int port = defaultPort;
344 endpoints.push_back(std::make_pair(host,
port));
347 endpoints.push_back(std::make_pair(
"::", defaultPort));
348 endpoints.push_back(std::make_pair(
"0.0.0.0", defaultPort));
352 for (std::vector<std::pair<std::string, uint16_t> >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
353 LogPrint(
"http",
"Binding RPC on address %s port %i\n", i->first, i->second);
354 evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? NULL : i->first.c_str(), i->second);
358 LogPrintf(
"Binding RPC on address %s port %i failed.\n", i->first, i->second);
374 #ifndef EVENT_LOG_WARN 376 # define EVENT_LOG_WARN _EVENT_LOG_WARN 386 struct evhttp* http = 0;
387 struct event_base*
base = 0;
394 "SSL mode for RPC (-rpcssl) is no longer supported.",
401 #if LIBEVENT_VERSION_NUMBER >= 0x02010100 405 event_enable_debug_logging(EVENT_DBG_ALL);
407 event_enable_debug_logging(EVENT_DBG_NONE);
410 evthread_use_windows_threads();
412 evthread_use_pthreads();
415 base = event_base_new();
417 LogPrintf(
"Couldn't create an event_base: exiting\n");
422 http = evhttp_new(
base);
424 LogPrintf(
"couldn't create evhttp. Exiting.\n");
425 event_base_free(
base);
431 evhttp_set_max_body_size(http,
MAX_SIZE);
435 LogPrintf(
"Unable to bind any endpoint for RPC server\n");
437 event_base_free(
base);
441 LogPrint(
"http",
"Initialized HTTP server\n");
443 LogPrintf(
"HTTP: creating work queue of depth %d\n", workQueueDepth);
455 LogPrint(
"http",
"Starting HTTP server\n");
457 LogPrintf(
"HTTP: starting %d worker threads\n", rpcThreads);
460 for (
int i = 0; i < rpcThreads; i++)
467 LogPrint(
"http",
"Interrupting HTTP server\n");
470 BOOST_FOREACH (evhttp_bound_socket *socket,
boundSockets) {
471 evhttp_del_accept_socket(
eventHTTP, socket);
482 LogPrint(
"http",
"Stopping HTTP server\n");
484 LogPrint(
"http",
"Waiting for HTTP worker threads to exit\n");
494 LogPrint(
"http",
"Waiting for HTTP event thread to exit\n");
501 #if BOOST_VERSION >= 105000 502 if (!
threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) {
504 if (!
threadHTTP.timed_join(boost::posix_time::milliseconds(2000))) {
507 LogPrintf(
"HTTP event loop did not exit within allotted time, sending loopbreak\n");
520 LogPrint(
"http",
"Stopped HTTP server\n");
533 if (self->deleteWhenTriggered)
550 event_active(
ev, 0, 0);
562 LogPrintf(
"%s: Unhandled request\n", __func__);
563 WriteReply(HTTP_INTERNAL,
"Unhandled request");
570 const struct evkeyvalq* headers = evhttp_request_get_input_headers(
req);
572 const char* val = evhttp_find_header(headers, hdr.c_str());
574 return std::make_pair(
true, val);
576 return std::make_pair(
false,
"");
581 struct evbuffer* buf = evhttp_request_get_input_buffer(
req);
584 size_t size = evbuffer_get_length(buf);
591 const char*
data = (
const char*)evbuffer_pullup(buf, size);
594 std::string rv(
data, size);
595 evbuffer_drain(buf, size);
601 struct evkeyvalq* headers = evhttp_request_get_output_headers(
req);
603 evhttp_add_header(headers, hdr.c_str(), value.c_str());
615 struct evbuffer* evb = evhttp_request_get_output_buffer(
req);
617 evbuffer_add(evb, strReply.data(), strReply.size());
619 boost::bind(evhttp_send_reply,
req, nStatus, (
const char*)NULL, (
struct evbuffer *)NULL));
627 evhttp_connection* con = evhttp_request_get_connection(
req);
631 const char* address =
"";
633 evhttp_connection_get_peer(con, (
char**)&address, &
port);
641 return evhttp_request_get_uri(
req);
646 switch (evhttp_request_get_command(
req)) {
650 case EVHTTP_REQ_POST:
653 case EVHTTP_REQ_HEAD:
667 LogPrint(
"http",
"Registering HTTP handler for %s (exactmatch %d)\n",
prefix, exactMatch);
673 std::vector<HTTPPathHandler>::iterator i =
pathHandlers.begin();
674 std::vector<HTTPPathHandler>::iterator iend =
pathHandlers.end();
675 for (; i != iend; ++i)
676 if (i->prefix ==
prefix && i->exactMatch == exactMatch)
680 LogPrint(
"http",
"Unregistering HTTP handler for %s (exactmatch %d)\n",
prefix, exactMatch);
std::deque< WorkItem * > queue
bool(* handler)(HTTPRequest *req, const std::string &strReq)
boost::condition_variable CConditionVariable
std::vector< evhttp_bound_socket * > boundSockets
Bound listening sockets.
static const int DEFAULT_HTTP_SERVER_TIMEOUT
static const int DEFAULT_HTTP_WORKQUEUE
ThreadCounter(WorkQueue &w)
std::vector< HTTPPathHandler > pathHandlers
Handlers for (sub)paths.
HTTPPathHandler(std::string prefix, bool exactMatch, HTTPRequestHandler handler)
std::string ToString() const
CService LookupNumeric(const char *pszName, int portDefault)
HTTPEvent(struct event_base *base, bool deleteWhenTriggered, const boost::function< void(void)> &handler)
static void httpevent_callback_fn(evutil_socket_t, short, void *data)
const CBaseChainParams & BaseParams()
static std::vector< CSubNet > rpc_allow_subnets
List of subnets to allow RPC connections from.
static void libevent_log_cb(int severity, const char *msg)
void trigger(struct timeval *tv)
static bool InitHTTPAllowList()
void InterruptHTTPServer()
void RenameThread(const char *name)
boost::signals2::signal< bool(const std::string &message, const std::string &caption, unsigned int style), boost::signals2::last_value< bool > > ThreadSafeMessageBox
static bool HTTPBindAddresses(struct evhttp *http)
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
#define L(x0, x1, x2, x3, x4, x5, x6, x7)
static std::string RequestMethodString(HTTPRequest::RequestMethod m)
static void http_reject_request_cb(struct evhttp_request *req, void *)
bool GetBoolArg(const std::string &strArg, bool fDefault)
HTTPRequestHandler handler
static int LogPrint(const char *category, const char *format)
CWaitableCriticalSection cs
void WriteReply(int nStatus, const std::string &strReply="")
CClientUIInterface uiInterface
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
boost::function< void(void)> handler
struct event_base * EventBase()
std::pair< bool, std::string > GetHeader(const std::string &hdr)
bool LookupSubNet(const char *pszName, CSubNet &ret)
void SplitHostPort(std::string in, int &portOut, std::string &hostOut)
static bool ClientAllowed(const CNetAddr &netaddr)
HTTPWorkItem(HTTPRequest *req, const std::string &path, const HTTPRequestHandler &func)
HTTPRequest(struct evhttp_request *req)
static WorkQueue< HTTPClosure > * workQueue
Work queue for handling longer requests off the event loop thread.
static const unsigned int MAX_SIZE
RequestMethod GetRequestMethod()
static void HTTPWorkQueueRun(WorkQueue< HTTPClosure > *queue)
bool LogAcceptCategory(const char *category)
struct evhttp_request * req
static const size_t MAX_HEADERS_SIZE
static void http_request_cb(struct evhttp_request *req, void *arg)
void WriteHeader(const std::string &hdr, const std::string &value)
boost::scoped_ptr< HTTPRequest > req
WorkQueue(size_t maxDepth)
std::string GetArg(const std::string &strArg, const std::string &strDefault)
bool LookupHost(const char *pszName, std::vector< CNetAddr > &vIP, unsigned int nMaxSolutions, bool fAllowLookup)
boost::function< void(HTTPRequest *req, const std::string &)> HTTPRequestHandler
map< string, vector< string > > mapMultiArgs
bool Match(const CNetAddr &addr) const
struct evhttp * eventHTTP
HTTP server.
bool Enqueue(WorkItem *item)
static const int DEFAULT_HTTP_THREADS
static void ThreadHTTP(struct event_base *base, struct evhttp *http)
map< string, string > mapArgs
static struct event_base * eventBase
libevent event loop