forked from ithewei/libhv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
wget.cpp
106 lines (96 loc) · 3.02 KB
/
wget.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
* @build: make examples
* @server bin/httpd -s restart -d
* @client bin/wget 127.0.0.1:8080/
*/
#include "requests.h"
static int wget(const char* url, const char* filepath) {
HFile file;
if (file.open(filepath, "wb") != 0) {
fprintf(stderr, "Failed to open file %s\n", filepath);
return -20;
}
printf("Save file to %s ...\n", filepath);
// HEAD
auto resp = requests::head(url);
if (resp == NULL) {
fprintf(stderr, "request failed!\n");
return -1;
}
printd("%s", resp->Dump(true, false).c_str());
if (resp->status_code == HTTP_STATUS_NOT_FOUND) {
fprintf(stderr, "404 Not Found\n");
return -1;
}
bool use_range = false;
int range_bytes = 1 << 20; // 1M
std::string accept_ranges = resp->GetHeader("Accept-Ranges");
size_t content_length = hv::from_string<size_t>(resp->GetHeader("Content-Length"));
// use Range if server accept_ranges and content_length > 1M
if (resp->status_code == 200 &&
accept_ranges == "bytes" &&
content_length > range_bytes) {
use_range = true;
}
// GET
if (!use_range) {
resp = requests::get(url);
if (resp == NULL) {
fprintf(stderr, "request failed!\n");
return -1;
}
printd("%s", resp->Dump(true, false).c_str());
file.write(resp->body.data(), resp->body.size());
printf("progress: %ld/%ld = 100%%\n", (long)resp->body.size(), (long)resp->body.size());
return 0;
}
// Range: bytes=from-to
long from = 0, to = 0;
int last_progress = 0;
http_client_t* cli = http_client_new();
HttpRequestPtr req(new HttpRequest);
req->method = HTTP_GET;
req->url = url;
while (from < content_length) {
to = from + range_bytes - 1;
if (to >= content_length) to = content_length - 1;
req->SetRange(from, to);
printd("%s", req->Dump(true, false).c_str());
int ret = http_client_send(cli, req.get(), resp.get());
if (ret != 0) {
fprintf(stderr, "request failed!\n");
return -1;
}
printd("%s", resp->Dump(true, false).c_str());
file.write(resp->body.data(), resp->body.size());
from = to + 1;
// print progress
int cur_progress = from * 100 / content_length;
if (cur_progress > last_progress) {
printf("\rprogress: %ld/%ld = %d%%", (long)from, (long)content_length, (int)cur_progress);
fflush(stdout);
last_progress = cur_progress;
}
}
printf("\n");
http_client_del(cli);
return 0;
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: %s url [filepath]\n", argv[0]);
return -10;
}
const char* url = argv[1];
const char* filepath = "index.html";
if (argc > 2) {
filepath = argv[2];
} else {
const char* path = strrchr(url, '/');
if (path && path[1]) {
filepath = path + 1;
}
}
wget(url, filepath);
return 0;
}