]> sjero.net Git - wget/blob - src/url.c
d48031916aa747391e4a3ddffc744d728290fe50
[wget] / src / url.c
1 /* URL handling.
2    Copyright (C) 1995, 1996, 1997, 2000, 2001, 2003, 2003
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Wget.
6
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11
12 GNU Wget is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Wget; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 In addition, as a special exception, the Free Software Foundation
22 gives permission to link the code of its release of Wget with the
23 OpenSSL project's "OpenSSL" library (or with modified versions of it
24 that use the same license as the "OpenSSL" library), and distribute
25 the linked executables.  You must obey the GNU General Public License
26 in all respects for all of the code used other than "OpenSSL".  If you
27 modify this file, you may extend this exception to your version of the
28 file, but you are not obligated to do so.  If you do not wish to do
29 so, delete this exception statement from your version.  */
30
31 #include <config.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #else
38 # include <strings.h>
39 #endif
40 #include <sys/types.h>
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <errno.h>
45 #include <assert.h>
46
47 #include "wget.h"
48 #include "utils.h"
49 #include "url.h"
50 #include "host.h"
51 #include "hash.h"
52
53 #ifndef errno
54 extern int errno;
55 #endif
56
57 struct scheme_data
58 {
59   char *leading_string;
60   int default_port;
61   int enabled;
62 };
63
64 /* Supported schemes: */
65 static struct scheme_data supported_schemes[] =
66 {
67   { "http://",  DEFAULT_HTTP_PORT,  1 },
68 #ifdef HAVE_SSL
69   { "https://", DEFAULT_HTTPS_PORT, 1 },
70 #endif
71   { "ftp://",   DEFAULT_FTP_PORT,   1 },
72
73   /* SCHEME_INVALID */
74   { NULL,       -1,                 0 }
75 };
76
77 /* Forward declarations: */
78
79 static char *construct_relative PARAMS ((const char *, const char *));
80 static int path_simplify PARAMS ((char *));
81
82
83 \f
84 /* Support for encoding and decoding of URL strings.  We determine
85    whether a character is unsafe through static table lookup.  This
86    code assumes ASCII character set and 8-bit chars.  */
87
88 enum {
89   /* rfc1738 reserved chars, preserved from encoding.  */
90   urlchr_reserved = 1,
91
92   /* rfc1738 unsafe chars, plus some more.  */
93   urlchr_unsafe   = 2
94 };
95
96 #define urlchr_test(c, mask) (urlchr_table[(unsigned char)(c)] & (mask))
97 #define URL_RESERVED_CHAR(c) urlchr_test(c, urlchr_reserved)
98 #define URL_UNSAFE_CHAR(c) urlchr_test(c, urlchr_unsafe)
99
100 /* Shorthands for the table: */
101 #define R  urlchr_reserved
102 #define U  urlchr_unsafe
103 #define RU R|U
104
105 const static unsigned char urlchr_table[256] =
106 {
107   U,  U,  U,  U,   U,  U,  U,  U,   /* NUL SOH STX ETX  EOT ENQ ACK BEL */
108   U,  U,  U,  U,   U,  U,  U,  U,   /* BS  HT  LF  VT   FF  CR  SO  SI  */
109   U,  U,  U,  U,   U,  U,  U,  U,   /* DLE DC1 DC2 DC3  DC4 NAK SYN ETB */
110   U,  U,  U,  U,   U,  U,  U,  U,   /* CAN EM  SUB ESC  FS  GS  RS  US  */
111   U,  0,  U, RU,   0,  U,  R,  0,   /* SP  !   "   #    $   %   &   '   */
112   0,  0,  0,  R,   0,  0,  0,  R,   /* (   )   *   +    ,   -   .   /   */
113   0,  0,  0,  0,   0,  0,  0,  0,   /* 0   1   2   3    4   5   6   7   */
114   0,  0, RU,  R,   U,  R,  U,  R,   /* 8   9   :   ;    <   =   >   ?   */
115  RU,  0,  0,  0,   0,  0,  0,  0,   /* @   A   B   C    D   E   F   G   */
116   0,  0,  0,  0,   0,  0,  0,  0,   /* H   I   J   K    L   M   N   O   */
117   0,  0,  0,  0,   0,  0,  0,  0,   /* P   Q   R   S    T   U   V   W   */
118   0,  0,  0, RU,   U, RU,  U,  0,   /* X   Y   Z   [    \   ]   ^   _   */
119   U,  0,  0,  0,   0,  0,  0,  0,   /* `   a   b   c    d   e   f   g   */
120   0,  0,  0,  0,   0,  0,  0,  0,   /* h   i   j   k    l   m   n   o   */
121   0,  0,  0,  0,   0,  0,  0,  0,   /* p   q   r   s    t   u   v   w   */
122   0,  0,  0,  U,   U,  U,  U,  U,   /* x   y   z   {    |   }   ~   DEL */
123
124   U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
125   U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
126   U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
127   U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
128
129   U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
130   U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
131   U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
132   U, U, U, U,  U, U, U, U,  U, U, U, U,  U, U, U, U,
133 };
134 #undef R
135 #undef U
136 #undef RU
137
138 /* URL-unescape the string S.
139
140    This is done by transforming the sequences "%HH" to the character
141    represented by the hexadecimal digits HH.  If % is not followed by
142    two hexadecimal digits, it is inserted literally.
143
144    The transformation is done in place.  If you need the original
145    string intact, make a copy before calling this function.  */
146
147 static void
148 url_unescape (char *s)
149 {
150   char *t = s;                  /* t - tortoise */
151   char *h = s;                  /* h - hare     */
152
153   for (; *h; h++, t++)
154     {
155       if (*h != '%')
156         {
157         copychar:
158           *t = *h;
159         }
160       else
161         {
162           /* Do nothing if '%' is not followed by two hex digits. */
163           if (!h[1] || !h[2] || !(ISXDIGIT (h[1]) && ISXDIGIT (h[2])))
164             goto copychar;
165           *t = X2DIGITS_TO_NUM (h[1], h[2]);
166           h += 2;
167         }
168     }
169   *t = '\0';
170 }
171
172 /* The core of url_escape_* functions.  Escapes the characters that
173    match the provided mask in urlchr_table.
174
175    If ALLOW_PASSTHROUGH is non-zero, a string with no unsafe chars
176    will be returned unchanged.  If ALLOW_PASSTHROUGH is zero, a
177    freshly allocated string will be returned in all cases.  */
178
179 static char *
180 url_escape_1 (const char *s, unsigned char mask, int allow_passthrough)
181 {
182   const char *p1;
183   char *p2, *newstr;
184   int newlen;
185   int addition = 0;
186
187   for (p1 = s; *p1; p1++)
188     if (urlchr_test (*p1, mask))
189       addition += 2;            /* Two more characters (hex digits) */
190
191   if (!addition)
192     return allow_passthrough ? (char *)s : xstrdup (s);
193
194   newlen = (p1 - s) + addition;
195   newstr = (char *)xmalloc (newlen + 1);
196
197   p1 = s;
198   p2 = newstr;
199   while (*p1)
200     {
201       /* Quote the characters that match the test mask. */
202       if (urlchr_test (*p1, mask))
203         {
204           unsigned char c = *p1++;
205           *p2++ = '%';
206           *p2++ = XNUM_TO_digit (c >> 4);
207           *p2++ = XNUM_TO_digit (c & 0xf);
208         }
209       else
210         *p2++ = *p1++;
211     }
212   assert (p2 - newstr == newlen);
213   *p2 = '\0';
214
215   return newstr;
216 }
217
218 /* URL-escape the unsafe characters (see urlchr_table) in a given
219    string, returning a freshly allocated string.  */
220
221 char *
222 url_escape (const char *s)
223 {
224   return url_escape_1 (s, urlchr_unsafe, 0);
225 }
226
227 /* URL-escape the unsafe characters (see urlchr_table) in a given
228    string.  If no characters are unsafe, S is returned.  */
229
230 static char *
231 url_escape_allow_passthrough (const char *s)
232 {
233   return url_escape_1 (s, urlchr_unsafe, 1);
234 }
235 \f
236 enum copy_method { CM_DECODE, CM_ENCODE, CM_PASSTHROUGH };
237
238 /* Decide whether to encode, decode, or pass through the char at P.
239    This used to be a macro, but it got a little too convoluted.  */
240 static inline enum copy_method
241 decide_copy_method (const char *p)
242 {
243   if (*p == '%')
244     {
245       if (ISXDIGIT (*(p + 1)) && ISXDIGIT (*(p + 2)))
246         {
247           /* %xx sequence: decode it, unless it would decode to an
248              unsafe or a reserved char; in that case, leave it as
249              is. */
250           char preempt = X2DIGITS_TO_NUM (*(p + 1), *(p + 2));
251           if (URL_UNSAFE_CHAR (preempt) || URL_RESERVED_CHAR (preempt))
252             return CM_PASSTHROUGH;
253           else
254             return CM_DECODE;
255         }
256       else
257         /* Garbled %.. sequence: encode `%'. */
258         return CM_ENCODE;
259     }
260   else if (URL_UNSAFE_CHAR (*p) && !URL_RESERVED_CHAR (*p))
261     return CM_ENCODE;
262   else
263     return CM_PASSTHROUGH;
264 }
265
266 /* Translate a %-escaped (but possibly non-conformant) input string S
267    into a %-escaped (and conformant) output string.  If no characters
268    are encoded or decoded, return the same string S; otherwise, return
269    a freshly allocated string with the new contents.
270
271    After a URL has been run through this function, the protocols that
272    use `%' as the quote character can use the resulting string as-is,
273    while those that don't call url_unescape() to get to the intended
274    data.  This function is also stable: after an input string is
275    transformed the first time, all further transformations of the
276    result yield the same result string.
277
278    Let's discuss why this function is needed.
279
280    Imagine Wget is to retrieve `http://abc.xyz/abc def'.  Since a raw
281    space character would mess up the HTTP request, it needs to be
282    quoted, like this:
283
284        GET /abc%20def HTTP/1.0
285
286    It appears that the unsafe chars need to be quoted, for example
287    with url_escape.  But what if we're requested to download
288    `abc%20def'?  url_escape transforms "%" to "%25", which would leave
289    us with `abc%2520def'.  This is incorrect -- since %-escapes are
290    part of URL syntax, "%20" is the correct way to denote a literal
291    space on the Wget command line.  This leaves us in the conclusion
292    that in that case Wget should not call url_escape, but leave the
293    `%20' as is.
294
295    And what if the requested URI is `abc%20 def'?  If we call
296    url_escape, we end up with `/abc%2520%20def', which is almost
297    certainly not intended.  If we don't call url_escape, we are left
298    with the embedded space and cannot complete the request.  What the
299    user meant was for Wget to request `/abc%20%20def', and this is
300    where reencode_escapes kicks in.
301
302    Wget used to solve this by first decoding %-quotes, and then
303    encoding all the "unsafe" characters found in the resulting string.
304    This was wrong because it didn't preserve certain URL special
305    (reserved) characters.  For instance, URI containing "a%2B+b" (0x2b
306    == '+') would get translated to "a%2B%2Bb" or "a++b" depending on
307    whether we considered `+' reserved (it is).  One of these results
308    is inevitable because by the second step we would lose information
309    on whether the `+' was originally encoded or not.  Both results
310    were wrong because in CGI parameters + means space, while %2B means
311    literal plus.  reencode_escapes correctly translates the above to
312    "a%2B+b", i.e. returns the original string.
313
314    This function uses an algorithm proposed by Anon Sricharoenchai:
315
316    1. Encode all URL_UNSAFE and the "%" that are not followed by 2
317       hexdigits.
318
319    2. Decode all "%XX" except URL_UNSAFE, URL_RESERVED (";/?:@=&") and
320       "+".
321
322    ...except that this code conflates the two steps, and decides
323    whether to encode, decode, or pass through each character in turn.
324    The function still uses two passes, but their logic is the same --
325    the first pass exists merely for the sake of allocation.  Another
326    small difference is that we include `+' to URL_RESERVED.
327
328    Anon's test case:
329
330    "http://abc.xyz/%20%3F%%36%31%25aa% a?a=%61+a%2Ba&b=b%26c%3Dc"
331    ->
332    "http://abc.xyz/%20%3F%2561%25aa%25%20a?a=a+a%2Ba&b=b%26c%3Dc"
333
334    Simpler test cases:
335
336    "foo bar"         -> "foo%20bar"
337    "foo%20bar"       -> "foo%20bar"
338    "foo %20bar"      -> "foo%20%20bar"
339    "foo%%20bar"      -> "foo%25%20bar"       (0x25 == '%')
340    "foo%25%20bar"    -> "foo%25%20bar"
341    "foo%2%20bar"     -> "foo%252%20bar"
342    "foo+bar"         -> "foo+bar"            (plus is reserved!)
343    "foo%2b+bar"      -> "foo%2b+bar"  */
344
345 static char *
346 reencode_escapes (const char *s)
347 {
348   const char *p1;
349   char *newstr, *p2;
350   int oldlen, newlen;
351
352   int encode_count = 0;
353   int decode_count = 0;
354
355   /* First, pass through the string to see if there's anything to do,
356      and to calculate the new length.  */
357   for (p1 = s; *p1; p1++)
358     {
359       switch (decide_copy_method (p1))
360         {
361         case CM_ENCODE:
362           ++encode_count;
363           break;
364         case CM_DECODE:
365           ++decode_count;
366           break;
367         case CM_PASSTHROUGH:
368           break;
369         }
370     }
371
372   if (!encode_count && !decode_count)
373     /* The string is good as it is. */
374     return (char *)s;           /* C const model sucks. */
375
376   oldlen = p1 - s;
377   /* Each encoding adds two characters (hex digits), while each
378      decoding removes two characters.  */
379   newlen = oldlen + 2 * (encode_count - decode_count);
380   newstr = xmalloc (newlen + 1);
381
382   p1 = s;
383   p2 = newstr;
384
385   while (*p1)
386     {
387       switch (decide_copy_method (p1))
388         {
389         case CM_ENCODE:
390           {
391             unsigned char c = *p1++;
392             *p2++ = '%';
393             *p2++ = XNUM_TO_DIGIT (c >> 4);
394             *p2++ = XNUM_TO_DIGIT (c & 0xf);
395           }
396           break;
397         case CM_DECODE:
398           *p2++ = X2DIGITS_TO_NUM (p1[1], p1[2]);
399           p1 += 3;              /* skip %xx */
400           break;
401         case CM_PASSTHROUGH:
402           *p2++ = *p1++;
403         }
404     }
405   *p2 = '\0';
406   assert (p2 - newstr == newlen);
407   return newstr;
408 }
409 \f
410 /* Returns the scheme type if the scheme is supported, or
411    SCHEME_INVALID if not.  */
412
413 enum url_scheme
414 url_scheme (const char *url)
415 {
416   int i;
417
418   for (i = 0; supported_schemes[i].leading_string; i++)
419     if (0 == strncasecmp (url, supported_schemes[i].leading_string,
420                           strlen (supported_schemes[i].leading_string)))
421       {
422         if (supported_schemes[i].enabled)
423           return (enum url_scheme) i;
424         else
425           return SCHEME_INVALID;
426       }
427
428   return SCHEME_INVALID;
429 }
430
431 #define SCHEME_CHAR(ch) (ISALNUM (ch) || (ch) == '-' || (ch) == '+')
432
433 /* Return 1 if the URL begins with any "scheme", 0 otherwise.  As
434    currently implemented, it returns true if URL begins with
435    [-+a-zA-Z0-9]+: .  */
436
437 int
438 url_has_scheme (const char *url)
439 {
440   const char *p = url;
441
442   /* The first char must be a scheme char. */
443   if (!*p || !SCHEME_CHAR (*p))
444     return 0;
445   ++p;
446   /* Followed by 0 or more scheme chars. */
447   while (*p && SCHEME_CHAR (*p))
448     ++p;
449   /* Terminated by ':'. */
450   return *p == ':';
451 }
452
453 int
454 scheme_default_port (enum url_scheme scheme)
455 {
456   return supported_schemes[scheme].default_port;
457 }
458
459 void
460 scheme_disable (enum url_scheme scheme)
461 {
462   supported_schemes[scheme].enabled = 0;
463 }
464
465 /* Skip the username and password, if present here.  The function
466    should *not* be called with the complete URL, but with the part
467    right after the scheme.
468
469    If no username and password are found, return 0.  */
470
471 static int
472 url_skip_credentials (const char *url)
473 {
474   /* Look for '@' that comes before terminators, such as '/', '?',
475      '#', or ';'.  */
476   const char *p = (const char *)strpbrk (url, "@/?#;");
477   if (!p || *p != '@')
478     return 0;
479   return p + 1 - url;
480 }
481
482 /* Parse credentials contained in [BEG, END).  The region is expected
483    to have come from a URL and is unescaped.  */
484
485 static int
486 parse_credentials (const char *beg, const char *end, char **user, char **passwd)
487 {
488   char *colon;
489   const char *userend;
490
491   if (beg == end)
492     return 0;                   /* empty user name */
493
494   colon = memchr (beg, ':', end - beg);
495   if (colon == beg)
496     return 0;                   /* again empty user name */
497
498   if (colon)
499     {
500       *passwd = strdupdelim (colon + 1, end);
501       userend = colon;
502       url_unescape (*passwd);
503     }
504   else
505     {
506       *passwd = NULL;
507       userend = end;
508     }
509   *user = strdupdelim (beg, userend);
510   url_unescape (*user);
511   return 1;
512 }
513
514 /* Used by main.c: detect URLs written using the "shorthand" URL forms
515    popularized by Netscape and NcFTP.  HTTP shorthands look like this:
516
517    www.foo.com[:port]/dir/file   -> http://www.foo.com[:port]/dir/file
518    www.foo.com[:port]            -> http://www.foo.com[:port]
519
520    FTP shorthands look like this:
521
522    foo.bar.com:dir/file          -> ftp://foo.bar.com/dir/file
523    foo.bar.com:/absdir/file      -> ftp://foo.bar.com//absdir/file
524
525    If the URL needs not or cannot be rewritten, return NULL.  */
526
527 char *
528 rewrite_shorthand_url (const char *url)
529 {
530   const char *p;
531
532   if (url_has_scheme (url))
533     return NULL;
534
535   /* Look for a ':' or '/'.  The former signifies NcFTP syntax, the
536      latter Netscape.  */
537   for (p = url; *p && *p != ':' && *p != '/'; p++)
538     ;
539
540   if (p == url)
541     return NULL;
542
543   if (*p == ':')
544     {
545       const char *pp;
546       char *res;
547       /* If the characters after the colon and before the next slash
548          or end of string are all digits, it's HTTP.  */
549       int digits = 0;
550       for (pp = p + 1; ISDIGIT (*pp); pp++)
551         ++digits;
552       if (digits > 0 && (*pp == '/' || *pp == '\0'))
553         goto http;
554
555       /* Prepend "ftp://" to the entire URL... */
556       res = xmalloc (6 + strlen (url) + 1);
557       sprintf (res, "ftp://%s", url);
558       /* ...and replace ':' with '/'. */
559       res[6 + (p - url)] = '/';
560       return res;
561     }
562   else
563     {
564       char *res;
565     http:
566       /* Just prepend "http://" to what we have. */
567       res = xmalloc (7 + strlen (url) + 1);
568       sprintf (res, "http://%s", url);
569       return res;
570     }
571 }
572 \f
573 static void split_path PARAMS ((const char *, char **, char **));
574
575 /* Like strpbrk, with the exception that it returns the pointer to the
576    terminating zero (end-of-string aka "eos") if no matching character
577    is found.
578
579    Although I normally balk at Gcc-specific optimizations, it probably
580    makes sense here: glibc has optimizations that detect strpbrk being
581    called with literal string as ACCEPT and inline the search.  That
582    optimization is defeated if strpbrk is hidden within the call to
583    another function.  (And no, making strpbrk_or_eos inline doesn't
584    help because the check for literal accept is in the
585    preprocessor.)  */
586
587 #ifdef __GNUC__
588
589 #define strpbrk_or_eos(s, accept) ({            \
590   char *SOE_p = strpbrk (s, accept);            \
591   if (!SOE_p)                                   \
592     SOE_p = (char *)s + strlen (s);             \
593   SOE_p;                                        \
594 })
595
596 #else  /* not __GNUC__ */
597
598 static char *
599 strpbrk_or_eos (const char *s, const char *accept)
600 {
601   char *p = strpbrk (s, accept);
602   if (!p)
603     p = (char *)s + strlen (s);
604   return p;
605 }
606 #endif
607
608 /* Turn STR into lowercase; return non-zero if a character was
609    actually changed. */
610
611 static int
612 lowercase_str (char *str)
613 {
614   int change = 0;
615   for (; *str; str++)
616     if (ISUPPER (*str))
617       {
618         change = 1;
619         *str = TOLOWER (*str);
620       }
621   return change;
622 }
623
624 static char *parse_errors[] = {
625 #define PE_NO_ERROR                     0
626   "No error",
627 #define PE_UNSUPPORTED_SCHEME           1
628   "Unsupported scheme",
629 #define PE_EMPTY_HOST                   2
630   "Empty host",
631 #define PE_BAD_PORT_NUMBER              3
632   "Bad port number",
633 #define PE_INVALID_USER_NAME            4
634   "Invalid user name",
635 #define PE_UNTERMINATED_IPV6_ADDRESS    5
636   "Unterminated IPv6 numeric address",
637 #define PE_IPV6_NOT_SUPPORTED           6
638   "IPv6 addresses not supported",
639 #define PE_INVALID_IPV6_ADDRESS         7
640   "Invalid IPv6 numeric address"
641 };
642
643 #define SETERR(p, v) do {                       \
644   if (p)                                        \
645     *(p) = (v);                                 \
646 } while (0)
647
648 #ifdef ENABLE_IPV6
649 /* The following two functions were adapted from glibc. */
650
651 static int
652 is_valid_ipv4_address (const char *str, const char *end)
653 {
654   int saw_digit, octets;
655   int val;
656
657   saw_digit = 0;
658   octets = 0;
659   val = 0;
660
661   while (str < end) {
662     int ch = *str++;
663
664     if (ch >= '0' && ch <= '9') {
665       val = val * 10 + (ch - '0');
666
667       if (val > 255)
668         return 0;
669       if (saw_digit == 0) {
670         if (++octets > 4)
671           return 0;
672         saw_digit = 1;
673       }
674     } else if (ch == '.' && saw_digit == 1) {
675       if (octets == 4)
676         return 0;
677       val = 0;
678       saw_digit = 0;
679     } else
680       return 0;
681   }
682   if (octets < 4)
683     return 0;
684   
685   return 1;
686 }
687
688 static const int NS_INADDRSZ  = 4;
689 static const int NS_IN6ADDRSZ = 16;
690 static const int NS_INT16SZ   = 2;
691
692 static int
693 is_valid_ipv6_address (const char *str, const char *end)
694 {
695   static const char xdigits[] = "0123456789abcdef";
696   const char *curtok;
697   int tp;
698   const char *colonp;
699   int saw_xdigit;
700   unsigned int val;
701
702   tp = 0;
703   colonp = NULL;
704
705   if (str == end)
706     return 0;
707   
708   /* Leading :: requires some special handling. */
709   if (*str == ':')
710     {
711       ++str;
712       if (str == end || *str != ':')
713         return 0;
714     }
715
716   curtok = str;
717   saw_xdigit = 0;
718   val = 0;
719
720   while (str < end) {
721     int ch = *str++;
722     const char *pch;
723
724     /* if ch is a number, add it to val. */
725     pch = strchr(xdigits, ch);
726     if (pch != NULL) {
727       val <<= 4;
728       val |= (pch - xdigits);
729       if (val > 0xffff)
730         return 0;
731       saw_xdigit = 1;
732       continue;
733     }
734
735     /* if ch is a colon ... */
736     if (ch == ':') {
737       curtok = str;
738       if (saw_xdigit == 0) {
739         if (colonp != NULL)
740           return 0;
741         colonp = str + tp;
742         continue;
743       } else if (str == end) {
744         return 0;
745       }
746       if (tp > NS_IN6ADDRSZ - NS_INT16SZ)
747         return 0;
748       tp += NS_INT16SZ;
749       saw_xdigit = 0;
750       val = 0;
751       continue;
752     }
753
754     /* if ch is a dot ... */
755     if (ch == '.' && (tp <= NS_IN6ADDRSZ - NS_INADDRSZ) &&
756         is_valid_ipv4_address(curtok, end) == 1) {
757       tp += NS_INADDRSZ;
758       saw_xdigit = 0;
759       break;
760     }
761     
762     return 0;
763   }
764
765   if (saw_xdigit == 1) {
766     if (tp > NS_IN6ADDRSZ - NS_INT16SZ) 
767       return 0;
768     tp += NS_INT16SZ;
769   }
770
771   if (colonp != NULL) {
772     if (tp == NS_IN6ADDRSZ) 
773       return 0;
774     tp = NS_IN6ADDRSZ;
775   }
776
777   if (tp != NS_IN6ADDRSZ)
778     return 0;
779
780   return 1;
781 }
782 #endif
783
784 /* Parse a URL.
785
786    Return a new struct url if successful, NULL on error.  In case of
787    error, and if ERROR is not NULL, also set *ERROR to the appropriate
788    error code. */
789 struct url *
790 url_parse (const char *url, int *error)
791 {
792   struct url *u;
793   const char *p;
794   int path_modified, host_modified;
795
796   enum url_scheme scheme;
797
798   const char *uname_b,     *uname_e;
799   const char *host_b,      *host_e;
800   const char *path_b,      *path_e;
801   const char *params_b,    *params_e;
802   const char *query_b,     *query_e;
803   const char *fragment_b,  *fragment_e;
804
805   int port;
806   char *user = NULL, *passwd = NULL;
807
808   char *url_encoded;
809
810   scheme = url_scheme (url);
811   if (scheme == SCHEME_INVALID)
812     {
813       SETERR (error, PE_UNSUPPORTED_SCHEME);
814       return NULL;
815     }
816
817   url_encoded = reencode_escapes (url);
818   p = url_encoded;
819
820   p += strlen (supported_schemes[scheme].leading_string);
821   uname_b = p;
822   p += url_skip_credentials (p);
823   uname_e = p;
824
825   /* scheme://user:pass@host[:port]... */
826   /*                    ^              */
827
828   /* We attempt to break down the URL into the components path,
829      params, query, and fragment.  They are ordered like this:
830
831        scheme://host[:port][/path][;params][?query][#fragment]  */
832
833   params_b   = params_e   = NULL;
834   query_b    = query_e    = NULL;
835   fragment_b = fragment_e = NULL;
836
837   host_b = p;
838
839   if (*p == '[')
840     {
841       /* Handle IPv6 address inside square brackets.  Ideally we'd
842          just look for the terminating ']', but rfc2732 mandates
843          rejecting invalid IPv6 addresses.  */
844
845       /* The address begins after '['. */
846       host_b = p + 1;
847       host_e = strchr (host_b, ']');
848
849       if (!host_e)
850         {
851           SETERR (error, PE_UNTERMINATED_IPV6_ADDRESS);
852           return NULL;
853         }
854
855 #ifdef ENABLE_IPV6
856       /* Check if the IPv6 address is valid. */
857       if (!is_valid_ipv6_address(host_b, host_e))
858         {
859           SETERR (error, PE_INVALID_IPV6_ADDRESS);
860           return NULL;
861         }
862
863       /* Continue parsing after the closing ']'. */
864       p = host_e + 1;
865 #else
866       SETERR (error, PE_IPV6_NOT_SUPPORTED);
867       return NULL;
868 #endif
869     }
870   else
871     {
872       p = strpbrk_or_eos (p, ":/;?#");
873       host_e = p;
874     }
875
876   if (host_b == host_e)
877     {
878       SETERR (error, PE_EMPTY_HOST);
879       return NULL;
880     }
881
882   port = scheme_default_port (scheme);
883   if (*p == ':')
884     {
885       const char *port_b, *port_e, *pp;
886
887       /* scheme://host:port/tralala */
888       /*              ^             */
889       ++p;
890       port_b = p;
891       p = strpbrk_or_eos (p, "/;?#");
892       port_e = p;
893
894       if (port_b == port_e)
895         {
896           /* http://host:/whatever */
897           /*             ^         */
898           SETERR (error, PE_BAD_PORT_NUMBER);
899           return NULL;
900         }
901
902       for (port = 0, pp = port_b; pp < port_e; pp++)
903         {
904           if (!ISDIGIT (*pp))
905             {
906               /* http://host:12randomgarbage/blah */
907               /*               ^                  */
908               SETERR (error, PE_BAD_PORT_NUMBER);
909               return NULL;
910             }
911           
912           port = 10 * port + (*pp - '0');
913         }
914     }
915
916   if (*p == '/')
917     {
918       ++p;
919       path_b = p;
920       p = strpbrk_or_eos (p, ";?#");
921       path_e = p;
922     }
923   else
924     {
925       /* Path is not allowed not to exist. */
926       path_b = path_e = p;
927     }
928
929   if (*p == ';')
930     {
931       ++p;
932       params_b = p;
933       p = strpbrk_or_eos (p, "?#");
934       params_e = p;
935     }
936   if (*p == '?')
937     {
938       ++p;
939       query_b = p;
940       p = strpbrk_or_eos (p, "#");
941       query_e = p;
942
943       /* Hack that allows users to use '?' (a wildcard character) in
944          FTP URLs without it being interpreted as a query string
945          delimiter.  */
946       if (scheme == SCHEME_FTP)
947         {
948           query_b = query_e = NULL;
949           path_e = p;
950         }
951     }
952   if (*p == '#')
953     {
954       ++p;
955       fragment_b = p;
956       p += strlen (p);
957       fragment_e = p;
958     }
959   assert (*p == 0);
960
961   if (uname_b != uname_e)
962     {
963       /* http://user:pass@host */
964       /*        ^         ^    */
965       /*     uname_b   uname_e */
966       if (!parse_credentials (uname_b, uname_e - 1, &user, &passwd))
967         {
968           SETERR (error, PE_INVALID_USER_NAME);
969           return NULL;
970         }
971     }
972
973   u = (struct url *)xmalloc (sizeof (struct url));
974   memset (u, 0, sizeof (*u));
975
976   u->scheme = scheme;
977   u->host   = strdupdelim (host_b, host_e);
978   u->port   = port;
979   u->user   = user;
980   u->passwd = passwd;
981
982   u->path = strdupdelim (path_b, path_e);
983   path_modified = path_simplify (u->path);
984   split_path (u->path, &u->dir, &u->file);
985
986   host_modified = lowercase_str (u->host);
987
988   if (params_b)
989     u->params = strdupdelim (params_b, params_e);
990   if (query_b)
991     u->query = strdupdelim (query_b, query_e);
992   if (fragment_b)
993     u->fragment = strdupdelim (fragment_b, fragment_e);
994
995   if (path_modified || u->fragment || host_modified || path_b == path_e)
996     {
997       /* If we suspect that a transformation has rendered what
998          url_string might return different from URL_ENCODED, rebuild
999          u->url using url_string.  */
1000       u->url = url_string (u, 0);
1001
1002       if (url_encoded != url)
1003         xfree ((char *) url_encoded);
1004     }
1005   else
1006     {
1007       if (url_encoded == url)
1008         u->url = xstrdup (url);
1009       else
1010         u->url = url_encoded;
1011     }
1012   url_encoded = NULL;
1013
1014   return u;
1015 }
1016
1017 const char *
1018 url_error (int error_code)
1019 {
1020   assert (error_code >= 0 && error_code < countof (parse_errors));
1021   return parse_errors[error_code];
1022 }
1023
1024 /* Split PATH into DIR and FILE.  PATH comes from the URL and is
1025    expected to be URL-escaped.
1026
1027    The path is split into directory (the part up to the last slash)
1028    and file (the part after the last slash), which are subsequently
1029    unescaped.  Examples:
1030
1031    PATH                 DIR           FILE
1032    "foo/bar/baz"        "foo/bar"     "baz"
1033    "foo/bar/"           "foo/bar"     ""
1034    "foo"                ""            "foo"
1035    "foo/bar/baz%2fqux"  "foo/bar"     "baz/qux" (!)
1036
1037    DIR and FILE are freshly allocated.  */
1038
1039 static void
1040 split_path (const char *path, char **dir, char **file)
1041 {
1042   char *last_slash = strrchr (path, '/');
1043   if (!last_slash)
1044     {
1045       *dir = xstrdup ("");
1046       *file = xstrdup (path);
1047     }
1048   else
1049     {
1050       *dir = strdupdelim (path, last_slash);
1051       *file = xstrdup (last_slash + 1);
1052     }
1053   url_unescape (*dir);
1054   url_unescape (*file);
1055 }
1056
1057 /* Note: URL's "full path" is the path with the query string and
1058    params appended.  The "fragment" (#foo) is intentionally ignored,
1059    but that might be changed.  For example, if the original URL was
1060    "http://host:port/foo/bar/baz;bullshit?querystring#uselessfragment",
1061    the full path will be "/foo/bar/baz;bullshit?querystring".  */
1062
1063 /* Return the length of the full path, without the terminating
1064    zero.  */
1065
1066 static int
1067 full_path_length (const struct url *url)
1068 {
1069   int len = 0;
1070
1071 #define FROB(el) if (url->el) len += 1 + strlen (url->el)
1072
1073   FROB (path);
1074   FROB (params);
1075   FROB (query);
1076
1077 #undef FROB
1078
1079   return len;
1080 }
1081
1082 /* Write out the full path. */
1083
1084 static void
1085 full_path_write (const struct url *url, char *where)
1086 {
1087 #define FROB(el, chr) do {                      \
1088   char *f_el = url->el;                         \
1089   if (f_el) {                                   \
1090     int l = strlen (f_el);                      \
1091     *where++ = chr;                             \
1092     memcpy (where, f_el, l);                    \
1093     where += l;                                 \
1094   }                                             \
1095 } while (0)
1096
1097   FROB (path, '/');
1098   FROB (params, ';');
1099   FROB (query, '?');
1100
1101 #undef FROB
1102 }
1103
1104 /* Public function for getting the "full path".  E.g. if u->path is
1105    "foo/bar" and u->query is "param=value", full_path will be
1106    "/foo/bar?param=value". */
1107
1108 char *
1109 url_full_path (const struct url *url)
1110 {
1111   int length = full_path_length (url);
1112   char *full_path = (char *)xmalloc(length + 1);
1113
1114   full_path_write (url, full_path);
1115   full_path[length] = '\0';
1116
1117   return full_path;
1118 }
1119
1120 /* Escape unsafe and reserved characters, except for the slash
1121    characters.  */
1122
1123 static char *
1124 url_escape_dir (const char *dir)
1125 {
1126   char *newdir = url_escape_1 (dir, urlchr_unsafe | urlchr_reserved, 1);
1127   char *h, *t;
1128   if (newdir == dir)
1129     return (char *)dir;
1130
1131   /* Unescape slashes in NEWDIR. */
1132
1133   h = newdir;                   /* hare */
1134   t = newdir;                   /* tortoise */
1135
1136   for (; *h; h++, t++)
1137     {
1138       if (*h == '%' && h[1] == '2' && h[2] == 'F')
1139         {
1140           *t = '/';
1141           h += 2;
1142         }
1143       else
1144         *t = *h;
1145     }
1146   *t = '\0';
1147
1148   return newdir;
1149 }
1150
1151 /* Sync u->path and u->url with u->dir and u->file.  Called after
1152    u->file or u->dir have been changed, typically by the FTP code.  */
1153
1154 static void
1155 sync_path (struct url *u)
1156 {
1157   char *newpath, *efile, *edir;
1158
1159   xfree (u->path);
1160
1161   /* u->dir and u->file are not escaped.  URL-escape them before
1162      reassembling them into u->path.  That way, if they contain
1163      separators like '?' or even if u->file contains slashes, the
1164      path will be correctly assembled.  (u->file can contain slashes
1165      if the URL specifies it with %2f, or if an FTP server returns
1166      it.)  */
1167   edir = url_escape_dir (u->dir);
1168   efile = url_escape_1 (u->file, urlchr_unsafe | urlchr_reserved, 1);
1169
1170   if (!*edir)
1171     newpath = xstrdup (efile);
1172   else
1173     {
1174       int dirlen = strlen (edir);
1175       int filelen = strlen (efile);
1176
1177       /* Copy "DIR/FILE" to newpath. */
1178       char *p = newpath = xmalloc (dirlen + 1 + filelen + 1);
1179       memcpy (p, edir, dirlen);
1180       p += dirlen;
1181       *p++ = '/';
1182       memcpy (p, efile, filelen);
1183       p += filelen;
1184       *p++ = '\0';
1185     }
1186
1187   u->path = newpath;
1188
1189   if (edir != u->dir)
1190     xfree (edir);
1191   if (efile != u->file)
1192     xfree (efile);
1193
1194   /* Regenerate u->url as well.  */
1195   xfree (u->url);
1196   u->url = url_string (u, 0);
1197 }
1198
1199 /* Mutators.  Code in ftp.c insists on changing u->dir and u->file.
1200    This way we can sync u->path and u->url when they get changed.  */
1201
1202 void
1203 url_set_dir (struct url *url, const char *newdir)
1204 {
1205   xfree (url->dir);
1206   url->dir = xstrdup (newdir);
1207   sync_path (url);
1208 }
1209
1210 void
1211 url_set_file (struct url *url, const char *newfile)
1212 {
1213   xfree (url->file);
1214   url->file = xstrdup (newfile);
1215   sync_path (url);
1216 }
1217
1218 void
1219 url_free (struct url *url)
1220 {
1221   xfree (url->host);
1222   xfree (url->path);
1223   xfree (url->url);
1224
1225   FREE_MAYBE (url->params);
1226   FREE_MAYBE (url->query);
1227   FREE_MAYBE (url->fragment);
1228   FREE_MAYBE (url->user);
1229   FREE_MAYBE (url->passwd);
1230
1231   xfree (url->dir);
1232   xfree (url->file);
1233
1234   xfree (url);
1235 }
1236 \f
1237 struct urlpos *
1238 get_urls_file (const char *file)
1239 {
1240   struct file_memory *fm;
1241   struct urlpos *head, *tail;
1242   const char *text, *text_end;
1243
1244   /* Load the file.  */
1245   fm = read_file (file);
1246   if (!fm)
1247     {
1248       logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
1249       return NULL;
1250     }
1251   DEBUGP (("Loaded %s (size %ld).\n", file, fm->length));
1252
1253   head = tail = NULL;
1254   text = fm->content;
1255   text_end = fm->content + fm->length;
1256   while (text < text_end)
1257     {
1258       const char *line_beg = text;
1259       const char *line_end = memchr (text, '\n', text_end - text);
1260       if (!line_end)
1261         line_end = text_end;
1262       else
1263         ++line_end;
1264       text = line_end;
1265
1266       /* Strip whitespace from the beginning and end of line. */
1267       while (line_beg < line_end && ISSPACE (*line_beg))
1268         ++line_beg;
1269       while (line_end > line_beg && ISSPACE (*(line_end - 1)))
1270         --line_end;
1271
1272       if (line_end > line_beg)
1273         {
1274           /* URL is in the [line_beg, line_end) region. */
1275
1276           int up_error_code;
1277           char *url_text;
1278           struct urlpos *entry;
1279           struct url *url;
1280
1281           /* We must copy the URL to a zero-terminated string, and we
1282              can't use alloca because we're in a loop.  *sigh*.  */
1283           url_text = strdupdelim (line_beg, line_end);
1284
1285           if (opt.base_href)
1286             {
1287               /* Merge opt.base_href with URL. */
1288               char *merged = uri_merge (opt.base_href, url_text);
1289               xfree (url_text);
1290               url_text = merged;
1291             }
1292
1293           url = url_parse (url_text, &up_error_code);
1294           if (!url)
1295             {
1296               logprintf (LOG_NOTQUIET, "%s: Invalid URL %s: %s\n",
1297                          file, url_text, url_error (up_error_code));
1298               xfree (url_text);
1299               continue;
1300             }
1301           xfree (url_text);
1302
1303           entry = (struct urlpos *)xmalloc (sizeof (struct urlpos));
1304           memset (entry, 0, sizeof (*entry));
1305           entry->next = NULL;
1306           entry->url = url;
1307
1308           if (!head)
1309             head = entry;
1310           else
1311             tail->next = entry;
1312           tail = entry;
1313         }
1314     }
1315   read_file_free (fm);
1316   return head;
1317 }
1318 \f
1319 /* Free the linked list of urlpos.  */
1320 void
1321 free_urlpos (struct urlpos *l)
1322 {
1323   while (l)
1324     {
1325       struct urlpos *next = l->next;
1326       if (l->url)
1327         url_free (l->url);
1328       FREE_MAYBE (l->local_name);
1329       xfree (l);
1330       l = next;
1331     }
1332 }
1333
1334 /* Rotate FNAME opt.backups times */
1335 void
1336 rotate_backups(const char *fname)
1337 {
1338   int maxlen = strlen (fname) + 1 + numdigit (opt.backups) + 1;
1339   char *from = (char *)alloca (maxlen);
1340   char *to = (char *)alloca (maxlen);
1341   struct stat sb;
1342   int i;
1343
1344   if (stat (fname, &sb) == 0)
1345     if (S_ISREG (sb.st_mode) == 0)
1346       return;
1347
1348   for (i = opt.backups; i > 1; i--)
1349     {
1350       sprintf (from, "%s.%d", fname, i - 1);
1351       sprintf (to, "%s.%d", fname, i);
1352       rename (from, to);
1353     }
1354
1355   sprintf (to, "%s.%d", fname, 1);
1356   rename(fname, to);
1357 }
1358
1359 /* Create all the necessary directories for PATH (a file).  Calls
1360    mkdirhier() internally.  */
1361 int
1362 mkalldirs (const char *path)
1363 {
1364   const char *p;
1365   char *t;
1366   struct stat st;
1367   int res;
1368
1369   p = path + strlen (path);
1370   for (; *p != '/' && p != path; p--)
1371     ;
1372
1373   /* Don't create if it's just a file.  */
1374   if ((p == path) && (*p != '/'))
1375     return 0;
1376   t = strdupdelim (path, p);
1377
1378   /* Check whether the directory exists.  */
1379   if ((stat (t, &st) == 0))
1380     {
1381       if (S_ISDIR (st.st_mode))
1382         {
1383           xfree (t);
1384           return 0;
1385         }
1386       else
1387         {
1388           /* If the dir exists as a file name, remove it first.  This
1389              is *only* for Wget to work with buggy old CERN http
1390              servers.  Here is the scenario: When Wget tries to
1391              retrieve a directory without a slash, e.g.
1392              http://foo/bar (bar being a directory), CERN server will
1393              not redirect it too http://foo/bar/ -- it will generate a
1394              directory listing containing links to bar/file1,
1395              bar/file2, etc.  Wget will lose because it saves this
1396              HTML listing to a file `bar', so it cannot create the
1397              directory.  To work around this, if the file of the same
1398              name exists, we just remove it and create the directory
1399              anyway.  */
1400           DEBUGP (("Removing %s because of directory danger!\n", t));
1401           unlink (t);
1402         }
1403     }
1404   res = make_directory (t);
1405   if (res != 0)
1406     logprintf (LOG_NOTQUIET, "%s: %s", t, strerror (errno));
1407   xfree (t);
1408   return res;
1409 }
1410 \f
1411 /* Functions for constructing the file name out of URL components.  */
1412
1413 /* A growable string structure, used by url_file_name and friends.
1414    This should perhaps be moved to utils.c.
1415
1416    The idea is to have a convenient and efficient way to construct a
1417    string by having various functions append data to it.  Instead of
1418    passing the obligatory BASEVAR, SIZEVAR and TAILPOS to all the
1419    functions in questions, we pass the pointer to this struct.  */
1420
1421 struct growable {
1422   char *base;
1423   int size;
1424   int tail;
1425 };
1426
1427 /* Ensure that the string can accept APPEND_COUNT more characters past
1428    the current TAIL position.  If necessary, this will grow the string
1429    and update its allocated size.  If the string is already large
1430    enough to take TAIL+APPEND_COUNT characters, this does nothing.  */
1431 #define GROW(g, append_size) do {                                       \
1432   struct growable *G_ = g;                                              \
1433   DO_REALLOC (G_->base, G_->size, G_->tail + append_size, char);        \
1434 } while (0)
1435
1436 /* Return the tail position of the string. */
1437 #define TAIL(r) ((r)->base + (r)->tail)
1438
1439 /* Move the tail position by APPEND_COUNT characters. */
1440 #define TAIL_INCR(r, append_count) ((r)->tail += append_count)
1441
1442 /* Append the string STR to DEST.  NOTICE: the string in DEST is not
1443    terminated.  */
1444
1445 static void
1446 append_string (const char *str, struct growable *dest)
1447 {
1448   int l = strlen (str);
1449   GROW (dest, l);
1450   memcpy (TAIL (dest), str, l);
1451   TAIL_INCR (dest, l);
1452 }
1453
1454 /* Append CH to DEST.  For example, append_char (0, DEST)
1455    zero-terminates DEST.  */
1456
1457 static void
1458 append_char (char ch, struct growable *dest)
1459 {
1460   GROW (dest, 1);
1461   *TAIL (dest) = ch;
1462   TAIL_INCR (dest, 1);
1463 }
1464
1465 enum {
1466   filechr_not_unix    = 1,      /* unusable on Unix, / and \0 */
1467   filechr_not_windows = 2,      /* unusable on Windows, one of \|/<>?:*" */
1468   filechr_control     = 4,      /* a control character, e.g. 0-31 */
1469 };
1470
1471 #define FILE_CHAR_TEST(c, mask) (filechr_table[(unsigned char)(c)] & (mask))
1472
1473 /* Shorthands for the table: */
1474 #define U filechr_not_unix
1475 #define W filechr_not_windows
1476 #define C filechr_control
1477
1478 #define UW U|W
1479 #define UWC U|W|C
1480
1481 /* Table of characters unsafe under various conditions (see above).
1482
1483    Arguably we could also claim `%' to be unsafe, since we use it as
1484    the escape character.  If we ever want to be able to reliably
1485    translate file name back to URL, this would become important
1486    crucial.  Right now, it's better to be minimal in escaping.  */
1487
1488 const static unsigned char filechr_table[256] =
1489 {
1490 UWC,  C,  C,  C,   C,  C,  C,  C,   /* NUL SOH STX ETX  EOT ENQ ACK BEL */
1491   C,  C,  C,  C,   C,  C,  C,  C,   /* BS  HT  LF  VT   FF  CR  SO  SI  */
1492   C,  C,  C,  C,   C,  C,  C,  C,   /* DLE DC1 DC2 DC3  DC4 NAK SYN ETB */
1493   C,  C,  C,  C,   C,  C,  C,  C,   /* CAN EM  SUB ESC  FS  GS  RS  US  */
1494   0,  0,  W,  0,   0,  0,  0,  0,   /* SP  !   "   #    $   %   &   '   */
1495   0,  0,  W,  0,   0,  0,  0, UW,   /* (   )   *   +    ,   -   .   /   */
1496   0,  0,  0,  0,   0,  0,  0,  0,   /* 0   1   2   3    4   5   6   7   */
1497   0,  0,  W,  0,   W,  0,  W,  W,   /* 8   9   :   ;    <   =   >   ?   */
1498   0,  0,  0,  0,   0,  0,  0,  0,   /* @   A   B   C    D   E   F   G   */
1499   0,  0,  0,  0,   0,  0,  0,  0,   /* H   I   J   K    L   M   N   O   */
1500   0,  0,  0,  0,   0,  0,  0,  0,   /* P   Q   R   S    T   U   V   W   */
1501   0,  0,  0,  0,   W,  0,  0,  0,   /* X   Y   Z   [    \   ]   ^   _   */
1502   0,  0,  0,  0,   0,  0,  0,  0,   /* `   a   b   c    d   e   f   g   */
1503   0,  0,  0,  0,   0,  0,  0,  0,   /* h   i   j   k    l   m   n   o   */
1504   0,  0,  0,  0,   0,  0,  0,  0,   /* p   q   r   s    t   u   v   w   */
1505   0,  0,  0,  0,   0,  0,  0,  0,   /* x   y   z   {    |   }   ~   DEL */
1506
1507   C, C, C, C,  C, C, C, C,  C, C, C, C,  C, C, C, C, /* 128-143 */
1508   C, C, C, C,  C, C, C, C,  C, C, C, C,  C, C, C, C, /* 144-159 */
1509   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1510   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1511
1512   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1513   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1514   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1515   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1516 };
1517 #undef U
1518 #undef W
1519 #undef C
1520 #undef UW
1521 #undef UWC
1522
1523 /* FN_PORT_SEP is the separator between host and port in file names
1524    for non-standard port numbers.  On Unix this is normally ':', as in
1525    "www.xemacs.org:4001/index.html".  Under Windows, we set it to +
1526    because Windows can't handle ':' in file names.  */
1527 #define FN_PORT_SEP  (opt.restrict_files_os != restrict_windows ? ':' : '+')
1528
1529 /* FN_QUERY_SEP is the separator between the file name and the URL
1530    query, normally '?'.  Since Windows cannot handle '?' as part of
1531    file name, we use '@' instead there.  */
1532 #define FN_QUERY_SEP (opt.restrict_files_os != restrict_windows ? '?' : '@')
1533
1534 /* Quote path element, characters in [b, e), as file name, and append
1535    the quoted string to DEST.  Each character is quoted as per
1536    file_unsafe_char and the corresponding table.  */
1537
1538 static void
1539 append_uri_pathel (const char *b, const char *e, struct growable *dest)
1540 {
1541   char *pathel;
1542   int pathlen;
1543
1544   const char *p;
1545   int quoted, outlen;
1546
1547   int mask;
1548   if (opt.restrict_files_os == restrict_unix)
1549     mask = filechr_not_unix;
1550   else
1551     mask = filechr_not_windows;
1552   if (opt.restrict_files_ctrl)
1553     mask |= filechr_control;
1554
1555   /* Copy [b, e) to PATHEL and URL-unescape it. */
1556   BOUNDED_TO_ALLOCA (b, e, pathel);
1557   url_unescape (pathel);
1558   pathlen = strlen (pathel);
1559
1560   /* Go through PATHEL and check how many characters we'll need to
1561      add for file quoting. */
1562   quoted = 0;
1563   for (p = pathel; *p; p++)
1564     if (FILE_CHAR_TEST (*p, mask))
1565       ++quoted;
1566
1567   /* p - pathel is the string length.  Each quoted char means two
1568      additional characters in the string, hence 2*quoted.  */
1569   outlen = (p - pathel) + (2 * quoted);
1570   GROW (dest, outlen);
1571
1572   if (!quoted)
1573     {
1574       /* If there's nothing to quote, we don't need to go through the
1575          string the second time.  */
1576       memcpy (TAIL (dest), pathel, outlen);
1577     }
1578   else
1579     {
1580       char *q = TAIL (dest);
1581       for (p = pathel; *p; p++)
1582         {
1583           if (!FILE_CHAR_TEST (*p, mask))
1584             *q++ = *p;
1585           else
1586             {
1587               unsigned char ch = *p;
1588               *q++ = '%';
1589               *q++ = XNUM_TO_DIGIT (ch >> 4);
1590               *q++ = XNUM_TO_DIGIT (ch & 0xf);
1591             }
1592         }
1593       assert (q - TAIL (dest) == outlen);
1594     }
1595   TAIL_INCR (dest, outlen);
1596 }
1597
1598 /* Append to DEST the directory structure that corresponds the
1599    directory part of URL's path.  For example, if the URL is
1600    http://server/dir1/dir2/file, this appends "/dir1/dir2".
1601
1602    Each path element ("dir1" and "dir2" in the above example) is
1603    examined, url-unescaped, and re-escaped as file name element.
1604
1605    Additionally, it cuts as many directories from the path as
1606    specified by opt.cut_dirs.  For example, if opt.cut_dirs is 1, it
1607    will produce "bar" for the above example.  For 2 or more, it will
1608    produce "".
1609
1610    Each component of the path is quoted for use as file name.  */
1611
1612 static void
1613 append_dir_structure (const struct url *u, struct growable *dest)
1614 {
1615   char *pathel, *next;
1616   int cut = opt.cut_dirs;
1617
1618   /* Go through the path components, de-URL-quote them, and quote them
1619      (if necessary) as file names.  */
1620
1621   pathel = u->path;
1622   for (; (next = strchr (pathel, '/')) != NULL; pathel = next + 1)
1623     {
1624       if (cut-- > 0)
1625         continue;
1626       if (pathel == next)
1627         /* Ignore empty pathels.  path_simplify should remove
1628            occurrences of "//" from the path, but it has special cases
1629            for starting / which generates an empty pathel here.  */
1630         continue;
1631
1632       if (dest->tail)
1633         append_char ('/', dest);
1634       append_uri_pathel (pathel, next, dest);
1635     }
1636 }
1637
1638 /* Return a unique file name that matches the given URL as good as
1639    possible.  Does not create directories on the file system.  */
1640
1641 char *
1642 url_file_name (const struct url *u)
1643 {
1644   struct growable fnres;
1645
1646   char *u_file, *u_query;
1647   char *fname, *unique;
1648
1649   fnres.base = NULL;
1650   fnres.size = 0;
1651   fnres.tail = 0;
1652
1653   /* Start with the directory prefix, if specified. */
1654   if (opt.dir_prefix)
1655     append_string (opt.dir_prefix, &fnres);
1656
1657   /* If "dirstruct" is turned on (typically the case with -r), add
1658      the host and port (unless those have been turned off) and
1659      directory structure.  */
1660   if (opt.dirstruct)
1661     {
1662       if (opt.add_hostdir)
1663         {
1664           if (fnres.tail)
1665             append_char ('/', &fnres);
1666           append_string (u->host, &fnres);
1667           if (u->port != scheme_default_port (u->scheme))
1668             {
1669               char portstr[24];
1670               number_to_string (portstr, u->port);
1671               append_char (FN_PORT_SEP, &fnres);
1672               append_string (portstr, &fnres);
1673             }
1674         }
1675
1676       append_dir_structure (u, &fnres);
1677     }
1678
1679   /* Add the file name. */
1680   if (fnres.tail)
1681     append_char ('/', &fnres);
1682   u_file = *u->file ? u->file : "index.html";
1683   append_uri_pathel (u_file, u_file + strlen (u_file), &fnres);
1684
1685   /* Append "?query" to the file name. */
1686   u_query = u->query && *u->query ? u->query : NULL;
1687   if (u_query)
1688     {
1689       append_char (FN_QUERY_SEP, &fnres);
1690       append_uri_pathel (u_query, u_query + strlen (u_query), &fnres);
1691     }
1692
1693   /* Zero-terminate the file name. */
1694   append_char ('\0', &fnres);
1695
1696   fname = fnres.base;
1697
1698   /* Check the cases in which the unique extensions are not used:
1699      1) Clobbering is turned off (-nc).
1700      2) Retrieval with regetting.
1701      3) Timestamping is used.
1702      4) Hierarchy is built.
1703
1704      The exception is the case when file does exist and is a
1705      directory (see `mkalldirs' for explanation).  */
1706
1707   if ((opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct)
1708       && !(file_exists_p (fname) && !file_non_directory_p (fname)))
1709     return fname;
1710
1711   unique = unique_name (fname, 1);
1712   if (unique != fname)
1713     xfree (fname);
1714   return unique;
1715 }
1716
1717 /* Return the length of URL's path.  Path is considered to be
1718    terminated by one of '?', ';', '#', or by the end of the
1719    string.  */
1720 static int
1721 path_length (const char *url)
1722 {
1723   const char *q = strpbrk_or_eos (url, "?;#");
1724   return q - url;
1725 }
1726
1727 /* Find the last occurrence of character C in the range [b, e), or
1728    NULL, if none are present.  This is equivalent to strrchr(b, c),
1729    except that it accepts an END argument instead of requiring the
1730    string to be zero-terminated.  Why is there no memrchr()?  */
1731 static const char *
1732 find_last_char (const char *b, const char *e, char c)
1733 {
1734   for (; e > b; e--)
1735     if (*e == c)
1736       return e;
1737   return NULL;
1738 }
1739 \f
1740 /* Resolve "." and ".." elements of PATH by destructively modifying
1741    PATH.  "." is resolved by removing that path element, and ".." is
1742    resolved by removing the preceding path element.  Leading and
1743    trailing slashes are preserved.
1744
1745    Return non-zero if any changes have been made.
1746
1747    For example, "a/b/c/./../d/.." will yield "a/b/".  More exhaustive
1748    test examples are provided below.  If you change anything in this
1749    function, run test_path_simplify to make sure you haven't broken a
1750    test case.
1751
1752    A previous version of this function was based on path_simplify()
1753    from GNU Bash, but it has been rewritten for Wget 1.8.1.  */
1754
1755 static int
1756 path_simplify (char *path)
1757 {
1758   int change = 0;
1759   char *p, *end;
1760
1761   if (path[0] == '/')
1762     ++path;                     /* preserve the leading '/'. */
1763
1764   p = path;
1765   end = p + strlen (p) + 1;     /* position past the terminating zero. */
1766
1767   while (1)
1768     {
1769     again:
1770       /* P should point to the beginning of a path element. */
1771
1772       if (*p == '.' && (*(p + 1) == '/' || *(p + 1) == '\0'))
1773         {
1774           /* Handle "./foo" by moving "foo" two characters to the
1775              left. */
1776           if (*(p + 1) == '/')
1777             {
1778               change = 1;
1779               memmove (p, p + 2, end - (p + 2));
1780               end -= 2;
1781               goto again;
1782             }
1783           else
1784             {
1785               change = 1;
1786               *p = '\0';
1787               break;
1788             }
1789         }
1790       else if (*p == '.' && *(p + 1) == '.'
1791                && (*(p + 2) == '/' || *(p + 2) == '\0'))
1792         {
1793           /* Handle "../foo" by moving "foo" one path element to the
1794              left.  */
1795           char *b = p;          /* not p-1 because P can equal PATH */
1796
1797           /* Backtrack by one path element, but not past the beginning
1798              of PATH. */
1799
1800           /* foo/bar/../baz */
1801           /*         ^ p    */
1802           /*     ^ b        */
1803
1804           if (b > path)
1805             {
1806               /* Move backwards until B hits the beginning of the
1807                  previous path element or the beginning of path. */
1808               for (--b; b > path && *(b - 1) != '/'; b--)
1809                 ;
1810             }
1811
1812           change = 1;
1813           if (*(p + 2) == '/')
1814             {
1815               memmove (b, p + 3, end - (p + 3));
1816               end -= (p + 3) - b;
1817               p = b;
1818             }
1819           else
1820             {
1821               *b = '\0';
1822               break;
1823             }
1824
1825           goto again;
1826         }
1827       else if (*p == '/')
1828         {
1829           /* Remove empty path elements.  Not mandated by rfc1808 et
1830              al, but it seems like a good idea to get rid of them.
1831              Supporting them properly is hard (in which directory do
1832              you save http://x.com///y.html?) and they don't seem to
1833              bring much gain.  */
1834           char *q = p;
1835           while (*q == '/')
1836             ++q;
1837           change = 1;
1838           if (*q == '\0')
1839             {
1840               *p = '\0';
1841               break;
1842             }
1843           memmove (p, q, end - q);
1844           end -= q - p;
1845           goto again;
1846         }
1847
1848       /* Skip to the next path element. */
1849       while (*p && *p != '/')
1850         ++p;
1851       if (*p == '\0')
1852         break;
1853
1854       /* Make sure P points to the beginning of the next path element,
1855          which is location after the slash. */
1856       ++p;
1857     }
1858
1859   return change;
1860 }
1861 \f
1862 /* Merge BASE with LINK and return the resulting URI.
1863
1864    Either of the URIs may be absolute or relative, complete with the
1865    host name, or path only.  This tries to reasonably handle all
1866    foreseeable cases.  It only employs minimal URL parsing, without
1867    knowledge of the specifics of schemes.
1868
1869    Perhaps this function should call path_simplify so that the callers
1870    don't have to call url_parse unconditionally.  */
1871
1872 char *
1873 uri_merge (const char *base, const char *link)
1874 {
1875   int linklength;
1876   const char *end;
1877   char *merge;
1878
1879   if (url_has_scheme (link))
1880     return xstrdup (link);
1881
1882   /* We may not examine BASE past END. */
1883   end = base + path_length (base);
1884   linklength = strlen (link);
1885
1886   if (!*link)
1887     {
1888       /* Empty LINK points back to BASE, query string and all. */
1889       return xstrdup (base);
1890     }
1891   else if (*link == '?')
1892     {
1893       /* LINK points to the same location, but changes the query
1894          string.  Examples: */
1895       /* uri_merge("path",         "?new") -> "path?new"     */
1896       /* uri_merge("path?foo",     "?new") -> "path?new"     */
1897       /* uri_merge("path?foo#bar", "?new") -> "path?new"     */
1898       /* uri_merge("path#foo",     "?new") -> "path?new"     */
1899       int baselength = end - base;
1900       merge = xmalloc (baselength + linklength + 1);
1901       memcpy (merge, base, baselength);
1902       memcpy (merge + baselength, link, linklength);
1903       merge[baselength + linklength] = '\0';
1904     }
1905   else if (*link == '#')
1906     {
1907       /* uri_merge("path",         "#new") -> "path#new"     */
1908       /* uri_merge("path#foo",     "#new") -> "path#new"     */
1909       /* uri_merge("path?foo",     "#new") -> "path?foo#new" */
1910       /* uri_merge("path?foo#bar", "#new") -> "path?foo#new" */
1911       int baselength;
1912       const char *end1 = strchr (base, '#');
1913       if (!end1)
1914         end1 = base + strlen (base);
1915       baselength = end1 - base;
1916       merge = xmalloc (baselength + linklength + 1);
1917       memcpy (merge, base, baselength);
1918       memcpy (merge + baselength, link, linklength);
1919       merge[baselength + linklength] = '\0';
1920     }
1921   else if (*link == '/' && *(link + 1) == '/')
1922     {
1923       /* LINK begins with "//" and so is a net path: we need to
1924          replace everything after (and including) the double slash
1925          with LINK. */
1926
1927       /* uri_merge("foo", "//new/bar")            -> "//new/bar"      */
1928       /* uri_merge("//old/foo", "//new/bar")      -> "//new/bar"      */
1929       /* uri_merge("http://old/foo", "//new/bar") -> "http://new/bar" */
1930
1931       int span;
1932       const char *slash;
1933       const char *start_insert;
1934
1935       /* Look for first slash. */
1936       slash = memchr (base, '/', end - base);
1937       /* If found slash and it is a double slash, then replace
1938          from this point, else default to replacing from the
1939          beginning.  */
1940       if (slash && *(slash + 1) == '/')
1941         start_insert = slash;
1942       else
1943         start_insert = base;
1944
1945       span = start_insert - base;
1946       merge = (char *)xmalloc (span + linklength + 1);
1947       if (span)
1948         memcpy (merge, base, span);
1949       memcpy (merge + span, link, linklength);
1950       merge[span + linklength] = '\0';
1951     }
1952   else if (*link == '/')
1953     {
1954       /* LINK is an absolute path: we need to replace everything
1955          after (and including) the FIRST slash with LINK.
1956
1957          So, if BASE is "http://host/whatever/foo/bar", and LINK is
1958          "/qux/xyzzy", our result should be
1959          "http://host/qux/xyzzy".  */
1960       int span;
1961       const char *slash;
1962       const char *start_insert = NULL; /* for gcc to shut up. */
1963       const char *pos = base;
1964       int seen_slash_slash = 0;
1965       /* We're looking for the first slash, but want to ignore
1966          double slash. */
1967     again:
1968       slash = memchr (pos, '/', end - pos);
1969       if (slash && !seen_slash_slash)
1970         if (*(slash + 1) == '/')
1971           {
1972             pos = slash + 2;
1973             seen_slash_slash = 1;
1974             goto again;
1975           }
1976
1977       /* At this point, SLASH is the location of the first / after
1978          "//", or the first slash altogether.  START_INSERT is the
1979          pointer to the location where LINK will be inserted.  When
1980          examining the last two examples, keep in mind that LINK
1981          begins with '/'. */
1982
1983       if (!slash && !seen_slash_slash)
1984         /* example: "foo" */
1985         /*           ^    */
1986         start_insert = base;
1987       else if (!slash && seen_slash_slash)
1988         /* example: "http://foo" */
1989         /*                     ^ */
1990         start_insert = end;
1991       else if (slash && !seen_slash_slash)
1992         /* example: "foo/bar" */
1993         /*           ^        */
1994         start_insert = base;
1995       else if (slash && seen_slash_slash)
1996         /* example: "http://something/" */
1997         /*                           ^  */
1998         start_insert = slash;
1999
2000       span = start_insert - base;
2001       merge = (char *)xmalloc (span + linklength + 1);
2002       if (span)
2003         memcpy (merge, base, span);
2004       memcpy (merge + span, link, linklength);
2005       merge[span + linklength] = '\0';
2006     }
2007   else
2008     {
2009       /* LINK is a relative URL: we need to replace everything
2010          after last slash (possibly empty) with LINK.
2011
2012          So, if BASE is "whatever/foo/bar", and LINK is "qux/xyzzy",
2013          our result should be "whatever/foo/qux/xyzzy".  */
2014       int need_explicit_slash = 0;
2015       int span;
2016       const char *start_insert;
2017       const char *last_slash = find_last_char (base, end, '/');
2018       if (!last_slash)
2019         {
2020           /* No slash found at all.  Append LINK to what we have,
2021              but we'll need a slash as a separator.
2022
2023              Example: if base == "foo" and link == "qux/xyzzy", then
2024              we cannot just append link to base, because we'd get
2025              "fooqux/xyzzy", whereas what we want is
2026              "foo/qux/xyzzy".
2027
2028              To make sure the / gets inserted, we set
2029              need_explicit_slash to 1.  We also set start_insert
2030              to end + 1, so that the length calculations work out
2031              correctly for one more (slash) character.  Accessing
2032              that character is fine, since it will be the
2033              delimiter, '\0' or '?'.  */
2034           /* example: "foo?..." */
2035           /*               ^    ('?' gets changed to '/') */
2036           start_insert = end + 1;
2037           need_explicit_slash = 1;
2038         }
2039       else if (last_slash && last_slash >= base + 2
2040                && last_slash[-2] == ':' && last_slash[-1] == '/')
2041         {
2042           /* example: http://host"  */
2043           /*                      ^ */
2044           start_insert = end + 1;
2045           need_explicit_slash = 1;
2046         }
2047       else
2048         {
2049           /* example: "whatever/foo/bar" */
2050           /*                        ^    */
2051           start_insert = last_slash + 1;
2052         }
2053
2054       span = start_insert - base;
2055       merge = (char *)xmalloc (span + linklength + 1);
2056       if (span)
2057         memcpy (merge, base, span);
2058       if (need_explicit_slash)
2059         merge[span - 1] = '/';
2060       memcpy (merge + span, link, linklength);
2061       merge[span + linklength] = '\0';
2062     }
2063
2064   return merge;
2065 }
2066 \f
2067 #define APPEND(p, s) do {                       \
2068   int len = strlen (s);                         \
2069   memcpy (p, s, len);                           \
2070   p += len;                                     \
2071 } while (0)
2072
2073 /* Use this instead of password when the actual password is supposed
2074    to be hidden.  We intentionally use a generic string without giving
2075    away the number of characters in the password, like previous
2076    versions did.  */
2077 #define HIDDEN_PASSWORD "*password*"
2078
2079 /* Recreate the URL string from the data in URL.
2080
2081    If HIDE is non-zero (as it is when we're calling this on a URL we
2082    plan to print, but not when calling it to canonicalize a URL for
2083    use within the program), password will be hidden.  Unsafe
2084    characters in the URL will be quoted.  */
2085
2086 char *
2087 url_string (const struct url *url, int hide_password)
2088 {
2089   int size;
2090   char *result, *p;
2091   char *quoted_user = NULL, *quoted_passwd = NULL;
2092
2093   int scheme_port  = supported_schemes[url->scheme].default_port;
2094   char *scheme_str = supported_schemes[url->scheme].leading_string;
2095   int fplen = full_path_length (url);
2096
2097   int brackets_around_host = 0;
2098
2099   assert (scheme_str != NULL);
2100
2101   /* Make sure the user name and password are quoted. */
2102   if (url->user)
2103     {
2104       quoted_user = url_escape_allow_passthrough (url->user);
2105       if (url->passwd)
2106         {
2107           if (hide_password)
2108             quoted_passwd = HIDDEN_PASSWORD;
2109           else
2110             quoted_passwd = url_escape_allow_passthrough (url->passwd);
2111         }
2112     }
2113
2114   if (strchr (url->host, ':'))
2115     brackets_around_host = 1;
2116
2117   size = (strlen (scheme_str)
2118           + strlen (url->host)
2119           + (brackets_around_host ? 2 : 0)
2120           + fplen
2121           + 1);
2122   if (url->port != scheme_port)
2123     size += 1 + numdigit (url->port);
2124   if (quoted_user)
2125     {
2126       size += 1 + strlen (quoted_user);
2127       if (quoted_passwd)
2128         size += 1 + strlen (quoted_passwd);
2129     }
2130
2131   p = result = xmalloc (size);
2132
2133   APPEND (p, scheme_str);
2134   if (quoted_user)
2135     {
2136       APPEND (p, quoted_user);
2137       if (quoted_passwd)
2138         {
2139           *p++ = ':';
2140           APPEND (p, quoted_passwd);
2141         }
2142       *p++ = '@';
2143     }
2144
2145   if (brackets_around_host)
2146     *p++ = '[';
2147   APPEND (p, url->host);
2148   if (brackets_around_host)
2149     *p++ = ']';
2150   if (url->port != scheme_port)
2151     {
2152       *p++ = ':';
2153       p = number_to_string (p, url->port);
2154     }
2155
2156   full_path_write (url, p);
2157   p += fplen;
2158   *p++ = '\0';
2159
2160   assert (p - result == size);
2161
2162   if (quoted_user && quoted_user != url->user)
2163     xfree (quoted_user);
2164   if (quoted_passwd && !hide_password
2165       && quoted_passwd != url->passwd)
2166     xfree (quoted_passwd);
2167
2168   return result;
2169 }
2170 \f
2171 /* Return the URL of the proxy appropriate for url U.  */
2172 char *
2173 getproxy (struct url *u)
2174 {
2175   char *proxy = NULL;
2176   char *rewritten_url;
2177   static char rewritten_storage[1024];
2178
2179   if (!opt.use_proxy)
2180     return NULL;
2181   if (!no_proxy_match (u->host, (const char **)opt.no_proxy))
2182     return NULL;
2183
2184   switch (u->scheme)
2185     {
2186     case SCHEME_HTTP:
2187       proxy = opt.http_proxy ? opt.http_proxy : getenv ("http_proxy");
2188       break;
2189 #ifdef HAVE_SSL
2190     case SCHEME_HTTPS:
2191       proxy = opt.https_proxy ? opt.https_proxy : getenv ("https_proxy");
2192       break;
2193 #endif
2194     case SCHEME_FTP:
2195       proxy = opt.ftp_proxy ? opt.ftp_proxy : getenv ("ftp_proxy");
2196       break;
2197     case SCHEME_INVALID:
2198       break;
2199     }
2200   if (!proxy || !*proxy)
2201     return NULL;
2202
2203   /* Handle shorthands.  `rewritten_storage' is a kludge to allow
2204      getproxy() to return static storage. */
2205   rewritten_url = rewrite_shorthand_url (proxy);
2206   if (rewritten_url)
2207     {
2208       strncpy (rewritten_storage, rewritten_url, sizeof(rewritten_storage));
2209       rewritten_storage[sizeof (rewritten_storage) - 1] = '\0';
2210       proxy = rewritten_storage;
2211     }
2212
2213   return proxy;
2214 }
2215
2216 /* Should a host be accessed through proxy, concerning no_proxy?  */
2217 int
2218 no_proxy_match (const char *host, const char **no_proxy)
2219 {
2220   if (!no_proxy)
2221     return 1;
2222   else
2223     return !sufmatch (no_proxy, host);
2224 }
2225 \f
2226 /* Support for converting links for local viewing in downloaded HTML
2227    files.  This should be moved to another file, because it has
2228    nothing to do with processing URLs.  */
2229
2230 static void write_backup_file PARAMS ((const char *, downloaded_file_t));
2231 static const char *replace_attr PARAMS ((const char *, int, FILE *,
2232                                          const char *));
2233 static const char *replace_attr_refresh_hack PARAMS ((const char *, int, FILE *,
2234                                                       const char *, int));
2235 static char *local_quote_string PARAMS ((const char *));
2236
2237 /* Change the links in one HTML file.  LINKS is a list of links in the
2238    document, along with their positions and the desired direction of
2239    the conversion.  */
2240 void
2241 convert_links (const char *file, struct urlpos *links)
2242 {
2243   struct file_memory *fm;
2244   FILE *fp;
2245   const char *p;
2246   downloaded_file_t downloaded_file_return;
2247
2248   struct urlpos *link;
2249   int to_url_count = 0, to_file_count = 0;
2250
2251   logprintf (LOG_VERBOSE, _("Converting %s... "), file);
2252
2253   {
2254     /* First we do a "dry run": go through the list L and see whether
2255        any URL needs to be converted in the first place.  If not, just
2256        leave the file alone.  */
2257     int dry_count = 0;
2258     struct urlpos *dry = links;
2259     for (dry = links; dry; dry = dry->next)
2260       if (dry->convert != CO_NOCONVERT)
2261         ++dry_count;
2262     if (!dry_count)
2263       {
2264         logputs (LOG_VERBOSE, _("nothing to do.\n"));
2265         return;
2266       }
2267   }
2268
2269   fm = read_file (file);
2270   if (!fm)
2271     {
2272       logprintf (LOG_NOTQUIET, _("Cannot convert links in %s: %s\n"),
2273                  file, strerror (errno));
2274       return;
2275     }
2276
2277   downloaded_file_return = downloaded_file (CHECK_FOR_FILE, file);
2278   if (opt.backup_converted && downloaded_file_return)
2279     write_backup_file (file, downloaded_file_return);
2280
2281   /* Before opening the file for writing, unlink the file.  This is
2282      important if the data in FM is mmaped.  In such case, nulling the
2283      file, which is what fopen() below does, would make us read all
2284      zeroes from the mmaped region.  */
2285   if (unlink (file) < 0 && errno != ENOENT)
2286     {
2287       logprintf (LOG_NOTQUIET, _("Unable to delete `%s': %s\n"),
2288                  file, strerror (errno));
2289       read_file_free (fm);
2290       return;
2291     }
2292   /* Now open the file for writing.  */
2293   fp = fopen (file, "wb");
2294   if (!fp)
2295     {
2296       logprintf (LOG_NOTQUIET, _("Cannot convert links in %s: %s\n"),
2297                  file, strerror (errno));
2298       read_file_free (fm);
2299       return;
2300     }
2301
2302   /* Here we loop through all the URLs in file, replacing those of
2303      them that are downloaded with relative references.  */
2304   p = fm->content;
2305   for (link = links; link; link = link->next)
2306     {
2307       char *url_start = fm->content + link->pos;
2308
2309       if (link->pos >= fm->length)
2310         {
2311           DEBUGP (("Something strange is going on.  Please investigate."));
2312           break;
2313         }
2314       /* If the URL is not to be converted, skip it.  */
2315       if (link->convert == CO_NOCONVERT)
2316         {
2317           DEBUGP (("Skipping %s at position %d.\n", link->url->url, link->pos));
2318           continue;
2319         }
2320
2321       /* Echo the file contents, up to the offending URL's opening
2322          quote, to the outfile.  */
2323       fwrite (p, 1, url_start - p, fp);
2324       p = url_start;
2325
2326       switch (link->convert)
2327         {
2328         case CO_CONVERT_TO_RELATIVE:
2329           /* Convert absolute URL to relative. */
2330           {
2331             char *newname = construct_relative (file, link->local_name);
2332             char *quoted_newname = local_quote_string (newname);
2333
2334             if (!link->link_refresh_p)
2335               p = replace_attr (p, link->size, fp, quoted_newname);
2336             else
2337               p = replace_attr_refresh_hack (p, link->size, fp, quoted_newname,
2338                                              link->refresh_timeout);
2339
2340             DEBUGP (("TO_RELATIVE: %s to %s at position %d in %s.\n",
2341                      link->url->url, newname, link->pos, file));
2342             xfree (newname);
2343             xfree (quoted_newname);
2344             ++to_file_count;
2345             break;
2346           }
2347         case CO_CONVERT_TO_COMPLETE:
2348           /* Convert the link to absolute URL. */
2349           {
2350             char *newlink = link->url->url;
2351             char *quoted_newlink = html_quote_string (newlink);
2352
2353             if (!link->link_refresh_p)
2354               p = replace_attr (p, link->size, fp, quoted_newlink);
2355             else
2356               p = replace_attr_refresh_hack (p, link->size, fp, quoted_newlink,
2357                                              link->refresh_timeout);
2358
2359             DEBUGP (("TO_COMPLETE: <something> to %s at position %d in %s.\n",
2360                      newlink, link->pos, file));
2361             xfree (quoted_newlink);
2362             ++to_url_count;
2363             break;
2364           }
2365         case CO_NULLIFY_BASE:
2366           /* Change the base href to "". */
2367           p = replace_attr (p, link->size, fp, "");
2368           break;
2369         case CO_NOCONVERT:
2370           abort ();
2371           break;
2372         }
2373     }
2374
2375   /* Output the rest of the file. */
2376   if (p - fm->content < fm->length)
2377     fwrite (p, 1, fm->length - (p - fm->content), fp);
2378   fclose (fp);
2379   read_file_free (fm);
2380
2381   logprintf (LOG_VERBOSE, "%d-%d\n", to_file_count, to_url_count);
2382 }
2383
2384 /* Construct and return a malloced copy of the relative link from two
2385    pieces of information: local name S1 of the referring file and
2386    local name S2 of the referred file.
2387
2388    So, if S1 is "jagor.srce.hr/index.html" and S2 is
2389    "jagor.srce.hr/images/news.gif", the function will return
2390    "images/news.gif".
2391
2392    Alternately, if S1 is "fly.cc.fer.hr/ioccc/index.html", and S2 is
2393    "fly.cc.fer.hr/images/fly.gif", the function will return
2394    "../images/fly.gif".
2395
2396    Caveats: S1 should not begin with `/', unless S2 also begins with
2397    '/'.  S1 should not contain things like ".." and such --
2398    construct_relative ("fly/ioccc/../index.html",
2399    "fly/images/fly.gif") will fail.  (A workaround is to call
2400    something like path_simplify() on S1).  */
2401 static char *
2402 construct_relative (const char *s1, const char *s2)
2403 {
2404   int i, cnt, sepdirs1;
2405   char *res;
2406
2407   if (*s2 == '/')
2408     return xstrdup (s2);
2409   /* S1 should *not* be absolute, if S2 wasn't.  */
2410   assert (*s1 != '/');
2411   i = cnt = 0;
2412   /* Skip the directories common to both strings.  */
2413   while (1)
2414     {
2415       while (s1[i] && s2[i]
2416              && (s1[i] == s2[i])
2417              && (s1[i] != '/')
2418              && (s2[i] != '/'))
2419         ++i;
2420       if (s1[i] == '/' && s2[i] == '/')
2421         cnt = ++i;
2422       else
2423         break;
2424     }
2425   for (sepdirs1 = 0; s1[i]; i++)
2426     if (s1[i] == '/')
2427       ++sepdirs1;
2428   /* Now, construct the file as of:
2429      - ../ repeated sepdirs1 time
2430      - all the non-mutual directories of S2.  */
2431   res = (char *)xmalloc (3 * sepdirs1 + strlen (s2 + cnt) + 1);
2432   for (i = 0; i < sepdirs1; i++)
2433     memcpy (res + 3 * i, "../", 3);
2434   strcpy (res + 3 * i, s2 + cnt);
2435   return res;
2436 }
2437 \f
2438 static void
2439 write_backup_file (const char *file, downloaded_file_t downloaded_file_return)
2440 {
2441   /* Rather than just writing over the original .html file with the
2442      converted version, save the former to *.orig.  Note we only do
2443      this for files we've _successfully_ downloaded, so we don't
2444      clobber .orig files sitting around from previous invocations. */
2445
2446   /* Construct the backup filename as the original name plus ".orig". */
2447   size_t         filename_len = strlen(file);
2448   char*          filename_plus_orig_suffix;
2449   boolean        already_wrote_backup_file = FALSE;
2450   slist*         converted_file_ptr;
2451   static slist*  converted_files = NULL;
2452
2453   if (downloaded_file_return == FILE_DOWNLOADED_AND_HTML_EXTENSION_ADDED)
2454     {
2455       /* Just write "orig" over "html".  We need to do it this way
2456          because when we're checking to see if we've downloaded the
2457          file before (to see if we can skip downloading it), we don't
2458          know if it's a text/html file.  Therefore we don't know yet
2459          at that stage that -E is going to cause us to tack on
2460          ".html", so we need to compare vs. the original URL plus
2461          ".orig", not the original URL plus ".html.orig". */
2462       filename_plus_orig_suffix = alloca (filename_len + 1);
2463       strcpy(filename_plus_orig_suffix, file);
2464       strcpy((filename_plus_orig_suffix + filename_len) - 4, "orig");
2465     }
2466   else /* downloaded_file_return == FILE_DOWNLOADED_NORMALLY */
2467     {
2468       /* Append ".orig" to the name. */
2469       filename_plus_orig_suffix = alloca (filename_len + sizeof(".orig"));
2470       strcpy(filename_plus_orig_suffix, file);
2471       strcpy(filename_plus_orig_suffix + filename_len, ".orig");
2472     }
2473
2474   /* We can get called twice on the same URL thanks to the
2475      convert_all_links() call in main().  If we write the .orig file
2476      each time in such a case, it'll end up containing the first-pass
2477      conversion, not the original file.  So, see if we've already been
2478      called on this file. */
2479   converted_file_ptr = converted_files;
2480   while (converted_file_ptr != NULL)
2481     if (strcmp(converted_file_ptr->string, file) == 0)
2482       {
2483         already_wrote_backup_file = TRUE;
2484         break;
2485       }
2486     else
2487       converted_file_ptr = converted_file_ptr->next;
2488
2489   if (!already_wrote_backup_file)
2490     {
2491       /* Rename <file> to <file>.orig before former gets written over. */
2492       if (rename(file, filename_plus_orig_suffix) != 0)
2493         logprintf (LOG_NOTQUIET, _("Cannot back up %s as %s: %s\n"),
2494                    file, filename_plus_orig_suffix, strerror (errno));
2495
2496       /* Remember that we've already written a .orig backup for this file.
2497          Note that we never free this memory since we need it till the
2498          convert_all_links() call, which is one of the last things the
2499          program does before terminating.  BTW, I'm not sure if it would be
2500          safe to just set 'converted_file_ptr->string' to 'file' below,
2501          rather than making a copy of the string...  Another note is that I
2502          thought I could just add a field to the urlpos structure saying
2503          that we'd written a .orig file for this URL, but that didn't work,
2504          so I had to make this separate list.
2505          -- Dan Harkless <wget@harkless.org>
2506
2507          This [adding a field to the urlpos structure] didn't work
2508          because convert_file() is called from convert_all_links at
2509          the end of the retrieval with a freshly built new urlpos
2510          list.
2511          -- Hrvoje Niksic <hniksic@arsdigita.com>
2512       */
2513       converted_file_ptr = xmalloc(sizeof(*converted_file_ptr));
2514       converted_file_ptr->string = xstrdup(file);  /* die on out-of-mem. */
2515       converted_file_ptr->next = converted_files;
2516       converted_files = converted_file_ptr;
2517     }
2518 }
2519
2520 static int find_fragment PARAMS ((const char *, int, const char **,
2521                                   const char **));
2522
2523 /* Replace an attribute's original text with NEW_TEXT. */
2524
2525 static const char *
2526 replace_attr (const char *p, int size, FILE *fp, const char *new_text)
2527 {
2528   int quote_flag = 0;
2529   char quote_char = '\"';       /* use "..." for quoting, unless the
2530                                    original value is quoted, in which
2531                                    case reuse its quoting char. */
2532   const char *frag_beg, *frag_end;
2533
2534   /* Structure of our string is:
2535        "...old-contents..."
2536        <---    size    --->  (with quotes)
2537      OR:
2538        ...old-contents...
2539        <---    size   -->    (no quotes)   */
2540
2541   if (*p == '\"' || *p == '\'')
2542     {
2543       quote_char = *p;
2544       quote_flag = 1;
2545       ++p;
2546       size -= 2;                /* disregard opening and closing quote */
2547     }
2548   putc (quote_char, fp);
2549   fputs (new_text, fp);
2550
2551   /* Look for fragment identifier, if any. */
2552   if (find_fragment (p, size, &frag_beg, &frag_end))
2553     fwrite (frag_beg, 1, frag_end - frag_beg, fp);
2554   p += size;
2555   if (quote_flag)
2556     ++p;
2557   putc (quote_char, fp);
2558
2559   return p;
2560 }
2561
2562 /* The same as REPLACE_ATTR, but used when replacing
2563    <meta http-equiv=refresh content="new_text"> because we need to
2564    append "timeout_value; URL=" before the next_text.  */
2565
2566 static const char *
2567 replace_attr_refresh_hack (const char *p, int size, FILE *fp,
2568                            const char *new_text, int timeout)
2569 {
2570   /* "0; URL=..." */
2571   char *new_with_timeout = (char *)alloca (numdigit (timeout)
2572                                            + 6 /* "; URL=" */
2573                                            + strlen (new_text)
2574                                            + 1);
2575   sprintf (new_with_timeout, "%d; URL=%s", timeout, new_text);
2576
2577   return replace_attr (p, size, fp, new_with_timeout);
2578 }
2579
2580 /* Find the first occurrence of '#' in [BEG, BEG+SIZE) that is not
2581    preceded by '&'.  If the character is not found, return zero.  If
2582    the character is found, return 1 and set BP and EP to point to the
2583    beginning and end of the region.
2584
2585    This is used for finding the fragment indentifiers in URLs.  */
2586
2587 static int
2588 find_fragment (const char *beg, int size, const char **bp, const char **ep)
2589 {
2590   const char *end = beg + size;
2591   int saw_amp = 0;
2592   for (; beg < end; beg++)
2593     {
2594       switch (*beg)
2595         {
2596         case '&':
2597           saw_amp = 1;
2598           break;
2599         case '#':
2600           if (!saw_amp)
2601             {
2602               *bp = beg;
2603               *ep = end;
2604               return 1;
2605             }
2606           /* fallthrough */
2607         default:
2608           saw_amp = 0;
2609         }
2610     }
2611   return 0;
2612 }
2613
2614 /* Quote FILE for use as local reference to an HTML file.
2615
2616    We quote ? as %3F to avoid passing part of the file name as the
2617    parameter when browsing the converted file through HTTP.  However,
2618    it is safe to do this only when `--html-extension' is turned on.
2619    This is because converting "index.html?foo=bar" to
2620    "index.html%3Ffoo=bar" would break local browsing, as the latter
2621    isn't even recognized as an HTML file!  However, converting
2622    "index.html?foo=bar.html" to "index.html%3Ffoo=bar.html" should be
2623    safe for both local and HTTP-served browsing.  */
2624
2625 static char *
2626 local_quote_string (const char *file)
2627 {
2628   const char *file_sans_qmark;
2629   int qm;
2630
2631   if (!opt.html_extension)
2632     return html_quote_string (file);
2633
2634   qm = count_char (file, '?');
2635
2636   if (qm)
2637     {
2638       const char *from = file;
2639       char *to, *newname;
2640
2641       /* qm * 2 because we replace each question mark with "%3F",
2642          i.e. replace one char with three, hence two more.  */
2643       int fsqlen = strlen (file) + qm * 2;
2644
2645       to = newname = (char *)alloca (fsqlen + 1);
2646       for (; *from; from++)
2647         {
2648           if (*from != '?')
2649             *to++ = *from;
2650           else
2651             {
2652               *to++ = '%';
2653               *to++ = '3';
2654               *to++ = 'F';
2655             }
2656         }
2657       assert (to - newname == fsqlen);
2658       *to = '\0';
2659
2660       file_sans_qmark = newname;
2661     }
2662   else
2663     file_sans_qmark = file;
2664
2665   return html_quote_string (file_sans_qmark);
2666 }
2667
2668 /* We're storing "modes" of type downloaded_file_t in the hash table.
2669    However, our hash tables only accept pointers for keys and values.
2670    So when we need a pointer, we use the address of a
2671    downloaded_file_t variable of static storage.  */
2672    
2673 static downloaded_file_t *
2674 downloaded_mode_to_ptr (downloaded_file_t mode)
2675 {
2676   static downloaded_file_t
2677     v1 = FILE_NOT_ALREADY_DOWNLOADED,
2678     v2 = FILE_DOWNLOADED_NORMALLY,
2679     v3 = FILE_DOWNLOADED_AND_HTML_EXTENSION_ADDED,
2680     v4 = CHECK_FOR_FILE;
2681
2682   switch (mode)
2683     {
2684     case FILE_NOT_ALREADY_DOWNLOADED:
2685       return &v1;
2686     case FILE_DOWNLOADED_NORMALLY:
2687       return &v2;
2688     case FILE_DOWNLOADED_AND_HTML_EXTENSION_ADDED:
2689       return &v3;
2690     case CHECK_FOR_FILE:
2691       return &v4;
2692     }
2693   return NULL;
2694 }
2695
2696 /* This should really be merged with dl_file_url_map and
2697    downloaded_html_files in recur.c.  This was originally a list, but
2698    I changed it to a hash table beause it was actually taking a lot of
2699    time to find things in it.  */
2700
2701 static struct hash_table *downloaded_files_hash;
2702
2703 /* Remembers which files have been downloaded.  In the standard case, should be
2704    called with mode == FILE_DOWNLOADED_NORMALLY for each file we actually
2705    download successfully (i.e. not for ones we have failures on or that we skip
2706    due to -N).
2707
2708    When we've downloaded a file and tacked on a ".html" extension due to -E,
2709    call this function with FILE_DOWNLOADED_AND_HTML_EXTENSION_ADDED rather than
2710    FILE_DOWNLOADED_NORMALLY.
2711
2712    If you just want to check if a file has been previously added without adding
2713    it, call with mode == CHECK_FOR_FILE.  Please be sure to call this function
2714    with local filenames, not remote URLs. */
2715 downloaded_file_t
2716 downloaded_file (downloaded_file_t mode, const char *file)
2717 {
2718   downloaded_file_t *ptr;
2719
2720   if (mode == CHECK_FOR_FILE)
2721     {
2722       if (!downloaded_files_hash)
2723         return FILE_NOT_ALREADY_DOWNLOADED;
2724       ptr = hash_table_get (downloaded_files_hash, file);
2725       if (!ptr)
2726         return FILE_NOT_ALREADY_DOWNLOADED;
2727       return *ptr;
2728     }
2729
2730   if (!downloaded_files_hash)
2731     downloaded_files_hash = make_string_hash_table (0);
2732
2733   ptr = hash_table_get (downloaded_files_hash, file);
2734   if (ptr)
2735     return *ptr;
2736
2737   ptr = downloaded_mode_to_ptr (mode);
2738   hash_table_put (downloaded_files_hash, xstrdup (file), &ptr);
2739
2740   return FILE_NOT_ALREADY_DOWNLOADED;
2741 }
2742
2743 static int
2744 df_free_mapper (void *key, void *value, void *ignored)
2745 {
2746   xfree (key);
2747   return 0;
2748 }
2749
2750 void
2751 downloaded_files_free (void)
2752 {
2753   if (downloaded_files_hash)
2754     {
2755       hash_table_map (downloaded_files_hash, df_free_mapper, NULL);
2756       hash_table_destroy (downloaded_files_hash);
2757       downloaded_files_hash = NULL;
2758     }
2759 }
2760
2761 /* Return non-zero if scheme a is similar to scheme b.
2762  
2763    Schemes are similar if they are equal.  If SSL is supported, schemes
2764    are also similar if one is http (SCHEME_HTTP) and the other is https
2765    (SCHEME_HTTPS).  */
2766 int
2767 schemes_are_similar_p (enum url_scheme a, enum url_scheme b)
2768 {
2769   if (a == b)
2770     return 1;
2771 #ifdef HAVE_SSL
2772   if ((a == SCHEME_HTTP && b == SCHEME_HTTPS)
2773       || (a == SCHEME_HTTPS && b == SCHEME_HTTP))
2774     return 1;
2775 #endif
2776   return 0;
2777 }
2778 \f
2779 #if 0
2780 /* Debugging and testing support for path_simplify. */
2781
2782 /* Debug: run path_simplify on PATH and return the result in a new
2783    string.  Useful for calling from the debugger.  */
2784 static char *
2785 ps (char *path)
2786 {
2787   char *copy = xstrdup (path);
2788   path_simplify (copy);
2789   return copy;
2790 }
2791
2792 static void
2793 run_test (char *test, char *expected_result, int expected_change)
2794 {
2795   char *test_copy = xstrdup (test);
2796   int modified = path_simplify (test_copy);
2797
2798   if (0 != strcmp (test_copy, expected_result))
2799     {
2800       printf ("Failed path_simplify(\"%s\"): expected \"%s\", got \"%s\".\n",
2801               test, expected_result, test_copy);
2802     }
2803   if (modified != expected_change)
2804     {
2805       if (expected_change == 1)
2806         printf ("Expected no modification with path_simplify(\"%s\").\n",
2807                 test);
2808       else
2809         printf ("Expected modification with path_simplify(\"%s\").\n",
2810                 test);
2811     }
2812   xfree (test_copy);
2813 }
2814
2815 static void
2816 test_path_simplify (void)
2817 {
2818   static struct {
2819     char *test, *result;
2820     int should_modify;
2821   } tests[] = {
2822     { "",               "",             0 },
2823     { ".",              "",             1 },
2824     { "..",             "",             1 },
2825     { "foo",            "foo",          0 },
2826     { "foo/bar",        "foo/bar",      0 },
2827     { "foo///bar",      "foo/bar",      1 },
2828     { "foo/.",          "foo/",         1 },
2829     { "foo/./",         "foo/",         1 },
2830     { "foo./",          "foo./",        0 },
2831     { "foo/../bar",     "bar",          1 },
2832     { "foo/../bar/",    "bar/",         1 },
2833     { "foo/bar/..",     "foo/",         1 },
2834     { "foo/bar/../x",   "foo/x",        1 },
2835     { "foo/bar/../x/",  "foo/x/",       1 },
2836     { "foo/..",         "",             1 },
2837     { "foo/../..",      "",             1 },
2838     { "a/b/../../c",    "c",            1 },
2839     { "./a/../b",       "b",            1 }
2840   };
2841   int i;
2842
2843   for (i = 0; i < countof (tests); i++)
2844     {
2845       char *test = tests[i].test;
2846       char *expected_result = tests[i].result;
2847       int   expected_change = tests[i].should_modify;
2848       run_test (test, expected_result, expected_change);
2849     }
2850
2851   /* Now run all the tests with a leading slash before the test case,
2852      to prove that the slash is being preserved.  */
2853   for (i = 0; i < countof (tests); i++)
2854     {
2855       char *test, *expected_result;
2856       int expected_change = tests[i].should_modify;
2857
2858       test = xmalloc (1 + strlen (tests[i].test) + 1);
2859       sprintf (test, "/%s", tests[i].test);
2860
2861       expected_result = xmalloc (1 + strlen (tests[i].result) + 1);
2862       sprintf (expected_result, "/%s", tests[i].result);
2863
2864       run_test (test, expected_result, expected_change);
2865
2866       xfree (test);
2867       xfree (expected_result);
2868     }
2869 }
2870 #endif