[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    [PATCH v2 2/2] wget: add support for retries in http requests
From:       Martin Lewis <martin.lewis.x84 () gmail ! com>
Date:       2019-01-15 11:05:11
Message-ID: CA+nwWBvnJqS5iVZvSbwY0bu1rPFU3DkvwHLSy4=auW-25buSEA () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


Replace die handlers with error returning so download_one_url can retry
from the beginning.
When retries is 1 (default) the behaviour should be the same as before.

v2: updated diff to mind the -o option, prettified help

Signed-off-by: Martin Lewis <martin.lewis.x84@gmail.com>
---
 networking/wget.c | 125
++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 98 insertions(+), 27 deletions(-)

diff --git a/networking/wget.c b/networking/wget.c
index d11b201..b41f8ed 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -125,13 +125,14 @@
 //usage:       "[-c|--continue] [--spider] [-q|--quiet]
[-O|--output-document FILE]\n"
 //usage:       "    [-o|--output-file FILE] [--header 'header: value']
[-Y|--proxy on/off]\n"
 /* Since we ignore these opts, we don't show them in --help */
-/* //usage:    "    [--no-check-certificate] [--no-cache] [--passive-ftp]
[-t TRIES]" */
+/* //usage:    "    [--no-check-certificate] [--no-cache] [--passive-ftp]"
*/
 /* //usage:    "    [-nv] [-nc] [-nH] [-np]" */
-//usage:       "    [-P DIR] [-S|--server-response] [-U|--user-agent
AGENT]" IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..."
+//usage:       "    [-t|--tries TRIES] [-P DIR] [-S|--server-response]\n"
+//usage:       "    [-U|--user-agent AGENT]" IF_FEATURE_WGET_TIMEOUT(" [-T
SEC]") " URL..."
 //usage:    )
 //usage:    IF_NOT_FEATURE_WGET_LONG_OPTIONS(
-//usage:       "[-cq] [-O FILE] [-o FILE] [-Y on/off] [-P DIR] [-S] [-U
AGENT]"
-//usage:            IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..."
+//usage:       "[-cq] [-O FILE] [-o FILE] [-Y on/off] [-P DIR] [-S] [-U
AGENT]\n"
+//usage:       "        [-t TRIES]" IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") "
URL..."
 //usage:    )
 //usage:#define wget_full_usage "\n\n"
 //usage:       "Retrieve files via HTTP or FTP\n"
@@ -150,6 +151,7 @@
 //usage:     "\n    -o FILE        Log messages to FILE"
 //usage:     "\n    -U STR        Use STR for User-Agent header"
 //usage:     "\n    -Y on/off    Use proxy"
+//usage:     "\n    -t TRIES    Set number of retries to TRIES (0
unlimits)"

 #include "libbb.h"

@@ -235,6 +237,7 @@ struct globals {
     char *fname_log;        /* where to direct log (-o) */
     const char *proxy_flag; /* Use proxies if env vars are set */
     const char *user_agent; /* "User-Agent" header field */
+    unsigned tries; /* For -t option */
     int output_fd;
     int log_fd;
     int o_flags;
@@ -410,6 +413,7 @@ static int is_ip_address(const char *string)
 }
 #endif

+/* Return NULL if connect() fails */
 static FILE *open_socket(len_and_sockaddr *lsa)
 {
     int fd;
@@ -417,13 +421,19 @@ static FILE *open_socket(len_and_sockaddr *lsa)
 #if ENABLE_FEATURE_WGET_TIMEOUT
     struct timeval timeout = {G.timeout_seconds, 0};
 #endif
+
     fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
 #if ENABLE_FEATURE_WGET_TIMEOUT
     if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof
(timeout)) < 0) {
         bb_perror_msg_and_die("setsockopt failed\n");
     }
 #endif
-    xconnect(fd, &lsa->u.sa, lsa->len);
+    if (connect(fd, &lsa->u.sa, lsa->len) < 0) {
+        /* Failure */
+        bb_perror_msg("connect failed");
+        close(fd);
+        return NULL;
+    }

     /* glibc 2.4 seems to try seeking on it - ??! */
     /* hopefully it understands what ESPIPE means... */
@@ -592,14 +602,16 @@ static int fread_buffered(char *buffer, size_t len,
FILE *fp)
     return fread(buffer, 1, len, fp);
 }

-/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */
-static char fgets_trim_sanitize(FILE *fp, const char *fmt)
+/* Returns '\n' if it was seen, -1 if timeout occured, else '\0'. Trims at
first '\r' or '\n' */
+static signed char fgets_trim_sanitize(FILE *fp, const char *fmt)
 {
     char c;
     char *buf_ptr;

-    if (fgets_read_to_newline(G.wget_buf, sizeof(G.wget_buf), fp) == NULL)
-        bb_perror_msg_and_die("error getting response");
+    if (fgets_read_to_newline(G.wget_buf, sizeof(G.wget_buf), fp) == NULL)
{
+        bb_perror_msg("error getting response");
+        return -1;
+    }

     buf_ptr = strchrnul(G.wget_buf, '\n');
     c = *buf_ptr;
@@ -637,7 +649,9 @@ static int ftpcmd(const char *s1, const char *s2, FILE
*fp)
     /* Read until "Nxx something" is received */
     G.wget_buf[3] = 0;
     do {
-        fgets_trim_sanitize(fp, "%s\n");
+        if (fgets_trim_sanitize(fp, "%s\n") == -1) {
+            xfunc_die();
+        }
     } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');

     G.wget_buf[3] = '\0';
@@ -742,6 +756,11 @@ static char *get_sanitized_hdr(FILE *fp)
     /* retrieve header line */
     c = fgets_trim_sanitize(fp, "  %s\n");

+    if (c == -1) {
+        /* Timed out */
+        return NULL;
+    }
+
     /* end of the headers? */
     if (G.wget_buf[0] == '\0')
         return NULL;
@@ -924,7 +943,11 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct
host_info *target, len_and_
     char *pass;
     int port;

+    /* TODO: Add retry support for ftp */
     sfp = open_socket(lsa);
+    if (!sfp) {
+        xfunc_die();
+    }
 #if ENABLE_FEATURE_WGET_HTTPS
     if (target->protocol == P_FTPS)
         spawn_ssl_client(target->host, fileno(sfp),
TLSLOOP_EXIT_ON_LOCAL_EOF);
@@ -979,7 +1002,11 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct
host_info *target, len_and_

     set_nport(&lsa->u.sa, htons(port));

+    /* TODO: Add retry support for ftp */
     *dfpp = open_socket(lsa);
+    if (!*dfpp) {
+        xfunc_die();
+    }

 #if ENABLE_FEATURE_WGET_HTTPS
     if (target->protocol == P_FTPS) {
@@ -1008,7 +1035,8 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct
host_info *target, len_and_
     return sfp;
 }

-static void NOINLINE retrieve_file_data(FILE *dfp)
+/* Return -1 if times out so we can retry */
+static int NOINLINE retrieve_file_data(FILE *dfp)
 {
 #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
 # if ENABLE_FEATURE_WGET_TIMEOUT
@@ -1065,6 +1093,8 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
                     rdsz = (unsigned)G.content_len;
                 }
             }
+            /* We probably have some data in fgets_buffer, so we need to
+               flush it first */
             n = fread_buffered(G.wget_buf, rdsz, dfp);

             if (n > 0) {
@@ -1105,7 +1135,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
 # if ENABLE_FEATURE_WGET_TIMEOUT
                 if (second_cnt != 0 && --second_cnt == 0) {
                     progress_meter(PROGRESS_END);
-                    bb_error_msg_and_die("download timed out");
+                    return -1;
                 }
 # endif
                 /* We used to loop back to poll here,
@@ -1129,7 +1159,9 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
             break;

         /* Each chunk ends with "\r\n" - eat it */
-        fgets_trim_sanitize(dfp, NULL);
+        if (fgets_trim_sanitize(dfp, NULL) == -1 ) {
+            return -1;
+        }
  get_clen:
         /* chunk size format is "HEXNUM[;name[=val]]\r\n" */
         fgets_trim_sanitize(dfp, NULL);
@@ -1172,6 +1204,8 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
         fprintf(stderr, "written to stdout\n");
     else
         fprintf(stderr, "'%s' saved\n", G.fname_out);
+
+    return 0;
 }

 static void download_one_url(const char *url)
@@ -1181,6 +1215,7 @@ static void download_one_url(const char *url)
     len_and_sockaddr *lsa;
     FILE *sfp;                      /* socket to web/ftp server         */
     FILE *dfp;                      /* socket to ftp server (data)      */
+    unsigned cur_tries = 0;         /* number of tries so far           */
     char *fname_out_alloc;
     char *redirected_path = NULL;
     struct host_info server;
@@ -1246,9 +1281,21 @@ static void download_one_url(const char *url)
          * We are not sure it exists on remote side */
     }

+ retry:
+    cur_tries++;
+    if (G.tries != 0 && cur_tries > G.tries) {
+        if (G.tries != 1) /* Show message about the tries only if was set
to more than one */
+            bb_error_msg_and_die("Gave up after %u tries", G.tries);
+        else
+            xfunc_die();
+    }
     redir_limit = 5;
  resolve_lsa:
-    lsa = xhost2sockaddr(server.host, server.port);
+    /* If DNS resolution fails, retry, don't die */
+    lsa = host2sockaddr(server.host, server.port);
+    if (!lsa)
+        goto retry;
+
     if (!(option_mask32 & WGET_OPT_QUIET)) {
         char *s = xmalloc_sockaddr2dotted(&lsa->u.sa);
         fprintf(stderr, "Connecting to %s (%s)\n", server.host, s);
@@ -1278,6 +1325,8 @@ static void download_one_url(const char *url)
 # if ENABLE_FEATURE_WGET_HTTPS
             if (fd < 0) { /* no openssl? try internal */
                 sfp = open_socket(lsa);
+                if (!sfp)
+                    goto retry;
                 spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0);
                 goto socket_opened;
             }
@@ -1290,15 +1339,22 @@ static void download_one_url(const char *url)
             goto socket_opened;
         }
         sfp = open_socket(lsa);
+        if (!sfp) {
+            goto retry;
+        }
  socket_opened:
 #elif ENABLE_FEATURE_WGET_HTTPS
         /* Only internal TLS support is configured */
         sfp = open_socket(lsa);
-        if (server.protocol == P_HTTPS)
+        if (!sfp)
+            goto retry;
+        if (server.protocol == P_HTTPS) {
             spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0);
 #else
         /* ssl (https) support is not configured */
         sfp = open_socket(lsa);
+        if (!sfp)
+            goto retry;
 #endif
         /* Send HTTP request */
         if (use_proxy) {
@@ -1374,7 +1430,11 @@ static void download_one_url(const char *url)
          * Retrieve HTTP response line and check for "200" status code.
          */
  read_response:
-        fgets_trim_sanitize(sfp, "  %s\n");
+        if (fgets_trim_sanitize(sfp, "  %s\n") == -1) {
+            /* Timed out */
+            bb_error_msg("timed out");
+            goto retry;
+        }

         str = G.wget_buf;
         str = skip_non_whitespace(str);
@@ -1449,7 +1509,8 @@ However, in real world it was observed that some web
servers
             /* Partial Content even though we did not ask for it??? */
             /* fall through */
         default:
-            bb_error_msg_and_die("server returned error: %s", G.wget_buf);
+            bb_error_msg("server returned error: %s", G.wget_buf);
+            goto retry;
         }

         /*
@@ -1475,19 +1536,24 @@ However, in real world it was observed that some
web servers
             if (key == KEY_content_length) {
                 G.content_len = BB_STRTOOFF(str, NULL, 10);
                 if (G.content_len < 0 || errno) {
-                    bb_error_msg_and_die("content-length %s is garbage",
str);
+                    bb_error_msg("content-length %s is garbage", str);
+                    goto retry;
                 }
                 G.got_clen = 1;
                 continue;
             }
             if (key == KEY_transfer_encoding) {
-                if (strcmp(str_tolower(str), "chunked") != 0)
-                    bb_error_msg_and_die("transfer encoding '%s' is not
supported", str);
+                if (strcmp(str_tolower(str), "chunked") != 0) {
+                    bb_error_msg("transfer encoding '%s' is not
supported", str);
+                    goto retry;
+                }
                 G.chunked = 1;
             }
             if (key == KEY_location && status >= 300) {
-                if (--redir_limit == 0)
-                    bb_error_msg_and_die("too many redirections");
+                if (--redir_limit == 0) {
+                    bb_error_msg("too many redirections");
+                    goto retry;
+                }
                 fclose(sfp);
                 if (str[0] == '/') {
                     free(redirected_path);
@@ -1526,13 +1592,18 @@ However, in real world it was observed that some
web servers
     free(lsa);

     if (!(option_mask32 & WGET_OPT_SPIDER)) {
+        int retrieve_retval;
         if (G.output_fd < 0)
             G.output_fd = xopen(G.fname_out, G.o_flags);
-        retrieve_file_data(dfp);
+        retrieve_retval = retrieve_file_data(dfp);
         if (!(option_mask32 & WGET_OPT_OUTNAME)) {
             xclose(G.output_fd);
             G.output_fd = -1;
         }
+        if (retrieve_retval < 0) { /* We timed out, if we retry so the fd
is closed */
+            bb_error_msg("download timed out");
+            goto retry;
+        }
     } else {
         fprintf(stderr, "remote file exists\n");
     }
@@ -1570,8 +1641,8 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
         "user-agent\0"       Required_argument "U"
 IF_FEATURE_WGET_TIMEOUT(
         "timeout\0"          Required_argument "T")
+        "tries\0"            Required_argument "t"
         /* Ignored: */
-IF_DESKTOP(    "tries\0"            Required_argument "t")
         "header\0"           Required_argument "\xff"
         "post-data\0"        Required_argument "\xfe"
         "spider\0"           No_argument       "\xfd"
@@ -1601,14 +1672,14 @@ IF_DESKTOP(    "no-parent\0"
No_argument       "\xf0")
 #if ENABLE_FEATURE_WGET_TIMEOUT
     G.timeout_seconds = 900;
 #endif
+    G.tries = 1;
     G.proxy_flag = "on";   /* use proxies if env vars are set */
     G.user_agent = "Wget"; /* "User-Agent" header field */

 #if ENABLE_FEATURE_WGET_LONG_OPTIONS
 #endif
     GETOPT32(argv, "^"
-        "cqSO:o:P:Y:U:T:+"
-        /*ignored:*/ "t:"
+        "cqSO:o:P:Y:U:T:+t:+"
         /*ignored:*/ "n::"
         /* wget has exactly four -n<letter> opts, all of which we can
ignore:
          * -nv --no-verbose: be moderately quiet (-q is full quiet)
@@ -1625,7 +1696,7 @@ IF_DESKTOP(    "no-parent\0"        No_argument
"\xf0")
         , &G.fname_out, &G.fname_log, &G.dir_prefix,
         &G.proxy_flag, &G.user_agent,
         IF_FEATURE_WGET_TIMEOUT(&G.timeout_seconds)
IF_NOT_FEATURE_WGET_TIMEOUT(NULL),
-        NULL, /* -t RETRIES */
+        &G.tries, /* -t RETRIES */
         NULL  /* -n[ARG] */
         IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist)
         IF_FEATURE_WGET_LONG_OPTIONS(, &G.post_data)
-- 
1.9.1

[Attachment #5 (text/html)]

<div dir="ltr"><div dir="ltr"><div dir="ltr">Replace die handlers with error \
returning so download_one_url can retry from the beginning.<br>When retries is 1 \
(default) the behaviour should be the same as before.<br><br>v2: updated diff to mind \
the -o option, prettified help<br><br>Signed-off-by: Martin Lewis &lt;<a \
href="mailto:martin.lewis.x84@gmail.com">martin.lewis.x84@gmail.com</a>&gt;<br>---<br> \
networking/wget.c | 125 ++++++++++++++++++++++++++++++++++++++++++------------<br> 1 \
file changed, 98 insertions(+), 27 deletions(-)<br><br>diff --git a/networking/wget.c \
b/networking/wget.c<br>index d11b201..b41f8ed 100644<br>--- \
a/networking/wget.c<br>+++ b/networking/wget.c<br>@@ -125,13 +125,14 @@<br> //usage:  \
&quot;[-c|--continue] [--spider] [-q|--quiet] [-O|--output-document FILE]\n&quot;<br> \
//usage:       &quot;    [-o|--output-file FILE] [--header &#39;header: value&#39;] \
[-Y|--proxy on/off]\n&quot;<br> /* Since we ignore these opts, we don&#39;t show them \
in --help */<br>-/* //usage:    &quot;    [--no-check-certificate] [--no-cache] \
[--passive-ftp] [-t TRIES]&quot; */<br>+/* //usage:    &quot;    \
[--no-check-certificate] [--no-cache] [--passive-ftp]&quot; */<br> /* //usage:    \
&quot;    [-nv] [-nc] [-nH] [-np]&quot; */<br>-//usage:       &quot;    [-P DIR] \
[-S|--server-response] [-U|--user-agent AGENT]&quot; IF_FEATURE_WGET_TIMEOUT(&quot; \
[-T SEC]&quot;) &quot; URL...&quot;<br>+//usage:       &quot;    [-t|--tries TRIES] \
[-P DIR] [-S|--server-response]\n&quot;<br>+//usage:       &quot;    [-U|--user-agent \
AGENT]&quot; IF_FEATURE_WGET_TIMEOUT(&quot; [-T SEC]&quot;) &quot; URL...&quot;<br> \
//usage:    )<br> //usage:    IF_NOT_FEATURE_WGET_LONG_OPTIONS(<br>-//usage:       \
&quot;[-cq] [-O FILE] [-o FILE] [-Y on/off] [-P DIR] [-S] [-U \
AGENT]&quot;<br>-//usage:            IF_FEATURE_WGET_TIMEOUT(&quot; [-T SEC]&quot;) \
&quot; URL...&quot;<br>+//usage:       &quot;[-cq] [-O FILE] [-o FILE] [-Y on/off] \
[-P DIR] [-S] [-U AGENT]\n&quot;<br>+//usage:       &quot;        [-t TRIES]&quot; \
IF_FEATURE_WGET_TIMEOUT(&quot; [-T SEC]&quot;) &quot; URL...&quot;<br> //usage:    \
)<br> //usage:#define wget_full_usage &quot;\n\n&quot;<br> //usage:       \
&quot;Retrieve files via HTTP or FTP\n&quot;<br>@@ -150,6 +151,7 @@<br> //usage:     \
&quot;\n    -o FILE        Log messages to FILE&quot;<br> //usage:     &quot;\n    -U \
STR        Use STR for User-Agent header&quot;<br> //usage:     &quot;\n    -Y on/off \
Use proxy&quot;<br>+//usage:     &quot;\n    -t TRIES    Set number of retries to \
TRIES (0 unlimits)&quot;<br> <br> #include &quot;libbb.h&quot;<br> <br>@@ -235,6 \
+237,7 @@ struct globals {<br>     char *fname_log;        /* where to direct log \
(-o) */<br>     const char *proxy_flag; /* Use proxies if env vars are set */<br>     \
const char *user_agent; /* &quot;User-Agent&quot; header field */<br>+    unsigned \
tries; /* For -t option */<br>     int output_fd;<br>     int log_fd;<br>     int \
o_flags;<br>@@ -410,6 +413,7 @@ static int is_ip_address(const char *string)<br> \
}<br> #endif<br> <br>+/* Return NULL if connect() fails */<br> static FILE \
*open_socket(len_and_sockaddr *lsa)<br> {<br>     int fd;<br>@@ -417,13 +421,19 @@ \
static FILE *open_socket(len_and_sockaddr *lsa)<br> #if \
ENABLE_FEATURE_WGET_TIMEOUT<br>     struct timeval timeout = {G.timeout_seconds, \
0};<br> #endif<br>+<br>     fd = xsocket(lsa-&gt;u.sa.sa_family, SOCK_STREAM, 0);<br> \
#if ENABLE_FEATURE_WGET_TIMEOUT<br>     if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, \
&amp;timeout, sizeof (timeout)) &lt; 0) {<br>         \
bb_perror_msg_and_die(&quot;setsockopt failed\n&quot;);<br>     }<br> #endif<br>-    \
xconnect(fd, &amp;lsa-&gt;<a href="http://u.sa">u.sa</a>, lsa-&gt;len);<br>+    if \
(connect(fd, &amp;lsa-&gt;<a href="http://u.sa">u.sa</a>, lsa-&gt;len) &lt; 0) {<br>+ \
/* Failure */<br>+        bb_perror_msg(&quot;connect failed&quot;);<br>+        \
close(fd);<br>+        return NULL;<br>+    }<br> <br>     /* glibc 2.4 seems to try \
seeking on it - ??! */<br>     /* hopefully it understands what ESPIPE means... \
*/<br>@@ -592,14 +602,16 @@ static int fread_buffered(char *buffer, size_t len, FILE \
*fp)<br>     return fread(buffer, 1, len, fp);<br> }<br> <br>-/* Returns &#39;\n&#39; \
if it was seen, else &#39;\0&#39;. Trims at first &#39;\r&#39; or &#39;\n&#39; \
*/<br>-static char fgets_trim_sanitize(FILE *fp, const char *fmt)<br>+/* Returns \
&#39;\n&#39; if it was seen, -1 if timeout occured, else &#39;\0&#39;. Trims at first \
&#39;\r&#39; or &#39;\n&#39; */<br>+static signed char fgets_trim_sanitize(FILE *fp, \
const char *fmt)<br> {<br>     char c;<br>     char *buf_ptr;<br> <br>-    if \
(fgets_read_to_newline(G.wget_buf, sizeof(G.wget_buf), fp) == NULL)<br>-        \
bb_perror_msg_and_die(&quot;error getting response&quot;);<br>+    if \
(fgets_read_to_newline(G.wget_buf, sizeof(G.wget_buf), fp) == NULL) {<br>+        \
bb_perror_msg(&quot;error getting response&quot;);<br>+        return -1;<br>+    \
}<br> <br>     buf_ptr = strchrnul(G.wget_buf, &#39;\n&#39;);<br>     c = \
*buf_ptr;<br>@@ -637,7 +649,9 @@ static int ftpcmd(const char *s1, const char *s2, \
FILE *fp)<br>     /* Read until &quot;Nxx something&quot; is received */<br>     \
G.wget_buf[3] = 0;<br>     do {<br>-        fgets_trim_sanitize(fp, \
&quot;%s\n&quot;);<br>+        if (fgets_trim_sanitize(fp, &quot;%s\n&quot;) == -1) \
{<br>+            xfunc_die();<br>+        }<br>     } while (!isdigit(G.wget_buf[0]) \
|| G.wget_buf[3] != &#39; &#39;);<br> <br>     G.wget_buf[3] = &#39;\0&#39;;<br>@@ \
-742,6 +756,11 @@ static char *get_sanitized_hdr(FILE *fp)<br>     /* retrieve header \
line */<br>     c = fgets_trim_sanitize(fp, &quot;  %s\n&quot;);<br> <br>+    if (c \
== -1) {<br>+        /* Timed out */<br>+        return NULL;<br>+    }<br>+<br>     \
/* end of the headers? */<br>     if (G.wget_buf[0] == &#39;\0&#39;)<br>         \
return NULL;<br>@@ -924,7 +943,11 @@ static FILE* prepare_ftp_session(FILE **dfpp, \
struct host_info *target, len_and_<br>     char *pass;<br>     int port;<br> <br>+    \
/* TODO: Add retry support for ftp */<br>     sfp = open_socket(lsa);<br>+    if \
(!sfp) {<br>+        xfunc_die();<br>+    }<br> #if ENABLE_FEATURE_WGET_HTTPS<br>     \
if (target-&gt;protocol == P_FTPS)<br>         spawn_ssl_client(target-&gt;host, \
fileno(sfp), TLSLOOP_EXIT_ON_LOCAL_EOF);<br>@@ -979,7 +1002,11 @@ static FILE* \
prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_<br> <br>     \
set_nport(&amp;lsa-&gt;<a href="http://u.sa">u.sa</a>, htons(port));<br> <br>+    /* \
TODO: Add retry support for ftp */<br>     *dfpp = open_socket(lsa);<br>+    if \
(!*dfpp) {<br>+        xfunc_die();<br>+    }<br> <br> #if \
ENABLE_FEATURE_WGET_HTTPS<br>     if (target-&gt;protocol == P_FTPS) {<br>@@ -1008,7 \
+1035,8 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, \
len_and_<br>     return sfp;<br> }<br> <br>-static void NOINLINE \
retrieve_file_data(FILE *dfp)<br>+/* Return -1 if times out so we can retry \
*/<br>+static int NOINLINE retrieve_file_data(FILE *dfp)<br> {<br> #if \
ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT<br> # if \
ENABLE_FEATURE_WGET_TIMEOUT<br>@@ -1065,6 +1093,8 @@ static void NOINLINE \
retrieve_file_data(FILE *dfp)<br>                     rdsz = \
(unsigned)G.content_len;<br>                 }<br>             }<br>+            /* \
We probably have some data in fgets_buffer, so we need to<br>+               flush it \
first */<br>             n = fread_buffered(G.wget_buf, rdsz, dfp);<br> <br>          \
if (n &gt; 0) {<br>@@ -1105,7 +1135,7 @@ static void NOINLINE retrieve_file_data(FILE \
*dfp)<br> # if ENABLE_FEATURE_WGET_TIMEOUT<br>                 if (second_cnt != 0 \
&amp;&amp; --second_cnt == 0) {<br>                     \
progress_meter(PROGRESS_END);<br>-                    \
bb_error_msg_and_die(&quot;download timed out&quot;);<br>+                    return \
-1;<br>                 }<br> # endif<br>                 /* We used to loop back to \
poll here,<br>@@ -1129,7 +1159,9 @@ static void NOINLINE retrieve_file_data(FILE \
*dfp)<br>             break;<br> <br>         /* Each chunk ends with \
&quot;\r\n&quot; - eat it */<br>-        fgets_trim_sanitize(dfp, NULL);<br>+        \
if (fgets_trim_sanitize(dfp, NULL) == -1 ) {<br>+            return -1;<br>+        \
}<br>  get_clen:<br>         /* chunk size format is \
&quot;HEXNUM[;name[=val]]\r\n&quot; */<br>         fgets_trim_sanitize(dfp, \
NULL);<br>@@ -1172,6 +1204,8 @@ static void NOINLINE retrieve_file_data(FILE \
*dfp)<br>         fprintf(stderr, &quot;written to stdout\n&quot;);<br>     else<br>  \
fprintf(stderr, &quot;&#39;%s&#39; saved\n&quot;, G.fname_out);<br>+<br>+    return \
0;<br> }<br> <br> static void download_one_url(const char *url)<br>@@ -1181,6 +1215,7 \
@@ static void download_one_url(const char *url)<br>     len_and_sockaddr *lsa;<br>   \
FILE *sfp;                      /* socket to web/ftp server         */<br>     FILE \
*dfp;                      /* socket to ftp server (data)      */<br>+    unsigned \
cur_tries = 0;         /* number of tries so far           */<br>     char \
*fname_out_alloc;<br>     char *redirected_path = NULL;<br>     struct host_info \
server;<br>@@ -1246,9 +1281,21 @@ static void download_one_url(const char *url)<br>   \
* We are not sure it exists on remote side */<br>     }<br> <br>+ retry:<br>+    \
cur_tries++;<br>+    if (G.tries != 0 &amp;&amp; cur_tries &gt; G.tries) {<br>+       \
if (G.tries != 1) /* Show message about the tries only if was set to more than one \
*/<br>+            bb_error_msg_and_die(&quot;Gave up after %u tries&quot;, \
G.tries);<br>+        else<br>+            xfunc_die();<br>+    }<br>     redir_limit \
= 5;<br>  resolve_lsa:<br>-    lsa = xhost2sockaddr(server.host, server.port);<br>+   \
/* If DNS resolution fails, retry, don&#39;t die */<br>+    lsa = \
host2sockaddr(server.host, server.port);<br>+    if (!lsa)<br>+        goto \
retry;<br>+<br>     if (!(option_mask32 &amp; WGET_OPT_QUIET)) {<br>         char *s \
= xmalloc_sockaddr2dotted(&amp;lsa-&gt;<a href="http://u.sa">u.sa</a>);<br>         \
fprintf(stderr, &quot;Connecting to %s (%s)\n&quot;, server.host, s);<br>@@ -1278,6 \
+1325,8 @@ static void download_one_url(const char *url)<br> # if \
ENABLE_FEATURE_WGET_HTTPS<br>             if (fd &lt; 0) { /* no openssl? try \
internal */<br>                 sfp = open_socket(lsa);<br>+                if \
(!sfp)<br>+                    goto retry;<br>                 \
spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0);<br>                 goto \
socket_opened;<br>             }<br>@@ -1290,15 +1339,22 @@ static void \
download_one_url(const char *url)<br>             goto socket_opened;<br>         \
}<br>         sfp = open_socket(lsa);<br>+        if (!sfp) {<br>+            goto \
retry;<br>+        }<br>  socket_opened:<br> #elif ENABLE_FEATURE_WGET_HTTPS<br>      \
/* Only internal TLS support is configured */<br>         sfp = \
open_socket(lsa);<br>-        if (server.protocol == P_HTTPS)<br>+        if \
(!sfp)<br>+            goto retry;<br>+        if (server.protocol == P_HTTPS) {<br>  \
spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0);<br> #else<br>         /* ssl \
(https) support is not configured */<br>         sfp = open_socket(lsa);<br>+        \
if (!sfp)<br>+            goto retry;<br> #endif<br>         /* Send HTTP request \
*/<br>         if (use_proxy) {<br>@@ -1374,7 +1430,11 @@ static void \
download_one_url(const char *url)<br>          * Retrieve HTTP response line and \
check for &quot;200&quot; status code.<br>          */<br>  read_response:<br>-       \
fgets_trim_sanitize(sfp, &quot;  %s\n&quot;);<br>+        if \
(fgets_trim_sanitize(sfp, &quot;  %s\n&quot;) == -1) {<br>+            /* Timed out \
*/<br>+            bb_error_msg(&quot;timed out&quot;);<br>+            goto \
retry;<br>+        }<br> <br>         str = G.wget_buf;<br>         str = \
skip_non_whitespace(str);<br>@@ -1449,7 +1509,8 @@ However, in real world it was \
observed that some web servers<br>             /* Partial Content even though we did \
not ask for it??? */<br>             /* fall through */<br>         default:<br>-     \
bb_error_msg_and_die(&quot;server returned error: %s&quot;, G.wget_buf);<br>+         \
bb_error_msg(&quot;server returned error: %s&quot;, G.wget_buf);<br>+            goto \
retry;<br>         }<br> <br>         /*<br>@@ -1475,19 +1536,24 @@ However, in real \
world it was observed that some web servers<br>             if (key == \
KEY_content_length) {<br>                 G.content_len = BB_STRTOOFF(str, NULL, \
10);<br>                 if (G.content_len &lt; 0 || errno) {<br>-                    \
bb_error_msg_and_die(&quot;content-length %s is garbage&quot;, str);<br>+             \
bb_error_msg(&quot;content-length %s is garbage&quot;, str);<br>+                    \
goto retry;<br>                 }<br>                 G.got_clen = 1;<br>             \
continue;<br>             }<br>             if (key == KEY_transfer_encoding) {<br>-  \
if (strcmp(str_tolower(str), &quot;chunked&quot;) != 0)<br>-                    \
bb_error_msg_and_die(&quot;transfer encoding &#39;%s&#39; is not supported&quot;, \
str);<br>+                if (strcmp(str_tolower(str), &quot;chunked&quot;) != 0) \
{<br>+                    bb_error_msg(&quot;transfer encoding &#39;%s&#39; is not \
supported&quot;, str);<br>+                    goto retry;<br>+                }<br>  \
G.chunked = 1;<br>             }<br>             if (key == KEY_location &amp;&amp; \
status &gt;= 300) {<br>-                if (--redir_limit == 0)<br>-                  \
bb_error_msg_and_die(&quot;too many redirections&quot;);<br>+                if \
(--redir_limit == 0) {<br>+                    bb_error_msg(&quot;too many \
redirections&quot;);<br>+                    goto retry;<br>+                }<br>    \
fclose(sfp);<br>                 if (str[0] == &#39;/&#39;) {<br>                     \
free(redirected_path);<br>@@ -1526,13 +1592,18 @@ However, in real world it was \
observed that some web servers<br>     free(lsa);<br> <br>     if (!(option_mask32 \
&amp; WGET_OPT_SPIDER)) {<br>+        int retrieve_retval;<br>         if \
(G.output_fd &lt; 0)<br>             G.output_fd = xopen(G.fname_out, \
G.o_flags);<br>-        retrieve_file_data(dfp);<br>+        retrieve_retval = \
retrieve_file_data(dfp);<br>         if (!(option_mask32 &amp; WGET_OPT_OUTNAME)) \
{<br>             xclose(G.output_fd);<br>             G.output_fd = -1;<br>         \
}<br>+        if (retrieve_retval &lt; 0) { /* We timed out, if we retry so the fd is \
closed */<br>+            bb_error_msg(&quot;download timed out&quot;);<br>+          \
goto retry;<br>+        }<br>     } else {<br>         fprintf(stderr, &quot;remote \
file exists\n&quot;);<br>     }<br>@@ -1570,8 +1641,8 @@ int wget_main(int argc \
UNUSED_PARAM, char **argv)<br>         &quot;user-agent\0&quot;       \
Required_argument &quot;U&quot;<br> IF_FEATURE_WGET_TIMEOUT(<br>         \
&quot;timeout\0&quot;          Required_argument &quot;T&quot;)<br>+        \
&quot;tries\0&quot;            Required_argument &quot;t&quot;<br>         /* \
Ignored: */<br>-IF_DESKTOP(    &quot;tries\0&quot;            Required_argument \
&quot;t&quot;)<br>         &quot;header\0&quot;           Required_argument \
&quot;\xff&quot;<br>         &quot;post-data\0&quot;        Required_argument \
&quot;\xfe&quot;<br>         &quot;spider\0&quot;           No_argument       \
&quot;\xfd&quot;<br>@@ -1601,14 +1672,14 @@ IF_DESKTOP(    &quot;no-parent\0&quot;    \
No_argument       &quot;\xf0&quot;)<br> #if ENABLE_FEATURE_WGET_TIMEOUT<br>     \
G.timeout_seconds = 900;<br> #endif<br>+    G.tries = 1;<br>     G.proxy_flag = \
&quot;on&quot;;   /* use proxies if env vars are set */<br>     G.user_agent = \
&quot;Wget&quot;; /* &quot;User-Agent&quot; header field */<br> <br> #if \
ENABLE_FEATURE_WGET_LONG_OPTIONS<br> #endif<br>     GETOPT32(argv, &quot;^&quot;<br>- \
&quot;cqSO:o:P:Y:U:T:+&quot;<br>-        /*ignored:*/ &quot;t:&quot;<br>+        \
&quot;cqSO:o:P:Y:U:T:+t:+&quot;<br>         /*ignored:*/ &quot;n::&quot;<br>         \
/* wget has exactly four -n&lt;letter&gt; opts, all of which we can ignore:<br>       \
* -nv --no-verbose: be moderately quiet (-q is full quiet)<br>@@ -1625,7 +1696,7 @@ \
IF_DESKTOP(    &quot;no-parent\0&quot;        No_argument       &quot;\xf0&quot;)<br> \



_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic