/* */ #include "RpcMethod.h" #include "DownloadEngine.h" #include "LogFactory.h" #include "RecoverableException.h" #include "message.h" #include "OptionParser.h" #include "OptionHandler.h" #include "Option.h" #include "array_fun.h" #include "download_helper.h" #include "RpcRequest.h" #include "RpcResponse.h" #include "prefs.h" #include "fmt.h" #include "DlAbortEx.h" #include "a2functional.h" #include "util.h" namespace aria2 { namespace rpc { RpcMethod::RpcMethod() : optionParser_(OptionParser::getInstance()) {} RpcMethod::~RpcMethod() {} std::unique_ptr RpcMethod::createErrorResponse(const Exception& e, const RpcRequest& req) { auto params = Dict::g(); params->put((req.jsonRpc ? "code" : "faultCode"), Integer::g(1)); params->put((req.jsonRpc ? "message" : "faultString"), std::string(e.what())); return std::move(params); } void RpcMethod::authorize(RpcRequest& req, DownloadEngine* e) { std::string token; // We always treat first parameter as token if it is string and // starts with "token:" and remove it from parameter list, so that // we don't have to add conditionals to all RPCMethod // implementations. if (req.params && !req.params->empty()) { auto t = downcast(req.params->get(0)); if (t) { if (util::startsWith(t->s(), "token:")) { token = t->s().substr(6); req.params->pop_front(); } } } if (!e || !e->validateToken(token)) { throw DL_ABORT_EX("Unauthorized"); } } RpcResponse RpcMethod::execute(RpcRequest req, DownloadEngine* e) { auto authorized = RpcResponse::NOTAUTHORIZED; try { authorize(req, e); authorized = RpcResponse::AUTHORIZED; auto r = process(req, e); return RpcResponse(0, authorized, std::move(r), std::move(req.id)); } catch (RecoverableException& ex) { A2_LOG_DEBUG_EX(EX_EXCEPTION_CAUGHT, ex); return RpcResponse(1, authorized, createErrorResponse(ex, req), std::move(req.id)); } } namespace { template void gatherOption(InputIterator first, InputIterator last, Pred pred, Option* option, const std::shared_ptr& optionParser) { for (; first != last; ++first) { const std::string& optionName = (*first).first; PrefPtr pref = option::k2p(optionName); const OptionHandler* handler = optionParser->find(pref); if (!handler || !pred(handler)) { // Just ignore the unacceptable options in this context. continue; } const String* opval = downcast((*first).second); if (opval) { handler->parse(*option, opval->s()); } else if (handler->getCumulative()) { // header and index-out option can take array as value const List* oplist = downcast((*first).second); if (oplist) { for (auto& elem : *oplist) { const String* opval = downcast(elem); if (opval) { handler->parse(*option, opval->s()); } } } } } } } // namespace void RpcMethod::gatherRequestOption(Option* option, const Dict* optionsDict) { if (optionsDict) { gatherOption(optionsDict->begin(), optionsDict->end(), std::mem_fn(&OptionHandler::getInitialOption), option, optionParser_); } } void RpcMethod::gatherChangeableOption(Option* option, const Dict* optionsDict) { if (optionsDict) { gatherOption(optionsDict->begin(), optionsDict->end(), std::mem_fn(&OptionHandler::getChangeOption), option, optionParser_); } } void RpcMethod::gatherChangeableOptionForReserved(Option* option, const Dict* optionsDict) { if (optionsDict) { gatherOption(optionsDict->begin(), optionsDict->end(), std::mem_fn(&OptionHandler::getChangeOptionForReserved), option, optionParser_); } } void RpcMethod::gatherChangeableGlobalOption(Option* option, const Dict* optionsDict) { if (optionsDict) { gatherOption(optionsDict->begin(), optionsDict->end(), std::mem_fn(&OptionHandler::getChangeGlobalOption), option, optionParser_); } } } // namespace rpc } // namespace aria2