]> sjero.net Git - wget/blobdiff - src/retr.c
Do not define max twice.
[wget] / src / retr.c
index 39627e4bbf5067e8ea563ac110c39c44e1cf087a..73947658c2d73b10b975ce589d39d1a2c2bb7401 100644 (file)
@@ -1,6 +1,7 @@
 /* File retrieval.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+   Inc.
 
 This file is part of GNU Wget.
 
@@ -32,13 +33,12 @@ as that of the covered work.  */
 
 #include <stdio.h>
 #include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
+#include <unistd.h>
 #include <errno.h>
 #include <string.h>
 #include <assert.h>
 
+#include "exits.h"
 #include "utils.h"
 #include "retr.h"
 #include "progress.h"
@@ -143,10 +143,8 @@ limit_bandwidth (wgint bytes, struct ptimer *timer)
 
 static int
 write_data (FILE *out, const char *buf, int bufsize, wgint *skip,
-            wgint *written, int flags)
+            wgint *written)
 {
-  static int cr_pending = 0;    /* Found CR in ASCII FTP data. */
-
   if (!out)
     return 1;
   if (*skip > bufsize)
@@ -163,72 +161,8 @@ write_data (FILE *out, const char *buf, int bufsize, wgint *skip,
         return 1;
     }
 
-/* Note: This code assumes that "\n" is the universal line ending
-   character, as on UNIX and VMS.  If this is not true, then here's
-   where to change it.
-*/
-
-#if 1
-# define EOL_STRING "\n"
-#else /* 1 */
-# define EOL_STRING "\r\n"
-#endif /* 1 [else] */
-#define EOL_STRING_LEN (sizeof( EOL_STRING)- 1)
-
-  if (flags & rb_ftp_ascii)
-    {
-      const char *bufend;
-
-      /* ASCII transfer.  Put out lines delimited by CRLF. */
-      bufend = buf+ bufsize;
-      while (buf < bufend)
-        {
-          /* If CR, put out any pending CR, then set CR-pending flag. */
-          if (*buf == '\r')
-            {
-              if (cr_pending)
-                {
-                  fwrite ("\r", 1, 1, out);
-                  *written += 1;
-                }
-              cr_pending = 1;
-              buf++;
-              continue;
-            }
-
-          if (cr_pending)
-            {
-              if (*buf == '\n')
-                {
-                  /* Found FTP EOL (CRLF).  Put out local EOL. */
-                  fwrite (EOL_STRING, 1, EOL_STRING_LEN, out);
-                  *written += EOL_STRING_LEN;
-                }
-              else
-                {
-                  /* Normal character.  Put out pending CR and it. */
-                  fwrite ("\r", 1, 1, out);
-                  fwrite (buf, 1, 1, out);
-                  *written += 2;
-                }
-              buf++;
-              cr_pending = 0;
-            }
-          else
-            {
-              /* Normal character.  Put it out. */
-              fwrite (buf, 1, 1, out);
-              *written += 1;
-              buf++;
-            }
-        }
-    }
-  else
-    {
-      /* Image transfer.  Put out buffer. */
-      fwrite (buf, 1, bufsize, out);
-      *written += bufsize;
-    }
+  fwrite (buf, 1, bufsize, out);
+  *written += bufsize;
 
   /* Immediately flush the downloaded data.  This should not hinder
      performance: fast downloads will arrive in large 16K chunks
@@ -273,9 +207,10 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
               wgint *qtyread, wgint *qtywritten, double *elapsed, int flags)
 {
   int ret = 0;
-
-  static char dlbuf[16384];
-  int dlbufsize = sizeof (dlbuf);
+#undef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+  int dlbufsize = max (BUFSIZ, 8 * 1024);
+  char *dlbuf = xmalloc (dlbufsize);
 
   struct ptimer *timer = NULL;
   double last_successful_read_tm = 0;
@@ -290,11 +225,15 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
   bool progress_interactive = false;
 
   bool exact = !!(flags & rb_read_exactly);
+
+  /* Used only by HTTP/HTTPS chunked transfer encoding.  */
+  bool chunked = flags & rb_chunked_transfer_encoding;
   wgint skip = 0;
 
   /* How much data we've read/written.  */
   wgint sum_read = 0;
   wgint sum_written = 0;
+  wgint remaining_chunk_size = 0;
 
   if (flags & rb_skip_startpos)
     skip = startpos;
@@ -334,8 +273,36 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
      should be read.  */
   while (!exact || (sum_read < toread))
     {
-      int rdsize = exact ? MIN (toread - sum_read, dlbufsize) : dlbufsize;
+      int rdsize;
       double tmout = opt.read_timeout;
+
+      if (chunked)
+        {
+          if (remaining_chunk_size == 0)
+            {
+              char *line = fd_read_line (fd);
+              char *endl;
+              if (line == NULL)
+                {
+                  ret = -1;
+                  break;
+                }
+
+              remaining_chunk_size = strtol (line, &endl, 16);
+              if (remaining_chunk_size == 0)
+                {
+                  ret = 0;
+                  if (fd_read_line (fd) == NULL)
+                    ret = -1;
+                  break;
+                }
+            }
+
+          rdsize = MIN (remaining_chunk_size, dlbufsize);
+        }
+      else
+        rdsize = exact ? MIN (toread - sum_read, dlbufsize) : dlbufsize;
+
       if (progress_interactive)
         {
           /* For interactive progress gauges, always specify a ~1s
@@ -366,7 +333,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
       else if (ret <= 0)
         break;                  /* EOF or read error */
 
-      if (progress || opt.limit_rate)
+      if (progress || opt.limit_rate || elapsed)
         {
           ptimer_measure (timer);
           if (ret > 0)
@@ -376,11 +343,21 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
       if (ret > 0)
         {
           sum_read += ret;
-          if (!write_data (out, dlbuf, ret, &skip, &sum_written, flags))
+          if (!write_data (out, dlbuf, ret, &skip, &sum_written))
             {
               ret = -2;
               goto out;
             }
+          if (chunked)
+            {
+              remaining_chunk_size -= ret;
+              if (remaining_chunk_size == 0)
+                if (fd_read_line (fd) == NULL)
+                  {
+                    ret = -1;
+                    break;
+                  }
+            }
         }
 
       if (opt.limit_rate)
@@ -411,6 +388,8 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
   if (qtywritten)
     *qtywritten += sum_written;
 
+  free (dlbuf);
+
   return ret;
 }
 \f
@@ -677,7 +656,7 @@ static char *getproxy (struct url *);
 uerr_t
 retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
               char **newloc, const char *refurl, int *dt, bool recursive,
-              struct iri *iri)
+              struct iri *iri, bool register_status)
 {
   uerr_t result;
   char *url;
@@ -734,7 +713,8 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
           xfree (url);
           xfree (error);
           RESTORE_POST_DATA;
-          return PROXERR;
+          result = PROXERR;
+          goto bail;
         }
       if (proxy_url->scheme != SCHEME_HTTP && proxy_url->scheme != u->scheme)
         {
@@ -742,7 +722,8 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
           url_free (proxy_url);
           xfree (url);
           RESTORE_POST_DATA;
-          return PROXERR;
+          result = PROXERR;
+          goto bail;
         }
     }
 
@@ -752,7 +733,8 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
 #endif
       || (proxy_url && proxy_url->scheme == SCHEME_HTTP))
     {
-      result = http_loop (u, &mynewloc, &local_file, refurl, dt, proxy_url, iri);
+      result = http_loop (u, orig_parsed, &mynewloc, &local_file, refurl, dt,
+                          proxy_url, iri);
     }
   else if (u->scheme == SCHEME_FTP)
     {
@@ -763,7 +745,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
       if (redirection_count)
         oldrec = glob = false;
 
-      result = ftp_loop (u, dt, proxy_url, recursive, glob);
+      result = ftp_loop (u, &local_file, dt, proxy_url, recursive, glob);
       recursive = oldrec;
 
       /* There is a possibility of having HTTP being redirected to
@@ -783,7 +765,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
       proxy_url = NULL;
     }
 
-  location_changed = (result == NEWLOCATION);
+  location_changed = (result == NEWLOCATION || result == NEWLOCATION_KEEP_POST);
   if (location_changed)
     {
       char *construced_newloc;
@@ -823,7 +805,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
           xfree (mynewloc);
           xfree (error);
           RESTORE_POST_DATA;
-          return result;
+          goto bail;
         }
 
       /* Now mynewloc will become newloc_parsed->url, because if the
@@ -845,7 +827,8 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
           xfree (url);
           xfree (mynewloc);
           RESTORE_POST_DATA;
-          return WRONGCODE;
+          result = WRONGCODE;
+          goto bail;
         }
 
       xfree (url);
@@ -856,12 +839,17 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
         }
       u = newloc_parsed;
 
-      /* If we're being redirected from POST, we don't want to POST
+      /* If we're being redirected from POST, and we received a
+         redirect code different than 307, we don't want to POST
          again.  Many requests answer POST with a redirection to an
          index page; that redirection is clearly a GET.  We "suspend"
          POST data for the duration of the redirections, and restore
-         it when we're done. */
-      if (!post_data_suspended)
+         it when we're done.
+        
+        RFC2616 HTTP/1.1 introduces code 307 Temporary Redirect
+        specifically to preserve the method of the request.
+        */
+      if (result != NEWLOCATION_KEEP_POST && !post_data_suspended)
         SUSPEND_POST_DATA;
 
       goto redirected;
@@ -887,23 +875,18 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
           DEBUGP (("[Couldn't fallback to non-utf8 for %s\n", quote (url)));
     }
 
-  if (local_file && *dt & RETROKF)
+  if (local_file && u && *dt & RETROKF)
     {
       register_download (u->url, local_file);
-      if (redirection_count && 0 != strcmp (origurl, u->url))
+
+      if (!opt.spider && redirection_count && 0 != strcmp (origurl, u->url))
         register_redirection (origurl, u->url);
+
       if (*dt & TEXTHTML)
         register_html (u->url, local_file);
-      if (*dt & RETROKF)
-        {
-          register_download (u->url, local_file);
-          if (redirection_count && 0 != strcmp (origurl, u->url))
-            register_redirection (origurl, u->url);
-          if (*dt & TEXTHTML)
-            register_html (u->url, local_file);
-          if (*dt & TEXTCSS)
-            register_css (u->url, local_file);
-        }
+
+      if (*dt & TEXTCSS)
+        register_css (u->url, local_file);
     }
 
   if (file)
@@ -932,6 +915,9 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
 
   RESTORE_POST_DATA;
 
+bail:
+  if (register_status)
+    inform_exit_status (result);
   return result;
 }
 
@@ -948,7 +934,7 @@ retrieve_from_file (const char *file, bool html, int *count)
   struct urlpos *url_list, *cur_url;
   struct iri *iri = iri_new();
 
-  char *input_file = NULL;
+  char *input_file, *url_file = NULL;
   const char *url = file;
 
   status = RETROK;             /* Suppose everything is OK.  */
@@ -958,12 +944,11 @@ retrieve_from_file (const char *file, bool html, int *count)
   set_uri_encoding (iri, opt.locale, true);
   set_content_encoding (iri, opt.locale);
 
-  if (url_has_scheme (url))
+  if (url_valid_scheme (url))
     {
       int dt,url_err;
       uerr_t status;
-      struct url * url_parsed = url_parse(url, &url_err, iri, true);
-
+      struct url *url_parsed = url_parse (url, &url_err, iri, true);
       if (!url_parsed)
         {
           char *error = url_error (url, url_err);
@@ -975,9 +960,11 @@ retrieve_from_file (const char *file, bool html, int *count)
       if (!opt.base_href)
         opt.base_href = xstrdup (url);
 
-      status = retrieve_url (url_parsed, url, &input_file, NULL, NULL, &dt,
-                             false, iri);
-      if (status != RETROK)
+      status = retrieve_url (url_parsed, url, &url_file, NULL, NULL, &dt,
+                             false, iri, true);
+      url_free (url_parsed);
+
+      if (!url_file || (status != RETROK))
         return status;
 
       if (dt & TEXTHTML)
@@ -992,6 +979,8 @@ retrieve_from_file (const char *file, bool html, int *count)
       iri->utf8_encode = opt.enable_iri;
       xfree_null (iri->orig_url);
       iri->orig_url = NULL;
+
+      input_file = url_file;
     }
   else
     input_file = (char *) file;
@@ -999,6 +988,8 @@ retrieve_from_file (const char *file, bool html, int *count)
   url_list = (html ? get_urls_html (input_file, NULL, NULL, iri)
               : get_urls_file (input_file));
 
+  xfree_null (url_file);
+
   for (cur_url = url_list; cur_url; cur_url = cur_url->next, ++*count)
     {
       char *filename = NULL, *new_file = NULL;
@@ -1015,9 +1006,7 @@ retrieve_from_file (const char *file, bool html, int *count)
           break;
         }
 
-      /* Need to reparse the url, since it didn't have iri information. */
-      if (opt.enable_iri)
-          parsed_url = url_parse (cur_url->url->url, NULL, tmpiri, true);
+      parsed_url = url_parse (cur_url->url->url, NULL, tmpiri, true);
 
       if ((opt.recursive || opt.page_requisites)
           && (cur_url->url->scheme != SCHEME_FTP || getproxy (cur_url->url)))
@@ -1036,7 +1025,8 @@ retrieve_from_file (const char *file, bool html, int *count)
       else
         status = retrieve_url (parsed_url ? parsed_url : cur_url->url,
                                cur_url->url->url, &filename,
-                               &new_file, NULL, &dt, opt.recursive, tmpiri);
+                               &new_file, NULL, &dt, opt.recursive, tmpiri,
+                               true);
 
       if (parsed_url)
           url_free (parsed_url);
@@ -1241,3 +1231,20 @@ set_local_file (const char **file, const char *default_file)
   else
     *file = default_file;
 }
+
+/* Return true for an input file's own URL, false otherwise.  */
+bool
+input_file_url (const char *input_file)
+{
+  static bool first = true;
+
+  if (input_file
+      && url_has_scheme (input_file)
+      && first)
+    {
+      first = false;
+      return true;
+    }
+  else
+    return false;
+}