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