bool validateCSRFForm(const http::Request& request, http::Response* pResponse) { // extract token from HTTP cookie (set above) std::string headerToken = request.cookieValue(kCSRFTokenName); http::Fields fields; // parse the form and check for a matching token http::util::parseForm(request.body(), &fields); std::string bodyToken = http::util::fieldValue<std::string>(fields, kCSRFTokenName, ""); // report an error if they don't match if (headerToken.empty() || bodyToken != headerToken) { pResponse->setStatusCode(http::status::BadRequest); pResponse->setBody("Missing or incorrect token."); return false; } // all is well return true; }
Error getGridData(const http::Request& request, http::Response* pResponse) { json::Value result; http::status::Code status = http::status::Ok; try { // find the data frame we're going to be pulling data from http::Fields fields; http::util::parseForm(request.body(), &fields); std::string envName = http::util::urlDecode( http::util::fieldValue<std::string>(fields, "env", "")); std::string objName = http::util::urlDecode( http::util::fieldValue<std::string>(fields, "obj", "")); std::string cacheKey = http::util::urlDecode( http::util::fieldValue<std::string>(fields, "cache_key", "")); std::string show = http::util::fieldValue<std::string>( fields, "show", "data"); if (objName.empty() && cacheKey.empty()) { return Success(); } r::sexp::Protect protect; // begin observing if we aren't already if (envName != kNoBoundEnv) { SEXP objSEXP = findInNamedEnvir(envName, objName); std::map<std::string, CachedFrame>::iterator it = s_cachedFrames.find(cacheKey); if (it == s_cachedFrames.end()) s_cachedFrames[cacheKey] = CachedFrame(envName, objName, objSEXP); } // attempt to find the original copy of the object (loads from cache key // if necessary) SEXP dataSEXP = R_NilValue; Error error = r::exec::RFunction(".rs.findDataFrame", envName, objName, cacheKey, viewerCacheDir()).call(&dataSEXP, &protect); if (error) { LOG_ERROR(error); } // couldn't find the original object if (dataSEXP == nullptr || dataSEXP == R_UnboundValue || Rf_isNull(dataSEXP) || TYPEOF(dataSEXP) == NILSXP) { json::Object err; err["error"] = "The object no longer exists."; status = http::status::NotFound; result = err; } else { // if the data is a promise (happens for built-in data), the value is // what we're looking for if (TYPEOF(dataSEXP) == PROMSXP) { dataSEXP = PRVALUE(dataSEXP); } if (show == "cols") { result = getCols(dataSEXP); } else if (show == "data") { result = getData(dataSEXP, fields); } } } catch(r::exec::RErrorException& e) { // marshal R errors to the client in the format DataTables (and our own // error handling code) expects json::Object err; err["error"] = e.message(); result = err; status = http::status::InternalServerError; } CATCH_UNEXPECTED_EXCEPTION std::ostringstream ostr; json::write(result, ostr); // There are some unprintable ASCII control characters that are written // verbatim by json::write, but that won't parse in most Javascript JSON // parsing implementations, even if contained in a string literal. Scan the // output data for these characters and replace them with spaces. Escaping // is another option here for some character ranges but since (a) these are // unprintable and (b) some characters are invalid *even if escaped* e.g. // \v, there's little to be gained here in trying to marshal them to the // viewer. std::string output = ostr.str(); for (size_t i = 0; i < output.size(); i++) { char c = output[i]; // These ranges for control character values come from empirical testing if ((c >= 1 && c <= 7) || c == 11 || (c >= 14 && c <= 31)) { output[i] = ' '; } } pResponse->setNoCacheHeaders(); // don't cache data/grid shape pResponse->setStatusCode(status); pResponse->setBody(output); return Success(); }
void handleLogRequest(const std::string& username, const http::Request& request, http::Response* pResponse) { // parse log method json::JsonRpcRequest jsonRpcRequest; if (!parseJsonRpcRequestForMethod(request.body(), "log", &jsonRpcRequest, pResponse) ) { return; } // read params int level = 0; std::string message ; Error error = json::readParams(jsonRpcRequest.params, &level, &message); if (error) { LOG_ERROR(error); json::setJsonRpcError(error, pResponse); return; } // convert level to appropriate enum and str using namespace core::system; LogLevel logLevel; std::string logLevelStr; switch(level) { case 0: logLevel = kLogLevelError; logLevelStr = "ERROR"; break; case 1: logLevel = kLogLevelWarning; logLevelStr = "WARNING"; break; case 2: logLevel = kLogLevelInfo; logLevelStr = "INFO"; break; default: LOG_WARNING_MESSAGE("Unexpected log level: " + safe_convert::numberToString(level)); logLevel = kLogLevelError; logLevelStr = "ERROR"; break; } // form the log entry boost::format fmt("CLIENT %1% (%2%-%3%): %4%; USER-AGENT: %5%"); std::string logEntry = boost::str(fmt % logLevelStr % username % jsonRpcRequest.clientId % message % request.userAgent()); // log it core::system::log(logLevel, logEntry); // set void result json::setVoidJsonRpcResult(pResponse); }