]> Git Repo - VerusCoin.git/blob - src/httpserver.cpp
Merge commit '51e448641d6cbcd582afa22cd8475f8c3086dad7' as 'src/snark'
[VerusCoin.git] / src / httpserver.cpp
1 // Copyright (c) 2015 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "httpserver.h"
6
7 #include "chainparamsbase.h"
8 #include "compat.h"
9 #include "util.h"
10 #include "netbase.h"
11 #include "rpcprotocol.h" // For HTTP status codes
12 #include "sync.h"
13 #include "ui_interface.h"
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <signal.h>
22
23 #include <event2/event.h>
24 #include <event2/http.h>
25 #include <event2/thread.h>
26 #include <event2/buffer.h>
27 #include <event2/util.h>
28 #include <event2/keyvalq_struct.h>
29
30 #ifdef EVENT__HAVE_NETINET_IN_H
31 #include <netinet/in.h>
32 #ifdef _XOPEN_SOURCE_EXTENDED
33 #include <arpa/inet.h>
34 #endif
35 #endif
36
37 #include <boost/algorithm/string/case_conv.hpp> // for to_lower()
38 #include <boost/foreach.hpp>
39 #include <boost/scoped_ptr.hpp>
40
41 /** HTTP request work item */
42 class HTTPWorkItem : public HTTPClosure
43 {
44 public:
45     HTTPWorkItem(HTTPRequest* req, const std::string &path, const HTTPRequestHandler& func):
46         req(req), path(path), func(func)
47     {
48     }
49     void operator()()
50     {
51         func(req.get(), path);
52     }
53
54     boost::scoped_ptr<HTTPRequest> req;
55
56 private:
57     std::string path;
58     HTTPRequestHandler func;
59 };
60
61 /** Simple work queue for distributing work over multiple threads.
62  * Work items are simply callable objects.
63  */
64 template <typename WorkItem>
65 class WorkQueue
66 {
67 private:
68     /** Mutex protects entire object */
69     CWaitableCriticalSection cs;
70     CConditionVariable cond;
71     /* XXX in C++11 we can use std::unique_ptr here and avoid manual cleanup */
72     std::deque<WorkItem*> queue;
73     bool running;
74     size_t maxDepth;
75
76 public:
77     WorkQueue(size_t maxDepth) : running(true),
78                                  maxDepth(maxDepth)
79     {
80     }
81     /* Precondition: worker threads have all stopped */
82     ~WorkQueue()
83     {
84         while (!queue.empty()) {
85             delete queue.front();
86             queue.pop_front();
87         }
88     }
89     /** Enqueue a work item */
90     bool Enqueue(WorkItem* item)
91     {
92         boost::unique_lock<boost::mutex> lock(cs);
93         if (queue.size() >= maxDepth) {
94             return false;
95         }
96         queue.push_back(item);
97         cond.notify_one();
98         return true;
99     }
100     /** Thread function */
101     void Run()
102     {
103         while (running) {
104             WorkItem* i = 0;
105             {
106                 boost::unique_lock<boost::mutex> lock(cs);
107                 while (running && queue.empty())
108                     cond.wait(lock);
109                 if (!running)
110                     break;
111                 i = queue.front();
112                 queue.pop_front();
113             }
114             (*i)();
115             delete i;
116         }
117     }
118     /** Interrupt and exit loops */
119     void Interrupt()
120     {
121         boost::unique_lock<boost::mutex> lock(cs);
122         running = false;
123         cond.notify_all();
124     }
125
126     /** Return current depth of queue */
127     size_t Depth()
128     {
129         boost::unique_lock<boost::mutex> lock(cs);
130         return queue.size();
131     }
132 };
133
134 struct HTTPPathHandler
135 {
136     HTTPPathHandler() {}
137     HTTPPathHandler(std::string prefix, bool exactMatch, HTTPRequestHandler handler):
138         prefix(prefix), exactMatch(exactMatch), handler(handler)
139     {
140     }
141     std::string prefix;
142     bool exactMatch;
143     HTTPRequestHandler handler;
144 };
145
146 /** HTTP module state */
147
148 //! libevent event loop
149 static struct event_base* eventBase = 0;
150 //! HTTP server
151 struct evhttp* eventHTTP = 0;
152 //! List of subnets to allow RPC connections from
153 static std::vector<CSubNet> rpc_allow_subnets;
154 //! Work queue for handling longer requests off the event loop thread
155 static WorkQueue<HTTPClosure>* workQueue = 0;
156 //! Handlers for (sub)paths
157 std::vector<HTTPPathHandler> pathHandlers;
158
159 /** Check if a network address is allowed to access the HTTP server */
160 static bool ClientAllowed(const CNetAddr& netaddr)
161 {
162     if (!netaddr.IsValid())
163         return false;
164     BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets)
165         if (subnet.Match(netaddr))
166             return true;
167     return false;
168 }
169
170 /** Initialize ACL list for HTTP server */
171 static bool InitHTTPAllowList()
172 {
173     rpc_allow_subnets.clear();
174     rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet
175     rpc_allow_subnets.push_back(CSubNet("::1"));         // always allow IPv6 localhost
176     if (mapMultiArgs.count("-rpcallowip")) {
177         const std::vector<std::string>& vAllow = mapMultiArgs["-rpcallowip"];
178         BOOST_FOREACH (std::string strAllow, vAllow) {
179             CSubNet subnet(strAllow);
180             if (!subnet.IsValid()) {
181                 uiInterface.ThreadSafeMessageBox(
182                     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),
183                     "", CClientUIInterface::MSG_ERROR);
184                 return false;
185             }
186             rpc_allow_subnets.push_back(subnet);
187         }
188     }
189     std::string strAllowed;
190     BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets)
191         strAllowed += subnet.ToString() + " ";
192     LogPrint("http", "Allowing HTTP connections from: %s\n", strAllowed);
193     return true;
194 }
195
196 /** HTTP request method as string - use for logging only */
197 static std::string RequestMethodString(HTTPRequest::RequestMethod m)
198 {
199     switch (m) {
200     case HTTPRequest::GET:
201         return "GET";
202         break;
203     case HTTPRequest::POST:
204         return "POST";
205         break;
206     case HTTPRequest::HEAD:
207         return "HEAD";
208         break;
209     case HTTPRequest::PUT:
210         return "PUT";
211         break;
212     default:
213         return "unknown";
214     }
215 }
216
217 /** HTTP request callback */
218 static void http_request_cb(struct evhttp_request* req, void* arg)
219 {
220     std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
221
222     LogPrint("http", "Received a %s request for %s from %s\n",
223              RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());
224
225     // Early address-based allow check
226     if (!ClientAllowed(hreq->GetPeer())) {
227         hreq->WriteReply(HTTP_FORBIDDEN);
228         return;
229     }
230
231     // Early reject unknown HTTP methods
232     if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
233         hreq->WriteReply(HTTP_BADMETHOD);
234         return;
235     }
236
237     // Find registered handler for prefix
238     std::string strURI = hreq->GetURI();
239     std::string path;
240     std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin();
241     std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end();
242     for (; i != iend; ++i) {
243         bool match = false;
244         if (i->exactMatch)
245             match = (strURI == i->prefix);
246         else
247             match = (strURI.substr(0, i->prefix.size()) == i->prefix);
248         if (match) {
249             path = strURI.substr(i->prefix.size());
250             break;
251         }
252     }
253
254     // Dispatch to worker thread
255     if (i != iend) {
256         std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(hreq.release(), path, i->handler));
257         assert(workQueue);
258         if (workQueue->Enqueue(item.get()))
259             item.release(); /* if true, queue took ownership */
260         else
261             item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded");
262     } else {
263         hreq->WriteReply(HTTP_NOTFOUND);
264     }
265 }
266
267 /** Event dispatcher thread */
268 static void ThreadHTTP(struct event_base* base, struct evhttp* http)
269 {
270     RenameThread("bitcoin-http");
271     LogPrint("http", "Entering http event loop\n");
272     event_base_dispatch(base);
273     // Event loop will be interrupted by InterruptHTTPServer()
274     LogPrint("http", "Exited http event loop\n");
275 }
276
277 /** Bind HTTP server to specified addresses */
278 static bool HTTPBindAddresses(struct evhttp* http)
279 {
280     int defaultPort = GetArg("-rpcport", BaseParams().RPCPort());
281     int nBound = 0;
282     std::vector<std::pair<std::string, uint16_t> > endpoints;
283
284     // Determine what addresses to bind to
285     if (!mapArgs.count("-rpcallowip")) { // Default to loopback if not allowing external IPs
286         endpoints.push_back(std::make_pair("::1", defaultPort));
287         endpoints.push_back(std::make_pair("127.0.0.1", defaultPort));
288         if (mapArgs.count("-rpcbind")) {
289             LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
290         }
291     } else if (mapArgs.count("-rpcbind")) { // Specific bind address
292         const std::vector<std::string>& vbind = mapMultiArgs["-rpcbind"];
293         for (std::vector<std::string>::const_iterator i = vbind.begin(); i != vbind.end(); ++i) {
294             int port = defaultPort;
295             std::string host;
296             SplitHostPort(*i, port, host);
297             endpoints.push_back(std::make_pair(host, port));
298         }
299     } else { // No specific bind address specified, bind to any
300         endpoints.push_back(std::make_pair("::", defaultPort));
301         endpoints.push_back(std::make_pair("0.0.0.0", defaultPort));
302     }
303
304     // Bind addresses
305     for (std::vector<std::pair<std::string, uint16_t> >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
306         LogPrint("http", "Binding RPC on address %s port %i\n", i->first, i->second);
307         if (evhttp_bind_socket(http, i->first.empty() ? NULL : i->first.c_str(), i->second) == 0) {
308             nBound += 1;
309         } else {
310             LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second);
311         }
312     }
313     return nBound > 0;
314 }
315
316 /** Simple wrapper to set thread name and run work queue */
317 static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue)
318 {
319     RenameThread("bitcoin-httpworker");
320     queue->Run();
321 }
322
323 /** libevent event log callback */
324 static void libevent_log_cb(int severity, const char *msg)
325 {
326 #ifndef EVENT_LOG_WARN
327 // EVENT_LOG_WARN was added in 2.0.19; but before then _EVENT_LOG_WARN existed.
328 # define EVENT_LOG_WARN _EVENT_LOG_WARN
329 #endif
330     if (severity >= EVENT_LOG_WARN) // Log warn messages and higher without debug category
331         LogPrintf("libevent: %s\n", msg);
332     else
333         LogPrint("libevent", "libevent: %s\n", msg);
334 }
335
336 bool InitHTTPServer()
337 {
338     struct evhttp* http = 0;
339     struct event_base* base = 0;
340
341     if (!InitHTTPAllowList())
342         return false;
343
344     if (GetBoolArg("-rpcssl", false)) {
345         uiInterface.ThreadSafeMessageBox(
346             "SSL mode for RPC (-rpcssl) is no longer supported.",
347             "", CClientUIInterface::MSG_ERROR);
348         return false;
349     }
350
351     // Redirect libevent's logging to our own log
352     event_set_log_callback(&libevent_log_cb);
353 #if LIBEVENT_VERSION_NUMBER >= 0x02010100
354     // If -debug=libevent, set full libevent debugging.
355     // Otherwise, disable all libevent debugging.
356     if (LogAcceptCategory("libevent"))
357         event_enable_debug_logging(EVENT_DBG_ALL);
358     else
359         event_enable_debug_logging(EVENT_DBG_NONE);
360 #endif
361 #ifdef WIN32
362     evthread_use_windows_threads();
363 #else
364     evthread_use_pthreads();
365 #endif
366
367     base = event_base_new(); // XXX RAII
368     if (!base) {
369         LogPrintf("Couldn't create an event_base: exiting\n");
370         return false;
371     }
372
373     /* Create a new evhttp object to handle requests. */
374     http = evhttp_new(base); // XXX RAII
375     if (!http) {
376         LogPrintf("couldn't create evhttp. Exiting.\n");
377         event_base_free(base);
378         return false;
379     }
380
381     evhttp_set_timeout(http, GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
382     evhttp_set_max_body_size(http, MAX_SIZE);
383     evhttp_set_gencb(http, http_request_cb, NULL);
384
385     if (!HTTPBindAddresses(http)) {
386         LogPrintf("Unable to bind any endpoint for RPC server\n");
387         evhttp_free(http);
388         event_base_free(base);
389         return false;
390     }
391
392     LogPrint("http", "Initialized HTTP server\n");
393     int workQueueDepth = std::max((long)GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
394     LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
395
396     workQueue = new WorkQueue<HTTPClosure>(workQueueDepth);
397     eventBase = base;
398     eventHTTP = http;
399     return true;
400 }
401
402 bool StartHTTPServer(boost::thread_group& threadGroup)
403 {
404     LogPrint("http", "Starting HTTP server\n");
405     int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
406     LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
407     threadGroup.create_thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP));
408
409     for (int i = 0; i < rpcThreads; i++)
410         threadGroup.create_thread(boost::bind(&HTTPWorkQueueRun, workQueue));
411     return true;
412 }
413
414 void InterruptHTTPServer()
415 {
416     LogPrint("http", "Interrupting HTTP server\n");
417     if (eventBase)
418         event_base_loopbreak(eventBase);
419     if (workQueue)
420         workQueue->Interrupt();
421 }
422
423 void StopHTTPServer()
424 {
425     LogPrint("http", "Stopping HTTP server\n");
426     delete workQueue;
427     if (eventHTTP) {
428         evhttp_free(eventHTTP);
429         eventHTTP = 0;
430     }
431     if (eventBase) {
432         event_base_free(eventBase);
433         eventBase = 0;
434     }
435 }
436
437 struct event_base* EventBase()
438 {
439     return eventBase;
440 }
441
442 static void httpevent_callback_fn(evutil_socket_t, short, void* data)
443 {
444     // Static handler: simply call inner handler
445     HTTPEvent *self = ((HTTPEvent*)data);
446     self->handler();
447     if (self->deleteWhenTriggered)
448         delete self;
449 }
450
451 HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler):
452     deleteWhenTriggered(deleteWhenTriggered), handler(handler)
453 {
454     ev = event_new(base, -1, 0, httpevent_callback_fn, this);
455     assert(ev);
456 }
457 HTTPEvent::~HTTPEvent()
458 {
459     event_free(ev);
460 }
461 void HTTPEvent::trigger(struct timeval* tv)
462 {
463     if (tv == NULL)
464         event_active(ev, 0, 0); // immediately trigger event in main thread
465     else
466         evtimer_add(ev, tv); // trigger after timeval passed
467 }
468 HTTPRequest::HTTPRequest(struct evhttp_request* req) : req(req),
469                                                        replySent(false)
470 {
471 }
472 HTTPRequest::~HTTPRequest()
473 {
474     if (!replySent) {
475         // Keep track of whether reply was sent to avoid request leaks
476         LogPrintf("%s: Unhandled request\n", __func__);
477         WriteReply(HTTP_INTERNAL, "Unhandled request");
478     }
479     // evhttpd cleans up the request, as long as a reply was sent.
480 }
481
482 std::pair<bool, std::string> HTTPRequest::GetHeader(const std::string& hdr)
483 {
484     const struct evkeyvalq* headers = evhttp_request_get_input_headers(req);
485     assert(headers);
486     const char* val = evhttp_find_header(headers, hdr.c_str());
487     if (val)
488         return std::make_pair(true, val);
489     else
490         return std::make_pair(false, "");
491 }
492
493 std::string HTTPRequest::ReadBody()
494 {
495     struct evbuffer* buf = evhttp_request_get_input_buffer(req);
496     if (!buf)
497         return "";
498     size_t size = evbuffer_get_length(buf);
499     /** Trivial implementation: if this is ever a performance bottleneck,
500      * internal copying can be avoided in multi-segment buffers by using
501      * evbuffer_peek and an awkward loop. Though in that case, it'd be even
502      * better to not copy into an intermediate string but use a stream
503      * abstraction to consume the evbuffer on the fly in the parsing algorithm.
504      */
505     const char* data = (const char*)evbuffer_pullup(buf, size);
506     if (!data) // returns NULL in case of empty buffer
507         return "";
508     std::string rv(data, size);
509     evbuffer_drain(buf, size);
510     return rv;
511 }
512
513 void HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value)
514 {
515     struct evkeyvalq* headers = evhttp_request_get_output_headers(req);
516     assert(headers);
517     evhttp_add_header(headers, hdr.c_str(), value.c_str());
518 }
519
520 /** Closure sent to main thread to request a reply to be sent to
521  * a HTTP request.
522  * Replies must be sent in the main loop in the main http thread,
523  * this cannot be done from worker threads.
524  */
525 void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
526 {
527     assert(!replySent && req);
528     // Send event to main http thread to send reply message
529     struct evbuffer* evb = evhttp_request_get_output_buffer(req);
530     assert(evb);
531     evbuffer_add(evb, strReply.data(), strReply.size());
532     HTTPEvent* ev = new HTTPEvent(eventBase, true,
533         boost::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
534     ev->trigger(0);
535     replySent = true;
536     req = 0; // transferred back to main thread
537 }
538
539 CService HTTPRequest::GetPeer()
540 {
541     evhttp_connection* con = evhttp_request_get_connection(req);
542     CService peer;
543     if (con) {
544         // evhttp retains ownership over returned address string
545         const char* address = "";
546         uint16_t port = 0;
547         evhttp_connection_get_peer(con, (char**)&address, &port);
548         peer = CService(address, port);
549     }
550     return peer;
551 }
552
553 std::string HTTPRequest::GetURI()
554 {
555     return evhttp_request_get_uri(req);
556 }
557
558 HTTPRequest::RequestMethod HTTPRequest::GetRequestMethod()
559 {
560     switch (evhttp_request_get_command(req)) {
561     case EVHTTP_REQ_GET:
562         return GET;
563         break;
564     case EVHTTP_REQ_POST:
565         return POST;
566         break;
567     case EVHTTP_REQ_HEAD:
568         return HEAD;
569         break;
570     case EVHTTP_REQ_PUT:
571         return PUT;
572         break;
573     default:
574         return UNKNOWN;
575         break;
576     }
577 }
578
579 void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
580 {
581     LogPrint("http", "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
582     pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler));
583 }
584
585 void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
586 {
587     std::vector<HTTPPathHandler>::iterator i = pathHandlers.begin();
588     std::vector<HTTPPathHandler>::iterator iend = pathHandlers.end();
589     for (; i != iend; ++i)
590         if (i->prefix == prefix && i->exactMatch == exactMatch)
591             break;
592     if (i != iend)
593     {
594         LogPrint("http", "Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
595         pathHandlers.erase(i);
596     }
597 }
598
This page took 0.053441 seconds and 4 git commands to generate.