MetalinkParserStateV3Impl.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2010 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 "MetalinkParserStateV3Impl.h"
  36. #include <cstring>
  37. #include "MetalinkParserStateMachine.h"
  38. #include "RecoverableException.h"
  39. #include "MetalinkResource.h"
  40. #include "util.h"
  41. #include "XmlAttr.h"
  42. namespace aria2 {
  43. const char METALINK3_NAMESPACE_URI[] = "http://www.metalinker.org/";
  44. namespace {
  45. bool checkNsUri(const char* nsUri)
  46. {
  47. return nsUri && strcmp(nsUri, METALINK3_NAMESPACE_URI) == 0;
  48. }
  49. } // namespace
  50. void MetalinkMetalinkParserState::beginElement(
  51. MetalinkParserStateMachine* psm, const char* localname, const char* prefix,
  52. const char* nsUri, const std::vector<XmlAttr>& attrs)
  53. {
  54. if (checkNsUri(nsUri) && strcmp(localname, "files") == 0) {
  55. psm->setFilesState();
  56. }
  57. else {
  58. psm->setSkipTagState();
  59. }
  60. }
  61. void FilesMetalinkParserState::beginElement(MetalinkParserStateMachine* psm,
  62. const char* localname,
  63. const char* prefix,
  64. const char* nsUri,
  65. const std::vector<XmlAttr>& attrs)
  66. {
  67. if (checkNsUri(nsUri) && strcmp(localname, "file") == 0) {
  68. psm->setFileState();
  69. auto itr = findAttr(attrs, "name", METALINK3_NAMESPACE_URI);
  70. if (itr != attrs.end()) {
  71. std::string name((*itr).value, (*itr).valueLength);
  72. if (name.empty() || util::detectDirTraversal(name)) {
  73. return;
  74. }
  75. psm->newEntryTransaction();
  76. psm->setFileNameOfEntry(name);
  77. }
  78. }
  79. else {
  80. psm->setSkipTagState();
  81. }
  82. }
  83. void FileMetalinkParserState::beginElement(MetalinkParserStateMachine* psm,
  84. const char* localname,
  85. const char* prefix,
  86. const char* nsUri,
  87. const std::vector<XmlAttr>& attrs)
  88. {
  89. if (!checkNsUri(nsUri)) {
  90. psm->setSkipTagState();
  91. }
  92. else if (strcmp(localname, "size") == 0) {
  93. psm->setSizeState();
  94. }
  95. else if (strcmp(localname, "version") == 0) {
  96. psm->setVersionState();
  97. }
  98. else if (strcmp(localname, "language") == 0) {
  99. psm->setLanguageState();
  100. }
  101. else if (strcmp(localname, "os") == 0) {
  102. psm->setOSState();
  103. }
  104. else if (strcmp(localname, "verification") == 0) {
  105. psm->setVerificationState();
  106. }
  107. else if (strcmp(localname, "resources") == 0) {
  108. psm->setResourcesState();
  109. int maxConnections;
  110. auto itr = findAttr(attrs, "maxconnections", METALINK3_NAMESPACE_URI);
  111. if (itr == attrs.end()) {
  112. maxConnections = -1;
  113. }
  114. else {
  115. if (!util::parseIntNoThrow(
  116. maxConnections, std::string((*itr).value, (*itr).valueLength)) ||
  117. maxConnections <= 0) {
  118. maxConnections = -1;
  119. }
  120. }
  121. psm->setMaxConnectionsOfEntry(maxConnections);
  122. }
  123. else {
  124. psm->setSkipTagState();
  125. }
  126. }
  127. void FileMetalinkParserState::endElement(MetalinkParserStateMachine* psm,
  128. const char* localname,
  129. const char* prefix, const char* nsUri,
  130. std::string characters)
  131. {
  132. psm->commitEntryTransaction();
  133. }
  134. void SizeMetalinkParserState::endElement(MetalinkParserStateMachine* psm,
  135. const char* localname,
  136. const char* prefix, const char* nsUri,
  137. std::string characters)
  138. {
  139. // current metalink specification doesn't require size element.
  140. int64_t size;
  141. if (util::parseLLIntNoThrow(size, characters) && size >= 0 &&
  142. size <= std::numeric_limits<a2_off_t>::max()) {
  143. psm->setFileLengthOfEntry(size);
  144. }
  145. }
  146. void VersionMetalinkParserState::endElement(MetalinkParserStateMachine* psm,
  147. const char* localname,
  148. const char* prefix,
  149. const char* nsUri,
  150. std::string characters)
  151. {
  152. psm->setVersionOfEntry(std::move(characters));
  153. }
  154. void LanguageMetalinkParserState::endElement(MetalinkParserStateMachine* psm,
  155. const char* localname,
  156. const char* prefix,
  157. const char* nsUri,
  158. std::string characters)
  159. {
  160. psm->setLanguageOfEntry(std::move(characters));
  161. }
  162. void OSMetalinkParserState::endElement(MetalinkParserStateMachine* psm,
  163. const char* localname,
  164. const char* prefix, const char* nsUri,
  165. std::string characters)
  166. {
  167. psm->setOSOfEntry(std::move(characters));
  168. }
  169. void VerificationMetalinkParserState::beginElement(
  170. MetalinkParserStateMachine* psm, const char* localname, const char* prefix,
  171. const char* nsUri, const std::vector<XmlAttr>& attrs)
  172. {
  173. if (!checkNsUri(nsUri)) {
  174. psm->setSkipTagState();
  175. }
  176. else if (strcmp(localname, "hash") == 0) {
  177. psm->setHashState();
  178. auto itr = findAttr(attrs, "type", METALINK3_NAMESPACE_URI);
  179. if (itr == attrs.end()) {
  180. return;
  181. }
  182. else {
  183. psm->newChecksumTransaction();
  184. psm->setTypeOfChecksum(std::string((*itr).value, (*itr).valueLength));
  185. }
  186. }
  187. else if (strcmp(localname, "pieces") == 0) {
  188. psm->setPiecesState();
  189. uint32_t length;
  190. {
  191. auto itr = findAttr(attrs, "length", METALINK3_NAMESPACE_URI);
  192. if (itr == attrs.end()) {
  193. return;
  194. }
  195. else {
  196. if (!util::parseUIntNoThrow(
  197. length, std::string((*itr).value, (*itr).valueLength))) {
  198. return;
  199. }
  200. }
  201. }
  202. std::string type;
  203. {
  204. auto itr = findAttr(attrs, "type", METALINK3_NAMESPACE_URI);
  205. if (itr == attrs.end()) {
  206. return;
  207. }
  208. else {
  209. type.assign((*itr).value, (*itr).valueLength);
  210. }
  211. }
  212. psm->newChunkChecksumTransaction();
  213. psm->setLengthOfChunkChecksum(length);
  214. psm->setTypeOfChunkChecksum(type);
  215. }
  216. else if (strcmp(localname, "signature") == 0) {
  217. psm->setSignatureState();
  218. auto itr = findAttr(attrs, "type", METALINK3_NAMESPACE_URI);
  219. if (itr == attrs.end()) {
  220. return;
  221. }
  222. else {
  223. psm->newSignatureTransaction();
  224. psm->setTypeOfSignature(std::string((*itr).value, (*itr).valueLength));
  225. auto itr = findAttr(attrs, "file", METALINK3_NAMESPACE_URI);
  226. if (itr != attrs.end()) {
  227. std::string file((*itr).value, (*itr).valueLength);
  228. if (!util::detectDirTraversal(file)) {
  229. psm->setFileOfSignature(file);
  230. }
  231. }
  232. }
  233. }
  234. else {
  235. psm->setSkipTagState();
  236. }
  237. }
  238. void HashMetalinkParserState::endElement(MetalinkParserStateMachine* psm,
  239. const char* localname,
  240. const char* prefix, const char* nsUri,
  241. std::string characters)
  242. {
  243. psm->setHashOfChecksum(std::move(characters));
  244. psm->commitChecksumTransaction();
  245. }
  246. void PiecesMetalinkParserState::beginElement(MetalinkParserStateMachine* psm,
  247. const char* localname,
  248. const char* prefix,
  249. const char* nsUri,
  250. const std::vector<XmlAttr>& attrs)
  251. {
  252. if (checkNsUri(nsUri) && strcmp(localname, "hash") == 0) {
  253. psm->setPieceHashState();
  254. auto itr = findAttr(attrs, "piece", METALINK3_NAMESPACE_URI);
  255. if (itr == attrs.end()) {
  256. psm->cancelChunkChecksumTransaction();
  257. }
  258. else {
  259. uint32_t idx;
  260. if (util::parseUIntNoThrow(
  261. idx, std::string((*itr).value, (*itr).valueLength))) {
  262. psm->createNewHashOfChunkChecksum(idx);
  263. }
  264. else {
  265. psm->cancelChunkChecksumTransaction();
  266. }
  267. }
  268. }
  269. else {
  270. psm->setSkipTagState();
  271. }
  272. }
  273. void PiecesMetalinkParserState::endElement(MetalinkParserStateMachine* psm,
  274. const char* localname,
  275. const char* prefix,
  276. const char* nsUri,
  277. std::string characters)
  278. {
  279. psm->commitChunkChecksumTransaction();
  280. }
  281. void PieceHashMetalinkParserState::endElement(MetalinkParserStateMachine* psm,
  282. const char* localname,
  283. const char* prefix,
  284. const char* nsUri,
  285. std::string characters)
  286. {
  287. psm->setMessageDigestOfChunkChecksum(std::move(characters));
  288. psm->addHashOfChunkChecksum();
  289. }
  290. void SignatureMetalinkParserState::endElement(MetalinkParserStateMachine* psm,
  291. const char* localname,
  292. const char* prefix,
  293. const char* nsUri,
  294. std::string characters)
  295. {
  296. psm->setBodyOfSignature(std::move(characters));
  297. psm->commitSignatureTransaction();
  298. }
  299. void ResourcesMetalinkParserState::beginElement(
  300. MetalinkParserStateMachine* psm, const char* localname, const char* prefix,
  301. const char* nsUri, const std::vector<XmlAttr>& attrs)
  302. {
  303. if (!checkNsUri(nsUri)) {
  304. psm->setSkipTagState();
  305. }
  306. else if (strcmp(localname, "url") == 0) {
  307. psm->setURLState();
  308. std::string type;
  309. {
  310. auto itr = findAttr(attrs, "type", METALINK3_NAMESPACE_URI);
  311. if (itr == attrs.end()) {
  312. return;
  313. }
  314. type.assign((*itr).value, (*itr).valueLength);
  315. }
  316. std::string location;
  317. {
  318. auto itr = findAttr(attrs, "location", METALINK3_NAMESPACE_URI);
  319. if (itr != attrs.end()) {
  320. location.assign((*itr).value, (*itr).valueLength);
  321. }
  322. }
  323. int preference;
  324. {
  325. auto itr = findAttr(attrs, "preference", METALINK3_NAMESPACE_URI);
  326. if (itr == attrs.end()) {
  327. preference = MetalinkResource::getLowestPriority();
  328. }
  329. else if (util::parseIntNoThrow(
  330. preference, std::string((*itr).value, (*itr).valueLength)) &&
  331. preference >= 0) {
  332. // In Metalink3Spec, highest preference value is 100. We
  333. // use Metalink4Spec priority unit system in which 1 is
  334. // highest.
  335. preference = 101 - preference;
  336. }
  337. else {
  338. preference = MetalinkResource::getLowestPriority();
  339. }
  340. }
  341. int maxConnections;
  342. {
  343. auto itr = findAttr(attrs, "maxconnections", METALINK3_NAMESPACE_URI);
  344. if (itr == attrs.end()) {
  345. maxConnections = -1;
  346. }
  347. else if (!util::parseIntNoThrow(
  348. maxConnections,
  349. std::string((*itr).value, (*itr).valueLength)) ||
  350. maxConnections <= 0) {
  351. maxConnections = -1;
  352. }
  353. }
  354. psm->newResourceTransaction();
  355. psm->setTypeOfResource(type);
  356. psm->setLocationOfResource(location);
  357. psm->setPriorityOfResource(preference);
  358. psm->setMaxConnectionsOfResource(maxConnections);
  359. }
  360. else {
  361. psm->setSkipTagState();
  362. }
  363. }
  364. void URLMetalinkParserState::endElement(MetalinkParserStateMachine* psm,
  365. const char* localname,
  366. const char* prefix, const char* nsUri,
  367. std::string characters)
  368. {
  369. psm->setURLOfResource(std::move(characters));
  370. psm->commitResourceTransaction();
  371. }
  372. } // namespace aria2