HttpClient.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  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. cli->Close();
  183. int blocktime = DEFAULT_CONNECT_TIMEOUT;
  184. if (timeout > 0) {
  185. blocktime = MIN(timeout*1000, blocktime);
  186. }
  187. int connfd = ConnectTimeout(host, port, blocktime);
  188. if (connfd < 0) {
  189. hloge("connect %s:%d failed!", host, port);
  190. return connfd;
  191. }
  192. tcp_nodelay(connfd, 1);
  193. if (https && cli->ssl == NULL) {
  194. // cli->ssl_ctx > g_ssl_ctx > hssl_ctx_new
  195. hssl_ctx_t ssl_ctx = NULL;
  196. if (cli->ssl_ctx) {
  197. ssl_ctx = cli->ssl_ctx;
  198. } else if (g_ssl_ctx) {
  199. ssl_ctx = g_ssl_ctx;
  200. } else {
  201. cli->ssl_ctx = ssl_ctx = hssl_ctx_new(NULL);
  202. cli->alloced_ssl_ctx = true;
  203. }
  204. if (ssl_ctx == NULL) {
  205. closesocket(connfd);
  206. return NABS(ERR_NEW_SSL_CTX);
  207. }
  208. cli->ssl = hssl_new(ssl_ctx, connfd);
  209. if (cli->ssl == NULL) {
  210. closesocket(connfd);
  211. return NABS(ERR_NEW_SSL);
  212. }
  213. if (!is_ipaddr(host)) {
  214. hssl_set_sni_hostname(cli->ssl, host);
  215. }
  216. so_rcvtimeo(connfd, blocktime);
  217. int ret = hssl_connect(cli->ssl);
  218. if (ret != 0) {
  219. fprintf(stderr, "* ssl handshake failed: %d\n", ret);
  220. hloge("ssl handshake failed: %d", ret);
  221. hssl_free(cli->ssl);
  222. cli->ssl = NULL;
  223. closesocket(connfd);
  224. return NABS(ret);
  225. }
  226. }
  227. cli->fd = connfd;
  228. cli->keepalive_requests = 0;
  229. return connfd;
  230. }
  231. int http_client_close(http_client_t* cli) {
  232. if (cli == NULL) return 0;
  233. cli->Close();
  234. return 0;
  235. }
  236. int http_client_send_data(http_client_t* cli, const char* data, int size) {
  237. if (!cli || !data || size <= 0) return -1;
  238. if (cli->ssl) {
  239. return hssl_write(cli->ssl, data, size);
  240. }
  241. return send(cli->fd, data, size, 0);
  242. }
  243. int http_client_recv_data(http_client_t* cli, char* data, int size) {
  244. if (!cli || !data || size <= 0) return -1;
  245. if (cli->ssl) {
  246. return hssl_read(cli->ssl, data, size);
  247. }
  248. return recv(cli->fd, data, size, 0);
  249. }
  250. static int http_client_exec(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
  251. // connect -> send -> recv -> http_parser
  252. int err = 0;
  253. int connfd = cli->fd;
  254. bool https = req->IsHttps() && !req->IsProxy();
  255. bool keepalive = true;
  256. time_t connect_timeout = MIN(req->connect_timeout, req->timeout);
  257. time_t timeout_ms = req->timeout * 1000;
  258. time_t start_time = gettick_ms();
  259. time_t cur_time = start_time, left_time = INFINITE;
  260. #define CHECK_TIMEOUT \
  261. do { \
  262. if (timeout_ms > 0) { \
  263. cur_time = gettick_ms(); \
  264. if (cur_time - start_time >= timeout_ms) { \
  265. goto timeout; \
  266. } \
  267. left_time = timeout_ms - (cur_time - start_time); \
  268. } \
  269. } while(0);
  270. uint32_t retry_count = req->retry_count;
  271. if (cli->keepalive_requests > 0 && retry_count == 0) {
  272. // maybe keep-alive timeout, retry at least once
  273. retry_count = 1;
  274. }
  275. if (cli->parser == NULL) {
  276. cli->parser = HttpParserPtr(HttpParser::New(HTTP_CLIENT, (http_version)req->http_major));
  277. if (cli->parser == NULL) {
  278. hloge("New HttpParser failed!");
  279. return ERR_NULL_POINTER;
  280. }
  281. }
  282. if (connfd <= 0 || cli->host != req->host || cli->port != req->port) {
  283. cli->host = req->host;
  284. cli->port = req->port;
  285. connect:
  286. connfd = http_client_connect(cli, req->host.c_str(), req->port, https, connect_timeout);
  287. if (connfd < 0) {
  288. return connfd;
  289. }
  290. }
  291. cli->parser->SubmitRequest(req);
  292. char recvbuf[1024] = {0};
  293. int total_nsend, nsend, nrecv;
  294. total_nsend = nsend = nrecv = 0;
  295. send:
  296. char* data = NULL;
  297. size_t len = 0;
  298. while (cli->parser->GetSendData(&data, &len)) {
  299. total_nsend = 0;
  300. while (total_nsend < len) {
  301. CHECK_TIMEOUT
  302. if (left_time != INFINITE) {
  303. so_sndtimeo(cli->fd, left_time);
  304. }
  305. if (req->cancel) goto disconnect;
  306. nsend = http_client_send_data(cli, data + total_nsend, len - total_nsend);
  307. if (req->cancel) goto disconnect;
  308. if (nsend <= 0) {
  309. CHECK_TIMEOUT
  310. err = socket_errno();
  311. if (err == EINTR) continue;
  312. if (retry_count-- > 0 && left_time > req->retry_delay + connect_timeout * 1000) {
  313. err = 0;
  314. if (req->retry_delay > 0) hv_msleep(req->retry_delay);
  315. goto connect;
  316. }
  317. goto disconnect;
  318. }
  319. total_nsend += nsend;
  320. }
  321. }
  322. if (resp == NULL) return 0;
  323. cli->parser->InitResponse(resp);
  324. recv:
  325. do {
  326. CHECK_TIMEOUT
  327. if (left_time != INFINITE) {
  328. so_rcvtimeo(cli->fd, left_time);
  329. }
  330. if (req->cancel) goto disconnect;
  331. nrecv = http_client_recv_data(cli, recvbuf, sizeof(recvbuf));
  332. if (req->cancel) goto disconnect;
  333. if (nrecv <= 0) {
  334. CHECK_TIMEOUT
  335. err = socket_errno();
  336. if (err == EINTR) continue;
  337. if (cli->parser->IsEof()) {
  338. err = 0;
  339. goto disconnect;
  340. }
  341. if (retry_count-- > 0 && left_time > req->retry_delay + connect_timeout * 1000) {
  342. err = 0;
  343. if (req->retry_delay > 0) hv_msleep(req->retry_delay);
  344. goto connect;
  345. }
  346. goto disconnect;
  347. }
  348. int nparse = cli->parser->FeedRecvData(recvbuf, nrecv);
  349. if (nparse != nrecv) {
  350. return ERR_PARSE;
  351. }
  352. } while(!cli->parser->IsComplete());
  353. keepalive = req->IsKeepAlive() && resp->IsKeepAlive();
  354. if (keepalive) {
  355. ++cli->keepalive_requests;
  356. } else {
  357. cli->Close();
  358. }
  359. return 0;
  360. timeout:
  361. err = ERR_TASK_TIMEOUT;
  362. disconnect:
  363. cli->Close();
  364. return err;
  365. }
  366. int http_client_send_header(http_client_t* cli, HttpRequest* req) {
  367. if (!cli || !req) return ERR_NULL_POINTER;
  368. http_client_make_request(cli, req);
  369. return http_client_exec(cli, req, NULL);
  370. }
  371. int http_client_recv_response(http_client_t* cli, HttpResponse* resp) {
  372. if (!cli || !resp) return ERR_NULL_POINTER;
  373. if (!cli->parser) {
  374. hloge("Call http_client_send_header first!");
  375. return ERR_NULL_POINTER;
  376. }
  377. char recvbuf[1024] = {0};
  378. cli->parser->InitResponse(resp);
  379. do {
  380. int nrecv = http_client_recv_data(cli, recvbuf, sizeof(recvbuf));
  381. if (nrecv <= 0) {
  382. int err = socket_errno();
  383. if (err == EINTR) continue;
  384. cli->Close();
  385. return err;
  386. }
  387. int nparse = cli->parser->FeedRecvData(recvbuf, nrecv);
  388. if (nparse != nrecv) {
  389. return ERR_PARSE;
  390. }
  391. } while(!cli->parser->IsComplete());
  392. return 0;
  393. }
  394. #ifdef WITH_CURL
  395. static size_t s_header_cb(char* buf, size_t size, size_t cnt, void* userdata) {
  396. if (buf == NULL || userdata == NULL) return 0;
  397. size_t len = size * cnt;
  398. std::string str(buf, len);
  399. HttpResponse* resp = (HttpResponse*)userdata;
  400. std::string::size_type pos = str.find_first_of(':');
  401. if (pos == std::string::npos) {
  402. if (strncmp(buf, "HTTP/", 5) == 0) {
  403. // status line
  404. //hlogd("%s", buf);
  405. int http_major = 1, http_minor = 1, status_code = 200;
  406. if (buf[5] == '1') {
  407. // HTTP/1.1 200 OK\r\n
  408. sscanf(buf, "HTTP/%d.%d %d", &http_major, &http_minor, &status_code);
  409. }
  410. else if (buf[5] == '2') {
  411. // HTTP/2 200\r\n
  412. sscanf(buf, "HTTP/%d %d", &http_major, &status_code);
  413. http_minor = 0;
  414. }
  415. resp->http_major = http_major;
  416. resp->http_minor = http_minor;
  417. resp->status_code = (http_status)status_code;
  418. if (resp->http_cb) {
  419. resp->http_cb(resp, HP_MESSAGE_BEGIN, NULL, 0);
  420. }
  421. }
  422. }
  423. else {
  424. // headers
  425. std::string key = trim(str.substr(0, pos));
  426. std::string value = trim(str.substr(pos+1));
  427. resp->headers[key] = value;
  428. }
  429. return len;
  430. }
  431. static size_t s_body_cb(char* buf, size_t size, size_t cnt, void *userdata) {
  432. if (buf == NULL || userdata == NULL) return 0;
  433. size_t len = size * cnt;
  434. HttpMessage* resp = (HttpMessage*)userdata;
  435. if (resp->http_cb) {
  436. if (resp->content == NULL && resp->content_length == 0) {
  437. resp->content = buf;
  438. resp->content_length = len;
  439. resp->http_cb(resp, HP_HEADERS_COMPLETE, NULL, 0);
  440. }
  441. resp->http_cb(resp, HP_BODY, buf, len);
  442. } else {
  443. resp->body.append(buf, len);
  444. }
  445. return len;
  446. }
  447. static int http_client_exec_curl(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
  448. if (cli->curl == NULL) {
  449. cli->curl = curl_easy_init();
  450. }
  451. CURL* curl = cli->curl;
  452. // proxy
  453. if (req->IsProxy()) {
  454. curl_easy_setopt(curl, CURLOPT_PROXY, req->host.c_str());
  455. curl_easy_setopt(curl, CURLOPT_PROXYPORT, req->port);
  456. }
  457. // SSL
  458. if (req->IsHttps()) {
  459. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
  460. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
  461. }
  462. // http2
  463. if (req->http_major == 2) {
  464. #if LIBCURL_VERSION_NUM < 0x073100 // 7.49.0
  465. curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2_0);
  466. #else
  467. // No Connection: Upgrade
  468. curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
  469. #endif
  470. }
  471. // TCP_NODELAY
  472. curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
  473. // method
  474. curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_method_str(req->method));
  475. // url
  476. req->DumpUrl();
  477. curl_easy_setopt(curl, CURLOPT_URL, req->url.c_str());
  478. //hlogd("%s %s HTTP/%d.%d", http_method_str(req->method), req->url.c_str(), req->http_major, req->http_minor);
  479. // headers
  480. req->FillContentType();
  481. struct curl_slist *headers = NULL;
  482. for (auto& pair : req->headers) {
  483. std::string header = pair.first;
  484. header += ": ";
  485. header += pair.second;
  486. headers = curl_slist_append(headers, header.c_str());
  487. }
  488. curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  489. // body
  490. //struct curl_httppost* httppost = NULL;
  491. //struct curl_httppost* lastpost = NULL;
  492. if (req->body.size() == 0) {
  493. req->DumpBody();
  494. /*
  495. if (req->body.size() == 0 &&
  496. req->content_type == MULTIPART_FORM_DATA) {
  497. for (auto& pair : req->mp) {
  498. if (pair.second.filename.size() != 0) {
  499. curl_formadd(&httppost, &lastpost,
  500. CURLFORM_COPYNAME, pair.first.c_str(),
  501. CURLFORM_FILE, pair.second.filename.c_str(),
  502. CURLFORM_END);
  503. }
  504. else if (pair.second.content.size() != 0) {
  505. curl_formadd(&httppost, &lastpost,
  506. CURLFORM_COPYNAME, pair.first.c_str(),
  507. CURLFORM_COPYCONTENTS, pair.second.content.c_str(),
  508. CURLFORM_END);
  509. }
  510. }
  511. if (httppost) {
  512. curl_easy_setopt(curl, CURLOPT_HTTPPOST, httppost);
  513. }
  514. }
  515. */
  516. }
  517. if (req->body.size() != 0) {
  518. curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req->body.c_str());
  519. curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req->body.size());
  520. }
  521. if (req->connect_timeout > 0) {
  522. curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, req->connect_timeout);
  523. }
  524. if (req->timeout > 0) {
  525. curl_easy_setopt(curl, CURLOPT_TIMEOUT, req->timeout);
  526. }
  527. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, s_body_cb);
  528. curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp);
  529. curl_easy_setopt(curl, CURLOPT_HEADER, 0);
  530. curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, s_header_cb);
  531. curl_easy_setopt(curl, CURLOPT_HEADERDATA, resp);
  532. int ret = curl_easy_perform(curl);
  533. /*
  534. if (ret != 0) {
  535. hloge("curl error: %d: %s", ret, curl_easy_strerror((CURLcode)ret));
  536. }
  537. if (resp->body.length() != 0) {
  538. hlogd("[Response]\n%s", resp->body.c_str());
  539. }
  540. double total_time, name_time, conn_time, pre_time;
  541. curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
  542. curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, &name_time);
  543. curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &conn_time);
  544. curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &pre_time);
  545. hlogd("TIME_INFO: %lf,%lf,%lf,%lf", total_time, name_time, conn_time, pre_time);
  546. */
  547. if (headers) {
  548. curl_slist_free_all(headers);
  549. }
  550. /*
  551. if (httppost) {
  552. curl_formfree(httppost);
  553. }
  554. */
  555. if (resp->http_cb) {
  556. resp->http_cb(resp, HP_MESSAGE_COMPLETE, NULL, 0);
  557. }
  558. return ret;
  559. }
  560. const char* http_client_strerror(int errcode) {
  561. return curl_easy_strerror((CURLcode)errcode);
  562. }
  563. #else
  564. const char* http_client_strerror(int errcode) {
  565. return socket_strerror(errcode);
  566. }
  567. #endif
  568. static int http_client_redirect(HttpRequest* req, HttpResponse* resp) {
  569. std::string location = resp->headers["Location"];
  570. if (!location.empty()) {
  571. hlogi("redirect %s => %s", req->url.c_str(), location.c_str());
  572. req->url = location;
  573. req->ParseUrl();
  574. req->headers["Host"] = req->host;
  575. resp->Reset();
  576. return http_client_send(req, resp);
  577. }
  578. return 0;
  579. }
  580. int http_client_send(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
  581. if (!cli || !req || !resp) return ERR_NULL_POINTER;
  582. http_client_make_request(cli, req);
  583. if (req->http_cb) resp->http_cb = std::move(req->http_cb);
  584. #if WITH_CURL
  585. int ret = http_client_exec_curl(cli, req, resp);
  586. #else
  587. int ret = http_client_exec(cli, req, resp);
  588. #endif
  589. if (ret != 0) return ret;
  590. // redirect
  591. if (req->redirect && HTTP_STATUS_IS_REDIRECT(resp->status_code)) {
  592. return http_client_redirect(req, resp);
  593. }
  594. return 0;
  595. }
  596. int http_client_send(HttpRequest* req, HttpResponse* resp) {
  597. if (!req || !resp) return ERR_NULL_POINTER;
  598. http_client_t cli;
  599. return http_client_send(&cli, req, resp);
  600. }
  601. // below for async
  602. static int http_client_exec_async(http_client_t* cli, HttpRequestPtr req, HttpResponseCallback resp_cb) {
  603. if (cli->async_client_ == NULL) {
  604. cli->mutex_.lock();
  605. if (cli->async_client_ == NULL) {
  606. cli->async_client_ = std::make_shared<hv::AsyncHttpClient>();
  607. }
  608. cli->mutex_.unlock();
  609. }
  610. return cli->async_client_->send(req, std::move(resp_cb));
  611. }
  612. int http_client_send_async(http_client_t* cli, HttpRequestPtr req, HttpResponseCallback resp_cb) {
  613. if (!cli || !req) return ERR_NULL_POINTER;
  614. http_client_make_request(cli, req.get());
  615. return http_client_exec_async(cli, req, std::move(resp_cb));
  616. }
  617. static http_client_t* s_async_http_client = NULL;
  618. static void hv_destroy_default_async_http_client() {
  619. hlogi("destory default http async client");
  620. if (s_async_http_client) {
  621. http_client_del(s_async_http_client);
  622. s_async_http_client = NULL;
  623. }
  624. }
  625. static http_client_t* hv_default_async_http_client() {
  626. static std::mutex s_mutex;
  627. if (s_async_http_client == NULL) {
  628. s_mutex.lock();
  629. if (s_async_http_client == NULL) {
  630. hlogi("create default http async client");
  631. s_async_http_client = http_client_new();
  632. // NOTE: I have No better idea
  633. atexit(hv_destroy_default_async_http_client);
  634. }
  635. s_mutex.unlock();
  636. }
  637. return s_async_http_client;
  638. }
  639. int http_client_send_async(HttpRequestPtr req, HttpResponseCallback resp_cb) {
  640. if (req == NULL) return ERR_NULL_POINTER;
  641. if (req->timeout == 0) {
  642. req->timeout = DEFAULT_HTTP_TIMEOUT;
  643. }
  644. return http_client_exec_async(hv_default_async_http_client(), req, std::move(resp_cb));
  645. }