HttpRequest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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. #include "Request.h"
  52. #include "DownloadHandlerConstants.h"
  53. namespace aria2 {
  54. const std::string HttpRequest::USER_AGENT("aria2");
  55. HttpRequest::HttpRequest()
  56. : cookieStorage_(nullptr),
  57. authConfigFactory_(nullptr),
  58. option_(nullptr),
  59. endOffsetOverride_(0),
  60. userAgent_(USER_AGENT),
  61. contentEncodingEnabled_(true),
  62. acceptMetalink_(false),
  63. noCache_(true),
  64. acceptGzip_(false)
  65. {}
  66. HttpRequest::~HttpRequest() {}
  67. void HttpRequest::setSegment(const std::shared_ptr<Segment>& segment)
  68. {
  69. segment_ = segment;
  70. }
  71. void HttpRequest::setRequest(const std::shared_ptr<Request>& request)
  72. {
  73. request_ = request;
  74. }
  75. int64_t HttpRequest::getStartByte() const
  76. {
  77. if(!segment_) {
  78. return 0;
  79. } else {
  80. return fileEntry_->gtoloff(segment_->getPositionToWrite());
  81. }
  82. }
  83. int64_t HttpRequest::getEndByte() const
  84. {
  85. if(!segment_ || !request_) {
  86. return 0;
  87. }
  88. if(request_->isPipeliningEnabled()) {
  89. int64_t endByte =
  90. fileEntry_->gtoloff(segment_->getPosition()+segment_->getLength()-1);
  91. return std::min(endByte, fileEntry_->getLength()-1);
  92. }
  93. if(endOffsetOverride_ > 0) {
  94. return endOffsetOverride_ - 1;
  95. }
  96. return 0;
  97. }
  98. Range HttpRequest::getRange() const
  99. {
  100. // content-length is always 0
  101. if(!segment_) {
  102. return Range();
  103. }
  104. return Range(getStartByte(), getEndByte(), fileEntry_->getLength());
  105. }
  106. bool HttpRequest::isRangeSatisfied(const Range& range) const
  107. {
  108. if(!segment_) {
  109. return true;
  110. }
  111. if((getStartByte() == range.startByte) &&
  112. ((getEndByte() == 0) ||
  113. (getEndByte() == range.endByte)) &&
  114. ((fileEntry_->getLength() == 0) ||
  115. (fileEntry_->getLength() == range.entityLength))) {
  116. return true;
  117. }
  118. return false;
  119. }
  120. namespace {
  121. std::string getHostText(const std::string& host, uint16_t port)
  122. {
  123. std::string hosttext = host;
  124. if(!(port == 80 || port == 443)) {
  125. hosttext += fmt(":%u", port);;
  126. }
  127. return hosttext;
  128. }
  129. } // namespace
  130. std::string HttpRequest::createRequest()
  131. {
  132. authConfig_ = authConfigFactory_->createAuthConfig(request_, option_);
  133. std::string requestLine = request_->getMethod();
  134. requestLine += " ";
  135. if(proxyRequest_) {
  136. if(getProtocol() == "ftp" &&
  137. request_->getUsername().empty() && authConfig_) {
  138. // Insert user into URI, like ftp://USER@host/
  139. std::string uri = getCurrentURI();
  140. assert(uri.size() >= 6);
  141. uri.insert(6, util::percentEncode(authConfig_->getUser())+"@");
  142. requestLine += uri;
  143. } else {
  144. requestLine += getCurrentURI();
  145. }
  146. } else {
  147. requestLine += getDir();
  148. requestLine += getFile();
  149. requestLine += getQuery();
  150. }
  151. requestLine += " HTTP/1.1\r\n";
  152. std::vector<std::pair<std::string, std::string> > builtinHds;
  153. builtinHds.reserve(20);
  154. builtinHds.push_back(std::make_pair("User-Agent:", userAgent_));
  155. std::string acceptTypes = "*/*";
  156. if(acceptMetalink_) {
  157. // The mime types of Metalink are used for "transparent metalink".
  158. const char** metalinkTypes = getMetalinkContentTypes();
  159. for(size_t i = 0; metalinkTypes[i]; ++i) {
  160. acceptTypes += ",";
  161. acceptTypes += metalinkTypes[i];
  162. }
  163. }
  164. builtinHds.push_back(std::make_pair("Accept:", acceptTypes));
  165. if(contentEncodingEnabled_) {
  166. std::string acceptableEncodings;
  167. #ifdef HAVE_ZLIB
  168. if(acceptGzip_) {
  169. acceptableEncodings += "deflate, gzip";
  170. }
  171. #endif // HAVE_ZLIB
  172. if(!acceptableEncodings.empty()) {
  173. builtinHds.push_back
  174. (std::make_pair("Accept-Encoding:", acceptableEncodings));
  175. }
  176. }
  177. builtinHds.push_back
  178. (std::make_pair("Host:", getHostText(getURIHost(), getPort())));
  179. if(noCache_) {
  180. builtinHds.push_back(std::make_pair("Pragma:", "no-cache"));
  181. builtinHds.push_back(std::make_pair("Cache-Control:", "no-cache"));
  182. }
  183. if(!request_->isKeepAliveEnabled() && !request_->isPipeliningEnabled()) {
  184. builtinHds.push_back(std::make_pair("Connection:", "close"));
  185. }
  186. if(segment_ && segment_->getLength() > 0 &&
  187. (request_->isPipeliningEnabled() || getStartByte() > 0 ||
  188. getEndByte() > 0)) {
  189. std::string rangeHeader(fmt("bytes=%" PRId64 "-", getStartByte()));
  190. if(request_->isPipeliningEnabled() || getEndByte() > 0) {
  191. // FTP via http proxy does not support endbytes, but in that
  192. // case, request_->isPipeliningEnabled() is false and
  193. // getEndByte() is 0.
  194. rangeHeader += util::itos(getEndByte());
  195. }
  196. builtinHds.push_back(std::make_pair("Range:", rangeHeader));
  197. }
  198. if(proxyRequest_) {
  199. if(request_->isKeepAliveEnabled() || request_->isPipeliningEnabled()) {
  200. builtinHds.push_back(std::make_pair("Connection:", "Keep-Alive"));
  201. }
  202. }
  203. if(proxyRequest_ && !proxyRequest_->getUsername().empty()) {
  204. builtinHds.push_back(getProxyAuthString());
  205. }
  206. if(authConfig_) {
  207. std::string authText = authConfig_->getAuthText();
  208. std::string val = "Basic ";
  209. val += base64::encode(authText.begin(), authText.end());
  210. builtinHds.push_back(std::make_pair("Authorization:", val));
  211. }
  212. if(!request_->getReferer().empty()) {
  213. builtinHds.push_back(std::make_pair("Referer:", request_->getReferer()));
  214. }
  215. if(cookieStorage_) {
  216. std::string cookiesValue;
  217. std::string path = getDir();
  218. path += getFile();
  219. auto cookies = cookieStorage_->criteriaFind(getHost(), path,
  220. Time().getTimeFromEpoch(),
  221. getProtocol() == "https");
  222. for(auto c : cookies) {
  223. cookiesValue += c->toString();
  224. cookiesValue += ";";
  225. }
  226. if(!cookiesValue.empty()) {
  227. builtinHds.push_back(std::make_pair("Cookie:", cookiesValue));
  228. }
  229. }
  230. if(!ifModSinceHeader_.empty()) {
  231. builtinHds.push_back
  232. (std::make_pair("If-Modified-Since:", ifModSinceHeader_));
  233. }
  234. for(std::vector<std::pair<std::string, std::string> >::const_iterator i =
  235. builtinHds.begin(), eoi = builtinHds.end(); i != eoi; ++i) {
  236. std::vector<std::string>::const_iterator j = headers_.begin();
  237. std::vector<std::string>::const_iterator jend = headers_.end();
  238. for(; j != jend; ++j) {
  239. if(util::startsWith(*j, (*i).first)) {
  240. break;
  241. }
  242. }
  243. if(j == jend) {
  244. requestLine += (*i).first;
  245. requestLine += " ";
  246. requestLine += (*i).second;
  247. requestLine += "\r\n";
  248. }
  249. }
  250. // append additional headers given by user.
  251. for(std::vector<std::string>::const_iterator i = headers_.begin(),
  252. eoi = headers_.end(); i != eoi; ++i) {
  253. requestLine += *i;
  254. requestLine += "\r\n";
  255. }
  256. requestLine += "\r\n";
  257. return requestLine;
  258. }
  259. std::string HttpRequest::createProxyRequest() const
  260. {
  261. assert(proxyRequest_);
  262. std::string requestLine(fmt("CONNECT %s:%u HTTP/1.1\r\n"
  263. "User-Agent: %s\r\n"
  264. "Host: %s:%u\r\n",
  265. getURIHost().c_str(),
  266. getPort(),
  267. userAgent_.c_str(),
  268. getURIHost().c_str(),
  269. getPort()));
  270. if(!proxyRequest_->getUsername().empty()) {
  271. std::pair<std::string, std::string> auth = getProxyAuthString();
  272. requestLine += auth.first;
  273. requestLine += " ";
  274. requestLine += auth.second;
  275. requestLine += "\r\n";
  276. }
  277. requestLine += "\r\n";
  278. return requestLine;
  279. }
  280. std::pair<std::string, std::string> HttpRequest::getProxyAuthString() const
  281. {
  282. std::string authText = proxyRequest_->getUsername();
  283. authText += ":";
  284. authText += proxyRequest_->getPassword();
  285. std::string val = "Basic ";
  286. val += base64::encode(authText.begin(), authText.end());
  287. return std::make_pair("Proxy-Authorization:", val);
  288. }
  289. void HttpRequest::enableContentEncoding()
  290. {
  291. contentEncodingEnabled_ = true;
  292. }
  293. void HttpRequest::disableContentEncoding()
  294. {
  295. contentEncodingEnabled_ = false;
  296. }
  297. void HttpRequest::addHeader(const std::string& headersString)
  298. {
  299. util::split(headersString.begin(), headersString.end(),
  300. std::back_inserter(headers_), '\n', true);
  301. }
  302. void HttpRequest::clearHeader()
  303. {
  304. headers_.clear();
  305. }
  306. void HttpRequest::setCookieStorage(CookieStorage* cookieStorage)
  307. {
  308. cookieStorage_ = cookieStorage;
  309. }
  310. CookieStorage* HttpRequest::getCookieStorage() const
  311. {
  312. return cookieStorage_;
  313. }
  314. void HttpRequest::setAuthConfigFactory(AuthConfigFactory* factory)
  315. {
  316. authConfigFactory_ = factory;
  317. }
  318. void HttpRequest::setOption(const Option* option)
  319. {
  320. option_ = option;
  321. }
  322. void HttpRequest::setProxyRequest(const std::shared_ptr<Request>& proxyRequest)
  323. {
  324. proxyRequest_ = proxyRequest;
  325. }
  326. bool HttpRequest::isProxyRequestSet() const
  327. {
  328. return proxyRequest_.get();
  329. }
  330. bool HttpRequest::authenticationUsed() const
  331. {
  332. return authConfig_.get();
  333. }
  334. const std::unique_ptr<AuthConfig>& HttpRequest::getAuthConfig() const
  335. {
  336. return authConfig_;
  337. }
  338. int64_t HttpRequest::getEntityLength() const
  339. {
  340. assert(fileEntry_);
  341. return fileEntry_->getLength();
  342. }
  343. const std::string& HttpRequest::getHost() const
  344. {
  345. return request_->getHost();
  346. }
  347. uint16_t HttpRequest::getPort() const
  348. {
  349. return request_->getPort();
  350. }
  351. const std::string& HttpRequest::getMethod() const
  352. {
  353. return request_->getMethod();
  354. }
  355. const std::string& HttpRequest::getProtocol() const
  356. {
  357. return request_->getProtocol();
  358. }
  359. const std::string& HttpRequest::getCurrentURI() const
  360. {
  361. return request_->getCurrentUri();
  362. }
  363. const std::string& HttpRequest::getDir() const
  364. {
  365. return request_->getDir();
  366. }
  367. const std::string& HttpRequest::getFile() const
  368. {
  369. return request_->getFile();
  370. }
  371. const std::string& HttpRequest::getQuery() const
  372. {
  373. return request_->getQuery();
  374. }
  375. std::string HttpRequest::getURIHost() const
  376. {
  377. return request_->getURIHost();
  378. }
  379. void HttpRequest::setUserAgent(const std::string& userAgent)
  380. {
  381. userAgent_ = userAgent;
  382. }
  383. void HttpRequest::setFileEntry(const std::shared_ptr<FileEntry>& fileEntry)
  384. {
  385. fileEntry_ = fileEntry;
  386. }
  387. void HttpRequest::setIfModifiedSinceHeader(const std::string& hd)
  388. {
  389. ifModSinceHeader_ = hd;
  390. }
  391. bool HttpRequest::conditionalRequest() const
  392. {
  393. if(!ifModSinceHeader_.empty()) {
  394. return true;
  395. }
  396. for(auto& h : headers_) {
  397. if(util::istartsWith(h, "if-modified-since") ||
  398. util::istartsWith(h, "if-none-match")) {
  399. return true;
  400. }
  401. }
  402. return false;
  403. }
  404. } // namespace aria2