Changeset View
Changeset View
Standalone View
Standalone View
src/httprpc.cpp
// Copyright (c) 2015-2016 The Bitcoin Core developers | // Copyright (c) 2015-2016 The Bitcoin Core developers | ||||
Lint: Code style violation: '/Users/jacox/personalprojects/bitcoin-abc/src/httprpc.cpp' has code style errors. | |||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "httprpc.h" | #include "httprpc.h" | ||||
#include "base58.h" | #include "base58.h" | ||||
#include "chainparams.h" | #include "chainparams.h" | ||||
#include "config.h" | #include "config.h" | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
private: | private: | ||||
struct event_base *base; | struct event_base *base; | ||||
}; | }; | ||||
/* Pre-base64-encoded authentication token */ | /* Pre-base64-encoded authentication token */ | ||||
static std::string strRPCUserColonPass; | static std::string strRPCUserColonPass; | ||||
/* Stored RPC timer interface (for unregistration) */ | /* Stored RPC timer interface (for unregistration) */ | ||||
static HTTPRPCTimerInterface *httpRPCTimerInterface = 0; | static HTTPRPCTimerInterface *httpRPCTimerInterface = 0; | ||||
/* RPC CORS Domain, allowed Origin */ | |||||
static std::string strRPCCORSDomain; | |||||
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(); | ||||
if (code == RPC_INVALID_REQUEST) | if (code == RPC_INVALID_REQUEST) | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | static bool RPCAuthorized(const std::string &strAuth, | ||||
// Check if authorized under single-user field | // Check if authorized under single-user field | ||||
if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) { | if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) { | ||||
return true; | return true; | ||||
} | } | ||||
return multiUserAuthorized(strUserPass); | return multiUserAuthorized(strUserPass); | ||||
} | } | ||||
static bool checkCORS(HTTPRequest *req) { | |||||
// https://www.w3.org/TR/cors/#resource-requests | |||||
// 1. If the Origin header is not present terminate this set of steps. | |||||
// The request is outside the scope of this specification. | |||||
std::pair<bool, std::string> origin = req->GetHeader("origin"); | |||||
if (!origin.first) { | |||||
return false; | |||||
} | |||||
// 2. If the value of the Origin header is not a case-sensitive match for | |||||
// any of the values in list of origins do not set any additional headers | |||||
// and terminate this set of steps. | |||||
// Note: Always matching is acceptable since the list of origins can be | |||||
// unbounded. | |||||
if (origin.second != strRPCCORSDomain) { | |||||
return false; | |||||
} | |||||
if (req->GetRequestMethod() == HTTPRequest::OPTIONS) { | |||||
// 6.2 Preflight Request | |||||
// In response to a preflight request the resource indicates which | |||||
// methods and headers (other than simple methods and simple | |||||
// headers) it is willing to handle and whether it supports | |||||
// credentials. | |||||
// Resources must use the following set of steps to determine which | |||||
// additional headers to use in the response: | |||||
// 3. Let method be the value as result of parsing the | |||||
// Access-Control-Request-Method header. | |||||
// If there is no Access-Control-Request-Method header or if parsing | |||||
// failed, do not set any additional headers and terminate this set | |||||
// of steps. The request is outside the scope of this specification. | |||||
std::pair<bool, std::string> method = | |||||
req->GetHeader("access-control-request-method"); | |||||
if (!method.first) { | |||||
return false; | |||||
} | |||||
// 4. Let header field-names be the values as result of parsing | |||||
// the Access-Control-Request-Headers headers. | |||||
// If there are no Access-Control-Request-Headers headers let header | |||||
// field-names be the empty list. | |||||
// If parsing failed do not set any additional headers and terminate | |||||
// this set of steps. The request is outside the scope of this | |||||
// specification. | |||||
std::pair<bool, std::string> header_field_names = | |||||
req->GetHeader("access-control-request-headers"); | |||||
// 5. If method is not a case-sensitive match for any of the | |||||
// values in list of methods do not set any additional headers | |||||
// and terminate this set of steps. | |||||
// Note: Always matching is acceptable since the list of methods | |||||
// can be unbounded. | |||||
if (method.second != "POST") { | |||||
return false; | |||||
} | |||||
// 6. If any of the header field-names is not a ASCII case- | |||||
// insensitive match for any of the values in list of headers do not | |||||
// set any additional headers and terminate this set of steps. | |||||
// Note: Always matching is acceptable since the list of headers can | |||||
// be unbounded. | |||||
const std::string& list_of_headers = "authorization,content-type"; | |||||
// 7. If the resource supports credentials add a single | |||||
// Access-Control-Allow-Origin header, with the value of the Origin | |||||
// header as value, and add a single | |||||
// Access-Control-Allow-Credentials header with the case-sensitive | |||||
// string "true" as value. | |||||
req->WriteHeader("Access-Control-Allow-Origin", origin.second); | |||||
req->WriteHeader("Access-Control-Allow-Credentials", "true"); | |||||
// 8. Optionally add a single Access-Control-Max-Age header with as | |||||
// value the amount of seconds the user agent is allowed to cache | |||||
// the result of the request. | |||||
// 9. If method is a simple method this step may be skipped. | |||||
// Add one or more Access-Control-Allow-Methods headers consisting | |||||
// of (a subset of) the list of methods. | |||||
// If a method is a simple method it does not need to be listed, but | |||||
// this is not prohibited. | |||||
// Note: Since the list of methods can be unbounded, simply | |||||
// returning the method indicated by | |||||
// Access-Control-Request-Method (if supported) can be enough. | |||||
req->WriteHeader("Access-Control-Allow-Methods", method.second); | |||||
// 10. If each of the header field-names is a simple header and none | |||||
// is Content-Type, this step may be skipped. | |||||
// Add one or more Access-Control-Allow-Headers headers consisting | |||||
// of (a subset of) the list of headers. | |||||
req->WriteHeader( | |||||
"Access-Control-Allow-Headers", | |||||
header_field_names.first ? header_field_names.second | |||||
: list_of_headers); | |||||
req->WriteReply(HTTP_OK); | |||||
return true; | |||||
} | |||||
// 6.1 Simple Cross-Origin Request, Actual Request, and Redirects | |||||
// In response to a simple cross-origin request or actual request the | |||||
// resource indicates whether or not to share the response. | |||||
// If the resource has been relocated, it indicates whether to share its | |||||
// new URL. | |||||
// Resources must use the following set of steps to determine which | |||||
// additional headers to use in the response: | |||||
// 3. If the resource supports credentials add a single | |||||
// Access-Control-Allow-Origin header, with the value of the Origin | |||||
// header as value, and add a single Access-Control-Allow-Credentials | |||||
// header with the case-sensitive string "true" as value. | |||||
req->WriteHeader("Access-Control-Allow-Origin", origin.second); | |||||
req->WriteHeader("Access-Control-Allow-Credentials", "true"); | |||||
// 4. If the list of exposed headers is not empty add one or more | |||||
// Access-Control-Expose-Headers headers, with as values the header | |||||
// field names given in the list of exposed headers. | |||||
req->WriteHeader("Access-Control-Expose-Headers", "WWW-Authenticate"); | |||||
return false; | |||||
} | |||||
static bool HTTPReq_JSONRPC(Config &config, HTTPRequest *req, | static bool HTTPReq_JSONRPC(Config &config, HTTPRequest *req, | ||||
const std::string &) { | const std::string &) { | ||||
// First, check and/or set CORS headers | |||||
if (checkCORS(req)) { | |||||
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, | ||||
"JSONRPC server handles only POST requests"); | "JSONRPC server handles only POST requests"); | ||||
return false; | return false; | ||||
} | } | ||||
// Check authorization | // Check authorization | ||||
std::pair<bool, std::string> authHeader = req->GetHeader("authorization"); | std::pair<bool, std::string> authHeader = req->GetHeader("authorization"); | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | static bool InitRPCAuthentication() { | ||||
} else { | } else { | ||||
LogPrintf("Config options rpcuser and rpcpassword will soon be " | LogPrintf("Config options rpcuser and rpcpassword will soon be " | ||||
"deprecated. Locally-run instances may remove rpcuser to use " | "deprecated. Locally-run instances may remove rpcuser to use " | ||||
"cookie-based auth, or may be replaced with rpcauth. Please " | "cookie-based auth, or may be replaced with rpcauth. Please " | ||||
"see share/rpcuser for rpcauth auth generation.\n"); | "see share/rpcuser for rpcauth auth generation.\n"); | ||||
strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + | strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + | ||||
gArgs.GetArg("-rpcpassword", ""); | gArgs.GetArg("-rpcpassword", ""); | ||||
} | } | ||||
strRPCCORSDomain = gArgs.GetArg("-rpccorsdomain", ""); | |||||
return true; | return true; | ||||
} | } | ||||
bool StartHTTPRPC() { | bool StartHTTPRPC() { | ||||
LogPrint(BCLog::RPC, "Starting HTTP RPC server\n"); | LogPrint(BCLog::RPC, "Starting HTTP RPC server\n"); | ||||
if (!InitRPCAuthentication()) return false; | if (!InitRPCAuthentication()) return false; | ||||
RegisterHTTPHandler("/", true, HTTPReq_JSONRPC); | RegisterHTTPHandler("/", true, HTTPReq_JSONRPC); | ||||
Show All 24 Lines |
'/Users/jacox/personalprojects/bitcoin-abc/src/httprpc.cpp' has code style errors.