MetalinkParserStateV3Impl.cc 11 KB

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