uri.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 "uri.h"
  36. #include "A2STR.h"
  37. #include "FeatureConfig.h"
  38. #include "util.h"
  39. namespace aria2 {
  40. namespace uri {
  41. UriStruct::UriStruct()
  42. : port(0), hasPassword(false), ipv6LiteralAddress(false)
  43. {}
  44. UriStruct::UriStruct(const UriStruct& c)
  45. : protocol(c.protocol),
  46. host(c.host),
  47. port(c.port),
  48. dir(c.dir),
  49. file(c.file),
  50. query(c.query),
  51. username(c.username),
  52. password(c.password),
  53. hasPassword(c.hasPassword),
  54. ipv6LiteralAddress(c.ipv6LiteralAddress)
  55. {}
  56. UriStruct::~UriStruct() {}
  57. UriStruct& UriStruct::operator=(const UriStruct& c)
  58. {
  59. if(this != &c) {
  60. protocol = c.protocol;
  61. host = c.host;
  62. port = c.port;
  63. dir = c.dir;
  64. file = c.file;
  65. query = c.query;
  66. username = c.username;
  67. password = c.password;
  68. hasPassword = c.hasPassword;
  69. ipv6LiteralAddress = c.ipv6LiteralAddress;
  70. }
  71. return *this;
  72. }
  73. bool parse(UriStruct& result, const std::string& uri)
  74. {
  75. // http://user:password@aria2.sourceforge.net:80/dir/file?query#fragment
  76. // | || || | | | |
  77. // | || hostLast| | | | |
  78. // | || portFirst| | | |
  79. // authorityFirst || authorityLast | | |
  80. // || | | | |
  81. // userInfoLast | | | |
  82. // | | | | |
  83. // hostPortFirst | | | |
  84. // | | | |
  85. // dirFirst dirLast| |
  86. // | |
  87. // queryFirst fragmentFirst
  88. // find fragment part
  89. std::string::const_iterator fragmentFirst = uri.begin();
  90. for(; fragmentFirst != uri.end(); ++fragmentFirst) {
  91. if(*fragmentFirst == '#') break;
  92. }
  93. // find query part
  94. std::string::const_iterator queryFirst = uri.begin();
  95. for(; queryFirst != fragmentFirst; ++queryFirst) {
  96. if(*queryFirst == '?') break;
  97. }
  98. result.query = std::string(queryFirst, fragmentFirst);
  99. // find protocol
  100. std::string::size_type protocolOffset = uri.find("://");
  101. if(protocolOffset == std::string::npos) return false;
  102. result.protocol = std::string(uri.begin(), uri.begin()+protocolOffset);
  103. uint16_t defPort;
  104. if((defPort = FeatureConfig::getInstance()->
  105. getDefaultPort(result.protocol)) == 0) {
  106. return false;
  107. }
  108. // find authority
  109. std::string::const_iterator authorityFirst = uri.begin()+protocolOffset+3;
  110. std::string::const_iterator authorityLast = authorityFirst;
  111. for(; authorityLast != queryFirst; ++authorityLast) {
  112. if(*authorityLast == '/') break;
  113. }
  114. if(authorityFirst == authorityLast) {
  115. // No authority found
  116. return false;
  117. }
  118. // find userinfo(username and password) in authority if they exist
  119. result.username = A2STR::NIL;
  120. result.password = A2STR::NIL;
  121. result.hasPassword = false;
  122. std::string::const_iterator userInfoLast = authorityLast;
  123. std::string::const_iterator hostPortFirst = authorityFirst;
  124. for(; userInfoLast != authorityFirst-1; --userInfoLast) {
  125. if(*userInfoLast == '@') {
  126. hostPortFirst = userInfoLast;
  127. ++hostPortFirst;
  128. std::string::const_iterator userLast = authorityFirst;
  129. for(; userLast != userInfoLast; ++userLast) {
  130. if(*userLast == ':') {
  131. result.password =
  132. util::percentDecode(std::string(userLast+1,userInfoLast));
  133. result.hasPassword = true;
  134. break;
  135. }
  136. }
  137. result.username =
  138. util::percentDecode(std::string(authorityFirst, userLast));
  139. break;
  140. }
  141. }
  142. std::string::const_iterator hostLast = hostPortFirst;
  143. std::string::const_iterator portFirst = authorityLast;
  144. result.ipv6LiteralAddress = false;
  145. if(*hostPortFirst == '[') {
  146. // Detected IPv6 literal address in square brackets
  147. for(; hostLast != authorityLast; ++hostLast) {
  148. if(*hostLast == ']') {
  149. ++hostLast;
  150. if(hostLast == authorityLast) {
  151. result.ipv6LiteralAddress = true;
  152. } else {
  153. if(*hostLast == ':') {
  154. portFirst = hostLast;
  155. ++portFirst;
  156. result.ipv6LiteralAddress = true;
  157. }
  158. }
  159. break;
  160. }
  161. }
  162. if(!result.ipv6LiteralAddress) {
  163. return false;
  164. }
  165. } else {
  166. for(; hostLast != authorityLast; ++hostLast) {
  167. if(*hostLast == ':') {
  168. portFirst = hostLast;
  169. ++portFirst;
  170. break;
  171. }
  172. }
  173. }
  174. if(hostPortFirst == hostLast) {
  175. // No host
  176. return false;
  177. }
  178. if(portFirst == authorityLast) {
  179. // If port is not specified, then we set it to default port of
  180. // its protocol..
  181. result.port = defPort;
  182. } else {
  183. uint32_t tempPort;
  184. if(util::parseUIntNoThrow(tempPort, std::string(portFirst, authorityLast))){
  185. if(65535 < tempPort) {
  186. return false;
  187. }
  188. result.port = tempPort;
  189. } else {
  190. return false;
  191. }
  192. }
  193. if(result.ipv6LiteralAddress) {
  194. result.host = std::string(hostPortFirst+1, hostLast-1);
  195. } else {
  196. result.host = std::string(hostPortFirst, hostLast);
  197. }
  198. // find directory and file part
  199. std::string::const_iterator dirLast = authorityLast;
  200. for(std::string::const_iterator i = authorityLast;
  201. i != queryFirst; ++i) {
  202. if(*i == '/') {
  203. dirLast = i;
  204. }
  205. }
  206. if(dirLast == queryFirst) {
  207. result.file = A2STR::NIL;
  208. } else {
  209. result.file = std::string(dirLast+1, queryFirst);
  210. }
  211. // Erase duplicated slashes.
  212. std::string::const_iterator dirFirst = authorityLast;
  213. for(; dirFirst != dirLast; ++dirFirst) {
  214. if(*dirFirst != '/') {
  215. --dirFirst;
  216. break;
  217. }
  218. }
  219. for(; dirLast != dirFirst; --dirLast) {
  220. if(*dirLast != '/') {
  221. ++dirLast;
  222. break;
  223. }
  224. }
  225. if(dirFirst == dirLast) {
  226. result.dir = A2STR::SLASH_C;
  227. } else {
  228. result.dir = std::string(dirFirst, dirLast);
  229. }
  230. return true;
  231. }
  232. } // namespace uri
  233. } // namespace aria2