http_client.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #include "http_client.h"
  2. #include "hstring.h"
  3. #ifdef WITH_CURL
  4. /***************************************************************
  5. HttpClient based libcurl
  6. ***************************************************************/
  7. #include "curl/curl.h"
  8. static size_t s_formget_cb(void *arg, const char *buf, size_t len) {
  9. return len;
  10. }
  11. static size_t s_header_cb(char* buf, size_t size, size_t cnt, void* userdata) {
  12. if (buf == NULL || userdata == NULL) return 0;
  13. HttpResponse* res = (HttpResponse*)userdata;
  14. string str(buf);
  15. string::size_type pos = str.find_first_of(':');
  16. if (pos == string::npos) {
  17. if (strncmp(buf, "HTTP/", 5) == 0) {
  18. // status line
  19. // HTTP/1.1 200 OK\r\n
  20. //hlogd("%s", buf);
  21. int http_major,http_minor,status_code;
  22. sscanf(buf, "HTTP/%d.%d %d", &http_major, &http_minor, &status_code);
  23. res->http_major = http_major;
  24. res->http_minor = http_minor;
  25. res->status_code = (http_status)status_code;
  26. }
  27. }
  28. else {
  29. // headers
  30. string key = trim(str.substr(0, pos));
  31. string value = trim(str.substr(pos+1));
  32. res->headers[key] = value;
  33. }
  34. return size*cnt;
  35. }
  36. static size_t s_body_cb(char *buf, size_t size, size_t cnt, void *userdata) {
  37. if (buf == NULL || userdata == NULL) return 0;
  38. HttpResponse* res = (HttpResponse*)userdata;
  39. res->body.append(buf, size*cnt);
  40. return size*cnt;
  41. }
  42. int http_client_send(HttpRequest* req, HttpResponse* res, int timeout) {
  43. if (req == NULL || res == NULL) {
  44. return -1;
  45. }
  46. CURL* handle = curl_easy_init();
  47. // SSL
  48. curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
  49. curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0);
  50. // TCP_NODELAY
  51. curl_easy_setopt(handle, CURLOPT_TCP_NODELAY, 1);
  52. // method
  53. curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, http_method_str(req->method));
  54. // url
  55. std::string url = req->dump_url();
  56. curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
  57. //hlogd("%s %s HTTP/%d.%d", http_method_str(req->method), url.c_str(), req->http_major, req->http_minor);
  58. // header
  59. req->fill_content_type();
  60. struct curl_slist *headers = NULL;
  61. for (auto& pair : req->headers) {
  62. string header = pair.first;
  63. header += ": ";
  64. header += pair.second;
  65. headers = curl_slist_append(headers, header.c_str());
  66. }
  67. curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
  68. // body
  69. struct curl_httppost* httppost = NULL;
  70. struct curl_httppost* lastpost = NULL;
  71. if (req->body.size() == 0) {
  72. req->dump_body();
  73. if (req->body.size() == 0 &&
  74. req->content_type == MULTIPART_FORM_DATA) {
  75. for (auto& pair : req->mp) {
  76. if (pair.second.filename.size() != 0) {
  77. curl_formadd(&httppost, &lastpost,
  78. CURLFORM_COPYNAME, pair.first.c_str(),
  79. CURLFORM_FILE, pair.second.filename.c_str(),
  80. CURLFORM_END);
  81. }
  82. else if (pair.second.content.size() != 0) {
  83. curl_formadd(&httppost, &lastpost,
  84. CURLFORM_COPYNAME, pair.first.c_str(),
  85. CURLFORM_COPYCONTENTS, pair.second.content.c_str(),
  86. CURLFORM_END);
  87. }
  88. }
  89. if (httppost) {
  90. curl_easy_setopt(handle, CURLOPT_HTTPPOST, httppost);
  91. curl_formget(httppost, NULL, s_formget_cb);
  92. }
  93. }
  94. }
  95. if (req->body.size() != 0) {
  96. curl_easy_setopt(handle, CURLOPT_POSTFIELDS, req->body.c_str());
  97. curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, req->body.size());
  98. }
  99. if (timeout > 0) {
  100. curl_easy_setopt(handle, CURLOPT_TIMEOUT, timeout);
  101. }
  102. curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, s_body_cb);
  103. curl_easy_setopt(handle, CURLOPT_WRITEDATA, res);
  104. curl_easy_setopt(handle, CURLOPT_HEADER, 0);
  105. curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, s_header_cb);
  106. curl_easy_setopt(handle, CURLOPT_HEADERDATA, res);
  107. int ret = curl_easy_perform(handle);
  108. /*
  109. if (ret != 0) {
  110. hloge("curl error: %d: %s", ret, curl_easy_strerror((CURLcode)ret));
  111. }
  112. if (res->body.length() != 0) {
  113. hlogd("[Response]\n%s", res->body.c_str());
  114. }
  115. double total_time, name_time, conn_time, pre_time;
  116. curl_easy_getinfo(handle, CURLINFO_TOTAL_TIME, &total_time);
  117. curl_easy_getinfo(handle, CURLINFO_NAMELOOKUP_TIME, &name_time);
  118. curl_easy_getinfo(handle, CURLINFO_CONNECT_TIME, &conn_time);
  119. curl_easy_getinfo(handle, CURLINFO_PRETRANSFER_TIME, &pre_time);
  120. hlogd("TIME_INFO: %lf,%lf,%lf,%lf", total_time, name_time, conn_time, pre_time);
  121. */
  122. if (headers) {
  123. curl_slist_free_all(headers);
  124. }
  125. if (httppost) {
  126. curl_formfree(httppost);
  127. }
  128. curl_easy_cleanup(handle);
  129. return ret;
  130. }
  131. const char* http_client_strerror(int errcode) {
  132. return curl_easy_strerror((CURLcode)errcode);
  133. }
  134. #else
  135. #include "herr.h"
  136. #include "hsocket.h"
  137. #include "HttpParser.h"
  138. #include "ssl_ctx.h"
  139. #ifdef WITH_OPENSSL
  140. #include "openssl/ssl.h"
  141. #endif
  142. int http_client_send(HttpRequest* req, HttpResponse* res, int timeout) {
  143. // connect -> send -> recv -> http_parser
  144. int ssl_enable = 0;
  145. if (strncmp(req->url.c_str(), "https", 5) == 0) {
  146. ssl_enable = 1;
  147. #ifdef WITH_OPENSSL
  148. if (g_ssl_ctx == NULL) {
  149. ssl_ctx_init(NULL, NULL, NULL);
  150. }
  151. #else
  152. fprintf(stderr, "Please recompile WITH_OPENSSL\n");
  153. return ERR_INVALID_PROTOCOL;
  154. #endif
  155. }
  156. time_t start_time = time(NULL);
  157. time_t cur_time;
  158. std::string http = req->dump(true, true);
  159. auto Host = req->headers.find("Host");
  160. if (Host == req->headers.end()) {
  161. return ERR_INVALID_PARAM;
  162. }
  163. StringList strlist = split(Host->second, ':');
  164. std::string host;
  165. int port = 80;
  166. host = strlist[0];
  167. if (strlist.size() == 2) {
  168. port = atoi(strlist[1].c_str());
  169. }
  170. int blocktime = 3000;
  171. if (timeout > 0) {
  172. blocktime = MIN(timeout*1000, blocktime);
  173. }
  174. SOCKET connfd = ConnectTimeout(host.c_str(), port, blocktime);
  175. if (connfd < 0) {
  176. return socket_errno();
  177. }
  178. #ifdef WITH_OPENSSL
  179. SSL* ssl = NULL;
  180. if (ssl_enable) {
  181. ssl = SSL_new((SSL_CTX*)g_ssl_ctx);
  182. SSL_set_fd(ssl, connfd);
  183. if (SSL_connect(ssl) != 1) {
  184. fprintf(stderr, "SSL handshark failed: %d\n", SSL_get_error(ssl, -1));
  185. }
  186. }
  187. #endif
  188. tcp_nodelay(connfd, 1);
  189. int err = 0;
  190. HttpParser parser;
  191. parser.parser_response_init(res);
  192. char recvbuf[1024] = {0};
  193. send:
  194. int total_nsend = 0;
  195. int nsend = 0;
  196. int nrecv = 0;
  197. while (1) {
  198. if (timeout > 0) {
  199. cur_time = time(NULL);
  200. if (cur_time - start_time >= timeout) {
  201. err = ERR_TASK_TIMEOUT;
  202. goto ret;
  203. }
  204. so_sndtimeo(connfd, (timeout-(cur_time-start_time)) * 1000);
  205. }
  206. #ifdef WITH_OPENSSL
  207. if (ssl_enable) {
  208. nsend = SSL_write(ssl, http.c_str()+total_nsend, http.size()-total_nsend);
  209. }
  210. #endif
  211. if (!ssl_enable) {
  212. nsend = send(connfd, http.c_str()+total_nsend, http.size()-total_nsend, 0);
  213. }
  214. if (nsend <= 0) {
  215. err = socket_errno();
  216. goto ret;
  217. }
  218. total_nsend += nsend;
  219. if (total_nsend == http.size()) {
  220. break;
  221. }
  222. }
  223. recv:
  224. while(1) {
  225. if (timeout > 0) {
  226. cur_time = time(NULL);
  227. if (cur_time - start_time >= timeout) {
  228. err = ERR_TASK_TIMEOUT;
  229. goto ret;
  230. }
  231. so_rcvtimeo(connfd, (timeout-(cur_time-start_time)) * 1000);
  232. }
  233. #ifdef WITH_OPENSSL
  234. if (ssl_enable) {
  235. nrecv = SSL_read(ssl, recvbuf, sizeof(recvbuf));
  236. }
  237. #endif
  238. if (!ssl_enable) {
  239. nrecv = recv(connfd, recvbuf, sizeof(recvbuf), 0);
  240. }
  241. if (nrecv <= 0) {
  242. err = socket_errno();
  243. goto ret;
  244. }
  245. int nparse = parser.execute(recvbuf, nrecv);
  246. if (nparse != nrecv || parser.get_errno() != HPE_OK) {
  247. err = ERR_PARSE;
  248. goto ret;
  249. }
  250. if (parser.get_state() == HP_MESSAGE_COMPLETE) {
  251. err = 0;
  252. break;
  253. }
  254. if (timeout > 0) {
  255. cur_time = time(NULL);
  256. if (cur_time - start_time >= timeout) {
  257. err = ERR_TASK_TIMEOUT;
  258. goto ret;
  259. }
  260. so_rcvtimeo(connfd, (timeout-(cur_time-start_time)) * 1000);
  261. }
  262. }
  263. ret:
  264. #ifdef WITH_OPENSSL
  265. if (ssl) {
  266. SSL_free(ssl);
  267. }
  268. #endif
  269. closesocket(connfd);
  270. return err;
  271. }
  272. const char* http_client_strerror(int errcode) {
  273. return socket_strerror(errcode);
  274. }
  275. #endif