aboutsummaryrefslogtreecommitdiff
path: root/networking/wget.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-02-10 06:29:06 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2011-02-10 06:29:06 +0100
commitdf4e16c9af6d6270d91d17d31c6098ecb259e5cc (patch)
treed3ec14d52efd21975d9f022d417115ff317528a4 /networking/wget.c
parent77350aa93392d36dc419d3e11bda6bf9bed993ff (diff)
downloadbusybox-w32-df4e16c9af6d6270d91d17d31c6098ecb259e5cc.tar.gz
busybox-w32-df4e16c9af6d6270d91d17d31c6098ecb259e5cc.tar.bz2
busybox-w32-df4e16c9af6d6270d91d17d31c6098ecb259e5cc.zip
wget: use FEATURE_COPYBUF_KB-sized buffer. Much faster for local transfers
function old new delta base64enc - 53 +53 gethdr 190 200 +10 ftpcmd 129 133 +4 progress_meter 160 122 -38 retrieve_file_data 431 392 -39 base64enc_512 46 - -46 wget_main 2456 2220 -236 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 2/3 up/down: 67/-359) Total: -292 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/wget.c')
-rw-r--r--networking/wget.c121
1 files changed, 61 insertions, 60 deletions
diff --git a/networking/wget.c b/networking/wget.c
index 0db9b3365..8e636bd39 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -35,12 +35,16 @@ struct globals {
35#endif 35#endif
36 smallint chunked; /* chunked transfer encoding */ 36 smallint chunked; /* chunked transfer encoding */
37 smallint got_clen; /* got content-length: from server */ 37 smallint got_clen; /* got content-length: from server */
38 /* Local downloads do benefit from big buffer.
39 * With 512 byte buffer, it was measured to be
40 * an order of magnitude slower than with big one.
41 */
42 uint64_t just_to_align_next_member;
43 char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024];
38} FIX_ALIASING; 44} FIX_ALIASING;
39#define G (*(struct globals*)&bb_common_bufsiz1) 45#define G (*ptr_to_globals)
40struct BUG_G_too_big {
41 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
42};
43#define INIT_G() do { \ 46#define INIT_G() do { \
47 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
44 IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) \ 48 IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) \
45} while (0) 49} while (0)
46 50
@@ -158,14 +162,14 @@ static char *safe_fgets(char *s, int size, FILE *stream)
158} 162}
159 163
160#if ENABLE_FEATURE_WGET_AUTHENTICATION 164#if ENABLE_FEATURE_WGET_AUTHENTICATION
161/* Base64-encode character string. buf is assumed to be char buf[512]. */ 165/* Base64-encode character string. */
162static char *base64enc_512(char buf[512], const char *str) 166static char *base64enc(const char *str)
163{ 167{
164 unsigned len = strlen(str); 168 unsigned len = strlen(str);
165 if (len > 512/4*3 - 10) /* paranoia */ 169 if (len > sizeof(G.wget_buf)/4*3 - 10) /* paranoia */
166 len = 512/4*3 - 10; 170 len = sizeof(G.wget_buf)/4*3 - 10;
167 bb_uuencode(buf, str, len, bb_uuenc_tbl_base64); 171 bb_uuencode(G.wget_buf, str, len, bb_uuenc_tbl_base64);
168 return buf; 172 return G.wget_buf;
169} 173}
170#endif 174#endif
171 175
@@ -191,7 +195,7 @@ static FILE *open_socket(len_and_sockaddr *lsa)
191 return fp; 195 return fp;
192} 196}
193 197
194static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf) 198static int ftpcmd(const char *s1, const char *s2, FILE *fp)
195{ 199{
196 int result; 200 int result;
197 if (s1) { 201 if (s1) {
@@ -203,18 +207,18 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf)
203 do { 207 do {
204 char *buf_ptr; 208 char *buf_ptr;
205 209
206 if (fgets(buf, 510, fp) == NULL) { 210 if (fgets(G.wget_buf, sizeof(G.wget_buf)-2, fp) == NULL) {
207 bb_perror_msg_and_die("error getting response"); 211 bb_perror_msg_and_die("error getting response");
208 } 212 }
209 buf_ptr = strstr(buf, "\r\n"); 213 buf_ptr = strstr(G.wget_buf, "\r\n");
210 if (buf_ptr) { 214 if (buf_ptr) {
211 *buf_ptr = '\0'; 215 *buf_ptr = '\0';
212 } 216 }
213 } while (!isdigit(buf[0]) || buf[3] != ' '); 217 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');
214 218
215 buf[3] = '\0'; 219 G.wget_buf[3] = '\0';
216 result = xatoi_positive(buf); 220 result = xatoi_positive(G.wget_buf);
217 buf[3] = ' '; 221 G.wget_buf[3] = ' ';
218 return result; 222 return result;
219} 223}
220 224
@@ -278,7 +282,7 @@ static void parse_url(char *src_url, struct host_info *h)
278 sp = h->host; 282 sp = h->host;
279} 283}
280 284
281static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/) 285static char *gethdr(FILE *fp /*, int *istrunc*/)
282{ 286{
283 char *s, *hdrval; 287 char *s, *hdrval;
284 int c; 288 int c;
@@ -286,24 +290,24 @@ static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/)
286 /* *istrunc = 0; */ 290 /* *istrunc = 0; */
287 291
288 /* retrieve header line */ 292 /* retrieve header line */
289 if (fgets(buf, bufsiz, fp) == NULL) 293 if (fgets(G.wget_buf, sizeof(G.wget_buf), fp) == NULL)
290 return NULL; 294 return NULL;
291 295
292 /* see if we are at the end of the headers */ 296 /* see if we are at the end of the headers */
293 for (s = buf; *s == '\r'; ++s) 297 for (s = G.wget_buf; *s == '\r'; ++s)
294 continue; 298 continue;
295 if (*s == '\n') 299 if (*s == '\n')
296 return NULL; 300 return NULL;
297 301
298 /* convert the header name to lower case */ 302 /* convert the header name to lower case */
299 for (s = buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) { 303 for (s = G.wget_buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) {
300 /* tolower for "A-Z", no-op for "0-9a-z-." */ 304 /* tolower for "A-Z", no-op for "0-9a-z-." */
301 *s = (*s | 0x20); 305 *s = (*s | 0x20);
302 } 306 }
303 307
304 /* verify we are at the end of the header name */ 308 /* verify we are at the end of the header name */
305 if (*s != ':') 309 if (*s != ':')
306 bb_error_msg_and_die("bad header line: %s", sanitize_string(buf)); 310 bb_error_msg_and_die("bad header line: %s", sanitize_string(G.wget_buf));
307 311
308 /* locate the start of the header value */ 312 /* locate the start of the header value */
309 *s++ = '\0'; 313 *s++ = '\0';
@@ -366,7 +370,6 @@ static char *URL_escape(const char *str)
366 370
367static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa) 371static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa)
368{ 372{
369 char buf[512];
370 FILE *sfp; 373 FILE *sfp;
371 char *str; 374 char *str;
372 int port; 375 int port;
@@ -375,8 +378,8 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
375 target->user = xstrdup("anonymous:busybox@"); 378 target->user = xstrdup("anonymous:busybox@");
376 379
377 sfp = open_socket(lsa); 380 sfp = open_socket(lsa);
378 if (ftpcmd(NULL, NULL, sfp, buf) != 220) 381 if (ftpcmd(NULL, NULL, sfp) != 220)
379 bb_error_msg_and_die("%s", sanitize_string(buf+4)); 382 bb_error_msg_and_die("%s", sanitize_string(G.wget_buf + 4));
380 383
381 /* 384 /*
382 * Splitting username:password pair, 385 * Splitting username:password pair,
@@ -385,24 +388,24 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
385 str = strchr(target->user, ':'); 388 str = strchr(target->user, ':');
386 if (str) 389 if (str)
387 *str++ = '\0'; 390 *str++ = '\0';
388 switch (ftpcmd("USER ", target->user, sfp, buf)) { 391 switch (ftpcmd("USER ", target->user, sfp)) {
389 case 230: 392 case 230:
390 break; 393 break;
391 case 331: 394 case 331:
392 if (ftpcmd("PASS ", str, sfp, buf) == 230) 395 if (ftpcmd("PASS ", str, sfp) == 230)
393 break; 396 break;
394 /* fall through (failed login) */ 397 /* fall through (failed login) */
395 default: 398 default:
396 bb_error_msg_and_die("ftp login: %s", sanitize_string(buf+4)); 399 bb_error_msg_and_die("ftp login: %s", sanitize_string(G.wget_buf + 4));
397 } 400 }
398 401
399 ftpcmd("TYPE I", NULL, sfp, buf); 402 ftpcmd("TYPE I", NULL, sfp);
400 403
401 /* 404 /*
402 * Querying file size 405 * Querying file size
403 */ 406 */
404 if (ftpcmd("SIZE ", target->path, sfp, buf) == 213) { 407 if (ftpcmd("SIZE ", target->path, sfp) == 213) {
405 G.content_len = BB_STRTOOFF(buf+4, NULL, 10); 408 G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10);
406 if (G.content_len < 0 || errno) { 409 if (G.content_len < 0 || errno) {
407 bb_error_msg_and_die("SIZE value is garbage"); 410 bb_error_msg_and_die("SIZE value is garbage");
408 } 411 }
@@ -412,20 +415,20 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
412 /* 415 /*
413 * Entering passive mode 416 * Entering passive mode
414 */ 417 */
415 if (ftpcmd("PASV", NULL, sfp, buf) != 227) { 418 if (ftpcmd("PASV", NULL, sfp) != 227) {
416 pasv_error: 419 pasv_error:
417 bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(buf)); 420 bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf));
418 } 421 }
419 // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage] 422 // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]
420 // Server's IP is N1.N2.N3.N4 (we ignore it) 423 // Server's IP is N1.N2.N3.N4 (we ignore it)
421 // Server's port for data connection is P1*256+P2 424 // Server's port for data connection is P1*256+P2
422 str = strrchr(buf, ')'); 425 str = strrchr(G.wget_buf, ')');
423 if (str) str[0] = '\0'; 426 if (str) str[0] = '\0';
424 str = strrchr(buf, ','); 427 str = strrchr(G.wget_buf, ',');
425 if (!str) goto pasv_error; 428 if (!str) goto pasv_error;
426 port = xatou_range(str+1, 0, 255); 429 port = xatou_range(str+1, 0, 255);
427 *str = '\0'; 430 *str = '\0';
428 str = strrchr(buf, ','); 431 str = strrchr(G.wget_buf, ',');
429 if (!str) goto pasv_error; 432 if (!str) goto pasv_error;
430 port += xatou_range(str+1, 0, 255) * 256; 433 port += xatou_range(str+1, 0, 255) * 256;
431 set_nport(lsa, htons(port)); 434 set_nport(lsa, htons(port));
@@ -433,20 +436,19 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
433 *dfpp = open_socket(lsa); 436 *dfpp = open_socket(lsa);
434 437
435 if (G.beg_range) { 438 if (G.beg_range) {
436 sprintf(buf, "REST %"OFF_FMT"u", G.beg_range); 439 sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range);
437 if (ftpcmd(buf, NULL, sfp, buf) == 350) 440 if (ftpcmd(G.wget_buf, NULL, sfp) == 350)
438 G.content_len -= G.beg_range; 441 G.content_len -= G.beg_range;
439 } 442 }
440 443
441 if (ftpcmd("RETR ", target->path, sfp, buf) > 150) 444 if (ftpcmd("RETR ", target->path, sfp) > 150)
442 bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(buf)); 445 bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(G.wget_buf));
443 446
444 return sfp; 447 return sfp;
445} 448}
446 449
447static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) 450static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
448{ 451{
449 char buf[512];
450#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 452#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
451# if ENABLE_FEATURE_WGET_TIMEOUT 453# if ENABLE_FEATURE_WGET_TIMEOUT
452 unsigned second_cnt; 454 unsigned second_cnt;
@@ -468,9 +470,9 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
468 int n; 470 int n;
469 unsigned rdsz; 471 unsigned rdsz;
470 472
471 rdsz = sizeof(buf); 473 rdsz = sizeof(G.wget_buf);
472 if (G.got_clen) { 474 if (G.got_clen) {
473 if (G.content_len < (off_t)sizeof(buf)) { 475 if (G.content_len < (off_t)sizeof(G.wget_buf)) {
474 if ((int)G.content_len <= 0) 476 if ((int)G.content_len <= 0)
475 break; 477 break;
476 rdsz = (unsigned)G.content_len; 478 rdsz = (unsigned)G.content_len;
@@ -493,7 +495,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
493 progress_meter(PROGRESS_BUMP); 495 progress_meter(PROGRESS_BUMP);
494 } 496 }
495#endif 497#endif
496 n = safe_fread(buf, rdsz, dfp); 498 n = safe_fread(G.wget_buf, rdsz, dfp);
497 if (n <= 0) { 499 if (n <= 0) {
498 if (ferror(dfp)) { 500 if (ferror(dfp)) {
499 /* perror will not work: ferror doesn't set errno */ 501 /* perror will not work: ferror doesn't set errno */
@@ -501,7 +503,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
501 } 503 }
502 break; 504 break;
503 } 505 }
504 xwrite(output_fd, buf, n); 506 xwrite(output_fd, G.wget_buf, n);
505#if ENABLE_FEATURE_WGET_STATUSBAR 507#if ENABLE_FEATURE_WGET_STATUSBAR
506 G.transferred += n; 508 G.transferred += n;
507 progress_meter(PROGRESS_BUMP); 509 progress_meter(PROGRESS_BUMP);
@@ -513,10 +515,10 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
513 if (!G.chunked) 515 if (!G.chunked)
514 break; 516 break;
515 517
516 safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */ 518 safe_fgets(G.wget_buf, sizeof(G.wget_buf), dfp); /* This is a newline */
517 get_clen: 519 get_clen:
518 safe_fgets(buf, sizeof(buf), dfp); 520 safe_fgets(G.wget_buf, sizeof(G.wget_buf), dfp);
519 G.content_len = STRTOOFF(buf, NULL, 16); 521 G.content_len = STRTOOFF(G.wget_buf, NULL, 16);
520 /* FIXME: error check? */ 522 /* FIXME: error check? */
521 if (G.content_len == 0) 523 if (G.content_len == 0)
522 break; /* all done! */ 524 break; /* all done! */
@@ -529,7 +531,6 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
529int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 531int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
530int wget_main(int argc UNUSED_PARAM, char **argv) 532int wget_main(int argc UNUSED_PARAM, char **argv)
531{ 533{
532 char buf[512];
533 struct host_info server, target; 534 struct host_info server, target;
534 len_and_sockaddr *lsa; 535 len_and_sockaddr *lsa;
535 unsigned opt; 536 unsigned opt;
@@ -709,11 +710,11 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
709#if ENABLE_FEATURE_WGET_AUTHENTICATION 710#if ENABLE_FEATURE_WGET_AUTHENTICATION
710 if (target.user) { 711 if (target.user) {
711 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, 712 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6,
712 base64enc_512(buf, target.user)); 713 base64enc(target.user));
713 } 714 }
714 if (use_proxy && server.user) { 715 if (use_proxy && server.user) {
715 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", 716 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
716 base64enc_512(buf, server.user)); 717 base64enc(server.user));
717 } 718 }
718#endif 719#endif
719 720
@@ -743,10 +744,10 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
743 * Retrieve HTTP response line and check for "200" status code. 744 * Retrieve HTTP response line and check for "200" status code.
744 */ 745 */
745 read_response: 746 read_response:
746 if (fgets(buf, sizeof(buf), sfp) == NULL) 747 if (fgets(G.wget_buf, sizeof(G.wget_buf), sfp) == NULL)
747 bb_error_msg_and_die("no response from server"); 748 bb_error_msg_and_die("no response from server");
748 749
749 str = buf; 750 str = G.wget_buf;
750 str = skip_non_whitespace(str); 751 str = skip_non_whitespace(str);
751 str = skip_whitespace(str); 752 str = skip_whitespace(str);
752 // FIXME: no error check 753 // FIXME: no error check
@@ -755,7 +756,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
755 switch (status) { 756 switch (status) {
756 case 0: 757 case 0:
757 case 100: 758 case 100:
758 while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL) 759 while (gethdr(sfp /*, &n*/) != NULL)
759 /* eat all remaining headers */; 760 /* eat all remaining headers */;
760 goto read_response; 761 goto read_response;
761 case 200: 762 case 200:
@@ -795,13 +796,13 @@ However, in real world it was observed that some web servers
795 break; 796 break;
796 /* fall through */ 797 /* fall through */
797 default: 798 default:
798 bb_error_msg_and_die("server returned error: %s", sanitize_string(buf)); 799 bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf));
799 } 800 }
800 801
801 /* 802 /*
802 * Retrieve HTTP headers. 803 * Retrieve HTTP headers.
803 */ 804 */
804 while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) { 805 while ((str = gethdr(sfp /*, &n*/)) != NULL) {
805 /* gethdr converted "FOO:" string to lowercase */ 806 /* gethdr converted "FOO:" string to lowercase */
806 smalluint key; 807 smalluint key;
807 /* strip trailing whitespace */ 808 /* strip trailing whitespace */
@@ -810,7 +811,7 @@ However, in real world it was observed that some web servers
810 *s = '\0'; 811 *s = '\0';
811 s--; 812 s--;
812 } 813 }
813 key = index_in_strings(keywords, buf) + 1; 814 key = index_in_strings(keywords, G.wget_buf) + 1;
814 if (key == KEY_content_length) { 815 if (key == KEY_content_length) {
815 G.content_len = BB_STRTOOFF(str, NULL, 10); 816 G.content_len = BB_STRTOOFF(str, NULL, 10);
816 if (G.content_len < 0 || errno) { 817 if (G.content_len < 0 || errno) {
@@ -881,9 +882,9 @@ However, in real world it was observed that some web servers
881 if (dfp != sfp) { 882 if (dfp != sfp) {
882 /* It's ftp. Close it properly */ 883 /* It's ftp. Close it properly */
883 fclose(dfp); 884 fclose(dfp);
884 if (ftpcmd(NULL, NULL, sfp, buf) != 226) 885 if (ftpcmd(NULL, NULL, sfp) != 226)
885 bb_error_msg_and_die("ftp error: %s", sanitize_string(buf+4)); 886 bb_error_msg_and_die("ftp error: %s", sanitize_string(G.wget_buf + 4));
886 /* ftpcmd("QUIT", NULL, sfp, buf); - why bother? */ 887 /* ftpcmd("QUIT", NULL, sfp); - why bother? */
887 } 888 }
888 889
889 return EXIT_SUCCESS; 890 return EXIT_SUCCESS;