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