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