PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/3rdParty/src/http/httpclient/http_client.cpp

https://gitlab.com/yoage/TTWinClient
C++ | 514 lines | 432 code | 50 blank | 32 comment | 54 complexity | a7683bc79881586dffac6671bb23012b MD5 | raw file
Possible License(s): LGPL-3.0
  1. /**
  2. * @file http_client.cpp
  3. * @brief Http传输类
  4. * @author xiangwangfeng <xiangwangfeng@gmail.com>
  5. * @data 2011-4-24
  6. * @website www.xiangwangfeng.com
  7. */
  8. #include "standard_header.h"
  9. #include "http_client.h"
  10. #include "util.h"
  11. #include "lock.h"
  12. #include "proxy_socket.h"
  13. #include "http_request.h"
  14. #include "http_response.h"
  15. #include "http_delegate.h"
  16. #include "file_writer.h"
  17. #include "http_header_parser.h"
  18. #include "http_response_receiver.h"
  19. #include "http_post_file.h"
  20. NAMESPACE_BEGIN(Http)
  21. HttpClient::HttpClient(bool keep_connection)
  22. :_http_error(HTTPERROR_PARAMETER),
  23. _keep_connection(keep_connection),
  24. _request(0),
  25. _response(0),
  26. _delegate(0),
  27. _is_valid(true)
  28. {
  29. _proxy_socket = new ProxySocket();
  30. _is_valid_lock = new Util::Lock();
  31. }
  32. HttpClient::~HttpClient()
  33. {
  34. delete _proxy_socket;
  35. delete _is_valid_lock;
  36. }
  37. bool HttpClient::execute(HttpRequest* request,HttpResponse* respone)
  38. {
  39. //参数检查
  40. PTR_BOOL(request);
  41. PTR_BOOL(respone);
  42. _request = request;
  43. _response = respone;
  44. setErrorCode(HTTPERROR_SUCCESS);
  45. //连接服务器
  46. const std::string& host = _request->getHost();
  47. int port_number = _request->getPortNumber();
  48. _proxy_socket->setHost(host,port_number);
  49. //尝试连接
  50. {
  51. const Util::ScopedLock scoped_lock(*_is_valid_lock);
  52. if (_is_valid) //判断HttpClient是否还有效
  53. {
  54. if (!(_keep_connection && _proxy_socket->isConnected()))
  55. {
  56. if (!_proxy_socket->connect())
  57. {
  58. setErrorCode(HTTPERROR_CONNECT);
  59. return false;
  60. }
  61. }
  62. }
  63. else
  64. {
  65. setErrorCode(HTTPERROR_INVALID);
  66. return false;
  67. }
  68. }
  69. //进行数据传输
  70. bool execute = false;
  71. const std::string& method = _request->getMethod();
  72. //Get方法
  73. if (_strcmpi(method.c_str(),kget) == 0)
  74. {
  75. execute = httpGet();
  76. }
  77. //Post方法
  78. else if (_strcmpi(method.c_str(),kpost) == 0)
  79. {
  80. execute = httpPost();
  81. }
  82. //其他,抛出错误
  83. else
  84. {
  85. assert(false);
  86. }
  87. //如果不是长连接 就关闭网络
  88. if (!_keep_connection)
  89. {
  90. _proxy_socket->close();
  91. }
  92. return execute;
  93. }
  94. void HttpClient::setProxy(const Http::ProxyConfig *proxy_config)
  95. {
  96. PTR_VOID(proxy_config);
  97. ProxySocket::setProxy(*proxy_config);
  98. }
  99. void HttpClient::setErrorCode(HTTPERROR http_error)
  100. {
  101. _http_error = http_error;
  102. //如果传输失败后,关闭当前Socket
  103. //(为了支持keep-alive模式,在服务器出错后能够正常进行重连)
  104. if (_http_error != HTTPERROR_SUCCESS)
  105. {
  106. _proxy_socket->close();
  107. }
  108. }
  109. void HttpClient::killSelf()
  110. {
  111. const Util::ScopedLock scoped_lock(*_is_valid_lock);
  112. _is_valid = false;
  113. _proxy_socket->close();
  114. }
  115. void HttpClient::reset()
  116. {
  117. const Util::ScopedLock scoped_lock(*_is_valid_lock);
  118. _proxy_socket->close();
  119. }
  120. bool HttpClient::httpGet()
  121. {
  122. //发送HTTP头请求
  123. if (sendHeader())
  124. {
  125. //接受反馈
  126. return getResponse();
  127. }
  128. else
  129. {
  130. setErrorCode(HTTPERROR_TRANSPORT);
  131. return false;
  132. }
  133. }
  134. bool HttpClient::httpPost()
  135. {
  136. //发送HTTP头请求
  137. bool complete = false;
  138. if (sendHeader())
  139. {
  140. if (_request->isMultipart())
  141. {
  142. complete = doMultipartPost();
  143. }
  144. else
  145. {
  146. if (sendBody())
  147. {
  148. complete = getResponse();
  149. }
  150. }
  151. }
  152. return complete;
  153. }
  154. bool HttpClient::sendHeader()
  155. {
  156. std::string header;
  157. int header_length = _request->generateHeader(header);
  158. bool send = _proxy_socket->writeAll(header.c_str(),header_length);
  159. if (!send)
  160. {
  161. setErrorCode(HTTPERROR_TRANSPORT);
  162. }
  163. return send;
  164. }
  165. bool HttpClient::sendBody()
  166. {
  167. const std::string& body = _request->getBody();
  168. size_t length = body.length();
  169. if (length == 0)
  170. {
  171. return true; //如果body内没有内容 直接返回true
  172. //(上传文件的时候body内容是动态生成,body内容可能为空)
  173. }
  174. bool send = _proxy_socket->writeAll(body.c_str(),body.length());
  175. if (!send)
  176. {
  177. setErrorCode(HTTPERROR_TRANSPORT);;
  178. }
  179. return send;
  180. }
  181. bool HttpClient::doMultipartPost()
  182. {
  183. //如果有Fields段 已经写入了body内 直接发送
  184. if (!sendBody())
  185. {
  186. setErrorCode(HTTPERROR_TRANSPORT);
  187. return false;
  188. }
  189. //发送文件
  190. const std::vector<HttpFile*>& post_files = _request->getFiles();
  191. const std::string& boundary = _request->getBoundary();
  192. for (size_t i = 0; i < post_files.size(); i++)
  193. {
  194. //modify by kuaidao "Content-Type:""Content-Disposition"大小写敏感
  195. const std::string name = post_files[i]->_name;
  196. IHttpPostFile* post_file = post_files[i]->_post_file;
  197. std::string file_header = "--" + boundary + "\r\n"
  198. "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" +
  199. post_file->getFilename() + "\"\r\n" +
  200. "Content-Type: " + post_file->getContentType() + "\r\n" +
  201. "\r\n";
  202. bool send_file_header = _proxy_socket->writeAll(file_header.c_str(),file_header.size());
  203. if (!send_file_header)
  204. {
  205. setErrorCode(HTTPERROR_TRANSPORT);
  206. return false;
  207. }
  208. bool post_file_success = uploadFile(post_file);
  209. if (!post_file_success)
  210. {
  211. setErrorCode(HTTPERROR_TRANSPORT);
  212. return false;
  213. }
  214. std::string file_tailer = "\r\n";
  215. bool send_file_tailer = _proxy_socket->writeAll(file_tailer.c_str(),file_tailer.size());
  216. if (!send_file_tailer)
  217. {
  218. setErrorCode(HTTPERROR_TRANSPORT);
  219. return false;
  220. }
  221. }
  222. //发送boundary结束标记
  223. std::string post_tailer = "--" + boundary + "--\r\n";
  224. bool send_post_tailer = _proxy_socket->writeAll(post_tailer.c_str(),post_tailer.size());
  225. return send_post_tailer ? getResponse() : setErrorCode(HTTPERROR_TRANSPORT) , false;
  226. }
  227. bool HttpClient::uploadFile(IHttpPostFile* post_file)
  228. {
  229. FilePoster file_poster(_proxy_socket,_http_error,_delegate);
  230. return post_file ? post_file->postFile(file_poster) : false;
  231. }
  232. bool HttpClient::getResponse()
  233. {
  234. std::string body_header; //收取的Body和Header的混合体
  235. if (downloadHeader(body_header))
  236. {
  237. //如果请求指定只需要获取Http头直接返回 (主要是为分段下载减少下载量)
  238. if (_request->onlyDownloadHeader())
  239. {
  240. return true;
  241. }
  242. else
  243. {
  244. return downloadBody(body_header);
  245. }
  246. }
  247. else
  248. {
  249. return false;
  250. }
  251. }
  252. bool HttpClient::downloadHeader(std::string& body_header)
  253. {
  254. body_header.clear();
  255. char buff[kmax_buffer_size] = {0};
  256. std::string header;
  257. bool complete = false;
  258. while(!complete)
  259. {
  260. int ret = _proxy_socket->read(buff,kmax_buffer_size);
  261. if (ret <= 0)
  262. {
  263. setErrorCode(HTTPERROR_TRANSPORT);
  264. break;
  265. }
  266. header.append(buff,ret); //因为Header往往很短,基本一次可以收完
  267. size_t end_index = header.find("\r\n\r\n"); //所以也不需要计算偏移来提高搜索速度
  268. if (end_index != std::string::npos)
  269. {
  270. complete = true;
  271. size_t length = header.length() ;
  272. body_header = header.substr(end_index + 4,length - end_index - 4);
  273. _response->setHeader(header.substr(0,end_index + 4));
  274. }
  275. }
  276. return complete;
  277. }
  278. bool HttpClient::downloadBody(const std::string& body_header)
  279. {
  280. const std::string& header = _response->getHeader();
  281. HttpHeaderParser header_parser(header);
  282. bool is_chunked = header_parser.isChunked();
  283. int http_code = header_parser.getHttpCode();
  284. int content_lenght = header_parser.getContentLength();
  285. bool complete = false;
  286. _response->setHttpCode(http_code);
  287. if (is_chunked) //Chunk类型的Http体
  288. {
  289. complete = downloadChunkedBody(body_header);
  290. }
  291. else //带Content-Length的Http体
  292. {
  293. complete = downloadFixedSizeBody(body_header,content_lenght);
  294. }
  295. return complete; //下载完毕
  296. }
  297. bool HttpClient::downloadFixedSizeBody(const std::string& body_header,int content_length)
  298. {
  299. int received_length = (int)body_header.length();
  300. if (received_length > content_length ||
  301. content_length < 0)
  302. {
  303. setErrorCode(HTTPERROR_TRANSPORT);
  304. assert(false);
  305. return false;
  306. }
  307. //构造Http反馈接收类
  308. HttpResponseReceiver* response_receiver = 0;
  309. if (_request->saveAsFile())
  310. {
  311. const std::wstring& filepath = _request->getFilePath();
  312. _response->setBody(Util::toUTF8(filepath)); //如果是下载到本地IO,则response的Body里面保存的是文件路径
  313. response_receiver = new HttpResponseReceiver(filepath);
  314. }
  315. else
  316. {
  317. response_receiver = new HttpResponseReceiver();
  318. }
  319. //接受Http体
  320. bool complete= false;
  321. bool write = response_receiver->write(body_header.c_str(),body_header.length());
  322. if (write)
  323. {
  324. int unreceived_length = content_length - received_length;
  325. onDataReadProgress(received_length,content_length);
  326. char buff[kmax_file_buffer_size] = {0};
  327. while (unreceived_length > 0)
  328. {
  329. int ret = _proxy_socket->read(buff,kmax_file_buffer_size);
  330. if (ret <= 0)
  331. {
  332. setErrorCode(HTTPERROR_TRANSPORT);
  333. break;
  334. }
  335. else if (!response_receiver->write(buff,ret))
  336. {
  337. setErrorCode(HTTPERROR_IO);
  338. break;
  339. }
  340. unreceived_length -= ret;
  341. onDataReadProgress(content_length - unreceived_length,content_length);
  342. }
  343. complete = (unreceived_length == 0);
  344. }
  345. else
  346. {
  347. setErrorCode(HTTPERROR_IO);
  348. }
  349. //如果是写入内存数据 需要赋回给HttpResponse
  350. if (complete && !_request->saveAsFile())
  351. {
  352. const std::string& body = response_receiver->getBody();
  353. _response->setBody(body);
  354. }
  355. delete response_receiver;
  356. return complete;
  357. }
  358. bool HttpClient::downloadChunkedBody(const std::string& body_header)
  359. {
  360. std::string body = body_header; //接受HTTP头时拿到的部分HTTP体信息
  361. bool complete = false; //是否已经接受完整了
  362. bool find_first_chunk = false; //是否找到第一个ChunkSize
  363. int chunk_size = 0; //Chunk的数据大小
  364. int chunk_size_length = 0; //ChunkSize的大小 比如 12\r\n 说明;chunk_size为18 chunk_size_length为2
  365. //构造Http反馈接收类
  366. HttpResponseReceiver* response_receiver = 0;
  367. bool save_as_file = _request->saveAsFile();
  368. if (save_as_file)
  369. {
  370. const std::wstring& filepath = _request->getFilePath();
  371. _response->setBody(Util::toUTF8(filepath));
  372. response_receiver = new HttpResponseReceiver(filepath);
  373. }
  374. else
  375. {
  376. response_receiver = new HttpResponseReceiver();
  377. }
  378. //接受并解析chunk内容
  379. while(true)
  380. {
  381. //如果在上次已经查询到第一块chunk的大小
  382. if (find_first_chunk)
  383. {
  384. if (chunk_size == 0)//如果是最后一块了
  385. {
  386. complete = true;
  387. break;
  388. }
  389. else //否则分析chunk内容并进行切割
  390. {
  391. size_t length = body.length();
  392. size_t first_chunk = chunk_size_length + 2 + chunk_size + 2;
  393. if (length >= first_chunk) //如果已经接受到一整块chunkdata了则进行切割,否则重新接受
  394. {
  395. find_first_chunk = false;
  396. std::string chunk_data = body.substr(chunk_size_length + 2, chunk_size);
  397. body.erase(0,first_chunk);
  398. if (!response_receiver->write(chunk_data.c_str(),chunk_data.length()))
  399. {
  400. setErrorCode(HTTPERROR_IO);
  401. break;
  402. }
  403. }
  404. else
  405. {
  406. if (!continueToReceiveBody(body))
  407. {
  408. setErrorCode(HTTPERROR_TRANSPORT);
  409. break;
  410. }
  411. }
  412. }
  413. }
  414. else//查找chunk_size
  415. {
  416. size_t index = body.find("\r\n");
  417. if (index != std::string::npos) //找到,做标记
  418. {
  419. find_first_chunk = true;
  420. chunk_size_length = (int)index;
  421. std::string raw_chunk_size = body.substr(0,chunk_size_length);
  422. chunk_size = (int)strtoul(raw_chunk_size.c_str(),0,16);
  423. }
  424. else //没有找到,继续接受信息
  425. {
  426. if (!continueToReceiveBody(body))
  427. {
  428. setErrorCode(HTTPERROR_TRANSPORT);
  429. break;
  430. }
  431. }
  432. }
  433. }
  434. if (!save_as_file && complete)
  435. {
  436. const std::string& body = response_receiver->getBody();
  437. _response->setBody(body);
  438. }
  439. delete response_receiver;
  440. return complete;
  441. }
  442. bool HttpClient::continueToReceiveBody(std::string& body)
  443. {
  444. char buff[kmax_file_buffer_size] = {0};
  445. int ret = _proxy_socket->read(buff,kmax_file_buffer_size);
  446. if (ret <= 0)
  447. {
  448. setErrorCode(HTTPERROR_TRANSPORT);
  449. return false;
  450. }
  451. else
  452. {
  453. body.append(buff,ret);
  454. return true;
  455. }
  456. }
  457. void HttpClient::onDataReadProgress(int read_length,int total_length)
  458. {
  459. if (_delegate)
  460. {
  461. _delegate->dataReadProgress(read_length,total_length);
  462. }
  463. }
  464. NAMESPACE_END(Http)