]> sjero.net Git - wget/blob - src/retr.c
[svn] Applied Adrian Aichner's patch from
[wget] / src / retr.c
1 /* File retrieval.
2    Copyright (C) 1995, 1996, 1997, 1998 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, already_redirected, dummy;
323   int local_use_proxy;
324   char *mynewloc, *proxy;
325   struct urlinfo *u;
326
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   already_redirected = 0;
337
338  again:
339   u = newurl ();
340   /* Parse the URL.  RFC2068 requires `Location' to contain an
341      absoluteURI, but many sites break this requirement.  #### We
342      should be liberal and accept a relative location, too.  */
343   result = parseurl (url, u, already_redirected);
344   if (result != URLOK)
345     {
346       freeurl (u, 1);
347       logprintf (LOG_NOTQUIET, "%s: %s.\n", url, uerrmsg (result));
348       return result;
349     }
350
351   /* Set the referer.  */
352   if (refurl)
353     u->referer = xstrdup (refurl);
354   else
355     {
356       if (opt.referer)
357         u->referer = xstrdup (opt.referer);
358       else
359         u->referer = NULL;
360     }
361
362   local_use_proxy = USE_PROXY_P (u);
363   if (local_use_proxy)
364     {
365       struct urlinfo *pu = newurl ();
366
367       /* Copy the original URL to new location.  */
368       memcpy (pu, u, sizeof (*u));
369       pu->proxy = NULL; /* A minor correction :) */
370       /* Initialize u to nil.  */
371       memset (u, 0, sizeof (*u));
372       u->proxy = pu;
373       /* Get the appropriate proxy server, appropriate for the
374          current protocol.  */
375       proxy = getproxy (pu->proto);
376       if (!proxy)
377         {
378           logputs (LOG_NOTQUIET, _("Could not find proxy host.\n"));
379           freeurl (u, 1);
380           return PROXERR;
381         }
382       /* Parse the proxy URL.  */
383       result = parseurl (proxy, u, 0);
384       if (result != URLOK || u->proto != URLHTTP)
385         {
386           if (u->proto == URLHTTP)
387             logprintf (LOG_NOTQUIET, "Proxy %s: %s.\n", proxy, uerrmsg(result));
388           else
389             logprintf (LOG_NOTQUIET, _("Proxy %s: Must be HTTP.\n"), proxy);
390           freeurl (u, 1);
391           return PROXERR;
392         }
393       u->proto = URLHTTP;
394     }
395
396   assert (u->proto != URLFILE); /* #### Implement me!  */
397   mynewloc = NULL;
398
399   if (u->proto == URLHTTP)
400     result = http_loop (u, &mynewloc, dt);
401   else if (u->proto == URLFTP)
402     {
403       /* If this is a redirection, we must not allow recursive FTP
404          retrieval, so we save recursion to oldrec, and restore it
405          later.  */
406       int oldrec = opt.recursive;
407       if (already_redirected)
408         opt.recursive = 0;
409       result = ftp_loop (u, dt);
410       opt.recursive = oldrec;
411       /* There is a possibility of having HTTP being redirected to
412          FTP.  In these cases we must decide whether the text is HTML
413          according to the suffix.  The HTML suffixes are `.html' and
414          `.htm', case-insensitive.
415
416          #### All of this is, of course, crap.  These types should be
417          determined through mailcap.  */
418       if (already_redirected && u->local && (u->proto == URLFTP ))
419         {
420           char *suf = suffix (u->local);
421           if (suf && (!strcasecmp (suf, "html") || !strcasecmp (suf, "htm")))
422             *dt |= TEXTHTML;
423           FREE_MAYBE (suf);
424         }
425     }
426   location_changed = (result == NEWLOCATION);
427   if (location_changed)
428     {
429       /* Check for redirection to oneself.  */
430       if (url_equal (url, mynewloc))
431         {
432           logprintf (LOG_NOTQUIET, _("%s: Redirection to itself.\n"),
433                      mynewloc);
434           return WRONGCODE;
435         }
436       if (mynewloc)
437         {
438           /* The HTTP specs only allow absolute URLs to appear in redirects, but
439              a ton of boneheaded webservers and CGIs out there break the rules
440              and use relative URLs, and popular browsers are lenient about this,
441              so wget should be too. */
442           if (strstr(mynewloc, "://") == NULL)
443             /* Doesn't look like an absolute URL (this check will incorrectly
444                think that rare relative URLs containing "://" later in the
445                string are absolute). */
446             {
447               char *temp = malloc(strlen(url) + strlen(mynewloc) + 1);
448               
449               if (mynewloc[0] == '/')
450                 /* "Hostless absolute" URL.  Convert to absolute. */
451                 sprintf(temp,"%s%s", url, mynewloc);
452               else
453                 /* Relative URL.  Convert to absolute. */
454                 sprintf(temp,"%s/%s", url, mynewloc);
455
456               free(mynewloc);
457               mynewloc = temp;
458             }
459           
460           free (url);
461           url = mynewloc;
462         }
463       freeurl (u, 1);
464       already_redirected = 1;
465       goto again;
466     }
467   if (file)
468     {
469       if (u->local)
470         *file = xstrdup (u->local);
471       else
472         *file = NULL;
473     }
474   freeurl (u, 1);
475
476   if (newloc)
477     *newloc = url;
478   else
479     free (url);
480
481   return result;
482 }
483
484 /* Find the URLs in the file and call retrieve_url() for each of
485    them.  If HTML is non-zero, treat the file as HTML, and construct
486    the URLs accordingly.
487
488    If opt.recursive is set, call recursive_retrieve() for each file.  */
489 uerr_t
490 retrieve_from_file (const char *file, int html, int *count)
491 {
492   uerr_t status;
493   urlpos *url_list, *cur_url;
494
495   /* If spider-mode is on, we do not want get_urls_html barfing
496      errors on baseless links.  */
497   url_list = (html ? get_urls_html (file, NULL, opt.spider, FALSE)
498               : get_urls_file (file));
499   status = RETROK;             /* Suppose everything is OK.  */
500   *count = 0;                  /* Reset the URL count.  */
501   recursive_reset ();
502   for (cur_url = url_list; cur_url; cur_url = cur_url->next, ++*count)
503     {
504       char *filename, *new_file;
505       int dt;
506
507       if (opt.quota && opt.downloaded > opt.quota)
508         {
509           status = QUOTEXC;
510           break;
511         }
512       status = retrieve_url (cur_url->url, &filename, &new_file, NULL, &dt);
513       if (opt.recursive && status == RETROK && (dt & TEXTHTML))
514         status = recursive_retrieve (filename, new_file ? new_file
515                                                         : cur_url->url);
516
517       if (filename && opt.delete_after && file_exists_p (filename))
518         {
519           DEBUGP (("Removing file due to --delete-after in"
520                    " retrieve_from_file():\n"));
521           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
522           if (unlink (filename))
523             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
524           dt &= ~RETROKF;
525         }
526
527       FREE_MAYBE (new_file);
528       FREE_MAYBE (filename);
529     }
530
531   /* Free the linked list of URL-s.  */
532   free_urlpos (url_list);
533
534   return status;
535 }
536
537 /* Print `giving up', or `retrying', depending on the impending
538    action.  N1 and N2 are the attempt number and the attempt limit.  */
539 void
540 printwhat (int n1, int n2)
541 {
542   logputs (LOG_VERBOSE, (n1 == n2) ? _("Giving up.\n\n") : _("Retrying.\n\n"));
543 }