HttpRequest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2006 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 "HttpRequest.h"
  36. #include <cassert>
  37. #include <numeric>
  38. #include <vector>
  39. #include "Segment.h"
  40. #include "Range.h"
  41. #include "CookieStorage.h"
  42. #include "Option.h"
  43. #include "util.h"
  44. #include "Base64.h"
  45. #include "prefs.h"
  46. #include "AuthConfigFactory.h"
  47. #include "AuthConfig.h"
  48. #include "a2functional.h"
  49. #include "TimeA2.h"
  50. #include "array_fun.h"
  51. namespace aria2 {
  52. const std::string HttpRequest::USER_AGENT("aria2");
  53. HttpRequest::HttpRequest():_contentEncodingEnabled(true),
  54. userAgent(USER_AGENT),
  55. _noCache(true),
  56. _acceptGzip(false)
  57. {}
  58. void HttpRequest::setSegment(const SharedHandle<Segment>& segment)
  59. {
  60. this->segment = segment;
  61. }
  62. void HttpRequest::setRequest(const SharedHandle<Request>& request)
  63. {
  64. this->request = request;
  65. }
  66. off_t HttpRequest::getStartByte() const
  67. {
  68. if(segment.isNull()) {
  69. return 0;
  70. } else {
  71. return _fileEntry->gtoloff(segment->getPositionToWrite());
  72. }
  73. }
  74. off_t HttpRequest::getEndByte() const
  75. {
  76. if(segment.isNull() || request.isNull()) {
  77. return 0;
  78. } else {
  79. if(request->isPipeliningEnabled()) {
  80. off_t endByte = _fileEntry->gtoloff(segment->getPosition()+segment->getLength()-1);
  81. return std::min(endByte, static_cast<off_t>(_fileEntry->getLength()-1));
  82. } else {
  83. return 0;
  84. }
  85. }
  86. }
  87. RangeHandle HttpRequest::getRange() const
  88. {
  89. // content-length is always 0
  90. if(segment.isNull()) {
  91. return SharedHandle<Range>(new Range());
  92. } else {
  93. return SharedHandle<Range>(new Range(getStartByte(), getEndByte(),
  94. _fileEntry->getLength()));
  95. }
  96. }
  97. bool HttpRequest::isRangeSatisfied(const RangeHandle& range) const
  98. {
  99. if(segment.isNull()) {
  100. return true;
  101. }
  102. if((getStartByte() == range->getStartByte()) &&
  103. ((getEndByte() == 0) ||
  104. (getEndByte() == range->getEndByte())) &&
  105. ((_fileEntry->getLength() == 0) ||
  106. (_fileEntry->getLength() == range->getEntityLength()))) {
  107. return true;
  108. } else {
  109. return false;
  110. }
  111. }
  112. static std::string getHostText(const std::string& host, uint16_t port)
  113. {
  114. std::string hosttext = host;
  115. if(!(port == 80 || port == 443)) {
  116. strappend(hosttext, ":", util::uitos(port));
  117. }
  118. return hosttext;
  119. }
  120. std::string HttpRequest::createRequest()
  121. {
  122. _authConfig = _authConfigFactory->createAuthConfig(request, _option);
  123. std::string requestLine = request->getMethod();
  124. requestLine += " ";
  125. if(!_proxyRequest.isNull()) {
  126. if(getProtocol() == Request::PROTO_FTP &&
  127. request->getUsername().empty() && !_authConfig.isNull()) {
  128. // Insert user into URI, like ftp://USER@host/
  129. std::string uri = getCurrentURI();
  130. assert(uri.size() >= 6);
  131. uri.insert(6, util::percentEncode(_authConfig->getUser())+"@");
  132. requestLine += uri;
  133. } else {
  134. requestLine += getCurrentURI();
  135. }
  136. } else {
  137. if(getDir() == A2STR::SLASH_C) {
  138. requestLine += getDir();
  139. } else {
  140. requestLine += getDir();
  141. requestLine += A2STR::SLASH_C;
  142. }
  143. requestLine += getFile();
  144. requestLine += getQuery();
  145. }
  146. requestLine += " HTTP/1.1\r\n";
  147. std::vector<std::pair<std::string, std::string> > builtinHds;
  148. builtinHds.reserve(20);
  149. builtinHds.push_back(std::make_pair("User-Agent:", userAgent));
  150. std::string acceptTypes = "*/*";
  151. for(std::vector<std::string>::const_iterator i = _acceptTypes.begin(),
  152. eoi = _acceptTypes.end(); i != eoi; ++i) {
  153. strappend(acceptTypes, ",", (*i));
  154. }
  155. builtinHds.push_back(std::make_pair("Accept:", acceptTypes));
  156. if(_contentEncodingEnabled) {
  157. std::string acceptableEncodings;
  158. #ifdef HAVE_LIBZ
  159. if(_acceptGzip) {
  160. acceptableEncodings += "deflate, gzip";
  161. }
  162. #endif // HAVE_LIBZ
  163. if(!acceptableEncodings.empty()) {
  164. builtinHds.push_back
  165. (std::make_pair("Accept-Encoding:", acceptableEncodings));
  166. }
  167. }
  168. builtinHds.push_back
  169. (std::make_pair("Host:", getHostText(getURIHost(), getPort())));
  170. if(_noCache) {
  171. builtinHds.push_back(std::make_pair("Pragma:", "no-cache"));
  172. builtinHds.push_back(std::make_pair("Cache-Control:", "no-cache"));
  173. }
  174. if(!request->isKeepAliveEnabled() && !request->isPipeliningEnabled()) {
  175. builtinHds.push_back(std::make_pair("Connection:", "close"));
  176. }
  177. if(!segment.isNull() && segment->getLength() > 0 &&
  178. (request->isPipeliningEnabled() || getStartByte() > 0)) {
  179. std::string rangeHeader = "bytes=";
  180. rangeHeader += util::itos(getStartByte());
  181. rangeHeader += "-";
  182. if(request->isPipeliningEnabled()) {
  183. rangeHeader += util::itos(getEndByte());
  184. }
  185. builtinHds.push_back(std::make_pair("Range:", rangeHeader));
  186. }
  187. if(!_proxyRequest.isNull()) {
  188. if(request->isKeepAliveEnabled() || request->isPipeliningEnabled()) {
  189. builtinHds.push_back(std::make_pair("Proxy-Connection:", "Keep-Alive"));
  190. } else {
  191. builtinHds.push_back(std::make_pair("Proxy-Connection:", "close"));
  192. }
  193. }
  194. if(!_proxyRequest.isNull() && !_proxyRequest->getUsername().empty()) {
  195. builtinHds.push_back(getProxyAuthString());
  196. }
  197. if(!_authConfig.isNull()) {
  198. builtinHds.push_back
  199. (std::make_pair("Authorization:",
  200. strconcat("Basic ",
  201. Base64::encode(_authConfig->getAuthText()))));
  202. }
  203. if(getPreviousURI().size()) {
  204. builtinHds.push_back(std::make_pair("Referer:", getPreviousURI()));
  205. }
  206. if(!_cookieStorage.isNull()) {
  207. std::string cookiesValue;
  208. std::vector<Cookie> cookies =
  209. _cookieStorage->criteriaFind(getHost(),
  210. getDir(),
  211. Time().getTime(),
  212. getProtocol() == Request::PROTO_HTTPS ?
  213. true : false);
  214. for(std::vector<Cookie>::const_iterator itr = cookies.begin(),
  215. eoi = cookies.end(); itr != eoi; ++itr) {
  216. strappend(cookiesValue, (*itr).toString(), ";");
  217. }
  218. if(!cookiesValue.empty()) {
  219. builtinHds.push_back(std::make_pair("Cookie:", cookiesValue));
  220. }
  221. }
  222. for(std::vector<std::pair<std::string, std::string> >::const_iterator i =
  223. builtinHds.begin(), eoi = builtinHds.end(); i != eoi; ++i) {
  224. std::vector<std::string>::const_iterator j = _headers.begin();
  225. std::vector<std::string>::const_iterator jend = _headers.end();
  226. for(; j != jend; ++j) {
  227. if(util::startsWith(*j, (*i).first)) {
  228. break;
  229. }
  230. }
  231. if(j == jend) {
  232. strappend(requestLine, (*i).first, " ", (*i).second, A2STR::CRLF);
  233. }
  234. }
  235. // append additional headers given by user.
  236. for(std::vector<std::string>::const_iterator i = _headers.begin(),
  237. eoi = _headers.end(); i != eoi; ++i) {
  238. strappend(requestLine, (*i), A2STR::CRLF);
  239. }
  240. requestLine += A2STR::CRLF;
  241. return requestLine;
  242. }
  243. std::string HttpRequest::createProxyRequest() const
  244. {
  245. assert(!_proxyRequest.isNull());
  246. std::string hostport = getURIHost();
  247. strappend(hostport, ":", util::uitos(getPort()));
  248. std::string requestLine = "CONNECT ";
  249. strappend(requestLine, hostport, " HTTP/1.1\r\n");
  250. strappend(requestLine, "User-Agent: ", userAgent, "\r\n");
  251. strappend(requestLine, "Host: ", hostport, "\r\n");
  252. // TODO Is "Proxy-Connection" needed here?
  253. // if(request->isKeepAliveEnabled() || request->isPipeliningEnabled()) {
  254. // requestLine += "Proxy-Connection: Keep-Alive\r\n";
  255. // }else {
  256. // requestLine += "Proxy-Connection: close\r\n";
  257. // }
  258. if(!_proxyRequest->getUsername().empty()) {
  259. std::pair<std::string, std::string> auth = getProxyAuthString();
  260. strappend(requestLine, auth.first, " ", auth.second, A2STR::CRLF);
  261. }
  262. requestLine += A2STR::CRLF;
  263. return requestLine;
  264. }
  265. std::pair<std::string, std::string> HttpRequest::getProxyAuthString() const
  266. {
  267. return std::make_pair
  268. ("Proxy-Authorization:",
  269. strconcat("Basic ",
  270. Base64::encode(strconcat(_proxyRequest->getUsername(),
  271. ":",
  272. _proxyRequest->getPassword()))));
  273. }
  274. void HttpRequest::enableContentEncoding()
  275. {
  276. _contentEncodingEnabled = true;
  277. }
  278. void HttpRequest::disableContentEncoding()
  279. {
  280. _contentEncodingEnabled = false;
  281. }
  282. void HttpRequest::addHeader(const std::string& headersString)
  283. {
  284. std::vector<std::string> headers;
  285. util::split(headersString, std::back_inserter(headers), "\n", true);
  286. _headers.insert(_headers.end(), headers.begin(), headers.end());
  287. }
  288. void HttpRequest::addAcceptType(const std::string& type)
  289. {
  290. _acceptTypes.push_back(type);
  291. }
  292. void HttpRequest::setCookieStorage
  293. (const SharedHandle<CookieStorage>& cookieStorage)
  294. {
  295. _cookieStorage = cookieStorage;
  296. }
  297. void HttpRequest::setAuthConfigFactory
  298. (const SharedHandle<AuthConfigFactory>& factory, const Option* option)
  299. {
  300. _authConfigFactory = factory;
  301. _option = option;
  302. }
  303. void HttpRequest::setProxyRequest(const SharedHandle<Request>& proxyRequest)
  304. {
  305. _proxyRequest = proxyRequest;
  306. }
  307. bool HttpRequest::isProxyRequestSet() const
  308. {
  309. return !_proxyRequest.isNull();
  310. }
  311. bool HttpRequest::authenticationUsed() const
  312. {
  313. return !_authConfig.isNull();
  314. }
  315. const SharedHandle<AuthConfig>& HttpRequest::getAuthConfig() const
  316. {
  317. return _authConfig;
  318. }
  319. } // namespace aria2