http_client.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #include "http_client.h"
  2. #include <string.h>
  3. #include <string>
  4. using std::string;
  5. #define SPACE_CHARS " \t\r\n"
  6. static string trim(const string& str) {
  7. string::size_type pos1 = str.find_first_not_of(SPACE_CHARS);
  8. if (pos1 == string::npos) return "";
  9. string::size_type pos2 = str.find_last_not_of(SPACE_CHARS);
  10. return str.substr(pos1, pos2-pos1+1);
  11. }
  12. /***************************************************************
  13. HttpClient based libcurl
  14. ***************************************************************/
  15. #include "curl/curl.h"
  16. //#include "hlog.h"
  17. static size_t s_formget_cb(void *arg, const char *buf, size_t len) {
  18. return len;
  19. }
  20. static size_t s_header_cb(char* buf, size_t size, size_t cnt, void* userdata) {
  21. if (buf == NULL || userdata == NULL) return 0;
  22. HttpResponse* res = (HttpResponse*)userdata;
  23. string str(buf);
  24. string::size_type pos = str.find_first_of(':');
  25. if (pos == string::npos) {
  26. if (strncmp(buf, "HTTP/", 5) == 0) {
  27. // status line
  28. // HTTP/1.1 200 OK\r\n
  29. //hlogd("%s", buf);
  30. int http_major,http_minor,status_code;
  31. sscanf(buf, "HTTP/%d.%d %d", &http_major, &http_minor, &status_code);
  32. res->http_major = http_major;
  33. res->http_minor = http_minor;
  34. res->status_code = (http_status)status_code;
  35. }
  36. }
  37. else {
  38. // headers
  39. string key = trim(str.substr(0, pos));
  40. string value = trim(str.substr(pos+1));
  41. res->headers[key] = value;
  42. }
  43. return size*cnt;
  44. }
  45. static size_t s_body_cb(char *buf, size_t size, size_t cnt, void *userdata) {
  46. if (buf == NULL || userdata == NULL) return 0;
  47. HttpResponse* res = (HttpResponse*)userdata;
  48. res->body.append(buf, size*cnt);
  49. return size*cnt;
  50. }
  51. #include <atomic>
  52. static std::atomic_flag s_curl_global_init(false);
  53. int http_client_send(HttpRequest* req, HttpResponse* res, int timeout) {
  54. if (req == NULL || res == NULL) {
  55. return -1;
  56. }
  57. if (!s_curl_global_init.test_and_set()) {
  58. curl_global_init(CURL_GLOBAL_ALL);
  59. }
  60. CURL* handle = curl_easy_init();
  61. // SSL
  62. curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
  63. curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0);
  64. // method
  65. curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, http_method_str(req->method));
  66. // url
  67. std::string url = req->dump_url();
  68. curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
  69. //hlogd("%s %s HTTP/%d.%d", http_method_str(req->method), url.c_str(), req->http_major, req->http_minor);
  70. // header
  71. req->fill_content_type();
  72. struct curl_slist *headers = NULL;
  73. for (auto& pair : req->headers) {
  74. string header = pair.first;
  75. header += ": ";
  76. header += pair.second;
  77. headers = curl_slist_append(headers, header.c_str());
  78. }
  79. curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
  80. // body
  81. struct curl_httppost* httppost = NULL;
  82. struct curl_httppost* lastpost = NULL;
  83. if (req->body.size() == 0) {
  84. req->dump_body();
  85. if (req->body.size() == 0 &&
  86. req->content_type == MULTIPART_FORM_DATA) {
  87. for (auto& pair : req->mp) {
  88. if (pair.second.filename.size() != 0) {
  89. curl_formadd(&httppost, &lastpost,
  90. CURLFORM_COPYNAME, pair.first.c_str(),
  91. CURLFORM_FILE, pair.second.filename.c_str(),
  92. CURLFORM_END);
  93. }
  94. else if (pair.second.content.size() != 0) {
  95. curl_formadd(&httppost, &lastpost,
  96. CURLFORM_COPYNAME, pair.first.c_str(),
  97. CURLFORM_COPYCONTENTS, pair.second.content.c_str(),
  98. CURLFORM_END);
  99. }
  100. }
  101. if (httppost) {
  102. curl_easy_setopt(handle, CURLOPT_HTTPPOST, httppost);
  103. curl_formget(httppost, NULL, s_formget_cb);
  104. }
  105. }
  106. }
  107. if (req->body.size() != 0) {
  108. curl_easy_setopt(handle, CURLOPT_POSTFIELDS, req->body.c_str());
  109. }
  110. if (timeout > 0) {
  111. curl_easy_setopt(handle, CURLOPT_TIMEOUT, timeout);
  112. }
  113. curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, s_body_cb);
  114. curl_easy_setopt(handle, CURLOPT_WRITEDATA, res);
  115. curl_easy_setopt(handle, CURLOPT_HEADER, 0);
  116. curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, s_header_cb);
  117. curl_easy_setopt(handle, CURLOPT_HEADERDATA, res);
  118. int ret = curl_easy_perform(handle);
  119. /*
  120. if (ret != 0) {
  121. hloge("curl error: %d: %s", ret, curl_easy_strerror((CURLcode)ret));
  122. }
  123. if (res->body.length() != 0) {
  124. hlogd("[Response]\n%s", res->body.c_str());
  125. }
  126. double total_time, name_time, conn_time, pre_time;
  127. curl_easy_getinfo(handle, CURLINFO_TOTAL_TIME, &total_time);
  128. curl_easy_getinfo(handle, CURLINFO_NAMELOOKUP_TIME, &name_time);
  129. curl_easy_getinfo(handle, CURLINFO_CONNECT_TIME, &conn_time);
  130. curl_easy_getinfo(handle, CURLINFO_PRETRANSFER_TIME, &pre_time);
  131. hlogd("TIME_INFO: %lf,%lf,%lf,%lf", total_time, name_time, conn_time, pre_time);
  132. */
  133. if (headers) {
  134. curl_slist_free_all(headers);
  135. }
  136. if (httppost) {
  137. curl_formfree(httppost);
  138. }
  139. curl_easy_cleanup(handle);
  140. return ret;
  141. }
  142. const char* http_client_strerror(int errcode) {
  143. return curl_easy_strerror((CURLcode)errcode);
  144. }