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