LCOV - code coverage report
Current view: top level - src - httpserver.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 320 377 84.9 %
Date: 2020-09-26 01:30:44 Functions: 59 60 98.3 %

          Line data    Source code
       1             : // Copyright (c) 2015-2020 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 <netbase.h>
      10             : #include <node/ui_interface.h>
      11             : #include <rpc/protocol.h> // For HTTP status codes
      12             : #include <shutdown.h>
      13             : #include <sync.h>
      14             : #include <util/strencodings.h>
      15             : #include <util/system.h>
      16             : #include <util/threadnames.h>
      17             : #include <util/translation.h>
      18             : 
      19             : #include <deque>
      20             : #include <memory>
      21             : #include <stdio.h>
      22             : #include <stdlib.h>
      23             : #include <string>
      24             : 
      25             : #include <sys/types.h>
      26             : #include <sys/stat.h>
      27             : 
      28             : #include <event2/thread.h>
      29             : #include <event2/buffer.h>
      30             : #include <event2/bufferevent.h>
      31             : #include <event2/util.h>
      32             : #include <event2/keyvalq_struct.h>
      33             : 
      34             : #include <support/events.h>
      35             : 
      36             : #ifdef EVENT__HAVE_NETINET_IN_H
      37             : #include <netinet/in.h>
      38             : #ifdef _XOPEN_SOURCE_EXTENDED
      39             : #include <arpa/inet.h>
      40             : #endif
      41             : #endif
      42             : 
      43             : /** Maximum size of http request (request line + headers) */
      44             : static const size_t MAX_HEADERS_SIZE = 8192;
      45             : 
      46             : /** HTTP request work item */
      47      237195 : class HTTPWorkItem final : public HTTPClosure
      48             : {
      49             : public:
      50      158130 :     HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
      51       79065 :         req(std::move(_req)), path(_path), func(_func)
      52      158130 :     {
      53      158130 :     }
      54       79065 :     void operator()() override
      55             :     {
      56       79065 :         func(req.get(), path);
      57       79065 :     }
      58             : 
      59             :     std::unique_ptr<HTTPRequest> req;
      60             : 
      61             : private:
      62             :     std::string path;
      63             :     HTTPRequestHandler func;
      64             : };
      65             : 
      66             : /** Simple work queue for distributing work over multiple threads.
      67             :  * Work items are simply callable objects.
      68             :  */
      69             : template <typename WorkItem>
      70             : class WorkQueue
      71             : {
      72             : private:
      73             :     /** Mutex protects entire object */
      74             :     Mutex cs;
      75             :     std::condition_variable cond;
      76             :     std::deque<std::unique_ptr<WorkItem>> queue;
      77             :     bool running;
      78             :     size_t maxDepth;
      79             : 
      80             : public:
      81        1052 :     explicit WorkQueue(size_t _maxDepth) : running(true),
      82         526 :                                  maxDepth(_maxDepth)
      83         526 :     {
      84        1052 :     }
      85             :     /** Precondition: worker threads have all stopped (they have been joined).
      86             :      */
      87        1052 :     ~WorkQueue()
      88         526 :     {
      89        1052 :     }
      90             :     /** Enqueue a work item */
      91       79065 :     bool Enqueue(WorkItem* item)
      92             :     {
      93       79065 :         LOCK(cs);
      94       79065 :         if (queue.size() >= maxDepth) {
      95           0 :             return false;
      96             :         }
      97       79065 :         queue.emplace_back(std::unique_ptr<WorkItem>(item));
      98       79065 :         cond.notify_one();
      99       79065 :         return true;
     100       79065 :     }
     101             :     /** Thread function */
     102        2095 :     void Run()
     103             :     {
     104        2095 :         while (true) {
     105       81164 :             std::unique_ptr<WorkItem> i;
     106             :             {
     107       81164 :                 WAIT_LOCK(cs, lock);
     108      162318 :                 while (running && queue.empty())
     109       81153 :                     cond.wait(lock);
     110       81165 :                 if (!running)
     111        2100 :                     break;
     112       79065 :                 i = std::move(queue.front());
     113       79065 :                 queue.pop_front();
     114       81165 :             }
     115       79065 :             (*i)();
     116       81165 :         }
     117        2098 :     }
     118             :     /** Interrupt and exit loops */
     119         526 :     void Interrupt()
     120             :     {
     121         526 :         LOCK(cs);
     122         526 :         running = false;
     123         526 :         cond.notify_all();
     124         526 :     }
     125             : };
     126             : 
     127        9089 : struct HTTPPathHandler
     128             : {
     129        2118 :     HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):
     130        1059 :         prefix(_prefix), exactMatch(_exactMatch), handler(_handler)
     131        1059 :     {
     132        2118 :     }
     133             :     std::string prefix;
     134             :     bool exactMatch;
     135             :     HTTPRequestHandler handler;
     136             : };
     137             : 
     138             : /** HTTP module state */
     139             : 
     140             : //! libevent event loop
     141             : static struct event_base* eventBase = nullptr;
     142             : //! HTTP server
     143             : static struct evhttp* eventHTTP = nullptr;
     144             : //! List of subnets to allow RPC connections from
     145         640 : static std::vector<CSubNet> rpc_allow_subnets;
     146             : //! Work queue for handling longer requests off the event loop thread
     147             : static WorkQueue<HTTPClosure>* workQueue = nullptr;
     148             : //! Handlers for (sub)paths
     149         640 : static std::vector<HTTPPathHandler> pathHandlers;
     150             : //! Bound listening sockets
     151         640 : static std::vector<evhttp_bound_socket *> boundSockets;
     152             : 
     153             : /** Check if a network address is allowed to access the HTTP server */
     154       79066 : static bool ClientAllowed(const CNetAddr& netaddr)
     155             : {
     156       79066 :     if (!netaddr.IsValid())
     157           0 :         return false;
     158      158132 :     for(const CSubNet& subnet : rpc_allow_subnets)
     159       79066 :         if (subnet.Match(netaddr))
     160       79066 :             return true;
     161           0 :     return false;
     162       79066 : }
     163             : 
     164             : /** Initialize ACL list for HTTP server */
     165         526 : static bool InitHTTPAllowList()
     166             : {
     167         526 :     rpc_allow_subnets.clear();
     168         526 :     CNetAddr localv4;
     169         526 :     CNetAddr localv6;
     170         526 :     LookupHost("127.0.0.1", localv4, false);
     171         526 :     LookupHost("::1", localv6, false);
     172         526 :     rpc_allow_subnets.push_back(CSubNet(localv4, 8));      // always allow IPv4 local subnet
     173         526 :     rpc_allow_subnets.push_back(CSubNet(localv6));         // always allow IPv6 localhost
     174         526 :     for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) {
     175           0 :         CSubNet subnet;
     176           0 :         LookupSubNet(strAllow, subnet);
     177           0 :         if (!subnet.IsValid()) {
     178           0 :             uiInterface.ThreadSafeMessageBox(
     179           0 :                 strprintf(Untranslated("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),
     180           0 :                 "", CClientUIInterface::MSG_ERROR);
     181           0 :             return false;
     182             :         }
     183           0 :         rpc_allow_subnets.push_back(subnet);
     184           0 :     }
     185         526 :     std::string strAllowed;
     186        1578 :     for (const CSubNet& subnet : rpc_allow_subnets)
     187        1052 :         strAllowed += subnet.ToString() + " ";
     188         526 :     LogPrint(BCLog::HTTP, "Allowing HTTP connections from: %s\n", strAllowed);
     189             :     return true;
     190         526 : }
     191             : 
     192             : /** HTTP request method as string - use for logging only */
     193       79066 : std::string RequestMethodString(HTTPRequest::RequestMethod m)
     194             : {
     195       79066 :     switch (m) {
     196             :     case HTTPRequest::GET:
     197          36 :         return "GET";
     198             :         break;
     199             :     case HTTPRequest::POST:
     200       79030 :         return "POST";
     201             :         break;
     202             :     case HTTPRequest::HEAD:
     203           0 :         return "HEAD";
     204             :         break;
     205             :     case HTTPRequest::PUT:
     206           0 :         return "PUT";
     207             :         break;
     208             :     default:
     209           0 :         return "unknown";
     210             :     }
     211       79066 : }
     212             : 
     213             : /** HTTP request callback */
     214       79066 : static void http_request_cb(struct evhttp_request* req, void* arg)
     215             : {
     216             :     // Disable reading to work around a libevent bug, fixed in 2.2.0.
     217       79066 :     if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
     218       79066 :         evhttp_connection* conn = evhttp_request_get_connection(req);
     219       79066 :         if (conn) {
     220       79066 :             bufferevent* bev = evhttp_connection_get_bufferevent(conn);
     221       79066 :             if (bev) {
     222       79066 :                 bufferevent_disable(bev, EV_READ);
     223       79066 :             }
     224       79066 :         }
     225       79066 :     }
     226       79066 :     std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
     227             : 
     228             :     // Early address-based allow check
     229       79066 :     if (!ClientAllowed(hreq->GetPeer())) {
     230           0 :         LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Client network is not allowed RPC access\n",
     231             :                  hreq->GetPeer().ToString());
     232           0 :         hreq->WriteReply(HTTP_FORBIDDEN);
     233           0 :         return;
     234             :     }
     235             : 
     236             :     // Early reject unknown HTTP methods
     237       79066 :     if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
     238           0 :         LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n",
     239             :                  hreq->GetPeer().ToString());
     240           0 :         hreq->WriteReply(HTTP_BAD_METHOD);
     241           0 :         return;
     242             :     }
     243             : 
     244       79066 :     LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
     245             :              RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToString());
     246             : 
     247             :     // Find registered handler for prefix
     248       79066 :     std::string strURI = hreq->GetURI();
     249       79066 :     std::string path;
     250       79066 :     std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin();
     251       79066 :     std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end();
     252       81183 :     for (; i != iend; ++i) {
     253             :         bool match = false;
     254       81182 :         if (i->exactMatch)
     255       79066 :             match = (strURI == i->prefix);
     256             :         else
     257        2116 :             match = (strURI.substr(0, i->prefix.size()) == i->prefix);
     258       81182 :         if (match) {
     259       79065 :             path = strURI.substr(i->prefix.size());
     260       79065 :             break;
     261             :         }
     262        2117 :     }
     263             : 
     264             :     // Dispatch to worker thread
     265       79066 :     if (i != iend) {
     266       79065 :         std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(std::move(hreq), path, i->handler));
     267       79065 :         assert(workQueue);
     268       79065 :         if (workQueue->Enqueue(item.get()))
     269       79065 :             item.release(); /* if true, queue took ownership */
     270             :         else {
     271           0 :             LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n");
     272           0 :             item->req->WriteReply(HTTP_INTERNAL_SERVER_ERROR, "Work queue depth exceeded");
     273             :         }
     274       79065 :     } else {
     275           1 :         hreq->WriteReply(HTTP_NOT_FOUND);
     276             :     }
     277       79066 : }
     278             : 
     279             : /** Callback to reject HTTP requests after shutdown. */
     280           1 : static void http_reject_request_cb(struct evhttp_request* req, void*)
     281             : {
     282           1 :     LogPrint(BCLog::HTTP, "Rejecting request while shutting down\n");
     283           1 :     evhttp_send_error(req, HTTP_SERVUNAVAIL, nullptr);
     284           1 : }
     285             : 
     286             : /** Event dispatcher thread */
     287         525 : static bool ThreadHTTP(struct event_base* base)
     288             : {
     289         525 :     util::ThreadRename("http");
     290         525 :     LogPrint(BCLog::HTTP, "Entering http event loop\n");
     291         525 :     event_base_dispatch(base);
     292             :     // Event loop will be interrupted by InterruptHTTPServer()
     293         525 :     LogPrint(BCLog::HTTP, "Exited http event loop\n");
     294         525 :     return event_base_got_break(base) == 0;
     295           0 : }
     296             : 
     297             : /** Bind HTTP server to specified addresses */
     298         526 : static bool HTTPBindAddresses(struct evhttp* http)
     299             : {
     300         526 :     int http_port = gArgs.GetArg("-rpcport", BaseParams().RPCPort());
     301         526 :     std::vector<std::pair<std::string, uint16_t> > endpoints;
     302             : 
     303             :     // Determine what addresses to bind to
     304         526 :     if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-rpcbind"))) { // Default to loopback if not allowing external IPs
     305         526 :         endpoints.push_back(std::make_pair("::1", http_port));
     306         526 :         endpoints.push_back(std::make_pair("127.0.0.1", http_port));
     307         526 :         if (gArgs.IsArgSet("-rpcallowip")) {
     308           0 :             LogPrintf("WARNING: option -rpcallowip was specified without -rpcbind; this doesn't usually make sense\n");
     309             :         }
     310         526 :         if (gArgs.IsArgSet("-rpcbind")) {
     311           1 :             LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
     312             :         }
     313           0 :     } else if (gArgs.IsArgSet("-rpcbind")) { // Specific bind address
     314           0 :         for (const std::string& strRPCBind : gArgs.GetArgs("-rpcbind")) {
     315           0 :             int port = http_port;
     316           0 :             std::string host;
     317           0 :             SplitHostPort(strRPCBind, port, host);
     318           0 :             endpoints.push_back(std::make_pair(host, port));
     319           0 :         }
     320           0 :     }
     321             : 
     322             :     // Bind addresses
     323        1578 :     for (std::vector<std::pair<std::string, uint16_t> >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
     324        1052 :         LogPrint(BCLog::HTTP, "Binding RPC on address %s port %i\n", i->first, i->second);
     325        1052 :         evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? nullptr : i->first.c_str(), i->second);
     326        1052 :         if (bind_handle) {
     327        1052 :             CNetAddr addr;
     328        1052 :             if (i->first.empty() || (LookupHost(i->first, addr, false) && addr.IsBindAny())) {
     329           0 :                 LogPrintf("WARNING: the RPC server is not safe to expose to untrusted networks such as the public internet\n");
     330             :             }
     331        1052 :             boundSockets.push_back(bind_handle);
     332        1052 :         } else {
     333           0 :             LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second);
     334             :         }
     335        1052 :     }
     336         526 :     return !boundSockets.empty();
     337         526 : }
     338             : 
     339             : /** Simple wrapper to set thread name and run work queue */
     340        2099 : static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue, int worker_num)
     341             : {
     342        2099 :     util::ThreadRename(strprintf("httpworker.%i", worker_num));
     343        2097 :     queue->Run();
     344        2097 : }
     345             : 
     346             : /** libevent event log callback */
     347           0 : static void libevent_log_cb(int severity, const char *msg)
     348             : {
     349             : #ifndef EVENT_LOG_WARN
     350             : // EVENT_LOG_WARN was added in 2.0.19; but before then _EVENT_LOG_WARN existed.
     351             : # define EVENT_LOG_WARN _EVENT_LOG_WARN
     352             : #endif
     353           0 :     if (severity >= EVENT_LOG_WARN) // Log warn messages and higher without debug category
     354           0 :         LogPrintf("libevent: %s\n", msg);
     355             :     else
     356           0 :         LogPrint(BCLog::LIBEVENT, "libevent: %s\n", msg);
     357           0 : }
     358             : 
     359         526 : bool InitHTTPServer()
     360             : {
     361         526 :     if (!InitHTTPAllowList())
     362           0 :         return false;
     363             : 
     364             :     // Redirect libevent's logging to our own log
     365         526 :     event_set_log_callback(&libevent_log_cb);
     366             :     // Update libevent's log handling. Returns false if our version of
     367             :     // libevent doesn't support debug logging, in which case we should
     368             :     // clear the BCLog::LIBEVENT flag.
     369         526 :     if (!UpdateHTTPServerLogging(LogInstance().WillLogCategory(BCLog::LIBEVENT))) {
     370           0 :         LogInstance().DisableCategory(BCLog::LIBEVENT);
     371           0 :     }
     372             : 
     373             : #ifdef WIN32
     374             :     evthread_use_windows_threads();
     375             : #else
     376         526 :     evthread_use_pthreads();
     377             : #endif
     378             : 
     379         526 :     raii_event_base base_ctr = obtain_event_base();
     380             : 
     381             :     /* Create a new evhttp object to handle requests. */
     382         526 :     raii_evhttp http_ctr = obtain_evhttp(base_ctr.get());
     383         526 :     struct evhttp* http = http_ctr.get();
     384         526 :     if (!http) {
     385           0 :         LogPrintf("couldn't create evhttp. Exiting.\n");
     386           0 :         return false;
     387             :     }
     388             : 
     389         526 :     evhttp_set_timeout(http, gArgs.GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
     390         526 :     evhttp_set_max_headers_size(http, MAX_HEADERS_SIZE);
     391         526 :     evhttp_set_max_body_size(http, MAX_SIZE);
     392         526 :     evhttp_set_gencb(http, http_request_cb, nullptr);
     393             : 
     394         526 :     if (!HTTPBindAddresses(http)) {
     395           0 :         LogPrintf("Unable to bind any endpoint for RPC server\n");
     396           0 :         return false;
     397             :     }
     398             : 
     399         526 :     LogPrint(BCLog::HTTP, "Initialized HTTP server\n");
     400         526 :     int workQueueDepth = std::max((long)gArgs.GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
     401         526 :     LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
     402             : 
     403         526 :     workQueue = new WorkQueue<HTTPClosure>(workQueueDepth);
     404             :     // transfer ownership to eventBase/HTTP via .release()
     405         526 :     eventBase = base_ctr.release();
     406         526 :     eventHTTP = http_ctr.release();
     407             :     return true;
     408         526 : }
     409             : 
     410         526 : bool UpdateHTTPServerLogging(bool enable) {
     411             : #if LIBEVENT_VERSION_NUMBER >= 0x02010100
     412         526 :     if (enable) {
     413           0 :         event_enable_debug_logging(EVENT_DBG_ALL);
     414           0 :     } else {
     415         526 :         event_enable_debug_logging(EVENT_DBG_NONE);
     416             :     }
     417         526 :     return true;
     418             : #else
     419             :     // Can't update libevent logging if version < 02010100
     420             :     return false;
     421             : #endif
     422             : }
     423             : 
     424         640 : static std::thread g_thread_http;
     425         640 : static std::vector<std::thread> g_thread_http_workers;
     426             : 
     427         525 : void StartHTTPServer()
     428             : {
     429         525 :     LogPrint(BCLog::HTTP, "Starting HTTP server\n");
     430         525 :     int rpcThreads = std::max((long)gArgs.GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
     431         525 :     LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
     432         525 :     g_thread_http = std::thread(ThreadHTTP, eventBase);
     433             : 
     434        2625 :     for (int i = 0; i < rpcThreads; i++) {
     435        2100 :         g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue, i);
     436             :     }
     437         525 : }
     438             : 
     439         529 : void InterruptHTTPServer()
     440             : {
     441         529 :     LogPrint(BCLog::HTTP, "Interrupting HTTP server\n");
     442         529 :     if (eventHTTP) {
     443             :         // Reject requests on current connections
     444         526 :         evhttp_set_gencb(eventHTTP, http_reject_request_cb, nullptr);
     445         526 :     }
     446         529 :     if (workQueue)
     447         526 :         workQueue->Interrupt();
     448         529 : }
     449             : 
     450         529 : void StopHTTPServer()
     451             : {
     452         529 :     LogPrint(BCLog::HTTP, "Stopping HTTP server\n");
     453         529 :     if (workQueue) {
     454         526 :         LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
     455        2626 :         for (auto& thread: g_thread_http_workers) {
     456        2100 :             thread.join();
     457             :         }
     458         526 :         g_thread_http_workers.clear();
     459         526 :         delete workQueue;
     460         526 :         workQueue = nullptr;
     461         526 :     }
     462             :     // Unlisten sockets, these are what make the event loop running, which means
     463             :     // that after this and all connections are closed the event loop will quit.
     464        1581 :     for (evhttp_bound_socket *socket : boundSockets) {
     465        1052 :         evhttp_del_accept_socket(eventHTTP, socket);
     466             :     }
     467         529 :     boundSockets.clear();
     468         529 :     if (eventBase) {
     469         526 :         LogPrint(BCLog::HTTP, "Waiting for HTTP event thread to exit\n");
     470         526 :         if (g_thread_http.joinable()) g_thread_http.join();
     471             :     }
     472         529 :     if (eventHTTP) {
     473         526 :         evhttp_free(eventHTTP);
     474         526 :         eventHTTP = nullptr;
     475         526 :     }
     476         529 :     if (eventBase) {
     477         526 :         event_base_free(eventBase);
     478         526 :         eventBase = nullptr;
     479         526 :     }
     480         529 :     LogPrint(BCLog::HTTP, "Stopped HTTP server\n");
     481         529 : }
     482             : 
     483         525 : struct event_base* EventBase()
     484             : {
     485         525 :     return eventBase;
     486             : }
     487             : 
     488       79074 : static void httpevent_callback_fn(evutil_socket_t, short, void* data)
     489             : {
     490             :     // Static handler: simply call inner handler
     491       79074 :     HTTPEvent *self = static_cast<HTTPEvent*>(data);
     492       79074 :     self->handler();
     493       79074 :     if (self->deleteWhenTriggered)
     494       79066 :         delete self;
     495       79074 : }
     496             : 
     497      158210 : HTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function<void()>& _handler):
     498       79105 :     deleteWhenTriggered(_deleteWhenTriggered), handler(_handler)
     499       79105 : {
     500       79105 :     ev = event_new(base, -1, 0, httpevent_callback_fn, this);
     501       79105 :     assert(ev);
     502      158210 : }
     503      158210 : HTTPEvent::~HTTPEvent()
     504       79105 : {
     505       79105 :     event_free(ev);
     506      158210 : }
     507       79105 : void HTTPEvent::trigger(struct timeval* tv)
     508             : {
     509       79105 :     if (tv == nullptr)
     510       79066 :         event_active(ev, 0, 0); // immediately trigger event in main thread
     511             :     else
     512          39 :         evtimer_add(ev, tv); // trigger after timeval passed
     513       79105 : }
     514      158132 : HTTPRequest::HTTPRequest(struct evhttp_request* _req, bool _replySent) : req(_req), replySent(_replySent)
     515       79066 : {
     516      158132 : }
     517             : 
     518      158132 : HTTPRequest::~HTTPRequest()
     519       79066 : {
     520       79066 :     if (!replySent) {
     521             :         // Keep track of whether reply was sent to avoid request leaks
     522           0 :         LogPrintf("%s: Unhandled request\n", __func__);
     523           0 :         WriteReply(HTTP_INTERNAL_SERVER_ERROR, "Unhandled request");
     524           0 :     }
     525             :     // evhttpd cleans up the request, as long as a reply was sent.
     526      158132 : }
     527             : 
     528       79024 : std::pair<bool, std::string> HTTPRequest::GetHeader(const std::string& hdr) const
     529             : {
     530       79024 :     const struct evkeyvalq* headers = evhttp_request_get_input_headers(req);
     531       79024 :     assert(headers);
     532       79024 :     const char* val = evhttp_find_header(headers, hdr.c_str());
     533       79024 :     if (val)
     534       79024 :         return std::make_pair(true, val);
     535             :     else
     536           0 :         return std::make_pair(false, "");
     537       79024 : }
     538             : 
     539       79021 : std::string HTTPRequest::ReadBody()
     540             : {
     541       79021 :     struct evbuffer* buf = evhttp_request_get_input_buffer(req);
     542       79021 :     if (!buf)
     543           0 :         return "";
     544       79021 :     size_t size = evbuffer_get_length(buf);
     545             :     /** Trivial implementation: if this is ever a performance bottleneck,
     546             :      * internal copying can be avoided in multi-segment buffers by using
     547             :      * evbuffer_peek and an awkward loop. Though in that case, it'd be even
     548             :      * better to not copy into an intermediate string but use a stream
     549             :      * abstraction to consume the evbuffer on the fly in the parsing algorithm.
     550             :      */
     551       79021 :     const char* data = (const char*)evbuffer_pullup(buf, size);
     552       79021 :     if (!data) // returns nullptr in case of empty buffer
     553          12 :         return "";
     554       79009 :     std::string rv(data, size);
     555       79009 :     evbuffer_drain(buf, size);
     556       79009 :     return rv;
     557      158030 : }
     558             : 
     559       79552 : void HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value)
     560             : {
     561       79552 :     struct evkeyvalq* headers = evhttp_request_get_output_headers(req);
     562       79552 :     assert(headers);
     563       79552 :     evhttp_add_header(headers, hdr.c_str(), value.c_str());
     564       79552 : }
     565             : 
     566             : /** Closure sent to main thread to request a reply to be sent to
     567             :  * a HTTP request.
     568             :  * Replies must be sent in the main loop in the main http thread,
     569             :  * this cannot be done from worker threads.
     570             :  */
     571       79066 : void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
     572             : {
     573       79066 :     assert(!replySent && req);
     574       79066 :     if (ShutdownRequested()) {
     575         492 :         WriteHeader("Connection", "close");
     576         492 :     }
     577             :     // Send event to main http thread to send reply message
     578       79066 :     struct evbuffer* evb = evhttp_request_get_output_buffer(req);
     579       79066 :     assert(evb);
     580       79066 :     evbuffer_add(evb, strReply.data(), strReply.size());
     581       79066 :     auto req_copy = req;
     582      158132 :     HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{
     583       79066 :         evhttp_send_reply(req_copy, nStatus, nullptr, nullptr);
     584             :         // Re-enable reading from the socket. This is the second part of the libevent
     585             :         // workaround above.
     586       79066 :         if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
     587       79066 :             evhttp_connection* conn = evhttp_request_get_connection(req_copy);
     588       79066 :             if (conn) {
     589       79066 :                 bufferevent* bev = evhttp_connection_get_bufferevent(conn);
     590       79066 :                 if (bev) {
     591       79066 :                     bufferevent_enable(bev, EV_READ | EV_WRITE);
     592       79066 :                 }
     593       79066 :             }
     594       79066 :         }
     595       79066 :     });
     596       79066 :     ev->trigger(nullptr);
     597       79066 :     replySent = true;
     598       79066 :     req = nullptr; // transferred back to main thread
     599       79066 : }
     600             : 
     601      237156 : CService HTTPRequest::GetPeer() const
     602             : {
     603      237156 :     evhttp_connection* con = evhttp_request_get_connection(req);
     604      237156 :     CService peer;
     605      237156 :     if (con) {
     606             :         // evhttp retains ownership over returned address string
     607      237156 :         const char* address = "";
     608      237156 :         uint16_t port = 0;
     609      237156 :         evhttp_connection_get_peer(con, (char**)&address, &port);
     610      237156 :         peer = LookupNumeric(address, port);
     611      237156 :     }
     612             :     return peer;
     613      237156 : }
     614             : 
     615      237138 : std::string HTTPRequest::GetURI() const
     616             : {
     617      237138 :     return evhttp_request_get_uri(req);
     618             : }
     619             : 
     620      237156 : HTTPRequest::RequestMethod HTTPRequest::GetRequestMethod() const
     621             : {
     622      237156 :     switch (evhttp_request_get_command(req)) {
     623             :     case EVHTTP_REQ_GET:
     624          72 :         return GET;
     625             :         break;
     626             :     case EVHTTP_REQ_POST:
     627      237084 :         return POST;
     628             :         break;
     629             :     case EVHTTP_REQ_HEAD:
     630           0 :         return HEAD;
     631             :         break;
     632             :     case EVHTTP_REQ_PUT:
     633           0 :         return PUT;
     634             :         break;
     635             :     default:
     636           0 :         return UNKNOWN;
     637             :         break;
     638             :     }
     639      237156 : }
     640             : 
     641        1059 : void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
     642             : {
     643        1059 :     LogPrint(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
     644        1059 :     pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler));
     645        1059 : }
     646             : 
     647        5819 : void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
     648             : {
     649        5819 :     std::vector<HTTPPathHandler>::iterator i = pathHandlers.begin();
     650        5819 :     std::vector<HTTPPathHandler>::iterator iend = pathHandlers.end();
     651        5819 :     for (; i != iend; ++i)
     652        1059 :         if (i->prefix == prefix && i->exactMatch == exactMatch)
     653             :             break;
     654        5819 :     if (i != iend)
     655             :     {
     656        1059 :         LogPrint(BCLog::HTTP, "Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
     657        1059 :         pathHandlers.erase(i);
     658        1059 :     }
     659        5819 : }

Generated by: LCOV version 1.15