1 /* <!-- copyright */
2 /*
3 * aria2 - The high speed download utility
4 *
5 * Copyright (C) 2009 Tatsuhiro Tsujikawa
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * In addition, as a special exception, the copyright holders give
22 * permission to link the code of portions of this program with the
23 * OpenSSL library under certain conditions as described in each
24 * individual source file, and distribute linked combinations
25 * including the two.
26 * You must obey the GNU General Public License in all respects
27 * for all of the code used other than OpenSSL. If you modify
28 * file(s) with this exception, you may extend this exception to your
29 * version of the file(s), but you are not obligated to do so. If you
30 * do not wish to do so, delete this exception statement from your
31 * version. If you delete this exception statement from all source
32 * files in the program, then also delete it here.
33 */
34 /* copyright --> */
35 #include "RpcMethod.h"
36 #include "DownloadEngine.h"
37 #include "LogFactory.h"
38 #include "RecoverableException.h"
39 #include "message.h"
40 #include "OptionParser.h"
41 #include "OptionHandler.h"
42 #include "Option.h"
43 #include "array_fun.h"
44 #include "download_helper.h"
45 #include "RpcRequest.h"
46 #include "RpcResponse.h"
47 #include "prefs.h"
48 #include "fmt.h"
49 #include "DlAbortEx.h"
50 #include "a2functional.h"
51 #include "util.h"
52
53 namespace aria2 {
54
55 namespace rpc {
56
RpcMethod()57 RpcMethod::RpcMethod() : optionParser_(OptionParser::getInstance()) {}
58
59 RpcMethod::~RpcMethod() = default;
60
createErrorResponse(const Exception & e,const RpcRequest & req)61 std::unique_ptr<ValueBase> RpcMethod::createErrorResponse(const Exception& e,
62 const RpcRequest& req)
63 {
64 auto params = Dict::g();
65 params->put((req.jsonRpc ? "code" : "faultCode"), Integer::g(1));
66 params->put((req.jsonRpc ? "message" : "faultString"), std::string(e.what()));
67 return std::move(params);
68 }
69
authorize(RpcRequest & req,DownloadEngine * e)70 void RpcMethod::authorize(RpcRequest& req, DownloadEngine* e)
71 {
72 std::string token;
73 // We always treat first parameter as token if it is string and
74 // starts with "token:" and remove it from parameter list, so that
75 // we don't have to add conditionals to all RPCMethod
76 // implementations.
77 if (req.params && !req.params->empty()) {
78 auto t = downcast<String>(req.params->get(0));
79 if (t) {
80 if (util::startsWith(t->s(), "token:")) {
81 token = t->s().substr(6);
82 req.params->pop_front();
83 }
84 }
85 }
86 if (!e || !e->validateToken(token)) {
87 throw DL_ABORT_EX("Unauthorized");
88 }
89 }
90
execute(RpcRequest req,DownloadEngine * e)91 RpcResponse RpcMethod::execute(RpcRequest req, DownloadEngine* e)
92 {
93 auto authorized = RpcResponse::NOTAUTHORIZED;
94 try {
95 authorize(req, e);
96 authorized = RpcResponse::AUTHORIZED;
97 auto r = process(req, e);
98 return RpcResponse(0, authorized, std::move(r), std::move(req.id));
99 }
100 catch (RecoverableException& ex) {
101 A2_LOG_DEBUG_EX(EX_EXCEPTION_CAUGHT, ex);
102 return RpcResponse(1, authorized, createErrorResponse(ex, req),
103 std::move(req.id));
104 }
105 }
106
107 namespace {
108 template <typename InputIterator, typename Pred>
gatherOption(InputIterator first,InputIterator last,Pred pred,Option * option,const std::shared_ptr<OptionParser> & optionParser)109 void gatherOption(InputIterator first, InputIterator last, Pred pred,
110 Option* option,
111 const std::shared_ptr<OptionParser>& optionParser)
112 {
113 for (; first != last; ++first) {
114 const std::string& optionName = (*first).first;
115 PrefPtr pref = option::k2p(optionName);
116 const OptionHandler* handler = optionParser->find(pref);
117 if (!handler || !pred(handler)) {
118 // Just ignore the unacceptable options in this context.
119 continue;
120 }
121 const String* opval = downcast<String>((*first).second);
122 if (opval) {
123 handler->parse(*option, opval->s());
124 }
125 else if (handler->getCumulative()) {
126 // header and index-out option can take array as value
127 const List* oplist = downcast<List>((*first).second);
128 if (oplist) {
129 for (auto& elem : *oplist) {
130 const String* opval = downcast<String>(elem);
131 if (opval) {
132 handler->parse(*option, opval->s());
133 }
134 }
135 }
136 }
137 }
138 }
139 } // namespace
140
gatherRequestOption(Option * option,const Dict * optionsDict)141 void RpcMethod::gatherRequestOption(Option* option, const Dict* optionsDict)
142 {
143 if (optionsDict) {
144 gatherOption(optionsDict->begin(), optionsDict->end(),
145 std::mem_fn(&OptionHandler::getInitialOption), option,
146 optionParser_);
147 }
148 }
149
gatherChangeableOption(Option * option,Option * pendingOption,const Dict * optionsDict)150 void RpcMethod::gatherChangeableOption(Option* option, Option* pendingOption,
151 const Dict* optionsDict)
152 {
153 if (!optionsDict) {
154 return;
155 }
156
157 auto first = optionsDict->begin();
158 auto last = optionsDict->end();
159
160 for (; first != last; ++first) {
161 const auto& optionName = (*first).first;
162 auto pref = option::k2p(optionName);
163 auto handler = optionParser_->find(pref);
164 if (!handler) {
165 // Just ignore the unacceptable options in this context.
166 continue;
167 }
168
169 Option* dst = nullptr;
170 if (handler->getChangeOption()) {
171 dst = option;
172 }
173 else if (handler->getChangeOptionForReserved()) {
174 dst = pendingOption;
175 }
176
177 if (!dst) {
178 continue;
179 }
180
181 const auto opval = downcast<String>((*first).second);
182 if (opval) {
183 handler->parse(*dst, opval->s());
184 }
185 else if (handler->getCumulative()) {
186 // header and index-out option can take array as value
187 const auto oplist = downcast<List>((*first).second);
188 if (oplist) {
189 for (auto& elem : *oplist) {
190 const auto opval = downcast<String>(elem);
191 if (opval) {
192 handler->parse(*dst, opval->s());
193 }
194 }
195 }
196 }
197 }
198 }
199
gatherChangeableOptionForReserved(Option * option,const Dict * optionsDict)200 void RpcMethod::gatherChangeableOptionForReserved(Option* option,
201 const Dict* optionsDict)
202 {
203 if (optionsDict) {
204 gatherOption(optionsDict->begin(), optionsDict->end(),
205 std::mem_fn(&OptionHandler::getChangeOptionForReserved),
206 option, optionParser_);
207 }
208 }
209
gatherChangeableGlobalOption(Option * option,const Dict * optionsDict)210 void RpcMethod::gatherChangeableGlobalOption(Option* option,
211 const Dict* optionsDict)
212 {
213 if (optionsDict) {
214 gatherOption(optionsDict->begin(), optionsDict->end(),
215 std::mem_fn(&OptionHandler::getChangeGlobalOption), option,
216 optionParser_);
217 }
218 }
219
220 } // namespace rpc
221
222 } // namespace aria2
223