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