其实这个http下载器的功能已经相当完善了,支持:限速、post投递和上传、自定义http header、设置user agent、设置range和超时

    而且它还不单纯只能下载http,由于使用了stream,所以也支持其他协议,你也可以用它来进行文件之间的copy、纯tcp下载等等。。

    使用方式:

    ./demo http://xxxxx/file /tmp/a

    具体使用以及参数设置就不详细说明,可以通过如下获取详细使用说明:

    ./demo --help

    1. /* //////////////////////////////////////////////////////////////////////////////////////
    2. * includes
    3. */
    4. #include "tbox/tbox.h"
    5.  
    6. /* //////////////////////////////////////////////////////////////////////////////////////
    7. * func
    8. */
    9. static tb_bool_t tb_demo_http_post_func(tb_size_t state, tb_hize_t offset, tb_hong_t size, tb_hize_t save, tb_size_t rate, tb_cpointer_t priv)
    10. {
    11. // percent
    12. tb_size_t percent = 0;
    13. if (size > 0) percent = (tb_size_t)((offset * 100) / size);
    14. else if (state == TB_STATE_CLOSED) percent = 100;
    15.  
    16. // trace
    17. tb_trace_i("post: %llu, rate: %lu bytes/s, percent: %lu%%, state: %s", save, rate, percent, tb_state_cstr(state));
    18.  
    19. // ok
    20. return tb_true;
    21. }
    22. static tb_bool_t tb_demo_stream_head_func(tb_char_t const* line, tb_cpointer_t priv)
    23. {
    24. tb_printf("response: %s\n", line);
    25. return tb_true;
    26. }
    27. static tb_bool_t tb_demo_stream_save_func(tb_size_t state, tb_hize_t offset, tb_hong_t size, tb_hize_t save, tb_size_t rate, tb_cpointer_t priv)
    28. {
    29. // check
    30. tb_bool_t verbose = (tb_bool_t)priv;
    31.  
    32. // print verbose info
    33. if (verbose)
    34. {
    35. // percent
    36. tb_size_t percent = 0;
    37. if (size > 0) percent = (tb_size_t)((offset * 100) / size);
    38. else if (state == TB_STATE_CLOSED) percent = 100;
    39.  
    40. // trace
    41. tb_printf("save: %llu bytes, rate: %lu bytes/s, percent: %lu%%, state: %s\n", save, rate, percent, tb_state_cstr(state));
    42. }
    43.  
    44. // ok
    45. return tb_true;
    46. }
    47.  
    48. /* //////////////////////////////////////////////////////////////////////////////////////
    49. * globals
    50. */
    51. static tb_option_item_t g_options[] =
    52. {
    53. {'-', "gzip", TB_OPTION_MODE_KEY, TB_OPTION_TYPE_BOOL, "enable gzip" }
    54. , {'-', "no-verbose", TB_OPTION_MODE_KEY, TB_OPTION_TYPE_BOOL, "disable verbose info" }
    55. , {'d', "debug", TB_OPTION_MODE_KEY, TB_OPTION_TYPE_BOOL, "enable debug info" }
    56. , {'k', "keep-alive", TB_OPTION_MODE_KEY, TB_OPTION_TYPE_BOOL, "keep alive" }
    57. , {'h', "header", TB_OPTION_MODE_KEY_VAL, TB_OPTION_TYPE_CSTR, "the custem http header" }
    58. , {'-', "post-data", TB_OPTION_MODE_KEY_VAL, TB_OPTION_TYPE_CSTR, "set the post data" }
    59. , {'-', "post-file", TB_OPTION_MODE_KEY_VAL, TB_OPTION_TYPE_CSTR, "set the post file" }
    60. , {'-', "range", TB_OPTION_MODE_KEY_VAL, TB_OPTION_TYPE_CSTR, "set the range" }
    61. , {'-', "timeout", TB_OPTION_MODE_KEY_VAL, TB_OPTION_TYPE_INTEGER, "set the timeout" }
    62. , {'-', "limitrate", TB_OPTION_MODE_KEY_VAL, TB_OPTION_TYPE_INTEGER, "set the limitrate" }
    63. , {'h', "help", TB_OPTION_MODE_KEY, TB_OPTION_TYPE_BOOL, "display this help and exit"}
    64. , {'-', "url", TB_OPTION_MODE_VAL, TB_OPTION_TYPE_CSTR, "the url" }
    65. , {'-', tb_null, TB_OPTION_MODE_MORE, TB_OPTION_TYPE_NONE, tb_null }
    66.  
    67. };
    68.  
    69. /* //////////////////////////////////////////////////////////////////////////////////////
    70. * main
    71. */
    72. tb_int_t main(tb_int_t argc, tb_char_t** argv)
    73. {
    74. // init tbox
    75. if (!tb_init(tb_null, tb_null, 0)) return 0;
    76.  
    77. // done
    78. tb_option_ref_t option = tb_null;
    79. tb_stream_ref_t istream = tb_null;
    80. tb_stream_ref_t ostream = tb_null;
    81. tb_stream_ref_t pstream = tb_null;
    82. do
    83. {
    84. // init option
    85. option = tb_option_init("stream", "the stream demo", g_options);
    86. tb_assert_and_check_break(option);
    87.  
    88. // done option
    89. if (tb_option_done(option, argc - 1, &argv[1]))
    90. {
    91. // debug & verbose
    92. tb_bool_t debug = tb_option_find(option, "debug");
    93. tb_bool_t verbose = tb_option_find(option, "no-verbose")? tb_false : tb_true;
    94.  
    95. // done url
    96. if (tb_option_find(option, "url"))
    97. {
    98. // init istream
    99. istream = tb_stream_init_from_url(tb_option_item_cstr(option, "url"));
    100. tb_assert_and_check_break(istream);
    101.  
    102. // ctrl http
    103. if (tb_stream_type(istream) == TB_STREAM_TYPE_HTTP)
    104. {
    105. // enable gzip?
    106. if (tb_option_find(option, "gzip"))
    107. {
    108. // auto unzip
    109. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_AUTO_UNZIP, 1)) break;
    110.  
    111. // need gzip
    112. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Accept-Encoding", "gzip,deflate")) break;
    113. }
    114.  
    115. // enable debug?
    116. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD_FUNC, debug? tb_demo_stream_head_func : tb_null)) break;
    117.  
    118. // custem header?
    119. if (tb_option_find(option, "header"))
    120. {
    121. // init
    122. tb_string_t key;
    123. tb_string_t val;
    124. tb_string_init(&key);
    125. tb_string_init(&val);
    126.  
    127. // done
    128. tb_bool_t k = tb_true;
    129. tb_char_t const* p = tb_option_item_cstr(option, "header");
    130. while (*p)
    131. {
    132. // is key?
    133. if (k)
    134. {
    135. if (*p != ':' && !tb_isspace(*p)) tb_string_chrcat(&key, *p++);
    136. else if (*p == ':')
    137. {
    138. // skip ':'
    139. p++;
    140.  
    141. // skip space
    142. while (*p && tb_isspace(*p)) p++;
    143.  
    144. // is val now
    145. k = tb_false;
    146. }
    147. else p++;
    148. }
    149. // is val?
    150. else
    151. {
    152. if (*p != ';') tb_string_chrcat(&val, *p++);
    153. else
    154. {
    155. // skip ';'
    156. p++;
    157.  
    158. // skip space
    159. while (*p && tb_isspace(*p)) p++;
    160.  
    161. // set header
    162. if (tb_string_size(&key) && tb_string_size(&val))
    163. {
    164. if (debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val));
    165. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break;
    166. }
    167.  
    168. // is key now
    169. k = tb_true;
    170.  
    171. // clear key & val
    172. tb_string_clear(&key);
    173. tb_string_clear(&val);
    174. }
    175. }
    176. }
    177.  
    178. // set header
    179. if (tb_string_size(&key) && tb_string_size(&val))
    180. {
    181. if (debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val));
    182. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break;
    183. }
    184.  
    185. // exit
    186. tb_string_exit(&key);
    187. tb_string_exit(&val);
    188. }
    189.  
    190. // keep alive?
    191. if (tb_option_find(option, "keep-alive"))
    192. {
    193. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Connection", "keep-alive")) break;
    194. }
    195.  
    196. // post-data?
    197. if (tb_option_find(option, "post-data"))
    198. {
    199. tb_char_t const* post_data = tb_option_item_cstr(option, "post-data");
    200. tb_hize_t post_size = tb_strlen(post_data);
    201. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break;
    202. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_DATA, post_data, post_size)) break;
    203. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break;
    204. if (debug) tb_printf("post: %llu\n", post_size);
    205. }
    206. // post-file?
    207. else if (tb_option_find(option, "post-file"))
    208. {
    209. tb_char_t const* url = tb_option_item_cstr(option, "post-file");
    210. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break;
    211. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_URL, url)) break;
    212. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break;
    213. if (debug) tb_printf("post: %s\n", url);
    214. }
    215. }
    216.  
    217. // set range
    218. if (tb_option_find(option, "range"))
    219. {
    220. tb_char_t const* p = tb_option_item_cstr(option, "range");
    221. if (p)
    222. {
    223. // the bof
    224. tb_hize_t eof = 0;
    225. tb_hize_t bof = tb_atoll(p);
    226. while (*p && tb_isdigit(*p)) p++;
    227. if (*p == '-')
    228. {
    229. p++;
    230. eof = tb_atoll(p);
    231. }
    232. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_RANGE, bof, eof)) break;
    233. }
    234. }
    235.  
    236. // set timeout
    237. if (tb_option_find(option, "timeout"))
    238. {
    239. tb_size_t timeout = tb_option_item_uint32(option, "timeout");
    240. if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_SET_TIMEOUT, timeout)) break;
    241. }
    242.  
    243. // print verbose info
    244. if (verbose) tb_printf("open: %s: ..\n", tb_option_item_cstr(option, "url"));
    245.  
    246. // open istream
    247. if (!tb_stream_open(istream))
    248. {
    249. // print verbose info
    250. if (verbose) tb_printf("open: %s\n", tb_state_cstr(tb_stream_state(istream)));
    251. break;
    252. }
    253.  
    254. // print verbose info
    255. if (verbose) tb_printf("open: ok\n");
    256.  
    257. // init ostream
    258. if (tb_option_find(option, "more0"))
    259. {
    260. // the path
    261. tb_char_t const* path = tb_option_item_cstr(option, "more0");
    262.  
    263. // init
    264. ostream = tb_stream_init_from_file(path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_BINARY | TB_FILE_MODE_TRUNC);
    265.  
    266. // print verbose info
    267. if (verbose) tb_printf("save: %s\n", path);
    268. }
    269. else
    270. {
    271. // the name
    272. tb_char_t const* name = tb_strrchr(tb_option_item_cstr(option, "url"), '/');
    273. if (!name) name = tb_strrchr(tb_option_item_cstr(option, "url"), '\\');
    274. if (!name) name = "/stream.file";
    275.  
    276. // the path
    277. tb_char_t path[TB_PATH_MAXN] = {0};
    278. if (tb_directory_curt(path, TB_PATH_MAXN))
    279. tb_strcat(path, name);
    280. else break;
    281.  
    282. // init file
    283. ostream = tb_stream_init_from_file(path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_BINARY | TB_FILE_MODE_TRUNC);
    284.  
    285. // print verbose info
    286. if (verbose) tb_printf("save: %s\n", path);
    287. }
    288. tb_assert_and_check_break(ostream);
    289.  
    290. // the limit rate
    291. tb_size_t limitrate = 0;
    292. if (tb_option_find(option, "limitrate"))
    293. limitrate = tb_option_item_uint32(option, "limitrate");
    294.  
    295. // save it
    296. tb_hong_t save = 0;
    297. if ((save = tb_transfer_done(istream, ostream, limitrate, tb_demo_stream_save_func, (tb_cpointer_t)verbose)) < 0) break;
    298. }
    299. else tb_option_help(option);
    300. }
    301. else tb_option_help(option);
    302.  
    303. } while (0);
    304.  
    305. // exit pstream
    306. if (pstream) tb_stream_exit(pstream);
    307. pstream = tb_null;
    308.  
    309. // exit istream
    310. if (istream) tb_stream_exit(istream);
    311. istream = tb_null;
    312.  
    313. // exit ostream
    314. if (ostream) tb_stream_exit(ostream);
    315. ostream = tb_null;
    316.  
    317. // exit option
    318. if (option) tb_option_exit(option);
    319. option = tb_null;
    320.  
    321. // exit tbox
    322. tb_exit();
    323. return 0;
    324. }