]> sjero.net Git - wget/blob - src/retr.c
[svn] Replace opt.no_flush with a function to disable/enable flushing.
[wget] / src / retr.c
1 /* File retrieval.
2    Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif /* HAVE_UNISTD_H */
28 #include <errno.h>
29 #ifdef HAVE_STRING_H
30 # include <string.h>
31 #else
32 # include <strings.h>
33 #endif /* HAVE_STRING_H */
34 #include <assert.h>
35
36 #include "wget.h"
37 #include "utils.h"
38 #include "retr.h"
39 #include "url.h"
40 #include "recur.h"
41 #include "ftp.h"
42 #include "host.h"
43 #include "connect.h"
44 #include "hash.h"
45
46 #ifndef errno
47 extern int errno;
48 #endif
49
50 /* See the comment in gethttp() why this is needed. */
51 int global_download_count;
52
53 \f
54 /* Flags for show_progress().  */
55 enum spflags { SP_NONE, SP_INIT, SP_FINISH };
56
57 static int show_progress PARAMS ((long, long, enum spflags));
58
59 #define MIN(i, j) ((i) <= (j) ? (i) : (j))
60
61 /* Reads the contents of file descriptor FD, until it is closed, or a
62    read error occurs.  The data is read in 8K chunks, and stored to
63    stream fp, which should have been open for writing.  If BUF is
64    non-NULL and its file descriptor is equal to FD, flush RBUF first.
65    This function will *not* use the rbuf_* functions!
66
67    The EXPECTED argument is passed to show_progress() unchanged, but
68    otherwise ignored.
69
70    If opt.verbose is set, the progress is also shown.  RESTVAL
71    represents a value from which to start downloading (which will be
72    shown accordingly).  If RESTVAL is non-zero, the stream should have
73    been open for appending.
74
75    The function exits and returns codes of 0, -1 and -2 if the
76    connection was closed, there was a read error, or if it could not
77    write to the output stream, respectively.
78
79    IMPORTANT: The function flushes the contents of the buffer in
80    rbuf_flush() before actually reading from fd.  If you wish to read
81    from fd immediately, flush or discard the buffer.  */
82 int
83 get_contents (int fd, FILE *fp, long *len, long restval, long expected,
84               struct rbuf *rbuf, int use_expected)
85 {
86   int res = 0;
87   static char c[8192];
88
89   *len = restval;
90   if (opt.verbose)
91     show_progress (restval, expected, SP_INIT);
92   if (rbuf && RBUF_FD (rbuf) == fd)
93     {
94       while ((res = rbuf_flush (rbuf, c, sizeof (c))) != 0)
95         {
96           if (fwrite (c, sizeof (char), res, fp) < res)
97             return -2;
98           if (opt.verbose)
99             {
100               if (show_progress (res, expected, SP_NONE))
101                 fflush (fp);
102             }
103           *len += res;
104         }
105     }
106   /* Read from fd while there is available data.
107
108      Normally, if expected is 0, it means that it is not known how
109      much data is expected.  However, if use_expected is specified,
110      then expected being zero means exactly that.  */
111   while (!use_expected || (*len < expected))
112     {
113       int amount_to_read = (use_expected
114                             ? MIN (expected - *len, sizeof (c))
115                             : sizeof (c));
116 #ifdef HAVE_SSL
117                 if (rbuf->ssl!=NULL) {
118                   res = ssl_iread (rbuf->ssl, c, amount_to_read);
119                 } else {
120 #endif /* HAVE_SSL */
121                   res = iread (fd, c, amount_to_read);
122 #ifdef HAVE_SSL
123                 }
124 #endif /* HAVE_SSL */
125       if (res > 0)
126         {
127           if (fwrite (c, sizeof (char), res, fp) < res)
128             return -2;
129           if (opt.verbose)
130             {
131               if (show_progress (res, expected, SP_NONE))
132                 fflush (fp);
133             }
134           *len += res;
135         }
136       else
137         break;
138     }
139   if (res < -1)
140     res = -1;
141   if (opt.verbose)
142     show_progress (0, expected, SP_FINISH);
143   return res;
144 }
145
146 static void
147 print_percentage (long bytes, long expected)
148 {
149   int percentage = (int)(100.0 * bytes / expected);
150   logprintf (LOG_VERBOSE, "%3d%%", percentage);
151 }
152
153 /* Show the dotted progress report of file loading.  Called with
154    length and a flag to tell it whether to reset or not.  It keeps the
155    offset information in static local variables.
156
157    Return value: 1 or 0, designating whether any dots have been drawn.
158
159    If the init argument is set, the routine will initialize.
160
161    If the res is non-zero, res/line_bytes lines are skipped
162    (meaning the appropriate number ok kilobytes), and the number of
163    "dots" fitting on the first line are drawn as ','.  */
164 static int
165 show_progress (long res, long expected, enum spflags flags)
166 {
167   static struct wget_timer *timer;
168   static long line_bytes;
169   static long offs, initial_skip;
170   static int ndot, nrow;
171   static long last_timer_value, time_offset;
172   int any_output = 0;
173
174   if (flags == SP_FINISH)
175     {
176       int dot = ndot;
177       char *tmpstr = (char *)alloca (2 * opt.dots_in_line + 1);
178       char *tmpp = tmpstr;
179       time_offset = wtimer_elapsed (timer) - last_timer_value;
180       for (; dot < opt.dots_in_line; dot++)
181         {
182           if (!(dot % opt.dot_spacing))
183             *tmpp++ = ' ';
184           *tmpp++ = ' ';
185         }
186       *tmpp = '\0';
187       logputs (LOG_VERBOSE, tmpstr);
188       if (expected)
189         print_percentage (nrow * line_bytes + ndot * opt.dot_bytes + offs,
190                           expected);
191       logprintf (LOG_VERBOSE, " @%s",
192                  rate (ndot * opt.dot_bytes
193                        + offs - (initial_skip % line_bytes),
194                        time_offset, 1));
195       logputs (LOG_VERBOSE, "\n\n");
196       return 0;
197     }
198
199   /* Temporarily disable flushing.  */
200   log_set_flush (0);
201
202   /* init set means initialization.  If res is set, it also means that
203      the retrieval is *not* done from the beginning.  The part that
204      was already retrieved is not shown again.  */
205   if (flags == SP_INIT)
206     {
207       /* Generic initialization of static variables.  */
208       offs = 0L;
209       ndot = nrow = 0;
210       line_bytes = (long)opt.dots_in_line * opt.dot_bytes;
211       if (!timer)
212         timer = wtimer_allocate ();
213       wtimer_reset (timer);
214       last_timer_value = 0;
215       time_offset = 0;
216       initial_skip = res;
217       if (res)
218         {
219           if (res >= line_bytes)
220             {
221               nrow = res / line_bytes;
222               res %= line_bytes;
223               logprintf (LOG_VERBOSE,
224                          _("\n          [ skipping %dK ]"),
225                          (int) ((nrow * line_bytes) / 1024));
226               ndot = 0;
227             }
228         }
229       logprintf (LOG_VERBOSE, "\n%5ldK", nrow * line_bytes / 1024);
230     }
231   /* Offset gets incremented by current value.  */
232   offs += res;
233   /* While offset is >= opt.dot_bytes, print dots, taking care to
234      precede every 50th dot with a status message.  */
235   for (; offs >= opt.dot_bytes; offs -= opt.dot_bytes)
236     {
237       if (!(ndot % opt.dot_spacing))
238         logputs (LOG_VERBOSE, " ");
239       any_output = 1;
240       logputs (LOG_VERBOSE, flags == SP_INIT ? "," : ".");
241       ++ndot;
242       if (ndot == opt.dots_in_line)
243         {
244           time_offset = wtimer_elapsed (timer) - last_timer_value;
245           last_timer_value += time_offset;
246
247           ndot = 0;
248           ++nrow;
249           if (expected)
250             print_percentage (nrow * line_bytes, expected);
251           logprintf (LOG_VERBOSE, " @%s",
252                      rate (line_bytes - (initial_skip % line_bytes),
253                            time_offset, 1));
254           initial_skip = 0;
255           logprintf (LOG_VERBOSE, "\n%5ldK", nrow * line_bytes / 1024);
256         }
257     }
258
259   /* Reenable flushing.  */
260   log_set_flush (1);
261
262   return any_output;
263 }
264 \f
265 /* Print out the appropriate download rate.  Appropriate means that if
266    rate is > 1024 bytes per second, kilobytes are used, and if rate >
267    1024 * 1024 bps, megabytes are used.
268
269    If PAD is non-zero, strings will be padded to the width of 7
270    characters (xxxx.xx).  */
271 char *
272 rate (long bytes, long msecs, int pad)
273 {
274   static char res[15];
275   double dlrate;
276
277   if (msecs == 0)
278     /* If elapsed time is 0, it means we're under the granularity of
279        the timer.  This often happens on systems that use time() for
280        the timer.  */
281     msecs = wtimer_granularity ();
282
283   dlrate = (double)1000 * bytes / msecs;
284   if (dlrate < 1024.0)
285     sprintf (res, pad ? "%7.2f B/s" : "%.2f B/s", dlrate);
286   else if (dlrate < 1024.0 * 1024.0)
287     sprintf (res, pad ? "%7.2f KB/s" : "%.2f KB/s", dlrate / 1024.0);
288   else if (dlrate < 1024.0 * 1024.0 * 1024.0)
289     sprintf (res, pad ? "%7.2f MB/s" : "%.2f MB/s", dlrate / (1024.0 * 1024.0));
290   else
291     /* Maybe someone will need this one day.  More realistically, it
292        will get tickled by buggy timers. */
293     sprintf (res, pad ? "%7.2f GB/s" : "%.2f GB/s",
294              dlrate / (1024.0 * 1024.0 * 1024.0));
295
296   return res;
297 }
298 \f
299 #define USE_PROXY_P(u) (opt.use_proxy && getproxy((u)->scheme)          \
300                         && no_proxy_match((u)->host,                    \
301                                           (const char **)opt.no_proxy))
302
303 /* Retrieve the given URL.  Decides which loop to call -- HTTP(S), FTP,
304    or simply copy it with file:// (#### the latter not yet
305    implemented!).  */
306 uerr_t
307 retrieve_url (const char *origurl, char **file, char **newloc,
308               const char *refurl, int *dt)
309 {
310   uerr_t result;
311   char *url;
312   int location_changed, dummy;
313   int use_proxy;
314   char *mynewloc, *proxy;
315   struct url *u;
316   int up_error_code;            /* url parse error code */
317   char *local_file;
318   struct hash_table *redirections = NULL;
319
320   /* If dt is NULL, just ignore it.  */
321   if (!dt)
322     dt = &dummy;
323   url = xstrdup (origurl);
324   if (newloc)
325     *newloc = NULL;
326   if (file)
327     *file = NULL;
328
329   u = url_parse (url, &up_error_code);
330   if (!u)
331     {
332       logprintf (LOG_NOTQUIET, "%s: %s.\n", url, url_error (up_error_code));
333       if (redirections)
334         string_set_free (redirections);
335       xfree (url);
336       return URLERROR;
337     }
338
339   if (!refurl)
340     refurl = opt.referer;
341
342  redirected:
343
344   result = NOCONERROR;
345   mynewloc = NULL;
346   local_file = NULL;
347
348   use_proxy = USE_PROXY_P (u);
349   if (use_proxy)
350     {
351       struct url *proxy_url;
352
353       /* Get the proxy server for the current scheme.  */
354       proxy = getproxy (u->scheme);
355       if (!proxy)
356         {
357           logputs (LOG_NOTQUIET, _("Could not find proxy host.\n"));
358           url_free (u);
359           if (redirections)
360             string_set_free (redirections);
361           xfree (url);
362           return PROXERR;
363         }
364
365       /* Parse the proxy URL.  */
366       proxy_url = url_parse (proxy, &up_error_code);
367       if (!proxy_url)
368         {
369           logprintf (LOG_NOTQUIET, "Error parsing proxy URL %s: %s.\n",
370                      proxy, url_error (up_error_code));
371           if (redirections)
372             string_set_free (redirections);
373           xfree (url);
374           return PROXERR;
375         }
376       if (proxy_url->scheme != SCHEME_HTTP)
377         {
378           logprintf (LOG_NOTQUIET, _("Error in proxy URL %s: Must be HTTP.\n"), proxy);
379           url_free (proxy_url);
380           if (redirections)
381             string_set_free (redirections);
382           xfree (url);
383           return PROXERR;
384         }
385
386       result = http_loop (u, &mynewloc, &local_file, refurl, dt, proxy_url);
387       url_free (proxy_url);
388     }
389   else if (u->scheme == SCHEME_HTTP
390 #ifdef HAVE_SSL
391       || u->scheme == SCHEME_HTTPS
392 #endif
393       )
394     {
395       result = http_loop (u, &mynewloc, &local_file, refurl, dt, NULL);
396     }
397   else if (u->scheme == SCHEME_FTP)
398     {
399       /* If this is a redirection, we must not allow recursive FTP
400          retrieval, so we save recursion to oldrec, and restore it
401          later.  */
402       int oldrec = opt.recursive;
403       if (redirections)
404         opt.recursive = 0;
405       result = ftp_loop (u, dt);
406       opt.recursive = oldrec;
407 #if 0
408       /* There is a possibility of having HTTP being redirected to
409          FTP.  In these cases we must decide whether the text is HTML
410          according to the suffix.  The HTML suffixes are `.html' and
411          `.htm', case-insensitive.  */
412       if (redirections && u->local && (u->scheme == SCHEME_FTP))
413         {
414           char *suf = suffix (u->local);
415           if (suf && (!strcasecmp (suf, "html") || !strcasecmp (suf, "htm")))
416             *dt |= TEXTHTML;
417           FREE_MAYBE (suf);
418         }
419 #endif
420     }
421   location_changed = (result == NEWLOCATION);
422   if (location_changed)
423     {
424       char *construced_newloc;
425       struct url *newloc_struct;
426
427       assert (mynewloc != NULL);
428
429       if (local_file)
430         xfree (local_file);
431
432       /* The HTTP specs only allow absolute URLs to appear in
433          redirects, but a ton of boneheaded webservers and CGIs out
434          there break the rules and use relative URLs, and popular
435          browsers are lenient about this, so wget should be too. */
436       construced_newloc = uri_merge (url, mynewloc);
437       xfree (mynewloc);
438       mynewloc = construced_newloc;
439
440       /* Now, see if this new location makes sense. */
441       newloc_struct = url_parse (mynewloc, NULL);
442       if (!newloc_struct)
443         {
444           logprintf (LOG_NOTQUIET, "%s: %s.\n", mynewloc, "UNKNOWN");
445           url_free (newloc_struct);
446           url_free (u);
447           if (redirections)
448             string_set_free (redirections);
449           xfree (url);
450           xfree (mynewloc);
451           return result;
452         }
453
454       /* Now mynewloc will become newloc_struct->url, because if the
455          Location contained relative paths like .././something, we
456          don't want that propagating as url.  */
457       xfree (mynewloc);
458       mynewloc = xstrdup (newloc_struct->url);
459
460       if (!redirections)
461         {
462           redirections = make_string_hash_table (0);
463           /* Add current URL immediately so we can detect it as soon
464              as possible in case of a cycle. */
465           string_set_add (redirections, u->url);
466         }
467
468       /* The new location is OK.  Check for redirection cycle by
469          peeking through the history of redirections. */
470       if (string_set_contains (redirections, newloc_struct->url))
471         {
472           logprintf (LOG_NOTQUIET, _("%s: Redirection cycle detected.\n"),
473                      mynewloc);
474           url_free (newloc_struct);
475           url_free (u);
476           if (redirections)
477             string_set_free (redirections);
478           xfree (url);
479           xfree (mynewloc);
480           return WRONGCODE;
481         }
482       string_set_add (redirections, newloc_struct->url);
483
484       xfree (url);
485       url = mynewloc;
486       url_free (u);
487       u = newloc_struct;
488       goto redirected;
489     }
490
491   if (local_file)
492     {
493       if (*dt & RETROKF)
494         {
495           register_download (url, local_file);
496           if (*dt & TEXTHTML)
497             register_html (url, local_file);
498         }
499     }
500
501   if (file)
502     *file = local_file ? local_file : NULL;
503   else
504     FREE_MAYBE (local_file);
505
506   url_free (u);
507   if (redirections)
508     string_set_free (redirections);
509
510   if (newloc)
511     *newloc = url;
512   else
513     xfree (url);
514
515   ++global_download_count;
516
517   return result;
518 }
519
520 /* Find the URLs in the file and call retrieve_url() for each of
521    them.  If HTML is non-zero, treat the file as HTML, and construct
522    the URLs accordingly.
523
524    If opt.recursive is set, call recursive_retrieve() for each file.  */
525 uerr_t
526 retrieve_from_file (const char *file, int html, int *count)
527 {
528   uerr_t status;
529   urlpos *url_list, *cur_url;
530
531   url_list = (html ? get_urls_html (file, NULL, FALSE, NULL)
532               : get_urls_file (file));
533   status = RETROK;             /* Suppose everything is OK.  */
534   *count = 0;                  /* Reset the URL count.  */
535   recursive_reset ();
536   for (cur_url = url_list; cur_url; cur_url = cur_url->next, ++*count)
537     {
538       char *filename, *new_file;
539       int dt;
540
541       if (downloaded_exceeds_quota ())
542         {
543           status = QUOTEXC;
544           break;
545         }
546       status = retrieve_url (cur_url->url, &filename, &new_file, NULL, &dt);
547       if (opt.recursive && status == RETROK && (dt & TEXTHTML))
548         status = recursive_retrieve (filename, new_file ? new_file
549                                                         : cur_url->url);
550
551       if (filename && opt.delete_after && file_exists_p (filename))
552         {
553           DEBUGP (("Removing file due to --delete-after in"
554                    " retrieve_from_file():\n"));
555           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
556           if (unlink (filename))
557             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
558           dt &= ~RETROKF;
559         }
560
561       FREE_MAYBE (new_file);
562       FREE_MAYBE (filename);
563     }
564
565   /* Free the linked list of URL-s.  */
566   free_urlpos (url_list);
567
568   return status;
569 }
570
571 /* Print `giving up', or `retrying', depending on the impending
572    action.  N1 and N2 are the attempt number and the attempt limit.  */
573 void
574 printwhat (int n1, int n2)
575 {
576   logputs (LOG_VERBOSE, (n1 == n2) ? _("Giving up.\n\n") : _("Retrying.\n\n"));
577 }
578
579 /* Increment opt.downloaded by BY_HOW_MUCH.  If an overflow occurs,
580    set opt.downloaded_overflow to 1. */
581 void
582 downloaded_increase (unsigned long by_how_much)
583 {
584   VERY_LONG_TYPE old;
585   if (opt.downloaded_overflow)
586     return;
587   old = opt.downloaded;
588   opt.downloaded += by_how_much;
589   if (opt.downloaded < old)     /* carry flag, where are you when I
590                                    need you? */
591     {
592       /* Overflow. */
593       opt.downloaded_overflow = 1;
594       opt.downloaded = ~((VERY_LONG_TYPE)0);
595     }
596 }
597
598 /* Return non-zero if the downloaded amount of bytes exceeds the
599    desired quota.  If quota is not set or if the amount overflowed, 0
600    is returned. */
601 int
602 downloaded_exceeds_quota (void)
603 {
604   if (!opt.quota)
605     return 0;
606   if (opt.downloaded_overflow)
607     /* We don't really know.  (Wildly) assume not. */
608     return 0;
609
610   return opt.downloaded > opt.quota;
611 }
612
613 /* If opt.wait or opt.waitretry are specified, and if certain
614    conditions are met, sleep the appropriate number of seconds.  See
615    the documentation of --wait and --waitretry for more information.
616
617    COUNT is the count of current retrieval, beginning with 1. */
618
619 void
620 sleep_between_retrievals (int count)
621 {
622   static int first_retrieval = 1;
623
624   if (!first_retrieval && (opt.wait || opt.waitretry))
625     {
626       if (opt.waitretry && count > 1)
627         {
628           /* If opt.waitretry is specified and this is a retry, wait
629              for COUNT-1 number of seconds, or for opt.waitretry
630              seconds.  */
631           if (count <= opt.waitretry)
632             sleep (count - 1);
633           else
634             sleep (opt.waitretry);
635         }
636       else if (opt.wait)
637         /* Otherwise, check if opt.wait is specified.  If so, sleep.  */
638         sleep (opt.wait);
639     }
640   if (first_retrieval)
641     first_retrieval = 0;
642 }