Changeset View
Changeset View
Standalone View
Standalone View
src/httprpc.cpp
Context not available. | |||||
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; | |||||
schancel: This commit looks good. If you have time, we've been moving things like this unto the… | |||||
jasonbcoxAuthorUnsubmitted Not Done Inline ActionsDoing this requires some cascading changes in this file. I'm going to take care of this in T329. jasonbcox: Doing this requires some cascading changes in this file. I'm going to take care of this in… | |||||
static void JSONErrorReply(HTTPRequest *req, const UniValue &objError, | static void JSONErrorReply(HTTPRequest *req, const UniValue &objError, | ||||
const UniValue &id) { | const UniValue &id) { | ||||
Context not available. | |||||
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, | ||||
Context not available. | |||||
strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + | strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + | ||||
gArgs.GetArg("-rpcpassword", ""); | gArgs.GetArg("-rpcpassword", ""); | ||||
} | } | ||||
strRPCCORSDomain = GetArg("-rpccorsdomain", ""); | |||||
return true; | return true; | ||||
} | } | ||||
Context not available. |
This commit looks good. If you have time, we've been moving things like this unto the configuration object. it would be good to have this there, then to pass it into checkCORS as a parameter