Changeset View
Standalone View
src/httprpc.cpp
Show All 18 Lines | |||||
#include <boost/algorithm/string.hpp> // boost::trim | #include <boost/algorithm/string.hpp> // boost::trim | ||||
#include <cstdio> | #include <cstdio> | ||||
/** WWW-Authenticate to present with 401 Unauthorized response */ | /** WWW-Authenticate to present with 401 Unauthorized response */ | ||||
static const char *WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\""; | static const char *WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\""; | ||||
/** Simple one-shot callback timer to be used by the RPC mechanism to e.g. | |||||
* re-lock the wallet. | |||||
*/ | |||||
class HTTPRPCTimer : public RPCTimerBase { | |||||
public: | |||||
HTTPRPCTimer(struct event_base *eventBase, std::function<void(void)> &func, | |||||
int64_t millis) | |||||
: ev(eventBase, false, func) { | |||||
struct timeval tv; | |||||
tv.tv_sec = millis / 1000; | |||||
tv.tv_usec = (millis % 1000) * 1000; | |||||
ev.trigger(&tv); | |||||
} | |||||
private: | |||||
HTTPEvent ev; | |||||
}; | |||||
class HTTPRPCTimerInterface : public RPCTimerInterface { | |||||
public: | |||||
HTTPRPCTimerInterface(struct event_base *_base) : base(_base) {} | |||||
const char *Name() override { return "HTTP"; } | |||||
RPCTimerBase *NewTimer(std::function<void(void)> &func, | |||||
int64_t millis) override { | |||||
return new HTTPRPCTimer(base, func, millis); | |||||
} | |||||
private: | |||||
struct event_base *base; | |||||
}; | |||||
/* Stored RPC timer interface (for unregistration) */ | /* Stored RPC timer interface (for unregistration) */ | ||||
static HTTPRPCTimerInterface *httpRPCTimerInterface = 0; | static HTTPRPCTimerInterface *httpRPCTimerInterface = 0; | ||||
static void JSONErrorReply(HTTPRequest *req, const UniValue &objError, | static void JSONErrorReply(HTTPRequest *req, const UniValue &objError, | ||||
const UniValue &id) { | const UniValue &id) { | ||||
// Send error reply from json-rpc error object. | // Send error reply from json-rpc error object. | ||||
int nStatus = HTTP_INTERNAL_SERVER_ERROR; | int nStatus = HTTP_INTERNAL_SERVER_ERROR; | ||||
int code = find_value(objError, "code").get_int(); | int code = find_value(objError, "code").get_int(); | ||||
▲ Show 20 Lines • Show All 197 Lines • ▼ Show 20 Lines | static bool checkCORS(Config &config, HTTPRequest *req) { | ||||
// 4. If the list of exposed headers is not empty add one or more | // 4. If the list of exposed headers is not empty add one or more | ||||
// Access-Control-Expose-Headers headers, with as values the header | // Access-Control-Expose-Headers headers, with as values the header | ||||
// field names given in the list of exposed headers. | // field names given in the list of exposed headers. | ||||
req->WriteHeader("Access-Control-Expose-Headers", "WWW-Authenticate"); | req->WriteHeader("Access-Control-Expose-Headers", "WWW-Authenticate"); | ||||
return false; | return false; | ||||
} | } | ||||
static bool HTTPReq_JSONRPC(Config &config, HTTPRequest *req, | bool HTTPRPCServer::ProcessHTTPRequest(HTTPRequest *req) { | ||||
const std::string &) { | |||||
// First, check and/or set CORS headers | // First, check and/or set CORS headers | ||||
if (checkCORS(config, req)) { | if (checkCORS(config, req)) { | ||||
return true; | return true; | ||||
} | } | ||||
// JSONRPC handles only POST | // JSONRPC handles only POST | ||||
if (req->GetRequestMethod() != HTTPRequest::POST) { | if (req->GetRequestMethod() != HTTPRequest::POST) { | ||||
req->WriteReply(HTTP_BAD_METHOD, | req->WriteReply(HTTP_BAD_METHOD, | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | if (gArgs.GetArg("-rpcpassword", "") == "") { | ||||
config.SetRPCUserAndPassword(gArgs.GetArg("-rpcuser", "") + ":" + | config.SetRPCUserAndPassword(gArgs.GetArg("-rpcuser", "") + ":" + | ||||
gArgs.GetArg("-rpcpassword", "")); | gArgs.GetArg("-rpcpassword", "")); | ||||
} | } | ||||
config.SetRPCCORSDomain(gArgs.GetArg("-rpccorsdomain", "")); | config.SetRPCCORSDomain(gArgs.GetArg("-rpccorsdomain", "")); | ||||
return true; | return true; | ||||
} | } | ||||
bool StartHTTPRPC(Config &config) { | bool StartHTTPRPC(Config &config, HTTPRPCServer &httpRPCServer) { | ||||
jasonbcox: It's entirely possible to put this, and many of the other functions in this file, into the… | |||||
LogPrint(BCLog::RPC, "Starting HTTP RPC server\n"); | LogPrint(BCLog::RPC, "Starting HTTP RPC server\n"); | ||||
if (!InitRPCAuthentication(config)) return false; | if (!InitRPCAuthentication(config)) return false; | ||||
RegisterHTTPHandler("/", true, HTTPReq_JSONRPC); | const std::function<bool(Config &, HTTPRequest *, const std::string &)> | ||||
&rpcFunction = std::bind(&HTTPRPCServer::ProcessHTTPRequest, | |||||
&httpRPCServer, std::placeholders::_2); | |||||
deadalnixUnsubmitted Not Done Inline ActionsPassing the this pointer down to function is ABI dependent, so my bet would be that this is undefined behavior. The best option here is to create a static function taking a pointer to a HTTPRPCServer and other parameters and forward the call. You can bind the server's reference to that function. This will also allow you t make ProcessHTTPRequest private which as per my previous comment seems like it should be. deadalnix: Passing the this pointer down to function is ABI dependent, so my bet would be that this is… | |||||
jasonbcoxAuthorUnsubmitted Not Done Inline ActionsThis will require me to add HTTPRPCServer to the API of RegisterHTTPHandler, which is called by the httpserver code as well (not just here). Do you think that is acceptable? The most common use case for RegisterHTTPHandler will not end up using it. Ideally, we should be able register HTTP handlers with different dependencies, but that will require reworking a bunch of the httpserver code. Thoughts? jasonbcox: This will require me to add HTTPRPCServer to the API of RegisterHTTPHandler, which is called by… | |||||
RegisterHTTPHandler("/", true, rpcFunction); | |||||
#ifdef ENABLE_WALLET | #ifdef ENABLE_WALLET | ||||
// ifdef can be removed once we switch to better endpoint support and API | // ifdef can be removed once we switch to better endpoint support and API | ||||
// versioning | // versioning | ||||
RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC); | RegisterHTTPHandler("/wallet/", false, rpcFunction); | ||||
#endif | #endif | ||||
assert(EventBase()); | assert(EventBase()); | ||||
httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase()); | httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase()); | ||||
RPCSetTimerInterface(httpRPCTimerInterface); | RPCSetTimerInterface(httpRPCTimerInterface); | ||||
return true; | return true; | ||||
} | } | ||||
void InterruptHTTPRPC() { | void InterruptHTTPRPC() { | ||||
Show All 12 Lines |
It's entirely possible to put this, and many of the other functions in this file, into the HTTPRPCServer class as member functions. I figured that was best left for a future diff. Please let me know if you disagree.