1
0

HttpClient.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. #include "HttpClient.h"
  2. #include <mutex>
  3. #ifdef WITH_CURL
  4. #include "curl/curl.h"
  5. #endif
  6. #include "herr.h"
  7. #include "hlog.h"
  8. #include "htime.h"
  9. #include "hstring.h"
  10. #include "hsocket.h"
  11. #include "hssl.h"
  12. #include "HttpParser.h"
  13. // for async
  14. #include "AsyncHttpClient.h"
  15. using namespace hv;
  16. struct http_client_s {
  17. std::string host;
  18. int port;
  19. int https;
  20. int timeout; // s
  21. http_headers headers;
  22. // http_proxy
  23. std::string http_proxy_host;
  24. int http_proxy_port;
  25. // https_proxy
  26. std::string https_proxy_host;
  27. int https_proxy_port;
  28. // no_proxy
  29. StringList no_proxy_hosts;
  30. //private:
  31. #ifdef WITH_CURL
  32. CURL* curl;
  33. #endif
  34. // for sync
  35. int fd;
  36. unsigned int keepalive_requests;
  37. hssl_t ssl;
  38. hssl_ctx_t ssl_ctx;
  39. bool alloced_ssl_ctx;
  40. HttpParserPtr parser;
  41. // for async
  42. std::mutex mutex_;
  43. std::shared_ptr<hv::AsyncHttpClient> async_client_;
  44. http_client_s() {
  45. host = LOCALHOST;
  46. port = DEFAULT_HTTP_PORT;
  47. https = 0;
  48. timeout = DEFAULT_HTTP_TIMEOUT;
  49. http_proxy_port = DEFAULT_HTTP_PORT;
  50. https_proxy_port = DEFAULT_HTTP_PORT;
  51. #ifdef WITH_CURL
  52. curl = NULL;
  53. #endif
  54. fd = -1;
  55. keepalive_requests = 0;
  56. ssl = NULL;
  57. ssl_ctx = NULL;
  58. alloced_ssl_ctx = false;
  59. }
  60. ~http_client_s() {
  61. Close();
  62. if (ssl_ctx && alloced_ssl_ctx) {
  63. hssl_ctx_free(ssl_ctx);
  64. ssl_ctx = NULL;
  65. }
  66. }
  67. void Close() {
  68. #ifdef WITH_CURL
  69. if (curl) {
  70. curl_easy_cleanup(curl);
  71. curl = NULL;
  72. }
  73. #endif
  74. if (ssl) {
  75. hssl_free(ssl);
  76. ssl = NULL;
  77. }
  78. SAFE_CLOSESOCKET(fd);
  79. }
  80. };
  81. http_client_t* http_client_new(const char* host, int port, int https) {
  82. http_client_t* cli = new http_client_t;
  83. if (host) cli->host = host;
  84. cli->port = port;
  85. cli->https = https;
  86. cli->headers["Connection"] = "keep-alive";
  87. return cli;
  88. }
  89. int http_client_del(http_client_t* cli) {
  90. if (cli == NULL) return 0;
  91. delete cli;
  92. return 0;
  93. }
  94. int http_client_set_timeout(http_client_t* cli, int timeout) {
  95. cli->timeout = timeout;
  96. return 0;
  97. }
  98. int http_client_set_ssl_ctx(http_client_t* cli, hssl_ctx_t ssl_ctx) {
  99. cli->ssl_ctx = ssl_ctx;
  100. return 0;
  101. }
  102. int http_client_new_ssl_ctx(http_client_t* cli, hssl_ctx_opt_t* opt) {
  103. opt->endpoint = HSSL_CLIENT;
  104. hssl_ctx_t ssl_ctx = hssl_ctx_new(opt);
  105. if (ssl_ctx == NULL) return ERR_NEW_SSL_CTX;
  106. cli->alloced_ssl_ctx = true;
  107. return http_client_set_ssl_ctx(cli, ssl_ctx);
  108. }
  109. int http_client_clear_headers(http_client_t* cli) {
  110. cli->headers.clear();
  111. return 0;
  112. }
  113. int http_client_set_header(http_client_t* cli, const char* key, const char* value) {
  114. cli->headers[key] = value;
  115. return 0;
  116. }
  117. int http_client_del_header(http_client_t* cli, const char* key) {
  118. auto iter = cli->headers.find(key);
  119. if (iter != cli->headers.end()) {
  120. cli->headers.erase(iter);
  121. }
  122. return 0;
  123. }
  124. const char* http_client_get_header(http_client_t* cli, const char* key) {
  125. auto iter = cli->headers.find(key);
  126. if (iter != cli->headers.end()) {
  127. return iter->second.c_str();
  128. }
  129. return NULL;
  130. }
  131. int http_client_set_http_proxy(http_client_t* cli, const char* host, int port) {
  132. cli->http_proxy_host = host;
  133. cli->http_proxy_port = port;
  134. return 0;
  135. }
  136. int http_client_set_https_proxy(http_client_t* cli, const char* host, int port) {
  137. cli->https_proxy_host = host;
  138. cli->https_proxy_port = port;
  139. return 0;
  140. }
  141. int http_client_add_no_proxy(http_client_t* cli, const char* host) {
  142. cli->no_proxy_hosts.push_back(host);
  143. return 0;
  144. }
  145. static int http_client_make_request(http_client_t* cli, HttpRequest* req) {
  146. if (req->url.empty() || *req->url.c_str() == '/') {
  147. req->scheme = cli->https ? "https" : "http";
  148. req->host = cli->host;
  149. req->port = cli->port;
  150. }
  151. req->ParseUrl();
  152. bool https = req->IsHttps();
  153. bool use_proxy = https ? (!cli->https_proxy_host.empty()) : (!cli->http_proxy_host.empty());
  154. if (use_proxy) {
  155. if (req->host == "127.0.0.1" || req->host == "localhost") {
  156. use_proxy = false;
  157. }
  158. }
  159. if (use_proxy) {
  160. for (const auto& host : cli->no_proxy_hosts) {
  161. if (req->host == host) {
  162. use_proxy = false;
  163. break;
  164. }
  165. }
  166. }
  167. if (use_proxy) {
  168. req->SetProxy(https ? cli->https_proxy_host.c_str() : cli->http_proxy_host.c_str(),
  169. https ? cli->https_proxy_port : cli->http_proxy_port);
  170. }
  171. if (req->timeout == 0) {
  172. req->timeout = cli->timeout;
  173. }
  174. for (const auto& pair : cli->headers) {
  175. if (req->headers.find(pair.first) == req->headers.end()) {
  176. req->headers.insert(pair);
  177. }
  178. }
  179. return 0;
  180. }
  181. int http_client_connect(http_client_t* cli, const char* host, int port, int https, int timeout) {
  182. int blocktime = DEFAULT_CONNECT_TIMEOUT;
  183. if (timeout > 0) {
  184. blocktime = MIN(timeout*1000, blocktime);
  185. }
  186. int connfd = ConnectTimeout(host, port, blocktime);
  187. if (connfd < 0) {
  188. hloge("connect %s:%d failed!", host, port);
  189. return connfd;
  190. }
  191. tcp_nodelay(connfd, 1);
  192. if (https && cli->ssl == NULL) {
  193. // cli->ssl_ctx > g_ssl_ctx > hssl_ctx_new
  194. hssl_ctx_t ssl_ctx = NULL;
  195. if (cli->ssl_ctx) {
  196. ssl_ctx = cli->ssl_ctx;
  197. } else if (g_ssl_ctx) {
  198. ssl_ctx = g_ssl_ctx;
  199. } else {
  200. cli->ssl_ctx = ssl_ctx = hssl_ctx_new(NULL);
  201. cli->alloced_ssl_ctx = true;
  202. }
  203. if (ssl_ctx == NULL) {
  204. closesocket(connfd);
  205. return NABS(ERR_NEW_SSL_CTX);
  206. }
  207. cli->ssl = hssl_new(ssl_ctx, connfd);
  208. if (cli->ssl == NULL) {
  209. closesocket(connfd);
  210. return NABS(ERR_NEW_SSL);
  211. }
  212. if (!is_ipaddr(host)) {
  213. hssl_set_sni_hostname(cli->ssl, host);
  214. }
  215. int ret = hssl_connect(cli->ssl);
  216. if (ret != 0) {
  217. fprintf(stderr, "* ssl handshake failed: %d\n", ret);
  218. hloge("ssl handshake failed: %d", ret);
  219. hssl_free(cli->ssl);
  220. cli->ssl = NULL;
  221. closesocket(connfd);
  222. return NABS(ret);
  223. }
  224. }
  225. cli->fd = connfd;
  226. cli->keepalive_requests = 0;
  227. return connfd;
  228. }
  229. int http_client_close(http_client_t* cli) {
  230. if (cli == NULL) return 0;
  231. cli->Close();
  232. return 0;
  233. }
  234. int http_client_send_data(http_client_t* cli, const char* data, int size) {
  235. if (!cli || !data || size <= 0) return -1;
  236. if (cli->ssl) {
  237. return hssl_write(cli->ssl, data, size);
  238. }
  239. return send(cli->fd, data, size, 0);
  240. }
  241. int http_client_recv_data(http_client_t* cli, char* data, int size) {
  242. if (!cli || !data || size <= 0) return -1;
  243. if (cli->ssl) {
  244. return hssl_read(cli->ssl, data, size);
  245. }
  246. return recv(cli->fd, data, size, 0);
  247. }
  248. static int http_client_exec(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
  249. // connect -> send -> recv -> http_parser
  250. int err = 0;
  251. int connfd = cli->fd;
  252. bool https = req->IsHttps() && !req->IsProxy();
  253. bool keepalive = true;
  254. time_t connect_timeout = MIN(req->connect_timeout, req->timeout);
  255. time_t timeout_ms = req->timeout * 1000;
  256. time_t start_time = gettick_ms();
  257. time_t cur_time = start_time, left_time = INFINITE;
  258. #define CHECK_TIMEOUT \
  259. do { \
  260. if (timeout_ms > 0) { \
  261. cur_time = gettick_ms(); \
  262. if (cur_time - start_time >= timeout_ms) { \
  263. goto timeout; \
  264. } \
  265. left_time = timeout_ms - (cur_time - start_time); \
  266. } \
  267. } while(0);
  268. uint32_t retry_count = req->retry_count;
  269. if (cli->keepalive_requests > 0 && retry_count == 0) {
  270. // maybe keep-alive timeout, retry at least once
  271. retry_count = 1;
  272. }
  273. if (cli->parser == NULL) {
  274. cli->parser = HttpParserPtr(HttpParser::New(HTTP_CLIENT, (http_version)req->http_major));
  275. if (cli->parser == NULL) {
  276. hloge("New HttpParser failed!");
  277. return ERR_NULL_POINTER;
  278. }
  279. }
  280. if (connfd <= 0) {
  281. connect:
  282. connfd = http_client_connect(cli, req->host.c_str(), req->port, https, connect_timeout);
  283. if (connfd < 0) {
  284. return connfd;
  285. }
  286. }
  287. cli->parser->SubmitRequest(req);
  288. char recvbuf[1024] = {0};
  289. int total_nsend, nsend, nrecv;
  290. total_nsend = nsend = nrecv = 0;
  291. send:
  292. char* data = NULL;
  293. size_t len = 0;
  294. while (cli->parser->GetSendData(&data, &len)) {
  295. total_nsend = 0;
  296. while (total_nsend < len) {
  297. CHECK_TIMEOUT
  298. if (left_time != INFINITE) {
  299. so_sndtimeo(cli->fd, left_time);
  300. }
  301. nsend = http_client_send_data(cli, data + total_nsend, len - total_nsend);
  302. if (nsend <= 0) {
  303. CHECK_TIMEOUT
  304. err = socket_errno();
  305. if (err == EINTR) continue;
  306. if (retry_count-- > 0 && left_time > req->retry_delay + connect_timeout * 1000) {
  307. cli->Close();
  308. err = 0;
  309. if (req->retry_delay > 0) hv_msleep(req->retry_delay);
  310. goto connect;
  311. }
  312. goto disconnect;
  313. }
  314. total_nsend += nsend;
  315. }
  316. }
  317. if (resp == NULL) return 0;
  318. cli->parser->InitResponse(resp);
  319. recv:
  320. do {
  321. CHECK_TIMEOUT
  322. if (left_time != INFINITE) {
  323. so_rcvtimeo(cli->fd, left_time);
  324. }
  325. nrecv = http_client_recv_data(cli, recvbuf, sizeof(recvbuf));
  326. if (nrecv <= 0) {
  327. CHECK_TIMEOUT
  328. err = socket_errno();
  329. if (err == EINTR) continue;
  330. if (cli->parser->IsEof()) {
  331. err = 0;
  332. goto disconnect;
  333. }
  334. if (retry_count-- > 0 && left_time > req->retry_delay + connect_timeout * 1000) {
  335. cli->Close();
  336. err = 0;
  337. if (req->retry_delay > 0) hv_msleep(req->retry_delay);
  338. goto connect;
  339. }
  340. goto disconnect;
  341. }
  342. int nparse = cli->parser->FeedRecvData(recvbuf, nrecv);
  343. if (nparse != nrecv) {
  344. return ERR_PARSE;
  345. }
  346. } while(!cli->parser->IsComplete());
  347. keepalive = req->IsKeepAlive() && resp->IsKeepAlive();
  348. if (keepalive) {
  349. ++cli->keepalive_requests;
  350. } else {
  351. cli->Close();
  352. }
  353. return 0;
  354. timeout:
  355. err = ERR_TASK_TIMEOUT;
  356. disconnect:
  357. cli->Close();
  358. return err;
  359. }
  360. int http_client_send_header(http_client_t* cli, HttpRequest* req) {
  361. if (!cli || !req) return ERR_NULL_POINTER;
  362. http_client_make_request(cli, req);
  363. return http_client_exec(cli, req, NULL);
  364. }
  365. int http_client_recv_response(http_client_t* cli, HttpResponse* resp) {
  366. if (!cli || !resp) return ERR_NULL_POINTER;
  367. if (!cli->parser) {
  368. hloge("Call http_client_send_header first!");
  369. return ERR_NULL_POINTER;
  370. }
  371. char recvbuf[1024] = {0};
  372. cli->parser->InitResponse(resp);
  373. do {
  374. int nrecv = http_client_recv_data(cli, recvbuf, sizeof(recvbuf));
  375. if (nrecv <= 0) {
  376. int err = socket_errno();
  377. if (err == EINTR) continue;
  378. cli->Close();
  379. return err;
  380. }
  381. int nparse = cli->parser->FeedRecvData(recvbuf, nrecv);
  382. if (nparse != nrecv) {
  383. return ERR_PARSE;
  384. }
  385. } while(!cli->parser->IsComplete());
  386. return 0;
  387. }
  388. #ifdef WITH_CURL
  389. static size_t s_header_cb(char* buf, size_t size, size_t cnt, void* userdata) {
  390. if (buf == NULL || userdata == NULL) return 0;
  391. size_t len = size * cnt;
  392. std::string str(buf, len);
  393. HttpResponse* resp = (HttpResponse*)userdata;
  394. std::string::size_type pos = str.find_first_of(':');
  395. if (pos == std::string::npos) {
  396. if (strncmp(buf, "HTTP/", 5) == 0) {
  397. // status line
  398. //hlogd("%s", buf);
  399. int http_major = 1, http_minor = 1, status_code = 200;
  400. if (buf[5] == '1') {
  401. // HTTP/1.1 200 OK\r\n
  402. sscanf(buf, "HTTP/%d.%d %d", &http_major, &http_minor, &status_code);
  403. }
  404. else if (buf[5] == '2') {
  405. // HTTP/2 200\r\n
  406. sscanf(buf, "HTTP/%d %d", &http_major, &status_code);
  407. http_minor = 0;
  408. }
  409. resp->http_major = http_major;
  410. resp->http_minor = http_minor;
  411. resp->status_code = (http_status)status_code;
  412. if (resp->http_cb) {
  413. resp->http_cb(resp, HP_MESSAGE_BEGIN, NULL, 0);
  414. }
  415. }
  416. }
  417. else {
  418. // headers
  419. std::string key = trim(str.substr(0, pos));
  420. std::string value = trim(str.substr(pos+1));
  421. resp->headers[key] = value;
  422. }
  423. return len;
  424. }
  425. static size_t s_body_cb(char* buf, size_t size, size_t cnt, void *userdata) {
  426. if (buf == NULL || userdata == NULL) return 0;
  427. size_t len = size * cnt;
  428. HttpMessage* resp = (HttpMessage*)userdata;
  429. if (resp->http_cb) {
  430. if (resp->content == NULL && resp->content_length == 0) {
  431. resp->content = buf;
  432. resp->content_length = len;
  433. resp->http_cb(resp, HP_HEADERS_COMPLETE, NULL, 0);
  434. }
  435. resp->http_cb(resp, HP_BODY, buf, len);
  436. } else {
  437. resp->body.append(buf, len);
  438. }
  439. return len;
  440. }
  441. static int http_client_exec_curl(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
  442. if (cli->curl == NULL) {
  443. cli->curl = curl_easy_init();
  444. }
  445. CURL* curl = cli->curl;
  446. // proxy
  447. if (req->IsProxy()) {
  448. curl_easy_setopt(curl, CURLOPT_PROXY, req->host.c_str());
  449. curl_easy_setopt(curl, CURLOPT_PROXYPORT, req->port);
  450. }
  451. // SSL
  452. if (req->IsHttps()) {
  453. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
  454. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
  455. }
  456. // http2
  457. if (req->http_major == 2) {
  458. #if LIBCURL_VERSION_NUM < 0x073100 // 7.49.0
  459. curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2_0);
  460. #else
  461. // No Connection: Upgrade
  462. curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
  463. #endif
  464. }
  465. // TCP_NODELAY
  466. curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
  467. // method
  468. curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_method_str(req->method));
  469. // url
  470. req->DumpUrl();
  471. curl_easy_setopt(curl, CURLOPT_URL, req->url.c_str());
  472. //hlogd("%s %s HTTP/%d.%d", http_method_str(req->method), req->url.c_str(), req->http_major, req->http_minor);
  473. // headers
  474. req->FillContentType();
  475. struct curl_slist *headers = NULL;
  476. for (auto& pair : req->headers) {
  477. std::string header = pair.first;
  478. header += ": ";
  479. header += pair.second;
  480. headers = curl_slist_append(headers, header.c_str());
  481. }
  482. curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  483. // body
  484. //struct curl_httppost* httppost = NULL;
  485. //struct curl_httppost* lastpost = NULL;
  486. if (req->body.size() == 0) {
  487. req->DumpBody();
  488. /*
  489. if (req->body.size() == 0 &&
  490. req->content_type == MULTIPART_FORM_DATA) {
  491. for (auto& pair : req->mp) {
  492. if (pair.second.filename.size() != 0) {
  493. curl_formadd(&httppost, &lastpost,
  494. CURLFORM_COPYNAME, pair.first.c_str(),
  495. CURLFORM_FILE, pair.second.filename.c_str(),
  496. CURLFORM_END);
  497. }
  498. else if (pair.second.content.size() != 0) {
  499. curl_formadd(&httppost, &lastpost,
  500. CURLFORM_COPYNAME, pair.first.c_str(),
  501. CURLFORM_COPYCONTENTS, pair.second.content.c_str(),
  502. CURLFORM_END);
  503. }
  504. }
  505. if (httppost) {
  506. curl_easy_setopt(curl, CURLOPT_HTTPPOST, httppost);
  507. }
  508. }
  509. */
  510. }
  511. if (req->body.size() != 0) {
  512. curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req->body.c_str());
  513. curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req->body.size());
  514. }
  515. if (req->connect_timeout > 0) {
  516. curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, req->connect_timeout);
  517. }
  518. if (req->timeout > 0) {
  519. curl_easy_setopt(curl, CURLOPT_TIMEOUT, req->timeout);
  520. }
  521. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, s_body_cb);
  522. curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp);
  523. curl_easy_setopt(curl, CURLOPT_HEADER, 0);
  524. curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, s_header_cb);
  525. curl_easy_setopt(curl, CURLOPT_HEADERDATA, resp);
  526. int ret = curl_easy_perform(curl);
  527. /*
  528. if (ret != 0) {
  529. hloge("curl error: %d: %s", ret, curl_easy_strerror((CURLcode)ret));
  530. }
  531. if (resp->body.length() != 0) {
  532. hlogd("[Response]\n%s", resp->body.c_str());
  533. }
  534. double total_time, name_time, conn_time, pre_time;
  535. curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
  536. curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, &name_time);
  537. curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &conn_time);
  538. curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &pre_time);
  539. hlogd("TIME_INFO: %lf,%lf,%lf,%lf", total_time, name_time, conn_time, pre_time);
  540. */
  541. if (headers) {
  542. curl_slist_free_all(headers);
  543. }
  544. /*
  545. if (httppost) {
  546. curl_formfree(httppost);
  547. }
  548. */
  549. if (resp->http_cb) {
  550. resp->http_cb(resp, HP_MESSAGE_COMPLETE, NULL, 0);
  551. }
  552. return ret;
  553. }
  554. const char* http_client_strerror(int errcode) {
  555. return curl_easy_strerror((CURLcode)errcode);
  556. }
  557. #else
  558. const char* http_client_strerror(int errcode) {
  559. return socket_strerror(errcode);
  560. }
  561. #endif
  562. static int http_client_redirect(HttpRequest* req, HttpResponse* resp) {
  563. std::string location = resp->headers["Location"];
  564. if (!location.empty()) {
  565. hlogi("redirect %s => %s", req->url.c_str(), location.c_str());
  566. req->url = location;
  567. req->ParseUrl();
  568. req->headers["Host"] = req->host;
  569. resp->Reset();
  570. return http_client_send(req, resp);
  571. }
  572. return 0;
  573. }
  574. int http_client_send(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
  575. if (!cli || !req || !resp) return ERR_NULL_POINTER;
  576. http_client_make_request(cli, req);
  577. if (req->http_cb) resp->http_cb = std::move(req->http_cb);
  578. #if WITH_CURL
  579. int ret = http_client_exec_curl(cli, req, resp);
  580. #else
  581. int ret = http_client_exec(cli, req, resp);
  582. #endif
  583. if (ret != 0) return ret;
  584. // redirect
  585. if (req->redirect && HTTP_STATUS_IS_REDIRECT(resp->status_code)) {
  586. return http_client_redirect(req, resp);
  587. }
  588. return 0;
  589. }
  590. int http_client_send(HttpRequest* req, HttpResponse* resp) {
  591. if (!req || !resp) return ERR_NULL_POINTER;
  592. http_client_t cli;
  593. return http_client_send(&cli, req, resp);
  594. }
  595. // below for async
  596. static int http_client_exec_async(http_client_t* cli, HttpRequestPtr req, HttpResponseCallback resp_cb) {
  597. if (cli->async_client_ == NULL) {
  598. cli->mutex_.lock();
  599. if (cli->async_client_ == NULL) {
  600. cli->async_client_ = std::make_shared<hv::AsyncHttpClient>();
  601. }
  602. cli->mutex_.unlock();
  603. }
  604. return cli->async_client_->send(req, std::move(resp_cb));
  605. }
  606. int http_client_send_async(http_client_t* cli, HttpRequestPtr req, HttpResponseCallback resp_cb) {
  607. if (!cli || !req) return ERR_NULL_POINTER;
  608. http_client_make_request(cli, req.get());
  609. return http_client_exec_async(cli, req, std::move(resp_cb));
  610. }
  611. static http_client_t* s_async_http_client = NULL;
  612. static void hv_destroy_default_async_http_client() {
  613. hlogi("destory default http async client");
  614. if (s_async_http_client) {
  615. http_client_del(s_async_http_client);
  616. s_async_http_client = NULL;
  617. }
  618. }
  619. static http_client_t* hv_default_async_http_client() {
  620. static std::mutex s_mutex;
  621. if (s_async_http_client == NULL) {
  622. s_mutex.lock();
  623. if (s_async_http_client == NULL) {
  624. hlogi("create default http async client");
  625. s_async_http_client = http_client_new();
  626. // NOTE: I have No better idea
  627. atexit(hv_destroy_default_async_http_client);
  628. }
  629. s_mutex.unlock();
  630. }
  631. return s_async_http_client;
  632. }
  633. int http_client_send_async(HttpRequestPtr req, HttpResponseCallback resp_cb) {
  634. if (req == NULL) return ERR_NULL_POINTER;
  635. if (req->timeout == 0) {
  636. req->timeout = DEFAULT_HTTP_TIMEOUT;
  637. }
  638. return http_client_exec_async(hv_default_async_http_client(), req, std::move(resp_cb));
  639. }