LCOV - code coverage report
Current view: top level - src - httpserver.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 308 355 86.8 %
Date: 2025-02-23 09:33:43 Functions: 38 40 95.0 %

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

Generated by: LCOV version 1.14