Dogecoin Core  1.14.2
P2P Digital Currency
httpserver.cpp
Go to the documentation of this file.
1 // Copyright (c) 2015-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include "httpserver.h"
6 
7 #include "chainparamsbase.h"
8 #include "compat.h"
9 #include "util.h"
10 #include "netbase.h"
11 #include "rpc/protocol.h" // For HTTP status codes
12 #include "sync.h"
13 #include "ui_interface.h"
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <signal.h>
22 #include <deque>
23 #include <future>
24 
25 #include <event2/event.h>
26 #include <event2/http.h>
27 #include <event2/thread.h>
28 #include <event2/buffer.h>
29 #include <event2/util.h>
30 #include <event2/keyvalq_struct.h>
31 
32 #ifdef EVENT__HAVE_NETINET_IN_H
33 #include <netinet/in.h>
34 #ifdef _XOPEN_SOURCE_EXTENDED
35 #include <arpa/inet.h>
36 #endif
37 #endif
38 
40 static const size_t MAX_HEADERS_SIZE = 8192;
41 
43 class HTTPWorkItem : public HTTPClosure
44 {
45 public:
46  HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
47  req(std::move(_req)), path(_path), func(_func)
48  {
49  }
50  void operator()()
51  {
52  func(req.get(), path);
53  }
54 
55  std::unique_ptr<HTTPRequest> req;
56 
57 private:
58  std::string path;
60 };
61 
65 template <typename WorkItem>
66 class WorkQueue
67 {
68 private:
70  std::mutex cs;
71  std::condition_variable cond;
72  std::deque<std::unique_ptr<WorkItem>> queue;
73  bool running;
74  size_t maxDepth;
76 
79  {
80  public:
83  {
84  std::lock_guard<std::mutex> lock(wq.cs);
85  wq.numThreads += 1;
86  }
88  {
89  std::lock_guard<std::mutex> lock(wq.cs);
90  wq.numThreads -= 1;
91  wq.cond.notify_all();
92  }
93  };
94 
95 public:
96  WorkQueue(size_t _maxDepth) : running(true),
97  maxDepth(_maxDepth),
98  numThreads(0)
99  {
100  }
105  {
106  }
108  bool Enqueue(WorkItem* item)
109  {
110  std::unique_lock<std::mutex> lock(cs);
111  if (queue.size() >= maxDepth) {
112  return false;
113  }
114  queue.emplace_back(std::unique_ptr<WorkItem>(item));
115  cond.notify_one();
116  return true;
117  }
119  void Run()
120  {
121  ThreadCounter count(*this);
122  while (true) {
123  std::unique_ptr<WorkItem> i;
124  {
125  std::unique_lock<std::mutex> lock(cs);
126  while (running && queue.empty())
127  cond.wait(lock);
128  if (!running)
129  break;
130  i = std::move(queue.front());
131  queue.pop_front();
132  }
133  (*i)();
134  }
135  }
137  void Interrupt()
138  {
139  std::unique_lock<std::mutex> lock(cs);
140  running = false;
141  cond.notify_all();
142  }
144  void WaitExit()
145  {
146  std::unique_lock<std::mutex> lock(cs);
147  while (numThreads > 0)
148  cond.wait(lock);
149  }
150 
152  size_t Depth()
153  {
154  std::unique_lock<std::mutex> lock(cs);
155  return queue.size();
156  }
157 };
158 
160 {
162  HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):
163  prefix(_prefix), exactMatch(_exactMatch), handler(_handler)
164  {
165  }
166  std::string prefix;
169 };
170 
174 static struct event_base* eventBase = 0;
176 struct evhttp* eventHTTP = 0;
178 static std::vector<CSubNet> rpc_allow_subnets;
180 static WorkQueue<HTTPClosure>* workQueue = 0;
182 std::vector<HTTPPathHandler> pathHandlers;
184 std::vector<evhttp_bound_socket *> boundSockets;
185 
187 static bool ClientAllowed(const CNetAddr& netaddr)
188 {
189  if (!netaddr.IsValid())
190  return false;
191  for(const CSubNet& subnet : rpc_allow_subnets)
192  if (subnet.Match(netaddr))
193  return true;
194  return false;
195 }
196 
198 static bool InitHTTPAllowList()
199 {
200  rpc_allow_subnets.clear();
201  CNetAddr localv4;
202  CNetAddr localv6;
203  LookupHost("127.0.0.1", localv4, false);
204  LookupHost("::1", localv6, false);
205  rpc_allow_subnets.push_back(CSubNet(localv4, 8)); // always allow IPv4 local subnet
206  rpc_allow_subnets.push_back(CSubNet(localv6)); // always allow IPv6 localhost
207  if (mapMultiArgs.count("-rpcallowip")) {
208  const std::vector<std::string>& vAllow = mapMultiArgs.at("-rpcallowip");
209  for (std::string strAllow : vAllow) {
210  CSubNet subnet;
211  LookupSubNet(strAllow.c_str(), subnet);
212  if (!subnet.IsValid()) {
214  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),
216  return false;
217  }
218  rpc_allow_subnets.push_back(subnet);
219  }
220  }
221  std::string strAllowed;
222  for (const CSubNet& subnet : rpc_allow_subnets)
223  strAllowed += subnet.ToString() + " ";
224  LogPrint("http", "Allowing HTTP connections from: %s\n", strAllowed);
225  return true;
226 }
227 
229 static std::string RequestMethodString(HTTPRequest::RequestMethod m)
230 {
231  switch (m) {
232  case HTTPRequest::GET:
233  return "GET";
234  break;
235  case HTTPRequest::POST:
236  return "POST";
237  break;
238  case HTTPRequest::HEAD:
239  return "HEAD";
240  break;
241  case HTTPRequest::PUT:
242  return "PUT";
243  break;
244  default:
245  return "unknown";
246  }
247 }
248 
250 static void http_request_cb(struct evhttp_request* req, void* arg)
251 {
252  std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
253 
254  LogPrint("http", "Received a %s request for %s from %s\n",
255  RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());
256 
257  // Early address-based allow check
258  if (!ClientAllowed(hreq->GetPeer())) {
259  hreq->WriteReply(HTTP_FORBIDDEN);
260  return;
261  }
262 
263  // Early reject unknown HTTP methods
264  if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
265  hreq->WriteReply(HTTP_BADMETHOD);
266  return;
267  }
268 
269  // Find registered handler for prefix
270  std::string strURI = hreq->GetURI();
271  std::string path;
272  std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin();
273  std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end();
274  for (; i != iend; ++i) {
275  bool match = false;
276  if (i->exactMatch)
277  match = (strURI == i->prefix);
278  else
279  match = (strURI.substr(0, i->prefix.size()) == i->prefix);
280  if (match) {
281  path = strURI.substr(i->prefix.size());
282  break;
283  }
284  }
285 
286  // Dispatch to worker thread
287  if (i != iend) {
288  std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(std::move(hreq), path, i->handler));
289  assert(workQueue);
290  if (workQueue->Enqueue(item.get()))
291  item.release(); /* if true, queue took ownership */
292  else {
293  LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n");
294  item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded");
295  }
296  } else {
297  hreq->WriteReply(HTTP_NOTFOUND);
298  }
299 }
300 
302 static void http_reject_request_cb(struct evhttp_request* req, void*)
303 {
304  LogPrint("http", "Rejecting request while shutting down\n");
305  evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
306 }
307 
309 static bool ThreadHTTP(struct event_base* base, struct evhttp* http)
310 {
311  RenameThread("dogecoin-http");
312  LogPrint("http", "Entering http event loop\n");
313  event_base_dispatch(base);
314  // Event loop will be interrupted by InterruptHTTPServer()
315  LogPrint("http", "Exited http event loop\n");
316  return event_base_got_break(base) == 0;
317 }
318 
320 static bool HTTPBindAddresses(struct evhttp* http)
321 {
322  int defaultPort = GetArg("-rpcport", BaseParams().RPCPort());
323  std::vector<std::pair<std::string, uint16_t> > endpoints;
324 
325  // Determine what addresses to bind to
326  if (!IsArgSet("-rpcallowip")) { // Default to loopback if not allowing external IPs
327  endpoints.push_back(std::make_pair("::1", defaultPort));
328  endpoints.push_back(std::make_pair("127.0.0.1", defaultPort));
329  if (IsArgSet("-rpcbind")) {
330  LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
331  }
332  } else if (mapMultiArgs.count("-rpcbind")) { // Specific bind address
333  const std::vector<std::string>& vbind = mapMultiArgs.at("-rpcbind");
334  for (std::vector<std::string>::const_iterator i = vbind.begin(); i != vbind.end(); ++i) {
335  int port = defaultPort;
336  std::string host;
337  SplitHostPort(*i, port, host);
338  endpoints.push_back(std::make_pair(host, port));
339  }
340  } else { // No specific bind address specified, bind to any
341  endpoints.push_back(std::make_pair("::", defaultPort));
342  endpoints.push_back(std::make_pair("0.0.0.0", defaultPort));
343  }
344 
345  // Bind addresses
346  for (std::vector<std::pair<std::string, uint16_t> >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
347  LogPrint("http", "Binding RPC on address %s port %i\n", i->first, i->second);
348  evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? NULL : i->first.c_str(), i->second);
349  if (bind_handle) {
350  boundSockets.push_back(bind_handle);
351  } else {
352  LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second);
353  }
354  }
355  return !boundSockets.empty();
356 }
357 
359 static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue)
360 {
361  RenameThread("dogecoin-httpworker");
362  queue->Run();
363 }
364 
366 static void libevent_log_cb(int severity, const char *msg)
367 {
368 #ifndef EVENT_LOG_WARN
369 // EVENT_LOG_WARN was added in 2.0.19; but before then _EVENT_LOG_WARN existed.
370 # define EVENT_LOG_WARN _EVENT_LOG_WARN
371 #endif
372  if (severity >= EVENT_LOG_WARN) // Log warn messages and higher without debug category
373  LogPrintf("libevent: %s\n", msg);
374  else
375  LogPrint("libevent", "libevent: %s\n", msg);
376 }
377 
379 {
380  struct evhttp* http = 0;
381  struct event_base* base = 0;
382 
383  if (!InitHTTPAllowList())
384  return false;
385 
386  if (GetBoolArg("-rpcssl", false)) {
388  "SSL mode for RPC (-rpcssl) is no longer supported.",
390  return false;
391  }
392 
393  // Redirect libevent's logging to our own log
394  event_set_log_callback(&libevent_log_cb);
395 #if LIBEVENT_VERSION_NUMBER >= 0x02010100
396  // If -debug=libevent, set full libevent debugging.
397  // Otherwise, disable all libevent debugging.
398  if (LogAcceptCategory("libevent"))
399  event_enable_debug_logging(EVENT_DBG_ALL);
400  else
401  event_enable_debug_logging(EVENT_DBG_NONE);
402 #endif
403 #ifdef WIN32
404  evthread_use_windows_threads();
405 #else
406  evthread_use_pthreads();
407 #endif
408 
409  base = event_base_new(); // XXX RAII
410  if (!base) {
411  LogPrintf("Couldn't create an event_base: exiting\n");
412  return false;
413  }
414 
415  /* Create a new evhttp object to handle requests. */
416  http = evhttp_new(base); // XXX RAII
417  if (!http) {
418  LogPrintf("couldn't create evhttp. Exiting.\n");
419  event_base_free(base);
420  return false;
421  }
422 
423  evhttp_set_timeout(http, GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
424  evhttp_set_max_headers_size(http, MAX_HEADERS_SIZE);
425  evhttp_set_max_body_size(http, MAX_SIZE);
426  evhttp_set_gencb(http, http_request_cb, NULL);
427 
428  if (!HTTPBindAddresses(http)) {
429  LogPrintf("Unable to bind any endpoint for RPC server\n");
430  evhttp_free(http);
431  event_base_free(base);
432  return false;
433  }
434 
435  LogPrint("http", "Initialized HTTP server\n");
436  int workQueueDepth = std::max((long)GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
437  LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
438 
439  workQueue = new WorkQueue<HTTPClosure>(workQueueDepth);
440  eventBase = base;
441  eventHTTP = http;
442  return true;
443 }
444 
445 std::thread threadHTTP;
446 std::future<bool> threadResult;
447 
449 {
450  LogPrint("http", "Starting HTTP server\n");
451  int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
452  LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
453  std::packaged_task<bool(event_base*, evhttp*)> task(ThreadHTTP);
454  threadResult = task.get_future();
455  threadHTTP = std::thread(std::move(task), eventBase, eventHTTP);
456 
457  for (int i = 0; i < rpcThreads; i++) {
458  std::thread rpc_worker(HTTPWorkQueueRun, workQueue);
459  rpc_worker.detach();
460  }
461  return true;
462 }
463 
465 {
466  LogPrint("http", "Interrupting HTTP server\n");
467  if (eventHTTP) {
468  // Unlisten sockets
469  for (evhttp_bound_socket *socket : boundSockets) {
470  evhttp_del_accept_socket(eventHTTP, socket);
471  }
472  // Reject requests on current connections
473  evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL);
474  }
475  if (workQueue)
476  workQueue->Interrupt();
477 }
478 
480 {
481  LogPrint("http", "Stopping HTTP server\n");
482  if (workQueue) {
483  LogPrint("http", "Waiting for HTTP worker threads to exit\n");
484  workQueue->WaitExit();
485  delete workQueue;
486  }
487  if (eventBase) {
488  LogPrint("http", "Waiting for HTTP event thread to exit\n");
489  // Give event loop a few seconds to exit (to send back last RPC responses), then break it
490  // Before this was solved with event_base_loopexit, but that didn't work as expected in
491  // at least libevent 2.0.21 and always introduced a delay. In libevent
492  // master that appears to be solved, so in the future that solution
493  // could be used again (if desirable).
494  // (see discussion in https://github.com/bitcoin/bitcoin/pull/6990)
495  if (threadResult.valid() && threadResult.wait_for(std::chrono::milliseconds(2000)) == std::future_status::timeout) {
496  LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n");
497  event_base_loopbreak(eventBase);
498  }
499  threadHTTP.join();
500  }
501  if (eventHTTP) {
502  evhttp_free(eventHTTP);
503  eventHTTP = 0;
504  }
505  if (eventBase) {
506  event_base_free(eventBase);
507  eventBase = 0;
508  }
509  LogPrint("http", "Stopped HTTP server\n");
510 }
511 
512 struct event_base* EventBase()
513 {
514  return eventBase;
515 }
516 
517 static void httpevent_callback_fn(evutil_socket_t, short, void* data)
518 {
519  // Static handler: simply call inner handler
520  HTTPEvent *self = ((HTTPEvent*)data);
521  self->handler();
522  if (self->deleteWhenTriggered)
523  delete self;
524 }
525 
526 HTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function<void(void)>& _handler):
527  deleteWhenTriggered(_deleteWhenTriggered), handler(_handler)
528 {
529  ev = event_new(base, -1, 0, httpevent_callback_fn, this);
530  assert(ev);
531 }
533 {
534  event_free(ev);
535 }
536 void HTTPEvent::trigger(struct timeval* tv)
537 {
538  if (tv == NULL)
539  event_active(ev, 0, 0); // immediately trigger event in main thread
540  else
541  evtimer_add(ev, tv); // trigger after timeval passed
542 }
543 HTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req),
544  replySent(false)
545 {
546 }
548 {
549  if (!replySent) {
550  // Keep track of whether reply was sent to avoid request leaks
551  LogPrintf("%s: Unhandled request\n", __func__);
552  WriteReply(HTTP_INTERNAL, "Unhandled request");
553  }
554  // evhttpd cleans up the request, as long as a reply was sent.
555 }
556 
557 std::pair<bool, std::string> HTTPRequest::GetHeader(const std::string& hdr)
558 {
559  const struct evkeyvalq* headers = evhttp_request_get_input_headers(req);
560  assert(headers);
561  const char* val = evhttp_find_header(headers, hdr.c_str());
562  if (val)
563  return std::make_pair(true, val);
564  else
565  return std::make_pair(false, "");
566 }
567 
569 {
570  struct evbuffer* buf = evhttp_request_get_input_buffer(req);
571  if (!buf)
572  return "";
573  size_t size = evbuffer_get_length(buf);
580  const char* data = (const char*)evbuffer_pullup(buf, size);
581  if (!data) // returns NULL in case of empty buffer
582  return "";
583  std::string rv(data, size);
584  evbuffer_drain(buf, size);
585  return rv;
586 }
587 
588 void HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value)
589 {
590  struct evkeyvalq* headers = evhttp_request_get_output_headers(req);
591  assert(headers);
592  evhttp_add_header(headers, hdr.c_str(), value.c_str());
593 }
594 
600 void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
601 {
602  assert(!replySent && req);
603  // Send event to main http thread to send reply message
604  struct evbuffer* evb = evhttp_request_get_output_buffer(req);
605  assert(evb);
606  evbuffer_add(evb, strReply.data(), strReply.size());
607  HTTPEvent* ev = new HTTPEvent(eventBase, true,
608  std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
609  ev->trigger(0);
610  replySent = true;
611  req = 0; // transferred back to main thread
612 }
613 
615 {
616  evhttp_connection* con = evhttp_request_get_connection(req);
617  CService peer;
618  if (con) {
619  // evhttp retains ownership over returned address string
620  const char* address = "";
621  uint16_t port = 0;
622  evhttp_connection_get_peer(con, (char**)&address, &port);
623  peer = LookupNumeric(address, port);
624  }
625  return peer;
626 }
627 
628 std::string HTTPRequest::GetURI()
629 {
630  return evhttp_request_get_uri(req);
631 }
632 
634 {
635  switch (evhttp_request_get_command(req)) {
636  case EVHTTP_REQ_GET:
637  return GET;
638  break;
639  case EVHTTP_REQ_POST:
640  return POST;
641  break;
642  case EVHTTP_REQ_HEAD:
643  return HEAD;
644  break;
645  case EVHTTP_REQ_PUT:
646  return PUT;
647  break;
648  default:
649  return UNKNOWN;
650  break;
651  }
652 }
653 
654 void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
655 {
656  LogPrint("http", "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
657  pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler));
658 }
659 
660 void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
661 {
662  std::vector<HTTPPathHandler>::iterator i = pathHandlers.begin();
663  std::vector<HTTPPathHandler>::iterator iend = pathHandlers.end();
664  for (; i != iend; ++i)
665  if (i->prefix == prefix && i->exactMatch == exactMatch)
666  break;
667  if (i != iend)
668  {
669  LogPrint("http", "Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
670  pathHandlers.erase(i);
671  }
672 }
673 
const CBaseChainParams & BaseParams()
Return the currently selected parameters.
boost::signals2::signal< bool(const std::string &message, const std::string &caption, unsigned int style), boost::signals2::last_value< bool > > ThreadSafeMessageBox
Show message box.
Definition: ui_interface.h:77
IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96))
Definition: netaddress.h:31
bool IsValid() const
Definition: netaddress.cpp:188
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:134
std::string ToString() const
Definition: netaddress.cpp:660
bool IsValid() const
Definition: netaddress.cpp:698
Event handler closure.
Definition: httpserver.h:118
Event class.
Definition: httpserver.h:127
struct event * ev
Definition: httpserver.h:144
std::function< void(void)> handler
Definition: httpserver.h:142
HTTPEvent(struct event_base *base, bool deleteWhenTriggered, const std::function< void(void)> &handler)
Create a new event.
Definition: httpserver.cpp:526
void trigger(struct timeval *tv)
Trigger the event.
Definition: httpserver.cpp:536
In-flight HTTP request.
Definition: httpserver.h:54
bool replySent
Definition: httpserver.h:57
void WriteReply(int nStatus, const std::string &strReply="")
Write HTTP reply.
Definition: httpserver.cpp:600
std::string GetURI()
Get requested URI.
Definition: httpserver.cpp:628
CService GetPeer()
Get CService (address:ip) for the origin of the http request.
Definition: httpserver.cpp:614
std::pair< bool, std::string > GetHeader(const std::string &hdr)
Get the request header specified by hdr, or an empty string.
Definition: httpserver.cpp:557
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
Definition: httpserver.cpp:588
struct evhttp_request * req
Definition: httpserver.h:56
HTTPRequest(struct evhttp_request *req)
Definition: httpserver.cpp:543
std::string ReadBody()
Read request body.
Definition: httpserver.cpp:568
RequestMethod GetRequestMethod()
Get request method.
Definition: httpserver.cpp:633
HTTP request work item.
Definition: httpserver.cpp:44
std::unique_ptr< HTTPRequest > req
Definition: httpserver.cpp:55
void operator()()
Definition: httpserver.cpp:50
HTTPWorkItem(std::unique_ptr< HTTPRequest > _req, const std::string &_path, const HTTPRequestHandler &_func)
Definition: httpserver.cpp:46
std::string path
Definition: httpserver.cpp:58
HTTPRequestHandler func
Definition: httpserver.cpp:59
RAII object to keep track of number of running worker threads.
Definition: httpserver.cpp:79
ThreadCounter(WorkQueue &w)
Definition: httpserver.cpp:82
Simple work queue for distributing work over multiple threads.
Definition: httpserver.cpp:67
size_t Depth()
Return current depth of queue.
Definition: httpserver.cpp:152
bool Enqueue(WorkItem *item)
Enqueue a work item.
Definition: httpserver.cpp:108
void WaitExit()
Wait for worker threads to exit.
Definition: httpserver.cpp:144
bool running
Definition: httpserver.cpp:73
void Run()
Thread function.
Definition: httpserver.cpp:119
std::mutex cs
Mutex protects entire object.
Definition: httpserver.cpp:70
~WorkQueue()
Precondition: worker threads have all stopped (call WaitExit)
Definition: httpserver.cpp:104
std::deque< std::unique_ptr< WorkItem > > queue
Definition: httpserver.cpp:72
size_t maxDepth
Definition: httpserver.cpp:74
void Interrupt()
Interrupt and exit loops.
Definition: httpserver.cpp:137
WorkQueue(size_t _maxDepth)
Definition: httpserver.cpp:96
std::condition_variable cond
Definition: httpserver.cpp:71
int numThreads
Definition: httpserver.cpp:75
std::thread threadHTTP
Definition: httpserver.cpp:445
struct evhttp * eventHTTP
HTTP server.
Definition: httpserver.cpp:176
void InterruptHTTPServer()
Interrupt HTTP server threads.
Definition: httpserver.cpp:464
std::future< bool > threadResult
Definition: httpserver.cpp:446
std::vector< evhttp_bound_socket * > boundSockets
Bound listening sockets.
Definition: httpserver.cpp:184
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
Definition: httpserver.cpp:660
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
Definition: httpserver.cpp:654
struct event_base * EventBase()
Return evhttp event base.
Definition: httpserver.cpp:512
bool InitHTTPServer()
Initialize HTTP server.
Definition: httpserver.cpp:378
#define EVENT_LOG_WARN
bool StartHTTPServer()
Start HTTP server.
Definition: httpserver.cpp:448
void StopHTTPServer()
Stop HTTP server.
Definition: httpserver.cpp:479
std::vector< HTTPPathHandler > pathHandlers
Handlers for (sub)paths.
Definition: httpserver.cpp:182
std::function< bool(HTTPRequest *req, const std::string &)> HTTPRequestHandler
Handler for requests to a certain HTTP path.
Definition: httpserver.h:36
void SplitHostPort(std::string in, int &portOut, std::string &hostOut)
Definition: netbase.cpp:61
bool LookupHost(const char *pszName, std::vector< CNetAddr > &vIP, unsigned int nMaxSolutions, bool fAllowLookup)
Definition: netbase.cpp:132
bool LookupSubNet(const char *pszName, CSubNet &ret)
Definition: netbase.cpp:618
CService LookupNumeric(const char *pszName, int portDefault)
Definition: netbase.cpp:183
const char * prefix
Definition: rest.cpp:605
bool(* handler)(HTTPRequest *req, const std::string &strReq)
Definition: rest.cpp:606
@ HTTP_FORBIDDEN
Definition: protocol.h:23
std::string prefix
Definition: httpserver.cpp:166
HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler)
Definition: httpserver.cpp:162
HTTPRequestHandler handler
Definition: httpserver.cpp:168
#define strprintf
Definition: tinyformat.h:1047
struct event_base * base
Definition: torcontrol.cpp:679
CClientUIInterface uiInterface
Definition: ui_interface.cpp:8
std::string GetArg(const std::string &strArg, const std::string &strDefault)
Return string argument or default value.
Definition: util.cpp:395
bool LogAcceptCategory(const char *category)
Return true if log accepts specified category.
Definition: util.cpp:234
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
Definition: util.cpp:411
void RenameThread(const char *name)
Definition: util.cpp:781
const map< string, vector< string > > & mapMultiArgs
Definition: util.cpp:112
bool IsArgSet(const std::string &strArg)
Return true if the given argument has been manually set.
Definition: util.cpp:389
#define LogPrint(category,...)
Definition: util.h:76
#define LogPrintf(...)
Definition: util.h:82