aboutsummaryrefslogtreecommitdiff
path: root/src/httpserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/httpserver.cpp')
-rw-r--r--src/httpserver.cpp116
1 files changed, 58 insertions, 58 deletions
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 91518d7c5f..b296b28503 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -8,7 +8,7 @@
#include "compat.h"
#include "util.h"
#include "netbase.h"
-#include "rpcprotocol.h" // For HTTP status codes
+#include "rpc/protocol.h" // For HTTP status codes
#include "sync.h"
#include "ui_interface.h"
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
+#include <future>
#include <event2/event.h>
#include <event2/http.h>
@@ -34,10 +35,6 @@
#endif
#endif
-#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
-#include <boost/foreach.hpp>
-#include <boost/scoped_ptr.hpp>
-
/** Maximum size of http request (request line + headers) */
static const size_t MAX_HEADERS_SIZE = 8192;
@@ -45,8 +42,8 @@ static const size_t MAX_HEADERS_SIZE = 8192;
class HTTPWorkItem : public HTTPClosure
{
public:
- HTTPWorkItem(HTTPRequest* req, const std::string &path, const HTTPRequestHandler& func):
- req(req), path(path), func(func)
+ HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
+ req(std::move(_req)), path(_path), func(_func)
{
}
void operator()()
@@ -54,7 +51,7 @@ public:
func(req.get(), path);
}
- boost::scoped_ptr<HTTPRequest> req;
+ std::unique_ptr<HTTPRequest> req;
private:
std::string path;
@@ -69,10 +66,9 @@ class WorkQueue
{
private:
/** Mutex protects entire object */
- CWaitableCriticalSection cs;
- CConditionVariable cond;
- /* XXX in C++11 we can use std::unique_ptr here and avoid manual cleanup */
- std::deque<WorkItem*> queue;
+ std::mutex cs;
+ std::condition_variable cond;
+ std::deque<std::unique_ptr<WorkItem>> queue;
bool running;
size_t maxDepth;
int numThreads;
@@ -84,41 +80,37 @@ private:
WorkQueue &wq;
ThreadCounter(WorkQueue &w): wq(w)
{
- boost::lock_guard<boost::mutex> lock(wq.cs);
+ std::lock_guard<std::mutex> lock(wq.cs);
wq.numThreads += 1;
}
~ThreadCounter()
{
- boost::lock_guard<boost::mutex> lock(wq.cs);
+ std::lock_guard<std::mutex> lock(wq.cs);
wq.numThreads -= 1;
wq.cond.notify_all();
}
};
public:
- WorkQueue(size_t maxDepth) : running(true),
- maxDepth(maxDepth),
+ WorkQueue(size_t _maxDepth) : running(true),
+ maxDepth(_maxDepth),
numThreads(0)
{
}
- /*( Precondition: worker threads have all stopped
+ /** Precondition: worker threads have all stopped
* (call WaitExit)
*/
~WorkQueue()
{
- while (!queue.empty()) {
- delete queue.front();
- queue.pop_front();
- }
}
/** Enqueue a work item */
bool Enqueue(WorkItem* item)
{
- boost::unique_lock<boost::mutex> lock(cs);
+ std::unique_lock<std::mutex> lock(cs);
if (queue.size() >= maxDepth) {
return false;
}
- queue.push_back(item);
+ queue.emplace_back(std::unique_ptr<WorkItem>(item));
cond.notify_one();
return true;
}
@@ -127,31 +119,30 @@ public:
{
ThreadCounter count(*this);
while (running) {
- WorkItem* i = 0;
+ std::unique_ptr<WorkItem> i;
{
- boost::unique_lock<boost::mutex> lock(cs);
+ std::unique_lock<std::mutex> lock(cs);
while (running && queue.empty())
cond.wait(lock);
if (!running)
break;
- i = queue.front();
+ i = std::move(queue.front());
queue.pop_front();
}
(*i)();
- delete i;
}
}
/** Interrupt and exit loops */
void Interrupt()
{
- boost::unique_lock<boost::mutex> lock(cs);
+ std::unique_lock<std::mutex> lock(cs);
running = false;
cond.notify_all();
}
/** Wait for worker threads to exit */
void WaitExit()
{
- boost::unique_lock<boost::mutex> lock(cs);
+ std::unique_lock<std::mutex> lock(cs);
while (numThreads > 0)
cond.wait(lock);
}
@@ -159,7 +150,7 @@ public:
/** Return current depth of queue */
size_t Depth()
{
- boost::unique_lock<boost::mutex> lock(cs);
+ std::unique_lock<std::mutex> lock(cs);
return queue.size();
}
};
@@ -167,8 +158,8 @@ public:
struct HTTPPathHandler
{
HTTPPathHandler() {}
- HTTPPathHandler(std::string prefix, bool exactMatch, HTTPRequestHandler handler):
- prefix(prefix), exactMatch(exactMatch), handler(handler)
+ HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):
+ prefix(_prefix), exactMatch(_exactMatch), handler(_handler)
{
}
std::string prefix;
@@ -196,7 +187,7 @@ static bool ClientAllowed(const CNetAddr& netaddr)
{
if (!netaddr.IsValid())
return false;
- BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets)
+ for(const CSubNet& subnet : rpc_allow_subnets)
if (subnet.Match(netaddr))
return true;
return false;
@@ -206,12 +197,17 @@ static bool ClientAllowed(const CNetAddr& netaddr)
static bool InitHTTPAllowList()
{
rpc_allow_subnets.clear();
- rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet
- rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost
+ CNetAddr localv4;
+ CNetAddr localv6;
+ LookupHost("127.0.0.1", localv4, false);
+ LookupHost("::1", localv6, false);
+ rpc_allow_subnets.push_back(CSubNet(localv4, 8)); // always allow IPv4 local subnet
+ rpc_allow_subnets.push_back(CSubNet(localv6)); // always allow IPv6 localhost
if (mapMultiArgs.count("-rpcallowip")) {
const std::vector<std::string>& vAllow = mapMultiArgs["-rpcallowip"];
- BOOST_FOREACH (std::string strAllow, vAllow) {
- CSubNet subnet(strAllow);
+ for (std::string strAllow : vAllow) {
+ CSubNet subnet;
+ LookupSubNet(strAllow.c_str(), subnet);
if (!subnet.IsValid()) {
uiInterface.ThreadSafeMessageBox(
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),
@@ -222,7 +218,7 @@ static bool InitHTTPAllowList()
}
}
std::string strAllowed;
- BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets)
+ for (const CSubNet& subnet : rpc_allow_subnets)
strAllowed += subnet.ToString() + " ";
LogPrint("http", "Allowing HTTP connections from: %s\n", strAllowed);
return true;
@@ -252,7 +248,7 @@ static std::string RequestMethodString(HTTPRequest::RequestMethod m)
/** HTTP request callback */
static void http_request_cb(struct evhttp_request* req, void* arg)
{
- std::auto_ptr<HTTPRequest> hreq(new HTTPRequest(req));
+ std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
LogPrint("http", "Received a %s request for %s from %s\n",
RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());
@@ -288,12 +284,14 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
// Dispatch to worker thread
if (i != iend) {
- std::auto_ptr<HTTPWorkItem> item(new HTTPWorkItem(hreq.release(), path, i->handler));
+ std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(std::move(hreq), path, i->handler));
assert(workQueue);
if (workQueue->Enqueue(item.get()))
item.release(); /* if true, queue took ownership */
- else
+ else {
+ LogPrintf("WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\n");
item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded");
+ }
} else {
hreq->WriteReply(HTTP_NOTFOUND);
}
@@ -307,13 +305,14 @@ static void http_reject_request_cb(struct evhttp_request* req, void*)
}
/** Event dispatcher thread */
-static void ThreadHTTP(struct event_base* base, struct evhttp* http)
+static bool ThreadHTTP(struct event_base* base, struct evhttp* http)
{
RenameThread("bitcoin-http");
LogPrint("http", "Entering http event loop\n");
event_base_dispatch(base);
// Event loop will be interrupted by InterruptHTTPServer()
LogPrint("http", "Exited http event loop\n");
+ return event_base_got_break(base) == 0;
}
/** Bind HTTP server to specified addresses */
@@ -442,17 +441,22 @@ bool InitHTTPServer()
return true;
}
-boost::thread threadHTTP;
+std::thread threadHTTP;
+std::future<bool> threadResult;
bool StartHTTPServer()
{
LogPrint("http", "Starting HTTP server\n");
int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
- threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP));
+ std::packaged_task<bool(event_base*, evhttp*)> task(ThreadHTTP);
+ threadResult = task.get_future();
+ threadHTTP = std::thread(std::move(task), eventBase, eventHTTP);
- for (int i = 0; i < rpcThreads; i++)
- boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue));
+ for (int i = 0; i < rpcThreads; i++) {
+ std::thread rpc_worker(HTTPWorkQueueRun, workQueue);
+ rpc_worker.detach();
+ }
return true;
}
@@ -461,7 +465,7 @@ void InterruptHTTPServer()
LogPrint("http", "Interrupting HTTP server\n");
if (eventHTTP) {
// Unlisten sockets
- BOOST_FOREACH (evhttp_bound_socket *socket, boundSockets) {
+ for (evhttp_bound_socket *socket : boundSockets) {
evhttp_del_accept_socket(eventHTTP, socket);
}
// Reject requests on current connections
@@ -487,15 +491,11 @@ void StopHTTPServer()
// master that appears to be solved, so in the future that solution
// could be used again (if desirable).
// (see discussion in https://github.com/bitcoin/bitcoin/pull/6990)
-#if BOOST_VERSION >= 105000
- if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) {
-#else
- if (!threadHTTP.timed_join(boost::posix_time::milliseconds(2000))) {
-#endif
+ if (threadResult.valid() && threadResult.wait_for(std::chrono::milliseconds(2000)) == std::future_status::timeout) {
LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n");
event_base_loopbreak(eventBase);
- threadHTTP.join();
}
+ threadHTTP.join();
}
if (eventHTTP) {
evhttp_free(eventHTTP);
@@ -522,8 +522,8 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data)
delete self;
}
-HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler):
- deleteWhenTriggered(deleteWhenTriggered), handler(handler)
+HTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function<void(void)>& _handler):
+ deleteWhenTriggered(_deleteWhenTriggered), handler(_handler)
{
ev = event_new(base, -1, 0, httpevent_callback_fn, this);
assert(ev);
@@ -539,7 +539,7 @@ void HTTPEvent::trigger(struct timeval* tv)
else
evtimer_add(ev, tv); // trigger after timeval passed
}
-HTTPRequest::HTTPRequest(struct evhttp_request* req) : req(req),
+HTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req),
replySent(false)
{
}
@@ -604,7 +604,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
assert(evb);
evbuffer_add(evb, strReply.data(), strReply.size());
HTTPEvent* ev = new HTTPEvent(eventBase, true,
- boost::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
+ std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
ev->trigger(0);
replySent = true;
req = 0; // transferred back to main thread
@@ -619,7 +619,7 @@ CService HTTPRequest::GetPeer()
const char* address = "";
uint16_t port = 0;
evhttp_connection_get_peer(con, (char**)&address, &port);
- peer = CService(address, port);
+ peer = LookupNumeric(address, port);
}
return peer;
}