wget.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /*
  2. * @build: make examples
  3. * @server bin/httpd -s restart -d
  4. * @client bin/wget 127.0.0.1:8080/
  5. */
  6. #include "requests.h"
  7. int main(int argc, char** argv) {
  8. if (argc < 2) {
  9. printf("Usage: %s url\n", argv[0]);
  10. return -10;
  11. }
  12. const char* url = argv[1];
  13. std::string filepath;
  14. const char* path = strrchr(url, '/');
  15. if (path == NULL || path[1] == '\0') {
  16. filepath = "index.html";
  17. } else {
  18. filepath = path + 1;
  19. }
  20. printf("Save file to %s ...\n", filepath.c_str());
  21. HFile file;
  22. if (file.open(filepath.c_str(), "wb") != 0) {
  23. fprintf(stderr, "Failed to open file %s\n", filepath.c_str());
  24. return -20;
  25. }
  26. // HEAD
  27. requests::Request req(new HttpRequest);
  28. req->url = url;
  29. req->method = HTTP_HEAD;
  30. printd("%s", req->Dump(true, true).c_str());
  31. auto resp = requests::request(req);
  32. if (resp == NULL) {
  33. fprintf(stderr, "request failed!\n");
  34. return -1;
  35. }
  36. printd("%s", resp->Dump(true, false).c_str());
  37. bool use_range = false;
  38. int range_bytes = 1 << 20; // 1M
  39. std::string accept_ranges = resp->GetHeader("Accept-Ranges");
  40. size_t content_length = hv::from_string<size_t>(resp->GetHeader("Content-Length"));
  41. // use Range if server accept_ranges and content_length > 1M
  42. if (resp->status_code == 200 &&
  43. accept_ranges == "bytes" &&
  44. content_length > range_bytes) {
  45. use_range = true;
  46. }
  47. // GET
  48. req->method = HTTP_GET;
  49. if (!use_range) {
  50. printd("%s", req->Dump(true, true).c_str());
  51. resp = requests::get(url);
  52. if (resp == NULL) {
  53. fprintf(stderr, "request failed!\n");
  54. return -1;
  55. }
  56. printd("%s", resp->Dump(true, false).c_str());
  57. file.write(resp->body.data(), resp->body.size());
  58. return 0;
  59. }
  60. // [from, to]
  61. long from, to;
  62. from = 0;
  63. http_client_t* cli = http_client_new();
  64. while (from < content_length) {
  65. to = from + range_bytes - 1;
  66. if (to >= content_length) to = content_length - 1;
  67. // Range: bytes=from-to
  68. req->SetRange(from, to);
  69. printd("%s", req->Dump(true, true).c_str());
  70. int ret = http_client_send(cli, req.get(), resp.get());
  71. if (ret != 0) {
  72. fprintf(stderr, "request failed!\n");
  73. return -1;
  74. }
  75. printd("%s", resp->Dump(true, false).c_str());
  76. file.write(resp->body.data(), resp->body.size());
  77. from = to + 1;
  78. }
  79. http_client_del(cli);
  80. return 0;
  81. }