11/*
22 * @build: make examples
33 * @server bin/httpd -s restart -d
4- * @client bin/wget 127.0.0.1:8080/
4+ * @client bin/wget http:// 127.0.0.1:8080/
55 */
66
7- #include " requests.h"
7+ #include " http_client.h"
8+ #include " htime.h"
9+ using namespace hv ;
810
9- static int wget (const char * url, const char * filepath) {
11+ typedef std::function<void (size_t received_bytes, size_t total_bytes)> wget_progress_cb;
12+
13+ static int wget (const char * url, const char * filepath, wget_progress_cb progress_cb = NULL ) {
1014 HFile file;
1115 if (file.open (filepath, " wb" ) != 0 ) {
1216 fprintf (stderr, " Failed to open file %s\n " , filepath);
1317 return -20 ;
1418 }
1519 printf (" Save file to %s ...\n " , filepath);
1620
21+ HttpClient cli;
22+ HttpRequest req;
23+ req.url = url;
24+ HttpResponse resp;
25+
1726 // HEAD
18- auto resp = requests::head (url);
19- if (resp == NULL ) {
20- fprintf (stderr, " request failed!\n " );
27+ req.method = HTTP_HEAD;
28+ int ret = cli.send (&req, &resp);
29+ if (ret != 0 ) {
30+ fprintf (stderr, " request error: %d\n " , ret);
2131 return -1 ;
2232 }
23- printd (" %s" , resp-> Dump (true , false ).c_str ());
24- if (resp-> status_code == HTTP_STATUS_NOT_FOUND) {
33+ printd (" %s" , resp. Dump (true , false ).c_str ());
34+ if (resp. status_code == HTTP_STATUS_NOT_FOUND) {
2535 fprintf (stderr, " 404 Not Found\n " );
2636 return -1 ;
2737 }
2838
2939 bool use_range = false ;
3040 int range_bytes = 1 << 20 ; // 1M
31- std::string accept_ranges = resp-> GetHeader (" Accept-Ranges" );
32- size_t content_length = hv::from_string<size_t >(resp-> GetHeader (" Content-Length" ));
41+ std::string accept_ranges = resp. GetHeader (" Accept-Ranges" );
42+ size_t content_length = hv::from_string<size_t >(resp. GetHeader (" Content-Length" ));
3343 // use Range if server accept_ranges and content_length > 1M
34- if (resp-> status_code == 200 &&
44+ if (resp. status_code == 200 &&
3545 accept_ranges == " bytes" &&
3646 content_length > range_bytes) {
3747 use_range = true ;
3848 }
3949
4050 // GET
51+ req.method = HTTP_GET;
52+ req.timeout = 3600 ; // 1h
4153 if (!use_range) {
42- resp = requests::get (url);
43- if (resp == NULL ) {
44- fprintf (stderr, " request failed!\n " );
54+ size_t received_bytes = 0 ;
55+ req.http_cb = [&file, &content_length, &received_bytes, &progress_cb]
56+ (HttpMessage* resp, http_parser_state state, const char * data, size_t size) {
57+ if (state == HP_HEADERS_COMPLETE) {
58+ content_length = hv::from_string<size_t >(resp->GetHeader (" Content-Length" ));
59+ printd (" %s" , resp->Dump (true , false ).c_str ());
60+ } else if (state == HP_BODY) {
61+ if (data && size) {
62+ file.write (data, size);
63+ received_bytes += size;
64+
65+ if (progress_cb) {
66+ progress_cb (received_bytes, content_length);
67+ }
68+ }
69+ }
70+ };
71+ ret = cli.send (&req, &resp);
72+ if (ret != 0 ) {
73+ fprintf (stderr, " request error: %d\n " , ret);
4574 return -1 ;
4675 }
47- printd (" %s" , resp->Dump (true , false ).c_str ());
48- file.write (resp->body .data (), resp->body .size ());
49- printf (" progress: %ld/%ld = 100%%\n " , (long )resp->body .size (), (long )resp->body .size ());
5076 return 0 ;
5177 }
5278
5379 // Range: bytes=from-to
5480 long from = 0 , to = 0 ;
55- int last_progress = 0 ;
56- http_client_t * cli = http_client_new ();
57- HttpRequestPtr req (new HttpRequest);
58- req->method = HTTP_GET;
59- req->url = url;
6081 while (from < content_length) {
6182 to = from + range_bytes - 1 ;
6283 if (to >= content_length) to = content_length - 1 ;
63- req-> SetRange (from, to);
64- printd (" %s" , req-> Dump (true , false ).c_str ());
65- int ret = http_client_send ( cli, req. get (), resp. get () );
84+ req. SetRange (from, to);
85+ printd (" %s" , req. Dump (true , false ).c_str ());
86+ ret = cli. send (&req, & resp);
6687 if (ret != 0 ) {
67- fprintf (stderr, " request failed! \n " );
88+ fprintf (stderr, " request error: %d \n " , ret );
6889 return -1 ;
6990 }
70- printd (" %s" , resp-> Dump (true , false ).c_str ());
71- file.write (resp-> body .data (), resp-> body .size ());
91+ printd (" %s" , resp. Dump (true , false ).c_str ());
92+ file.write (resp. body .data (), resp. body .size ());
7293 from = to + 1 ;
7394
74- // print progress
75- int cur_progress = from * 100 / content_length;
76- if (cur_progress > last_progress) {
77- printf (" \r progress: %ld/%ld = %d%%" , (long )from, (long )content_length, (int )cur_progress);
78- fflush (stdout);
79- last_progress = cur_progress;
95+ if (progress_cb) {
96+ progress_cb (from, content_length);
8097 }
8198 }
82- printf (" \n " );
83- http_client_del (cli);
8499
85100 return 0 ;
86101}
@@ -101,6 +116,23 @@ int main(int argc, char** argv) {
101116 }
102117 }
103118
104- wget (url, filepath);
119+ unsigned int start_time = gettick_ms ();
120+ int last_progress = 0 ;
121+ wget (url, filepath, [&last_progress](size_t received_bytes, size_t total_bytes) {
122+ // print progress
123+ if (total_bytes == 0 ) {
124+ printf (" \r progress: %lu/? = ?" , (unsigned long )received_bytes);
125+ } else {
126+ int cur_progress = received_bytes * 100 / total_bytes;
127+ if (cur_progress > last_progress) {
128+ printf (" \r progress: %lu/%lu = %d%%" , (unsigned long )received_bytes, (unsigned long )total_bytes, (int )cur_progress);
129+ last_progress = cur_progress;
130+ }
131+ }
132+ fflush (stdout);
133+ });
134+ unsigned int end_time = gettick_ms ();
135+ printf (" \n cost time %u ms\n " , end_time - start_time);
136+
105137 return 0 ;
106138}
0 commit comments