1
0

http_client.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. #include "http_client.h"
  2. #include "hstring.h"
  3. #define MAX_CONNECT_TIMEOUT 3000 // ms
  4. #ifdef WITH_CURL
  5. #include "curl/curl.h"
  6. #else
  7. #include "herr.h"
  8. #include "hsocket.h"
  9. #include "HttpParser.h"
  10. #include "ssl_ctx.h"
  11. #endif
  12. #ifdef WITH_OPENSSL
  13. #include "openssl/ssl.h"
  14. #endif
  15. struct http_session_s {
  16. int use_tls;
  17. std::string host;
  18. int port;
  19. int timeout;
  20. http_headers headers;
  21. //private:
  22. #ifdef WITH_CURL
  23. CURL* curl;
  24. #else
  25. int fd;
  26. #endif
  27. #ifdef WITH_OPENSSL
  28. SSL* ssl;
  29. #endif
  30. http_session_s() {
  31. use_tls = 0;
  32. port = DEFAULT_HTTP_PORT;
  33. timeout = DEFAULT_HTTP_TIMEOUT;
  34. #ifdef WITH_CURL
  35. curl = NULL;
  36. #else
  37. fd = -1;
  38. #endif
  39. #ifdef WITH_OPENSSL
  40. ssl = NULL;
  41. #endif
  42. }
  43. ~http_session_s() {
  44. #ifdef WITH_OPENSSL
  45. if (ssl) {
  46. SSL_free(ssl);
  47. ssl = NULL;
  48. }
  49. #endif
  50. #ifdef WITH_CURL
  51. if (curl) {
  52. curl_easy_cleanup(curl);
  53. curl = NULL;
  54. }
  55. #else
  56. if (fd > 0) {
  57. closesocket(fd);
  58. fd = -1;
  59. }
  60. #endif
  61. }
  62. };
  63. static int __http_session_send(http_session_t* hss, HttpRequest* req, HttpResponse* res);
  64. http_session_t* http_session_new(const char* host, int port) {
  65. http_session_t* hss = new http_session_t;
  66. hss->host = host;
  67. hss->port = port;
  68. hss->headers["Host"] = asprintf("%s:%d", host, port);
  69. hss->headers["Connection"] = "keep-alive";
  70. return hss;
  71. }
  72. int http_session_del(http_session_t* hss) {
  73. if (hss == NULL) return 0;
  74. delete hss;
  75. return 0;
  76. }
  77. int http_session_set_timeout(http_session_t* hss, int timeout) {
  78. hss->timeout = timeout;
  79. return 0;
  80. }
  81. int http_session_clear_headers(http_session_t* hss) {
  82. hss->headers.clear();
  83. return 0;
  84. }
  85. int http_session_set_header(http_session_t* hss, const char* key, const char* value) {
  86. hss->headers[key] = value;
  87. return 0;
  88. }
  89. int http_session_del_header(http_session_t* hss, const char* key) {
  90. auto iter = hss->headers.find(key);
  91. if (iter != hss->headers.end()) {
  92. hss->headers.erase(iter);
  93. }
  94. return 0;
  95. }
  96. const char* http_session_get_header(http_session_t* hss, const char* key) {
  97. auto iter = hss->headers.find(key);
  98. if (iter != hss->headers.end()) {
  99. return iter->second.c_str();
  100. }
  101. return NULL;
  102. }
  103. int http_session_send(http_session_t* hss, HttpRequest* req, HttpResponse* res) {
  104. for (auto& pair : hss->headers) {
  105. req->headers[pair.first] = pair.second;
  106. }
  107. return __http_session_send(hss, req, res);
  108. }
  109. int http_client_send(HttpRequest* req, HttpResponse* res, int timeout) {
  110. http_session_t hss;
  111. hss.timeout = timeout;
  112. return __http_session_send(&hss, req, res);
  113. }
  114. #ifdef WITH_CURL
  115. static size_t s_formget_cb(void *arg, const char *buf, size_t len) {
  116. return len;
  117. }
  118. static size_t s_header_cb(char* buf, size_t size, size_t cnt, void* userdata) {
  119. if (buf == NULL || userdata == NULL) return 0;
  120. HttpResponse* res = (HttpResponse*)userdata;
  121. string str(buf);
  122. string::size_type pos = str.find_first_of(':');
  123. if (pos == string::npos) {
  124. if (strncmp(buf, "HTTP/", 5) == 0) {
  125. // status line
  126. // HTTP/1.1 200 OK\r\n
  127. //hlogd("%s", buf);
  128. int http_major,http_minor,status_code;
  129. sscanf(buf, "HTTP/%d.%d %d", &http_major, &http_minor, &status_code);
  130. res->http_major = http_major;
  131. res->http_minor = http_minor;
  132. res->status_code = (http_status)status_code;
  133. }
  134. }
  135. else {
  136. // headers
  137. string key = trim(str.substr(0, pos));
  138. string value = trim(str.substr(pos+1));
  139. res->headers[key] = value;
  140. }
  141. return size*cnt;
  142. }
  143. static size_t s_body_cb(char *buf, size_t size, size_t cnt, void *userdata) {
  144. if (buf == NULL || userdata == NULL) return 0;
  145. HttpResponse* res = (HttpResponse*)userdata;
  146. res->body.append(buf, size*cnt);
  147. return size*cnt;
  148. }
  149. int __http_session_send(http_session_t* hss, HttpRequest* req, HttpResponse* res) {
  150. if (req == NULL || res == NULL) {
  151. return -1;
  152. }
  153. if (hss->curl == NULL) {
  154. hss->curl = curl_easy_init();
  155. }
  156. CURL* curl = hss->curl;
  157. int timeout = hss->timeout;
  158. // SSL
  159. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
  160. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
  161. // TCP_NODELAY
  162. curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
  163. // method
  164. curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_method_str(req->method));
  165. // url
  166. std::string url = req->dump_url();
  167. curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  168. //hlogd("%s %s HTTP/%d.%d", http_method_str(req->method), url.c_str(), req->http_major, req->http_minor);
  169. // header
  170. req->fill_content_type();
  171. struct curl_slist *headers = NULL;
  172. for (auto& pair : req->headers) {
  173. string header = pair.first;
  174. header += ": ";
  175. header += pair.second;
  176. headers = curl_slist_append(headers, header.c_str());
  177. }
  178. curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  179. // body
  180. struct curl_httppost* httppost = NULL;
  181. struct curl_httppost* lastpost = NULL;
  182. if (req->body.size() == 0) {
  183. req->dump_body();
  184. if (req->body.size() == 0 &&
  185. req->content_type == MULTIPART_FORM_DATA) {
  186. for (auto& pair : req->mp) {
  187. if (pair.second.filename.size() != 0) {
  188. curl_formadd(&httppost, &lastpost,
  189. CURLFORM_COPYNAME, pair.first.c_str(),
  190. CURLFORM_FILE, pair.second.filename.c_str(),
  191. CURLFORM_END);
  192. }
  193. else if (pair.second.content.size() != 0) {
  194. curl_formadd(&httppost, &lastpost,
  195. CURLFORM_COPYNAME, pair.first.c_str(),
  196. CURLFORM_COPYCONTENTS, pair.second.content.c_str(),
  197. CURLFORM_END);
  198. }
  199. }
  200. if (httppost) {
  201. curl_easy_setopt(curl, CURLOPT_HTTPPOST, httppost);
  202. curl_formget(httppost, NULL, s_formget_cb);
  203. }
  204. }
  205. }
  206. if (req->body.size() != 0) {
  207. curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req->body.c_str());
  208. curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req->body.size());
  209. }
  210. if (timeout > 0) {
  211. curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
  212. }
  213. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, s_body_cb);
  214. curl_easy_setopt(curl, CURLOPT_WRITEDATA, res);
  215. curl_easy_setopt(curl, CURLOPT_HEADER, 0);
  216. curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, s_header_cb);
  217. curl_easy_setopt(curl, CURLOPT_HEADERDATA, res);
  218. int ret = curl_easy_perform(curl);
  219. /*
  220. if (ret != 0) {
  221. hloge("curl error: %d: %s", ret, curl_easy_strerror((CURLcode)ret));
  222. }
  223. if (res->body.length() != 0) {
  224. hlogd("[Response]\n%s", res->body.c_str());
  225. }
  226. double total_time, name_time, conn_time, pre_time;
  227. curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
  228. curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, &name_time);
  229. curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &conn_time);
  230. curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &pre_time);
  231. hlogd("TIME_INFO: %lf,%lf,%lf,%lf", total_time, name_time, conn_time, pre_time);
  232. */
  233. if (headers) {
  234. curl_slist_free_all(headers);
  235. }
  236. if (httppost) {
  237. curl_formfree(httppost);
  238. }
  239. return ret;
  240. }
  241. const char* http_client_strerror(int errcode) {
  242. return curl_easy_strerror((CURLcode)errcode);
  243. }
  244. #else
  245. static int __http_session_connect(http_session_t* hss) {
  246. int blocktime = MAX_CONNECT_TIMEOUT;
  247. if (hss->timeout > 0) {
  248. blocktime = MIN(hss->timeout*1000, blocktime);
  249. }
  250. int connfd = ConnectTimeout(hss->host.c_str(), hss->port, blocktime);
  251. if (connfd < 0) {
  252. return socket_errno();
  253. }
  254. tcp_nodelay(connfd, 1);
  255. if (hss->use_tls) {
  256. #ifdef WITH_OPENSSL
  257. if (g_ssl_ctx == NULL) {
  258. ssl_ctx_init(NULL, NULL, NULL);
  259. }
  260. hss->ssl = SSL_new((SSL_CTX*)g_ssl_ctx);
  261. SSL_set_fd(hss->ssl, connfd);
  262. if (SSL_connect(hss->ssl) != 1) {
  263. int err = SSL_get_error(hss->ssl, -1);
  264. fprintf(stderr, "SSL handshark failed: %d\n", err);
  265. SSL_free(hss->ssl);
  266. hss->ssl = NULL;
  267. closesocket(connfd);
  268. return err;
  269. }
  270. #else
  271. fprintf(stderr, "Please recompile WITH_OPENSSL\n");
  272. closesocket(connfd);
  273. return ERR_INVALID_PROTOCOL;
  274. #endif
  275. }
  276. hss->fd = connfd;
  277. return 0;
  278. }
  279. static int __http_session_close(http_session_t* hss) {
  280. #ifdef WITH_OPENSSL
  281. if (hss->ssl) {
  282. SSL_free(hss->ssl);
  283. hss->ssl = NULL;
  284. }
  285. #endif
  286. if (hss->fd > 0) {
  287. closesocket(hss->fd);
  288. hss->fd = -1;
  289. }
  290. return 0;
  291. }
  292. static int __http_session_send(http_session_t* hss, HttpRequest* req, HttpResponse* res) {
  293. // connect -> send -> recv -> http_parser
  294. int err = 0;
  295. int timeout = hss->timeout;
  296. int connfd = hss->fd;
  297. // use_tls ?
  298. int use_tls = hss->use_tls;
  299. if (strncmp(req->url.c_str(), "https", 5) == 0) {
  300. hss->use_tls = use_tls = 1;
  301. }
  302. // parse host:port from Headers
  303. std::string http = req->dump(true, true);
  304. if (hss->host.size() == 0) {
  305. auto Host = req->headers.find("Host");
  306. if (Host == req->headers.end()) {
  307. return ERR_INVALID_PARAM;
  308. }
  309. StringList strlist = split(Host->second, ':');
  310. hss->host = strlist[0];
  311. if (strlist.size() == 2) {
  312. hss->port = atoi(strlist[1].c_str());
  313. }
  314. else {
  315. hss->port = DEFAULT_HTTP_PORT;
  316. }
  317. }
  318. time_t start_time = time(NULL);
  319. time_t cur_time;
  320. int fail_cnt = 0;
  321. connect:
  322. if (connfd <= 0) {
  323. int ret = __http_session_connect(hss);
  324. if (ret != 0) {
  325. return ret;
  326. }
  327. connfd = hss->fd;
  328. }
  329. HttpParser parser;
  330. parser.parser_response_init(res);
  331. char recvbuf[1024] = {0};
  332. int total_nsend, nsend, nrecv;
  333. send:
  334. total_nsend = nsend = nrecv = 0;
  335. while (1) {
  336. if (timeout > 0) {
  337. cur_time = time(NULL);
  338. if (cur_time - start_time >= timeout) {
  339. return ERR_TASK_TIMEOUT;
  340. }
  341. so_sndtimeo(connfd, (timeout-(cur_time-start_time)) * 1000);
  342. }
  343. #ifdef WITH_OPENSSL
  344. if (use_tls) {
  345. nsend = SSL_write(hss->ssl, http.c_str()+total_nsend, http.size()-total_nsend);
  346. }
  347. #endif
  348. if (!use_tls) {
  349. nsend = send(connfd, http.c_str()+total_nsend, http.size()-total_nsend, 0);
  350. }
  351. if (nsend <= 0) {
  352. if (++fail_cnt == 1) {
  353. // maybe keep-alive timeout, try again
  354. __http_session_close(hss);
  355. goto connect;
  356. }
  357. else {
  358. return socket_errno();
  359. }
  360. }
  361. total_nsend += nsend;
  362. if (total_nsend == http.size()) {
  363. break;
  364. }
  365. }
  366. recv:
  367. while(1) {
  368. if (timeout > 0) {
  369. cur_time = time(NULL);
  370. if (cur_time - start_time >= timeout) {
  371. return ERR_TASK_TIMEOUT;
  372. }
  373. so_rcvtimeo(connfd, (timeout-(cur_time-start_time)) * 1000);
  374. }
  375. #ifdef WITH_OPENSSL
  376. if (use_tls) {
  377. nrecv = SSL_read(hss->ssl, recvbuf, sizeof(recvbuf));
  378. }
  379. #endif
  380. if (!use_tls) {
  381. nrecv = recv(connfd, recvbuf, sizeof(recvbuf), 0);
  382. }
  383. if (nrecv <= 0) {
  384. return socket_errno();
  385. }
  386. int nparse = parser.execute(recvbuf, nrecv);
  387. if (nparse != nrecv || parser.get_errno() != HPE_OK) {
  388. return ERR_PARSE;
  389. }
  390. if (parser.get_state() == HP_MESSAGE_COMPLETE) {
  391. err = 0;
  392. break;
  393. }
  394. if (timeout > 0) {
  395. cur_time = time(NULL);
  396. if (cur_time - start_time >= timeout) {
  397. return ERR_TASK_TIMEOUT;
  398. }
  399. so_rcvtimeo(connfd, (timeout-(cur_time-start_time)) * 1000);
  400. }
  401. }
  402. return err;
  403. }
  404. const char* http_client_strerror(int errcode) {
  405. return socket_strerror(errcode);
  406. }
  407. #endif