]> sjero.net Git - wget/blob - src/retr.c
[svn] Update the progress gauge even when the data does not arrive.
[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 (at
9 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 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif /* HAVE_UNISTD_H */
38 #include <errno.h>
39 #ifdef HAVE_STRING_H
40 # include <string.h>
41 #else
42 # include <strings.h>
43 #endif /* HAVE_STRING_H */
44 #include <assert.h>
45
46 #include "wget.h"
47 #include "utils.h"
48 #include "retr.h"
49 #include "progress.h"
50 #include "url.h"
51 #include "recur.h"
52 #include "ftp.h"
53 #include "host.h"
54 #include "connect.h"
55 #include "hash.h"
56 #include "convert.h"
57
58 #ifdef HAVE_SSL
59 # include "gen_sslfunc.h"       /* for ssl_iread */
60 #endif
61
62 #ifndef errno
63 extern int errno;
64 #endif
65
66 /* See the comment in gethttp() why this is needed. */
67 int global_download_count;
68
69 /* Total size of downloaded files.  Used to enforce quota.  */
70 LARGE_INT total_downloaded_bytes;
71
72 \f
73 static struct {
74   long chunk_bytes;
75   double chunk_start;
76   double sleep_adjust;
77 } limit_data;
78
79 static void
80 limit_bandwidth_reset (void)
81 {
82   limit_data.chunk_bytes = 0;
83   limit_data.chunk_start = 0;
84 }
85
86 /* Limit the bandwidth by pausing the download for an amount of time.
87    BYTES is the number of bytes received from the network, and TIMER
88    is the timer that started at the beginning of download.  */
89
90 static void
91 limit_bandwidth (long bytes, struct wget_timer *timer)
92 {
93   double delta_t = wtimer_read (timer) - limit_data.chunk_start;
94   double expected;
95
96   limit_data.chunk_bytes += bytes;
97
98   /* Calculate the amount of time we expect downloading the chunk
99      should take.  If in reality it took less time, sleep to
100      compensate for the difference.  */
101   expected = 1000.0 * limit_data.chunk_bytes / opt.limit_rate;
102
103   if (expected > delta_t)
104     {
105       double slp = expected - delta_t + limit_data.sleep_adjust;
106       double t0, t1;
107       if (slp < 200)
108         {
109           DEBUGP (("deferring a %.2f ms sleep (%ld/%.2f).\n",
110                    slp, limit_data.chunk_bytes, delta_t));
111           return;
112         }
113       DEBUGP (("\nsleeping %.2f ms for %ld bytes, adjust %.2f ms\n",
114                slp, limit_data.chunk_bytes, limit_data.sleep_adjust));
115
116       t0 = wtimer_read (timer);
117       xsleep (slp / 1000);
118       wtimer_update (timer);
119       t1 = wtimer_read (timer);
120
121       /* Due to scheduling, we probably slept slightly longer (or
122          shorter) than desired.  Calculate the difference between the
123          desired and the actual sleep, and adjust the next sleep by
124          that amount.  */
125       limit_data.sleep_adjust = slp - (t1 - t0);
126     }
127
128   limit_data.chunk_bytes = 0;
129   limit_data.chunk_start = wtimer_read (timer);
130 }
131
132 #define MIN(i, j) ((i) <= (j) ? (i) : (j))
133
134 /* Reads the contents of file descriptor FD, until it is closed, or a
135    read error occurs.  The data is read in 8K chunks, and stored to
136    stream fp, which should have been open for writing.  If BUF is
137    non-NULL and its file descriptor is equal to FD, flush RBUF first.
138    This function will *not* use the rbuf_* functions!
139
140    The EXPECTED argument is passed to show_progress() unchanged, but
141    otherwise ignored.
142
143    If opt.verbose is set, the progress is also shown.  RESTVAL
144    represents a value from which to start downloading (which will be
145    shown accordingly).  If RESTVAL is non-zero, the stream should have
146    been open for appending.
147
148    The function exits and returns codes of 0, -1 and -2 if the
149    connection was closed, there was a read error, or if it could not
150    write to the output stream, respectively.
151
152    IMPORTANT: The function flushes the contents of the buffer in
153    rbuf_flush() before actually reading from fd.  If you wish to read
154    from fd immediately, flush or discard the buffer.  */
155 int
156 get_contents (int fd, FILE *fp, long *len, long restval, long expected,
157               struct rbuf *rbuf, int use_expected, double *elapsed)
158 {
159   int res = 0;
160
161   static char dlbuf[16384];
162   int dlbufsize = sizeof (dlbuf);
163
164   struct wget_timer *timer = wtimer_allocate ();
165   double last_successful_read_tm;
166
167   /* The progress gauge, set according to the user preferences. */
168   void *progress = NULL;
169
170   /* Non-zero if the progress gauge is interactive, i.e. if it can
171      continually update the display.  When true, smaller timeout
172      values are used so that the gauge can update the display when
173      data arrives slowly. */
174   int progress_interactive = 0;
175
176   *len = restval;
177
178   if (opt.verbose)
179     {
180       progress = progress_create (restval, expected);
181       progress_interactive = progress_interactive_p (progress);
182     }
183
184   if (rbuf && RBUF_FD (rbuf) == fd)
185     {
186       int sz = 0;
187       while ((res = rbuf_flush (rbuf, dlbuf, sizeof (dlbuf))) != 0)
188         {
189           fwrite (dlbuf, 1, res, fp);
190           *len += res;
191           sz += res;
192         }
193       if (sz)
194         fflush (fp);
195       if (ferror (fp))
196         {
197           res = -2;
198           goto out;
199         }
200       if (progress)
201         progress_update (progress, sz, 0);
202     }
203
204   if (opt.limit_rate)
205     limit_bandwidth_reset ();
206   wtimer_reset (timer);
207   last_successful_read_tm = 0;
208
209   /* Use a smaller buffer for low requested bandwidths.  For example,
210      with --limit-rate=2k, it doesn't make sense to slurp in 16K of
211      data and then sleep for 8s.  With buffer size equal to the limit,
212      we never have to sleep for more than one second.  */
213   if (opt.limit_rate && opt.limit_rate < dlbufsize)
214     dlbufsize = opt.limit_rate;
215
216   /* Read from fd while there is available data.
217
218      Normally, if expected is 0, it means that it is not known how
219      much data is expected.  However, if use_expected is specified,
220      then expected being zero means exactly that.  */
221   while (!use_expected || (*len < expected))
222     {
223       int amount_to_read = (use_expected
224                             ? MIN (expected - *len, dlbufsize) : dlbufsize);
225       double tmout = opt.read_timeout;
226       if (progress_interactive)
227         {
228           double waittm;
229           /* For interactive progress gauges, always specify a ~1s
230              timeout, so that the gauge can be updated regularly even
231              when the data arrives very slowly or stalls.  */
232           tmout = 0.95;
233           waittm = (wtimer_read (timer) - last_successful_read_tm) / 1000;
234           if (waittm + tmout > opt.read_timeout)
235             {
236               /* Don't allow waiting for data to exceed read timeout. */
237               tmout = opt.read_timeout - waittm;
238               if (tmout < 0)
239                 {
240                   /* We've already exceeded the timeout. */
241                   res = -1;
242                   errno = ETIMEDOUT;
243                   break;
244                 }
245             }
246         }
247       res = xread (fd, dlbuf, amount_to_read, tmout);
248
249       if (res == 0 || (res < 0 && errno != ETIMEDOUT))
250         break;
251       else if (res < 0)
252         res = 0;                /* timeout */
253
254       wtimer_update (timer);
255       if (res > 0)
256         {
257           fwrite (dlbuf, 1, res, fp);
258           /* Always flush the contents of the network packet.  This
259              should not hinder performance: fast downloads will be
260              received in 16K chunks (which stdio would write out
261              anyway), and slow downloads won't be limited by disk
262              performance.  */
263           fflush (fp);
264           if (ferror (fp))
265             {
266               res = -2;
267               goto out;
268             }
269           last_successful_read_tm = wtimer_read (timer);
270         }
271
272       if (opt.limit_rate)
273         limit_bandwidth (res, timer);
274
275       *len += res;
276       if (progress)
277         progress_update (progress, res, wtimer_read (timer));
278 #ifdef WINDOWS
279       if (use_expected && expected > 0)
280         ws_percenttitle (100.0 * (double)(*len) / (double)expected);
281 #endif
282     }
283   if (res < -1)
284     res = -1;
285
286  out:
287   if (progress)
288     progress_finish (progress, wtimer_read (timer));
289   if (elapsed)
290     *elapsed = wtimer_read (timer);
291   wtimer_delete (timer);
292
293   return res;
294 }
295 \f
296 /* Return a printed representation of the download rate, as
297    appropriate for the speed.  If PAD is non-zero, strings will be
298    padded to the width of 7 characters (xxxx.xx).  */
299 char *
300 retr_rate (long bytes, double msecs, int pad)
301 {
302   static char res[20];
303   static char *rate_names[] = {"B/s", "KB/s", "MB/s", "GB/s" };
304   int units = 0;
305
306   double dlrate = calc_rate (bytes, msecs, &units);
307   sprintf (res, pad ? "%7.2f %s" : "%.2f %s", dlrate, rate_names[units]);
308
309   return res;
310 }
311
312 /* Calculate the download rate and trim it as appropriate for the
313    speed.  Appropriate means that if rate is greater than 1K/s,
314    kilobytes are used, and if rate is greater than 1MB/s, megabytes
315    are used.
316
317    UNITS is zero for B/s, one for KB/s, two for MB/s, and three for
318    GB/s.  */
319 double
320 calc_rate (long bytes, double msecs, int *units)
321 {
322   double dlrate;
323
324   assert (msecs >= 0);
325   assert (bytes >= 0);
326
327   if (msecs == 0)
328     /* If elapsed time is exactly zero, it means we're under the
329        granularity of the timer.  This often happens on systems that
330        use time() for the timer.  */
331     msecs = wtimer_granularity ();
332
333   dlrate = (double)1000 * bytes / msecs;
334   if (dlrate < 1024.0)
335     *units = 0;
336   else if (dlrate < 1024.0 * 1024.0)
337     *units = 1, dlrate /= 1024.0;
338   else if (dlrate < 1024.0 * 1024.0 * 1024.0)
339     *units = 2, dlrate /= (1024.0 * 1024.0);
340   else
341     /* Maybe someone will need this, one day. */
342     *units = 3, dlrate /= (1024.0 * 1024.0 * 1024.0);
343
344   return dlrate;
345 }
346 \f
347 /* Maximum number of allowed redirections.  20 was chosen as a
348    "reasonable" value, which is low enough to not cause havoc, yet
349    high enough to guarantee that normal retrievals will not be hurt by
350    the check.  */
351
352 #define MAX_REDIRECTIONS 20
353
354 #define SUSPEND_POST_DATA do {                  \
355   post_data_suspended = 1;                      \
356   saved_post_data = opt.post_data;              \
357   saved_post_file_name = opt.post_file_name;    \
358   opt.post_data = NULL;                         \
359   opt.post_file_name = NULL;                    \
360 } while (0)
361
362 #define RESTORE_POST_DATA do {                          \
363   if (post_data_suspended)                              \
364     {                                                   \
365       opt.post_data = saved_post_data;                  \
366       opt.post_file_name = saved_post_file_name;        \
367       post_data_suspended = 0;                          \
368     }                                                   \
369 } while (0)
370
371 static char *getproxy PARAMS ((struct url *));
372
373 /* Retrieve the given URL.  Decides which loop to call -- HTTP, FTP,
374    FTP, proxy, etc.  */
375
376 /* #### This function should be rewritten so it doesn't return from
377    multiple points. */
378
379 uerr_t
380 retrieve_url (const char *origurl, char **file, char **newloc,
381               const char *refurl, int *dt)
382 {
383   uerr_t result;
384   char *url;
385   int location_changed, dummy;
386   char *mynewloc, *proxy;
387   struct url *u, *proxy_url;
388   int up_error_code;            /* url parse error code */
389   char *local_file;
390   int redirection_count = 0;
391
392   int post_data_suspended = 0;
393   char *saved_post_data = NULL;
394   char *saved_post_file_name = NULL;
395
396   /* If dt is NULL, use local storage.  */
397   if (!dt)
398     {
399       dt = &dummy;
400       dummy = 0;
401     }
402   url = xstrdup (origurl);
403   if (newloc)
404     *newloc = NULL;
405   if (file)
406     *file = NULL;
407
408   u = url_parse (url, &up_error_code);
409   if (!u)
410     {
411       logprintf (LOG_NOTQUIET, "%s: %s.\n", url, url_error (up_error_code));
412       xfree (url);
413       return URLERROR;
414     }
415
416   if (!refurl)
417     refurl = opt.referer;
418
419  redirected:
420
421   result = NOCONERROR;
422   mynewloc = NULL;
423   local_file = NULL;
424   proxy_url = NULL;
425
426   proxy = getproxy (u);
427   if (proxy)
428     {
429       /* Parse the proxy URL.  */
430       proxy_url = url_parse (proxy, &up_error_code);
431       if (!proxy_url)
432         {
433           logprintf (LOG_NOTQUIET, _("Error parsing proxy URL %s: %s.\n"),
434                      proxy, url_error (up_error_code));
435           xfree (url);
436           RESTORE_POST_DATA;
437           return PROXERR;
438         }
439       if (proxy_url->scheme != SCHEME_HTTP && proxy_url->scheme != u->scheme)
440         {
441           logprintf (LOG_NOTQUIET, _("Error in proxy URL %s: Must be HTTP.\n"), proxy);
442           url_free (proxy_url);
443           xfree (url);
444           RESTORE_POST_DATA;
445           return PROXERR;
446         }
447     }
448
449   if (u->scheme == SCHEME_HTTP
450 #ifdef HAVE_SSL
451       || u->scheme == SCHEME_HTTPS
452 #endif
453       || (proxy_url && proxy_url->scheme == SCHEME_HTTP))
454     {
455       result = http_loop (u, &mynewloc, &local_file, refurl, dt, proxy_url);
456     }
457   else if (u->scheme == SCHEME_FTP)
458     {
459       /* If this is a redirection, we must not allow recursive FTP
460          retrieval, so we save recursion to oldrec, and restore it
461          later.  */
462       int oldrec = opt.recursive;
463       if (redirection_count)
464         opt.recursive = 0;
465       result = ftp_loop (u, dt, proxy_url);
466       opt.recursive = oldrec;
467
468       /* There is a possibility of having HTTP being redirected to
469          FTP.  In these cases we must decide whether the text is HTML
470          according to the suffix.  The HTML suffixes are `.html',
471          `.htm' and a few others, case-insensitive.  */
472       if (redirection_count && local_file && u->scheme == SCHEME_FTP)
473         {
474           if (has_html_suffix_p (local_file))
475             *dt |= TEXTHTML;
476         }
477     }
478
479   if (proxy_url)
480     {
481       url_free (proxy_url);
482       proxy_url = NULL;
483     }
484
485   location_changed = (result == NEWLOCATION);
486   if (location_changed)
487     {
488       char *construced_newloc;
489       struct url *newloc_parsed;
490
491       assert (mynewloc != NULL);
492
493       if (local_file)
494         xfree (local_file);
495
496       /* The HTTP specs only allow absolute URLs to appear in
497          redirects, but a ton of boneheaded webservers and CGIs out
498          there break the rules and use relative URLs, and popular
499          browsers are lenient about this, so wget should be too. */
500       construced_newloc = uri_merge (url, mynewloc);
501       xfree (mynewloc);
502       mynewloc = construced_newloc;
503
504       /* Now, see if this new location makes sense. */
505       newloc_parsed = url_parse (mynewloc, &up_error_code);
506       if (!newloc_parsed)
507         {
508           logprintf (LOG_NOTQUIET, "%s: %s.\n", mynewloc,
509                      url_error (up_error_code));
510           url_free (u);
511           xfree (url);
512           xfree (mynewloc);
513           RESTORE_POST_DATA;
514           return result;
515         }
516
517       /* Now mynewloc will become newloc_parsed->url, because if the
518          Location contained relative paths like .././something, we
519          don't want that propagating as url.  */
520       xfree (mynewloc);
521       mynewloc = xstrdup (newloc_parsed->url);
522
523       /* Check for max. number of redirections.  */
524       if (++redirection_count > MAX_REDIRECTIONS)
525         {
526           logprintf (LOG_NOTQUIET, _("%d redirections exceeded.\n"),
527                      MAX_REDIRECTIONS);
528           url_free (newloc_parsed);
529           url_free (u);
530           xfree (url);
531           xfree (mynewloc);
532           RESTORE_POST_DATA;
533           return WRONGCODE;
534         }
535
536       xfree (url);
537       url = mynewloc;
538       url_free (u);
539       u = newloc_parsed;
540
541       /* If we're being redirected from POST, we don't want to POST
542          again.  Many requests answer POST with a redirection to an
543          index page; that redirection is clearly a GET.  We "suspend"
544          POST data for the duration of the redirections, and restore
545          it when we're done. */
546       if (!post_data_suspended)
547         SUSPEND_POST_DATA;
548
549       goto redirected;
550     }
551
552   if (local_file)
553     {
554       if (*dt & RETROKF)
555         {
556           register_download (u->url, local_file);
557           if (redirection_count && 0 != strcmp (origurl, u->url))
558             register_redirection (origurl, u->url);
559           if (*dt & TEXTHTML)
560             register_html (u->url, local_file);
561         }
562     }
563
564   if (file)
565     *file = local_file ? local_file : NULL;
566   else
567     xfree_null (local_file);
568
569   url_free (u);
570
571   if (redirection_count)
572     {
573       if (newloc)
574         *newloc = url;
575       else
576         xfree (url);
577     }
578   else
579     {
580       if (newloc)
581         *newloc = NULL;
582       xfree (url);
583     }
584
585   ++global_download_count;
586   RESTORE_POST_DATA;
587
588   return result;
589 }
590
591 /* Find the URLs in the file and call retrieve_url() for each of
592    them.  If HTML is non-zero, treat the file as HTML, and construct
593    the URLs accordingly.
594
595    If opt.recursive is set, call retrieve_tree() for each file.  */
596
597 uerr_t
598 retrieve_from_file (const char *file, int html, int *count)
599 {
600   uerr_t status;
601   struct urlpos *url_list, *cur_url;
602
603   url_list = (html ? get_urls_html (file, NULL, NULL)
604               : get_urls_file (file));
605   status = RETROK;             /* Suppose everything is OK.  */
606   *count = 0;                  /* Reset the URL count.  */
607
608   for (cur_url = url_list; cur_url; cur_url = cur_url->next, ++*count)
609     {
610       char *filename = NULL, *new_file = NULL;
611       int dt;
612
613       if (cur_url->ignore_when_downloading)
614         continue;
615
616       if (opt.quota && total_downloaded_bytes > opt.quota)
617         {
618           status = QUOTEXC;
619           break;
620         }
621       if ((opt.recursive || opt.page_requisites)
622           && cur_url->url->scheme != SCHEME_FTP)
623         status = retrieve_tree (cur_url->url->url);
624       else
625         status = retrieve_url (cur_url->url->url, &filename, &new_file, NULL, &dt);
626
627       if (filename && opt.delete_after && file_exists_p (filename))
628         {
629           DEBUGP (("Removing file due to --delete-after in"
630                    " retrieve_from_file():\n"));
631           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
632           if (unlink (filename))
633             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
634           dt &= ~RETROKF;
635         }
636
637       xfree_null (new_file);
638       xfree_null (filename);
639     }
640
641   /* Free the linked list of URL-s.  */
642   free_urlpos (url_list);
643
644   return status;
645 }
646
647 /* Print `giving up', or `retrying', depending on the impending
648    action.  N1 and N2 are the attempt number and the attempt limit.  */
649 void
650 printwhat (int n1, int n2)
651 {
652   logputs (LOG_VERBOSE, (n1 == n2) ? _("Giving up.\n\n") : _("Retrying.\n\n"));
653 }
654
655 /* If opt.wait or opt.waitretry are specified, and if certain
656    conditions are met, sleep the appropriate number of seconds.  See
657    the documentation of --wait and --waitretry for more information.
658
659    COUNT is the count of current retrieval, beginning with 1. */
660
661 void
662 sleep_between_retrievals (int count)
663 {
664   static int first_retrieval = 1;
665
666   if (first_retrieval)
667     {
668       /* Don't sleep before the very first retrieval. */
669       first_retrieval = 0;
670       return;
671     }
672
673   if (opt.waitretry && count > 1)
674     {
675       /* If opt.waitretry is specified and this is a retry, wait for
676          COUNT-1 number of seconds, or for opt.waitretry seconds.  */
677       if (count <= opt.waitretry)
678         xsleep (count - 1);
679       else
680         xsleep (opt.waitretry);
681     }
682   else if (opt.wait)
683     {
684       if (!opt.random_wait || count > 1)
685         /* If random-wait is not specified, or if we are sleeping
686            between retries of the same download, sleep the fixed
687            interval.  */
688         xsleep (opt.wait);
689       else
690         {
691           /* Sleep a random amount of time averaging in opt.wait
692              seconds.  The sleeping amount ranges from 0 to
693              opt.wait*2, inclusive.  */
694           double waitsecs = 2 * opt.wait * random_float ();
695           DEBUGP (("sleep_between_retrievals: avg=%f,sleep=%f\n",
696                    opt.wait, waitsecs));
697           xsleep (waitsecs);
698         }
699     }
700 }
701
702 /* Free the linked list of urlpos.  */
703 void
704 free_urlpos (struct urlpos *l)
705 {
706   while (l)
707     {
708       struct urlpos *next = l->next;
709       if (l->url)
710         url_free (l->url);
711       xfree_null (l->local_name);
712       xfree (l);
713       l = next;
714     }
715 }
716
717 /* Rotate FNAME opt.backups times */
718 void
719 rotate_backups(const char *fname)
720 {
721   int maxlen = strlen (fname) + 1 + numdigit (opt.backups) + 1;
722   char *from = (char *)alloca (maxlen);
723   char *to = (char *)alloca (maxlen);
724   struct stat sb;
725   int i;
726
727   if (stat (fname, &sb) == 0)
728     if (S_ISREG (sb.st_mode) == 0)
729       return;
730
731   for (i = opt.backups; i > 1; i--)
732     {
733       sprintf (from, "%s.%d", fname, i - 1);
734       sprintf (to, "%s.%d", fname, i);
735       rename (from, to);
736     }
737
738   sprintf (to, "%s.%d", fname, 1);
739   rename(fname, to);
740 }
741
742 static int no_proxy_match PARAMS ((const char *, const char **));
743
744 /* Return the URL of the proxy appropriate for url U.  */
745
746 static char *
747 getproxy (struct url *u)
748 {
749   char *proxy = NULL;
750   char *rewritten_url;
751   static char rewritten_storage[1024];
752
753   if (!opt.use_proxy)
754     return NULL;
755   if (!no_proxy_match (u->host, (const char **)opt.no_proxy))
756     return NULL;
757
758   switch (u->scheme)
759     {
760     case SCHEME_HTTP:
761       proxy = opt.http_proxy ? opt.http_proxy : getenv ("http_proxy");
762       break;
763 #ifdef HAVE_SSL
764     case SCHEME_HTTPS:
765       proxy = opt.https_proxy ? opt.https_proxy : getenv ("https_proxy");
766       break;
767 #endif
768     case SCHEME_FTP:
769       proxy = opt.ftp_proxy ? opt.ftp_proxy : getenv ("ftp_proxy");
770       break;
771     case SCHEME_INVALID:
772       break;
773     }
774   if (!proxy || !*proxy)
775     return NULL;
776
777   /* Handle shorthands.  `rewritten_storage' is a kludge to allow
778      getproxy() to return static storage. */
779   rewritten_url = rewrite_shorthand_url (proxy);
780   if (rewritten_url)
781     {
782       strncpy (rewritten_storage, rewritten_url, sizeof(rewritten_storage));
783       rewritten_storage[sizeof (rewritten_storage) - 1] = '\0';
784       proxy = rewritten_storage;
785     }
786
787   return proxy;
788 }
789
790 /* Should a host be accessed through proxy, concerning no_proxy?  */
791 int
792 no_proxy_match (const char *host, const char **no_proxy)
793 {
794   if (!no_proxy)
795     return 1;
796   else
797     return !sufmatch (no_proxy, host);
798 }