requests.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #ifndef HV_REQUESTS_H_
  2. #define HV_REQUESTS_H_
  3. /*
  4. * Inspired by python requests
  5. *
  6. * @code
  7. #include "requests.h"
  8. int main() {
  9. auto resp = requests::get("http://127.0.0.1:8080/ping");
  10. if (resp == NULL) {
  11. printf("request failed!\n");
  12. } else {
  13. printf("%d %s\r\n", resp->status_code, resp->status_message());
  14. printf("%s\n", resp->body.c_str());
  15. }
  16. resp = requests::post("http://127.0.0.1:8080/echo", "hello,world!");
  17. if (resp == NULL) {
  18. printf("request failed!\n");
  19. } else {
  20. printf("%d %s\r\n", resp->status_code, resp->status_message());
  21. printf("%s\n", resp->body.c_str());
  22. }
  23. return 0;
  24. }
  25. **/
  26. #include <memory>
  27. #include "HttpClient.h"
  28. namespace requests {
  29. typedef HttpRequestPtr Request;
  30. typedef HttpResponsePtr Response;
  31. typedef HttpResponseCallback ResponseCallback;
  32. HV_INLINE Response request(Request req) {
  33. Response resp(new HttpResponse);
  34. int ret = http_client_send(req.get(), resp.get());
  35. return ret ? NULL : resp;
  36. }
  37. HV_INLINE Response request(http_method method, const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders) {
  38. Request req(new HttpRequest);
  39. req->method = method;
  40. req->url = url;
  41. if (&body != &NoBody) {
  42. req->body = body;
  43. }
  44. if (&headers != &DefaultHeaders) {
  45. req->headers = headers;
  46. }
  47. return request(req);
  48. }
  49. HV_INLINE Response head(const char* url, const http_headers& headers = DefaultHeaders) {
  50. return request(HTTP_HEAD, url, NoBody, headers);
  51. }
  52. HV_INLINE Response get(const char* url, const http_headers& headers = DefaultHeaders) {
  53. return request(HTTP_GET, url, NoBody, headers);
  54. }
  55. HV_INLINE Response post(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders) {
  56. return request(HTTP_POST, url, body, headers);
  57. }
  58. HV_INLINE Response put(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders) {
  59. return request(HTTP_PUT, url, body, headers);
  60. }
  61. HV_INLINE Response patch(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders) {
  62. return request(HTTP_PATCH, url, body, headers);
  63. }
  64. // delete is c++ keyword, we have to replace delete with Delete.
  65. HV_INLINE Response Delete(const char* url, const http_headers& headers = DefaultHeaders) {
  66. return request(HTTP_DELETE, url, NoBody, headers);
  67. }
  68. HV_INLINE int async(Request req, ResponseCallback resp_cb) {
  69. return http_client_send_async(req, std::move(resp_cb));
  70. }
  71. // Sample codes for uploading and downloading files
  72. HV_INLINE Response uploadFile(const char* url, const char* filepath, http_method method = HTTP_POST, const http_headers& headers = DefaultHeaders) {
  73. Request req(new HttpRequest);
  74. req->method = method;
  75. req->url = url;
  76. req->timeout = 600; // 10min
  77. if (req->File(filepath) != 200) return NULL;
  78. if (&headers != &DefaultHeaders) {
  79. req->headers = headers;
  80. }
  81. return request(req);
  82. }
  83. #ifndef WITHOUT_HTTP_CONTENT
  84. HV_INLINE Response uploadFormFile(const char* url, const char* name, const char* filepath, std::map<std::string, std::string>& params = hv::empty_map, http_method method = HTTP_POST, const http_headers& headers = DefaultHeaders) {
  85. Request req(new HttpRequest);
  86. req->method = method;
  87. req->url = url;
  88. req->timeout = 600; // 10min
  89. req->content_type = MULTIPART_FORM_DATA;
  90. req->SetFormFile(name, filepath);
  91. for (auto& param : params) {
  92. req->SetFormData(param.first.c_str(), param.second);
  93. }
  94. if (&headers != &DefaultHeaders) {
  95. req->headers = headers;
  96. }
  97. return request(req);
  98. }
  99. #endif
  100. typedef std::function<void(size_t sended_bytes, size_t total_bytes)> upload_progress_cb;
  101. HV_INLINE Response uploadLargeFile(const char* url, const char* filepath, upload_progress_cb progress_cb = NULL, http_method method = HTTP_POST, const http_headers& headers = DefaultHeaders) {
  102. // open file
  103. HFile file;
  104. int ret = file.open(filepath, "rb");
  105. if (ret != 0) {
  106. return NULL;
  107. }
  108. hv::HttpClient cli;
  109. Request req(new HttpRequest);
  110. req->method = method;
  111. req->url = url;
  112. req->timeout = 3600; // 1h
  113. if (&headers != &DefaultHeaders) {
  114. req->headers = headers;
  115. }
  116. // connect
  117. req->ParseUrl();
  118. int connfd = cli.connect(req->host.c_str(), req->port, req->IsHttps(), req->connect_timeout);
  119. if (connfd < 0) {
  120. return NULL;
  121. }
  122. // send header
  123. size_t total_bytes = file.size(filepath);
  124. req->SetHeader("Content-Length", hv::to_string(total_bytes));
  125. ret = cli.sendHeader(req.get());
  126. if (ret != 0) {
  127. return NULL;
  128. }
  129. // send file
  130. size_t sended_bytes = 0;
  131. char filebuf[40960]; // 40K
  132. int filebuflen = sizeof(filebuf);
  133. int nread = 0, nsend = 0;
  134. while (sended_bytes < total_bytes) {
  135. nread = file.read(filebuf, filebuflen);
  136. if (nread <= 0) {
  137. return NULL;
  138. }
  139. nsend = cli.sendData(filebuf, nread);
  140. if (nsend != nread) {
  141. return NULL;
  142. }
  143. sended_bytes += nsend;
  144. if (progress_cb) {
  145. progress_cb(sended_bytes, total_bytes);
  146. }
  147. }
  148. // recv response
  149. Response resp(new HttpResponse);
  150. ret = cli.recvResponse(resp.get());
  151. if (ret != 0) {
  152. return NULL;
  153. }
  154. return resp;
  155. }
  156. // see examples/wget.cpp
  157. typedef std::function<void(size_t received_bytes, size_t total_bytes)> download_progress_cb;
  158. HV_INLINE size_t downloadFile(const char* url, const char* filepath, download_progress_cb progress_cb = NULL) {
  159. // open file
  160. std::string filepath_download(filepath);
  161. filepath_download += ".download";
  162. HFile file;
  163. int ret = file.open(filepath_download.c_str(), "wb");
  164. if (ret != 0) {
  165. return 0;
  166. }
  167. // download
  168. Request req(new HttpRequest);
  169. req->method = HTTP_GET;
  170. req->url = url;
  171. req->timeout = 3600; // 1h
  172. size_t content_length = 0;
  173. size_t received_bytes = 0;
  174. req->http_cb = [&file, &content_length, &received_bytes, &progress_cb]
  175. (HttpMessage* resp, http_parser_state state, const char* data, size_t size) {
  176. if (!resp->headers["Location"].empty()) return;
  177. if (state == HP_HEADERS_COMPLETE) {
  178. content_length = hv::from_string<size_t>(resp->GetHeader("Content-Length"));
  179. } else if (state == HP_BODY) {
  180. if (data && size) {
  181. // write file
  182. file.write(data, size);
  183. received_bytes += size;
  184. if (progress_cb) {
  185. progress_cb(received_bytes, content_length);
  186. }
  187. }
  188. }
  189. };
  190. auto resp = request(req);
  191. file.close();
  192. if (resp == NULL || resp->status_code != 200) {
  193. return 0;
  194. }
  195. // check filesize
  196. if (content_length != 0) {
  197. if (hv_filesize(filepath_download.c_str()) == content_length) {
  198. rename(filepath_download.c_str(), filepath);
  199. } else {
  200. remove(filepath_download.c_str());
  201. return 0;
  202. }
  203. }
  204. return hv_filesize(filepath);
  205. }
  206. }
  207. #endif // HV_REQUESTS_H_