]> sjero.net Git - wget/blob - src/url.c
[svn] Allow empty port spec in URL.
[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
51 #ifndef errno
52 extern int errno;
53 #endif
54
55 struct scheme_data
56 {
57   char *leading_string;
58   int default_port;
59   int enabled;
60 };
61
62 /* Supported schemes: */
63 static struct scheme_data supported_schemes[] =
64 {
65   { "http://",  DEFAULT_HTTP_PORT,  1 },
66 #ifdef HAVE_SSL
67   { "https://", DEFAULT_HTTPS_PORT, 1 },
68 #endif
69   { "ftp://",   DEFAULT_FTP_PORT,   1 },
70
71   /* SCHEME_INVALID */
72   { NULL,       -1,                 0 }
73 };
74
75 /* Forward declarations: */
76
77 static int path_simplify PARAMS ((char *));
78 \f
79 /* Support for encoding and decoding of URL strings.  We determine
80    whether a character is unsafe through static table lookup.  This
81    code assumes ASCII character set and 8-bit chars.
82
83    Note that rfc2396 chose a different terminology from rfc1738.  The
84    recoding that URL does should be compliant with both specs,
85    although escaping the "unsafe" ("unreserved" in rfc2396 parlance)
86    chars where not strictly necessary is now frowned upon.  */
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,   R,  U,  R,  0,   /* SP  !   "   #    $   %   &   '   */
112   0,  0,  0,  R,   R,  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   N_("No error"),
627 #define PE_UNSUPPORTED_SCHEME           1
628   N_("Unsupported scheme"),
629 #define PE_EMPTY_HOST                   2
630   N_("Empty host"),
631 #define PE_BAD_PORT_NUMBER              3
632   N_("Bad port number"),
633 #define PE_INVALID_USER_NAME            4
634   N_("Invalid user name"),
635 #define PE_UNTERMINATED_IPV6_ADDRESS    5
636   N_("Unterminated IPv6 numeric address"),
637 #define PE_IPV6_NOT_SUPPORTED           6
638   N_("IPv6 addresses not supported"),
639 #define PE_INVALID_IPV6_ADDRESS         7
640   N_("Invalid IPv6 numeric address")
641 };
642
643 #ifdef ENABLE_IPV6
644 /* The following two functions were adapted from glibc. */
645
646 static int
647 is_valid_ipv4_address (const char *str, const char *end)
648 {
649   int saw_digit = 0;
650   int octets = 0;
651   int val = 0;
652
653   while (str < end)
654     {
655       int ch = *str++;
656
657       if (ch >= '0' && ch <= '9')
658         {
659           val = val * 10 + (ch - '0');
660
661           if (val > 255)
662             return 0;
663           if (saw_digit == 0)
664             {
665               if (++octets > 4)
666                 return 0;
667               saw_digit = 1;
668             }
669         }
670       else if (ch == '.' && saw_digit == 1)
671         {
672           if (octets == 4)
673             return 0;
674           val = 0;
675           saw_digit = 0;
676         }
677       else
678         return 0;
679     }
680   if (octets < 4)
681     return 0;
682   
683   return 1;
684 }
685
686 static int
687 is_valid_ipv6_address (const char *str, const char *end)
688 {
689   enum {
690     NS_INADDRSZ  = 4,
691     NS_IN6ADDRSZ = 16,
692     NS_INT16SZ   = 2
693   };
694
695   const char *curtok;
696   int tp;
697   const char *colonp;
698   int saw_xdigit;
699   unsigned int val;
700
701   tp = 0;
702   colonp = NULL;
703
704   if (str == end)
705     return 0;
706   
707   /* Leading :: requires some special handling. */
708   if (*str == ':')
709     {
710       ++str;
711       if (str == end || *str != ':')
712         return 0;
713     }
714
715   curtok = str;
716   saw_xdigit = 0;
717   val = 0;
718
719   while (str < end)
720     {
721       int ch = *str++;
722
723       /* if ch is a number, add it to val. */
724       if (ISXDIGIT (ch))
725         {
726           val <<= 4;
727           val |= XDIGIT_TO_NUM (ch);
728           if (val > 0xffff)
729             return 0;
730           saw_xdigit = 1;
731           continue;
732         }
733
734       /* if ch is a colon ... */
735       if (ch == ':')
736         {
737           curtok = str;
738           if (saw_xdigit == 0)
739             {
740               if (colonp != NULL)
741                 return 0;
742               colonp = str + tp;
743               continue;
744             }
745           else if (str == end)
746             return 0;
747           if (tp > NS_IN6ADDRSZ - NS_INT16SZ)
748             return 0;
749           tp += NS_INT16SZ;
750           saw_xdigit = 0;
751           val = 0;
752           continue;
753         }
754
755       /* if ch is a dot ... */
756       if (ch == '.' && (tp <= NS_IN6ADDRSZ - NS_INADDRSZ)
757           && is_valid_ipv4_address (curtok, end) == 1)
758         {
759           tp += NS_INADDRSZ;
760           saw_xdigit = 0;
761           break;
762         }
763     
764       return 0;
765     }
766
767   if (saw_xdigit == 1)
768     {
769       if (tp > NS_IN6ADDRSZ - NS_INT16SZ) 
770         return 0;
771       tp += NS_INT16SZ;
772     }
773
774   if (colonp != NULL)
775     {
776       if (tp == NS_IN6ADDRSZ) 
777         return 0;
778       tp = NS_IN6ADDRSZ;
779     }
780
781   if (tp != NS_IN6ADDRSZ)
782     return 0;
783
784   return 1;
785 }
786 #endif
787
788 /* Parse a URL.
789
790    Return a new struct url if successful, NULL on error.  In case of
791    error, and if ERROR is not NULL, also set *ERROR to the appropriate
792    error code. */
793 struct url *
794 url_parse (const char *url, int *error)
795 {
796   struct url *u;
797   const char *p;
798   int path_modified, host_modified;
799
800   enum url_scheme scheme;
801
802   const char *uname_b,     *uname_e;
803   const char *host_b,      *host_e;
804   const char *path_b,      *path_e;
805   const char *params_b,    *params_e;
806   const char *query_b,     *query_e;
807   const char *fragment_b,  *fragment_e;
808
809   int port;
810   char *user = NULL, *passwd = NULL;
811
812   char *url_encoded = NULL;
813
814   int error_code;
815
816   scheme = url_scheme (url);
817   if (scheme == SCHEME_INVALID)
818     {
819       error_code = PE_UNSUPPORTED_SCHEME;
820       goto error;
821     }
822
823   url_encoded = reencode_escapes (url);
824   p = url_encoded;
825
826   p += strlen (supported_schemes[scheme].leading_string);
827   uname_b = p;
828   p += url_skip_credentials (p);
829   uname_e = p;
830
831   /* scheme://user:pass@host[:port]... */
832   /*                    ^              */
833
834   /* We attempt to break down the URL into the components path,
835      params, query, and fragment.  They are ordered like this:
836
837        scheme://host[:port][/path][;params][?query][#fragment]  */
838
839   params_b   = params_e   = NULL;
840   query_b    = query_e    = NULL;
841   fragment_b = fragment_e = NULL;
842
843   host_b = p;
844
845   if (*p == '[')
846     {
847       /* Handle IPv6 address inside square brackets.  Ideally we'd
848          just look for the terminating ']', but rfc2732 mandates
849          rejecting invalid IPv6 addresses.  */
850
851       /* The address begins after '['. */
852       host_b = p + 1;
853       host_e = strchr (host_b, ']');
854
855       if (!host_e)
856         {
857           error_code = PE_UNTERMINATED_IPV6_ADDRESS;
858           goto error;
859         }
860
861 #ifdef ENABLE_IPV6
862       /* Check if the IPv6 address is valid. */
863       if (!is_valid_ipv6_address(host_b, host_e))
864         {
865           error_code = PE_INVALID_IPV6_ADDRESS;
866           goto error;
867         }
868
869       /* Continue parsing after the closing ']'. */
870       p = host_e + 1;
871 #else
872       error_code = PE_IPV6_NOT_SUPPORTED;
873       goto error;
874 #endif
875     }
876   else
877     {
878       p = strpbrk_or_eos (p, ":/;?#");
879       host_e = p;
880     }
881
882   if (host_b == host_e)
883     {
884       error_code = PE_EMPTY_HOST;
885       goto error;
886     }
887
888   port = scheme_default_port (scheme);
889   if (*p == ':')
890     {
891       const char *port_b, *port_e, *pp;
892
893       /* scheme://host:port/tralala */
894       /*              ^             */
895       ++p;
896       port_b = p;
897       p = strpbrk_or_eos (p, "/;?#");
898       port_e = p;
899
900       /* Allow empty port, as per rfc2396. */
901       if (port_b != port_e)
902         {
903           for (port = 0, pp = port_b; pp < port_e; pp++)
904             {
905               if (!ISDIGIT (*pp))
906                 {
907                   /* http://host:12randomgarbage/blah */
908                   /*               ^                  */
909                   error_code = PE_BAD_PORT_NUMBER;
910                   goto error;
911                 }
912               port = 10 * port + (*pp - '0');
913             }
914         }
915     }
916
917   if (*p == '/')
918     {
919       ++p;
920       path_b = p;
921       p = strpbrk_or_eos (p, ";?#");
922       path_e = p;
923     }
924   else
925     {
926       /* Path is not allowed not to exist. */
927       path_b = path_e = p;
928     }
929
930   if (*p == ';')
931     {
932       ++p;
933       params_b = p;
934       p = strpbrk_or_eos (p, "?#");
935       params_e = p;
936     }
937   if (*p == '?')
938     {
939       ++p;
940       query_b = p;
941       p = strpbrk_or_eos (p, "#");
942       query_e = p;
943
944       /* Hack that allows users to use '?' (a wildcard character) in
945          FTP URLs without it being interpreted as a query string
946          delimiter.  */
947       if (scheme == SCHEME_FTP)
948         {
949           query_b = query_e = NULL;
950           path_e = p;
951         }
952     }
953   if (*p == '#')
954     {
955       ++p;
956       fragment_b = p;
957       p += strlen (p);
958       fragment_e = p;
959     }
960   assert (*p == 0);
961
962   if (uname_b != uname_e)
963     {
964       /* http://user:pass@host */
965       /*        ^         ^    */
966       /*     uname_b   uname_e */
967       if (!parse_credentials (uname_b, uname_e - 1, &user, &passwd))
968         {
969           error_code = PE_INVALID_USER_NAME;
970           goto error;
971         }
972     }
973
974   u = xnew0 (struct url);
975   u->scheme = scheme;
976   u->host   = strdupdelim (host_b, host_e);
977   u->port   = port;
978   u->user   = user;
979   u->passwd = passwd;
980
981   u->path = strdupdelim (path_b, path_e);
982   path_modified = path_simplify (u->path);
983   split_path (u->path, &u->dir, &u->file);
984
985   host_modified = lowercase_str (u->host);
986
987   if (params_b)
988     u->params = strdupdelim (params_b, params_e);
989   if (query_b)
990     u->query = strdupdelim (query_b, query_e);
991   if (fragment_b)
992     u->fragment = strdupdelim (fragment_b, fragment_e);
993
994   if (path_modified || u->fragment || host_modified || path_b == path_e)
995     {
996       /* If we suspect that a transformation has rendered what
997          url_string might return different from URL_ENCODED, rebuild
998          u->url using url_string.  */
999       u->url = url_string (u, 0);
1000
1001       if (url_encoded != url)
1002         xfree ((char *) url_encoded);
1003     }
1004   else
1005     {
1006       if (url_encoded == url)
1007         u->url = xstrdup (url);
1008       else
1009         u->url = url_encoded;
1010     }
1011   url_encoded = NULL;
1012
1013   return u;
1014
1015  error:
1016   /* Cleanup in case of error: */
1017   if (url_encoded && url_encoded != url)
1018     xfree (url_encoded);
1019
1020   /* Transmit the error code to the caller, if the caller wants to
1021      know.  */
1022   if (error)
1023     *error = error_code;
1024   return NULL;
1025 }
1026
1027 /* Return the error message string from ERROR_CODE, which should have
1028    been retrieved from url_parse.  The error message is translated.  */
1029
1030 const char *
1031 url_error (int error_code)
1032 {
1033   assert (error_code >= 0 && error_code < countof (parse_errors));
1034   return _(parse_errors[error_code]);
1035 }
1036
1037 /* Split PATH into DIR and FILE.  PATH comes from the URL and is
1038    expected to be URL-escaped.
1039
1040    The path is split into directory (the part up to the last slash)
1041    and file (the part after the last slash), which are subsequently
1042    unescaped.  Examples:
1043
1044    PATH                 DIR           FILE
1045    "foo/bar/baz"        "foo/bar"     "baz"
1046    "foo/bar/"           "foo/bar"     ""
1047    "foo"                ""            "foo"
1048    "foo/bar/baz%2fqux"  "foo/bar"     "baz/qux" (!)
1049
1050    DIR and FILE are freshly allocated.  */
1051
1052 static void
1053 split_path (const char *path, char **dir, char **file)
1054 {
1055   char *last_slash = strrchr (path, '/');
1056   if (!last_slash)
1057     {
1058       *dir = xstrdup ("");
1059       *file = xstrdup (path);
1060     }
1061   else
1062     {
1063       *dir = strdupdelim (path, last_slash);
1064       *file = xstrdup (last_slash + 1);
1065     }
1066   url_unescape (*dir);
1067   url_unescape (*file);
1068 }
1069
1070 /* Note: URL's "full path" is the path with the query string and
1071    params appended.  The "fragment" (#foo) is intentionally ignored,
1072    but that might be changed.  For example, if the original URL was
1073    "http://host:port/foo/bar/baz;bullshit?querystring#uselessfragment",
1074    the full path will be "/foo/bar/baz;bullshit?querystring".  */
1075
1076 /* Return the length of the full path, without the terminating
1077    zero.  */
1078
1079 static int
1080 full_path_length (const struct url *url)
1081 {
1082   int len = 0;
1083
1084 #define FROB(el) if (url->el) len += 1 + strlen (url->el)
1085
1086   FROB (path);
1087   FROB (params);
1088   FROB (query);
1089
1090 #undef FROB
1091
1092   return len;
1093 }
1094
1095 /* Write out the full path. */
1096
1097 static void
1098 full_path_write (const struct url *url, char *where)
1099 {
1100 #define FROB(el, chr) do {                      \
1101   char *f_el = url->el;                         \
1102   if (f_el) {                                   \
1103     int l = strlen (f_el);                      \
1104     *where++ = chr;                             \
1105     memcpy (where, f_el, l);                    \
1106     where += l;                                 \
1107   }                                             \
1108 } while (0)
1109
1110   FROB (path, '/');
1111   FROB (params, ';');
1112   FROB (query, '?');
1113
1114 #undef FROB
1115 }
1116
1117 /* Public function for getting the "full path".  E.g. if u->path is
1118    "foo/bar" and u->query is "param=value", full_path will be
1119    "/foo/bar?param=value". */
1120
1121 char *
1122 url_full_path (const struct url *url)
1123 {
1124   int length = full_path_length (url);
1125   char *full_path = (char *)xmalloc(length + 1);
1126
1127   full_path_write (url, full_path);
1128   full_path[length] = '\0';
1129
1130   return full_path;
1131 }
1132
1133 /* Escape unsafe and reserved characters, except for the slash
1134    characters.  */
1135
1136 static char *
1137 url_escape_dir (const char *dir)
1138 {
1139   char *newdir = url_escape_1 (dir, urlchr_unsafe | urlchr_reserved, 1);
1140   char *h, *t;
1141   if (newdir == dir)
1142     return (char *)dir;
1143
1144   /* Unescape slashes in NEWDIR. */
1145
1146   h = newdir;                   /* hare */
1147   t = newdir;                   /* tortoise */
1148
1149   for (; *h; h++, t++)
1150     {
1151       /* url_escape_1 having converted '/' to "%2F" exactly. */
1152       if (*h == '%' && h[1] == '2' && h[2] == 'F')
1153         {
1154           *t = '/';
1155           h += 2;
1156         }
1157       else
1158         *t = *h;
1159     }
1160   *t = '\0';
1161
1162   return newdir;
1163 }
1164
1165 /* Sync u->path and u->url with u->dir and u->file.  Called after
1166    u->file or u->dir have been changed, typically by the FTP code.  */
1167
1168 static void
1169 sync_path (struct url *u)
1170 {
1171   char *newpath, *efile, *edir;
1172
1173   xfree (u->path);
1174
1175   /* u->dir and u->file are not escaped.  URL-escape them before
1176      reassembling them into u->path.  That way, if they contain
1177      separators like '?' or even if u->file contains slashes, the
1178      path will be correctly assembled.  (u->file can contain slashes
1179      if the URL specifies it with %2f, or if an FTP server returns
1180      it.)  */
1181   edir = url_escape_dir (u->dir);
1182   efile = url_escape_1 (u->file, urlchr_unsafe | urlchr_reserved, 1);
1183
1184   if (!*edir)
1185     newpath = xstrdup (efile);
1186   else
1187     {
1188       int dirlen = strlen (edir);
1189       int filelen = strlen (efile);
1190
1191       /* Copy "DIR/FILE" to newpath. */
1192       char *p = newpath = xmalloc (dirlen + 1 + filelen + 1);
1193       memcpy (p, edir, dirlen);
1194       p += dirlen;
1195       *p++ = '/';
1196       memcpy (p, efile, filelen);
1197       p += filelen;
1198       *p++ = '\0';
1199     }
1200
1201   u->path = newpath;
1202
1203   if (edir != u->dir)
1204     xfree (edir);
1205   if (efile != u->file)
1206     xfree (efile);
1207
1208   /* Regenerate u->url as well.  */
1209   xfree (u->url);
1210   u->url = url_string (u, 0);
1211 }
1212
1213 /* Mutators.  Code in ftp.c insists on changing u->dir and u->file.
1214    This way we can sync u->path and u->url when they get changed.  */
1215
1216 void
1217 url_set_dir (struct url *url, const char *newdir)
1218 {
1219   xfree (url->dir);
1220   url->dir = xstrdup (newdir);
1221   sync_path (url);
1222 }
1223
1224 void
1225 url_set_file (struct url *url, const char *newfile)
1226 {
1227   xfree (url->file);
1228   url->file = xstrdup (newfile);
1229   sync_path (url);
1230 }
1231
1232 void
1233 url_free (struct url *url)
1234 {
1235   xfree (url->host);
1236   xfree (url->path);
1237   xfree (url->url);
1238
1239   xfree_null (url->params);
1240   xfree_null (url->query);
1241   xfree_null (url->fragment);
1242   xfree_null (url->user);
1243   xfree_null (url->passwd);
1244
1245   xfree (url->dir);
1246   xfree (url->file);
1247
1248   xfree (url);
1249 }
1250 \f
1251 /* Create all the necessary directories for PATH (a file).  Calls
1252    mkdirhier() internally.  */
1253 int
1254 mkalldirs (const char *path)
1255 {
1256   const char *p;
1257   char *t;
1258   struct stat st;
1259   int res;
1260
1261   p = path + strlen (path);
1262   for (; *p != '/' && p != path; p--)
1263     ;
1264
1265   /* Don't create if it's just a file.  */
1266   if ((p == path) && (*p != '/'))
1267     return 0;
1268   t = strdupdelim (path, p);
1269
1270   /* Check whether the directory exists.  */
1271   if ((stat (t, &st) == 0))
1272     {
1273       if (S_ISDIR (st.st_mode))
1274         {
1275           xfree (t);
1276           return 0;
1277         }
1278       else
1279         {
1280           /* If the dir exists as a file name, remove it first.  This
1281              is *only* for Wget to work with buggy old CERN http
1282              servers.  Here is the scenario: When Wget tries to
1283              retrieve a directory without a slash, e.g.
1284              http://foo/bar (bar being a directory), CERN server will
1285              not redirect it too http://foo/bar/ -- it will generate a
1286              directory listing containing links to bar/file1,
1287              bar/file2, etc.  Wget will lose because it saves this
1288              HTML listing to a file `bar', so it cannot create the
1289              directory.  To work around this, if the file of the same
1290              name exists, we just remove it and create the directory
1291              anyway.  */
1292           DEBUGP (("Removing %s because of directory danger!\n", t));
1293           unlink (t);
1294         }
1295     }
1296   res = make_directory (t);
1297   if (res != 0)
1298     logprintf (LOG_NOTQUIET, "%s: %s", t, strerror (errno));
1299   xfree (t);
1300   return res;
1301 }
1302 \f
1303 /* Functions for constructing the file name out of URL components.  */
1304
1305 /* A growable string structure, used by url_file_name and friends.
1306    This should perhaps be moved to utils.c.
1307
1308    The idea is to have a convenient and efficient way to construct a
1309    string by having various functions append data to it.  Instead of
1310    passing the obligatory BASEVAR, SIZEVAR and TAILPOS to all the
1311    functions in questions, we pass the pointer to this struct.  */
1312
1313 struct growable {
1314   char *base;
1315   int size;
1316   int tail;
1317 };
1318
1319 /* Ensure that the string can accept APPEND_COUNT more characters past
1320    the current TAIL position.  If necessary, this will grow the string
1321    and update its allocated size.  If the string is already large
1322    enough to take TAIL+APPEND_COUNT characters, this does nothing.  */
1323 #define GROW(g, append_size) do {                                       \
1324   struct growable *G_ = g;                                              \
1325   DO_REALLOC (G_->base, G_->size, G_->tail + append_size, char);        \
1326 } while (0)
1327
1328 /* Return the tail position of the string. */
1329 #define TAIL(r) ((r)->base + (r)->tail)
1330
1331 /* Move the tail position by APPEND_COUNT characters. */
1332 #define TAIL_INCR(r, append_count) ((r)->tail += append_count)
1333
1334 /* Append the string STR to DEST.  NOTICE: the string in DEST is not
1335    terminated.  */
1336
1337 static void
1338 append_string (const char *str, struct growable *dest)
1339 {
1340   int l = strlen (str);
1341   GROW (dest, l);
1342   memcpy (TAIL (dest), str, l);
1343   TAIL_INCR (dest, l);
1344 }
1345
1346 /* Append CH to DEST.  For example, append_char (0, DEST)
1347    zero-terminates DEST.  */
1348
1349 static void
1350 append_char (char ch, struct growable *dest)
1351 {
1352   GROW (dest, 1);
1353   *TAIL (dest) = ch;
1354   TAIL_INCR (dest, 1);
1355 }
1356
1357 enum {
1358   filechr_not_unix    = 1,      /* unusable on Unix, / and \0 */
1359   filechr_not_windows = 2,      /* unusable on Windows, one of \|/<>?:*" */
1360   filechr_control     = 4       /* a control character, e.g. 0-31 */
1361 };
1362
1363 #define FILE_CHAR_TEST(c, mask) (filechr_table[(unsigned char)(c)] & (mask))
1364
1365 /* Shorthands for the table: */
1366 #define U filechr_not_unix
1367 #define W filechr_not_windows
1368 #define C filechr_control
1369
1370 #define UW U|W
1371 #define UWC U|W|C
1372
1373 /* Table of characters unsafe under various conditions (see above).
1374
1375    Arguably we could also claim `%' to be unsafe, since we use it as
1376    the escape character.  If we ever want to be able to reliably
1377    translate file name back to URL, this would become important
1378    crucial.  Right now, it's better to be minimal in escaping.  */
1379
1380 const static unsigned char filechr_table[256] =
1381 {
1382 UWC,  C,  C,  C,   C,  C,  C,  C,   /* NUL SOH STX ETX  EOT ENQ ACK BEL */
1383   C,  C,  C,  C,   C,  C,  C,  C,   /* BS  HT  LF  VT   FF  CR  SO  SI  */
1384   C,  C,  C,  C,   C,  C,  C,  C,   /* DLE DC1 DC2 DC3  DC4 NAK SYN ETB */
1385   C,  C,  C,  C,   C,  C,  C,  C,   /* CAN EM  SUB ESC  FS  GS  RS  US  */
1386   0,  0,  W,  0,   0,  0,  0,  0,   /* SP  !   "   #    $   %   &   '   */
1387   0,  0,  W,  0,   0,  0,  0, UW,   /* (   )   *   +    ,   -   .   /   */
1388   0,  0,  0,  0,   0,  0,  0,  0,   /* 0   1   2   3    4   5   6   7   */
1389   0,  0,  W,  0,   W,  0,  W,  W,   /* 8   9   :   ;    <   =   >   ?   */
1390   0,  0,  0,  0,   0,  0,  0,  0,   /* @   A   B   C    D   E   F   G   */
1391   0,  0,  0,  0,   0,  0,  0,  0,   /* H   I   J   K    L   M   N   O   */
1392   0,  0,  0,  0,   0,  0,  0,  0,   /* P   Q   R   S    T   U   V   W   */
1393   0,  0,  0,  0,   W,  0,  0,  0,   /* X   Y   Z   [    \   ]   ^   _   */
1394   0,  0,  0,  0,   0,  0,  0,  0,   /* `   a   b   c    d   e   f   g   */
1395   0,  0,  0,  0,   0,  0,  0,  0,   /* h   i   j   k    l   m   n   o   */
1396   0,  0,  0,  0,   0,  0,  0,  0,   /* p   q   r   s    t   u   v   w   */
1397   0,  0,  0,  0,   0,  0,  0,  0,   /* x   y   z   {    |   }   ~   DEL */
1398
1399   C, C, C, C,  C, C, C, C,  C, C, C, C,  C, C, C, C, /* 128-143 */
1400   C, C, C, C,  C, C, C, C,  C, C, C, C,  C, C, C, C, /* 144-159 */
1401   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1402   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1403
1404   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1405   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1406   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1407   0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
1408 };
1409 #undef U
1410 #undef W
1411 #undef C
1412 #undef UW
1413 #undef UWC
1414
1415 /* FN_PORT_SEP is the separator between host and port in file names
1416    for non-standard port numbers.  On Unix this is normally ':', as in
1417    "www.xemacs.org:4001/index.html".  Under Windows, we set it to +
1418    because Windows can't handle ':' in file names.  */
1419 #define FN_PORT_SEP  (opt.restrict_files_os != restrict_windows ? ':' : '+')
1420
1421 /* FN_QUERY_SEP is the separator between the file name and the URL
1422    query, normally '?'.  Since Windows cannot handle '?' as part of
1423    file name, we use '@' instead there.  */
1424 #define FN_QUERY_SEP (opt.restrict_files_os != restrict_windows ? '?' : '@')
1425
1426 /* Quote path element, characters in [b, e), as file name, and append
1427    the quoted string to DEST.  Each character is quoted as per
1428    file_unsafe_char and the corresponding table.
1429
1430    If ESCAPED_P is non-zero, the path element is considered to be
1431    URL-escaped and will be unescaped prior to inspection.  */
1432
1433 static void
1434 append_uri_pathel (const char *b, const char *e, int escaped_p,
1435                    struct growable *dest)
1436 {
1437   const char *p;
1438   int quoted, outlen;
1439
1440   int mask;
1441   if (opt.restrict_files_os == restrict_unix)
1442     mask = filechr_not_unix;
1443   else
1444     mask = filechr_not_windows;
1445   if (opt.restrict_files_ctrl)
1446     mask |= filechr_control;
1447
1448   /* Copy [b, e) to PATHEL and URL-unescape it. */
1449   if (escaped_p)
1450     {
1451       char *unescaped;
1452       BOUNDED_TO_ALLOCA (b, e, unescaped);
1453       url_unescape (unescaped);
1454       b = unescaped;
1455       e = unescaped + strlen (unescaped);
1456     }
1457
1458   /* Walk the PATHEL string and check how many characters we'll need
1459      to add for file quoting.  */
1460   quoted = 0;
1461   for (p = b; p < e; p++)
1462     if (FILE_CHAR_TEST (*p, mask))
1463       ++quoted;
1464
1465   /* e-b is the string length.  Each quoted char means two additional
1466      characters in the string, hence 2*quoted.  */
1467   outlen = (e - b) + (2 * quoted);
1468   GROW (dest, outlen);
1469
1470   if (!quoted)
1471     {
1472       /* If there's nothing to quote, we don't need to go through the
1473          string the second time.  */
1474       memcpy (TAIL (dest), b, outlen);
1475     }
1476   else
1477     {
1478       char *q = TAIL (dest);
1479       for (p = b; p < e; p++)
1480         {
1481           if (!FILE_CHAR_TEST (*p, mask))
1482             *q++ = *p;
1483           else
1484             {
1485               unsigned char ch = *p;
1486               *q++ = '%';
1487               *q++ = XNUM_TO_DIGIT (ch >> 4);
1488               *q++ = XNUM_TO_DIGIT (ch & 0xf);
1489             }
1490         }
1491       assert (q - TAIL (dest) == outlen);
1492     }
1493   TAIL_INCR (dest, outlen);
1494 }
1495
1496 /* Append to DEST the directory structure that corresponds the
1497    directory part of URL's path.  For example, if the URL is
1498    http://server/dir1/dir2/file, this appends "/dir1/dir2".
1499
1500    Each path element ("dir1" and "dir2" in the above example) is
1501    examined, url-unescaped, and re-escaped as file name element.
1502
1503    Additionally, it cuts as many directories from the path as
1504    specified by opt.cut_dirs.  For example, if opt.cut_dirs is 1, it
1505    will produce "bar" for the above example.  For 2 or more, it will
1506    produce "".
1507
1508    Each component of the path is quoted for use as file name.  */
1509
1510 static void
1511 append_dir_structure (const struct url *u, struct growable *dest)
1512 {
1513   char *pathel, *next;
1514   int cut = opt.cut_dirs;
1515
1516   /* Go through the path components, de-URL-quote them, and quote them
1517      (if necessary) as file names.  */
1518
1519   pathel = u->path;
1520   for (; (next = strchr (pathel, '/')) != NULL; pathel = next + 1)
1521     {
1522       if (cut-- > 0)
1523         continue;
1524       if (pathel == next)
1525         /* Ignore empty pathels.  */
1526         continue;
1527
1528       if (dest->tail)
1529         append_char ('/', dest);
1530       append_uri_pathel (pathel, next, 1, dest);
1531     }
1532 }
1533
1534 /* Return a unique file name that matches the given URL as good as
1535    possible.  Does not create directories on the file system.  */
1536
1537 char *
1538 url_file_name (const struct url *u)
1539 {
1540   struct growable fnres;
1541
1542   char *u_file, *u_query;
1543   char *fname, *unique;
1544
1545   fnres.base = NULL;
1546   fnres.size = 0;
1547   fnres.tail = 0;
1548
1549   /* Start with the directory prefix, if specified. */
1550   if (opt.dir_prefix)
1551     append_string (opt.dir_prefix, &fnres);
1552
1553   /* If "dirstruct" is turned on (typically the case with -r), add
1554      the host and port (unless those have been turned off) and
1555      directory structure.  */
1556   if (opt.dirstruct)
1557     {
1558       if (opt.add_hostdir)
1559         {
1560           if (fnres.tail)
1561             append_char ('/', &fnres);
1562           append_string (u->host, &fnres);
1563           if (u->port != scheme_default_port (u->scheme))
1564             {
1565               char portstr[24];
1566               number_to_string (portstr, u->port);
1567               append_char (FN_PORT_SEP, &fnres);
1568               append_string (portstr, &fnres);
1569             }
1570         }
1571
1572       append_dir_structure (u, &fnres);
1573     }
1574
1575   /* Add the file name. */
1576   if (fnres.tail)
1577     append_char ('/', &fnres);
1578   u_file = *u->file ? u->file : "index.html";
1579   append_uri_pathel (u_file, u_file + strlen (u_file), 0, &fnres);
1580
1581   /* Append "?query" to the file name. */
1582   u_query = u->query && *u->query ? u->query : NULL;
1583   if (u_query)
1584     {
1585       append_char (FN_QUERY_SEP, &fnres);
1586       append_uri_pathel (u_query, u_query + strlen (u_query), 1, &fnres);
1587     }
1588
1589   /* Zero-terminate the file name. */
1590   append_char ('\0', &fnres);
1591
1592   fname = fnres.base;
1593
1594   /* Check the cases in which the unique extensions are not used:
1595      1) Clobbering is turned off (-nc).
1596      2) Retrieval with regetting.
1597      3) Timestamping is used.
1598      4) Hierarchy is built.
1599
1600      The exception is the case when file does exist and is a
1601      directory (see `mkalldirs' for explanation).  */
1602
1603   if ((opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct)
1604       && !(file_exists_p (fname) && !file_non_directory_p (fname)))
1605     return fname;
1606
1607   unique = unique_name (fname, 1);
1608   if (unique != fname)
1609     xfree (fname);
1610   return unique;
1611 }
1612
1613 /* Return the length of URL's path.  Path is considered to be
1614    terminated by one of '?', ';', '#', or by the end of the
1615    string.  */
1616 static int
1617 path_length (const char *url)
1618 {
1619   const char *q = strpbrk_or_eos (url, "?;#");
1620   return q - url;
1621 }
1622
1623 /* Find the last occurrence of character C in the range [b, e), or
1624    NULL, if none are present.  This is equivalent to strrchr(b, c),
1625    except that it accepts an END argument instead of requiring the
1626    string to be zero-terminated.  Why is there no memrchr()?  */
1627 static const char *
1628 find_last_char (const char *b, const char *e, char c)
1629 {
1630   for (; e > b; e--)
1631     if (*e == c)
1632       return e;
1633   return NULL;
1634 }
1635 \f
1636 /* Resolve "." and ".." elements of PATH by destructively modifying
1637    PATH and return non-zero if PATH has been modified, zero otherwise.
1638
1639    The algorithm is in spirit similar to the one described in rfc1808,
1640    although implemented differently, in one pass.  To recap, path
1641    elements containing only "." are removed, and ".." is taken to mean
1642    "back up one element".  Single leading and trailing slashes are
1643    preserved.
1644
1645    This function does not handle URL escapes explicitly.  If you're
1646    passing paths from URLs, make sure to unquote "%2e" and "%2E" to
1647    ".", so that this function can find the dots.  (Wget's URL parser
1648    calls reencode_escapes, which see.)
1649
1650    For example, "a/b/c/./../d/.." will yield "a/b/".  More exhaustive
1651    test examples are provided below.  If you change anything in this
1652    function, run test_path_simplify to make sure you haven't broken a
1653    test case.  */
1654
1655 static int
1656 path_simplify (char *path)
1657 {
1658   char *h, *t, *end;
1659
1660   /* Preserve the leading '/'. */
1661   if (path[0] == '/')
1662     ++path;
1663
1664   h = path;                     /* hare */
1665   t = path;                     /* tortoise */
1666   end = path + strlen (path);
1667
1668   while (h < end)
1669     {
1670       /* Hare should be at the beginning of a path element. */
1671
1672       if (h[0] == '.' && (h[1] == '/' || h[1] == '\0'))
1673         {
1674           /* Ignore "./". */
1675           h += 2;
1676         }
1677       else if (h[0] == '.' && h[1] == '.' && (h[2] == '/' || h[2] == '\0'))
1678         {
1679           /* Handle "../" by retreating the tortoise by one path
1680              element -- but not past beggining of PATH.  */
1681           if (t > path)
1682             {
1683               /* Move backwards until T hits the beginning of the
1684                  previous path element or the beginning of path. */
1685               for (--t; t > path && t[-1] != '/'; t--)
1686                 ;
1687             }
1688           h += 3;
1689         }
1690       else if (*h == '/')
1691         {
1692           /* Ignore empty path elements.  Supporting them well is hard
1693              (where do you save "http://x.com///y.html"?), and they
1694              don't bring any practical gain.  Plus, they break our
1695              filesystem-influenced assumptions: allowing them would
1696              make "x/y//../z" simplify to "x/y/z", whereas most people
1697              would expect "x/z".  */
1698           ++h;
1699         }
1700       else
1701         {
1702           /* A regular path element.  If H hasn't advanced past T,
1703              simply skip to the next path element.  Otherwise, copy
1704              the path element until the next slash.  */
1705           if (t == h)
1706             {
1707               /* Skip the path element, including the slash.  */
1708               while (h < end && *h != '/')
1709                 t++, h++;
1710               if (h < end)
1711                 t++, h++;
1712             }
1713           else
1714             {
1715               /* Copy the path element, including the final slash.  */
1716               while (h < end && *h != '/')
1717                 *t++ = *h++;
1718               if (h < end)
1719                 *t++ = *h++;
1720             }
1721         }
1722     }
1723
1724   if (t != h)
1725     *t = '\0';
1726
1727   return t != h;
1728 }
1729 \f
1730 /* Merge BASE with LINK and return the resulting URI.
1731
1732    Either of the URIs may be absolute or relative, complete with the
1733    host name, or path only.  This tries to reasonably handle all
1734    foreseeable cases.  It only employs minimal URL parsing, without
1735    knowledge of the specifics of schemes.
1736
1737    Perhaps this function should call path_simplify so that the callers
1738    don't have to call url_parse unconditionally.  */
1739
1740 char *
1741 uri_merge (const char *base, const char *link)
1742 {
1743   int linklength;
1744   const char *end;
1745   char *merge;
1746
1747   if (url_has_scheme (link))
1748     return xstrdup (link);
1749
1750   /* We may not examine BASE past END. */
1751   end = base + path_length (base);
1752   linklength = strlen (link);
1753
1754   if (!*link)
1755     {
1756       /* Empty LINK points back to BASE, query string and all. */
1757       return xstrdup (base);
1758     }
1759   else if (*link == '?')
1760     {
1761       /* LINK points to the same location, but changes the query
1762          string.  Examples: */
1763       /* uri_merge("path",         "?new") -> "path?new"     */
1764       /* uri_merge("path?foo",     "?new") -> "path?new"     */
1765       /* uri_merge("path?foo#bar", "?new") -> "path?new"     */
1766       /* uri_merge("path#foo",     "?new") -> "path?new"     */
1767       int baselength = end - base;
1768       merge = xmalloc (baselength + linklength + 1);
1769       memcpy (merge, base, baselength);
1770       memcpy (merge + baselength, link, linklength);
1771       merge[baselength + linklength] = '\0';
1772     }
1773   else if (*link == '#')
1774     {
1775       /* uri_merge("path",         "#new") -> "path#new"     */
1776       /* uri_merge("path#foo",     "#new") -> "path#new"     */
1777       /* uri_merge("path?foo",     "#new") -> "path?foo#new" */
1778       /* uri_merge("path?foo#bar", "#new") -> "path?foo#new" */
1779       int baselength;
1780       const char *end1 = strchr (base, '#');
1781       if (!end1)
1782         end1 = base + strlen (base);
1783       baselength = end1 - base;
1784       merge = xmalloc (baselength + linklength + 1);
1785       memcpy (merge, base, baselength);
1786       memcpy (merge + baselength, link, linklength);
1787       merge[baselength + linklength] = '\0';
1788     }
1789   else if (*link == '/' && *(link + 1) == '/')
1790     {
1791       /* LINK begins with "//" and so is a net path: we need to
1792          replace everything after (and including) the double slash
1793          with LINK. */
1794
1795       /* uri_merge("foo", "//new/bar")            -> "//new/bar"      */
1796       /* uri_merge("//old/foo", "//new/bar")      -> "//new/bar"      */
1797       /* uri_merge("http://old/foo", "//new/bar") -> "http://new/bar" */
1798
1799       int span;
1800       const char *slash;
1801       const char *start_insert;
1802
1803       /* Look for first slash. */
1804       slash = memchr (base, '/', end - base);
1805       /* If found slash and it is a double slash, then replace
1806          from this point, else default to replacing from the
1807          beginning.  */
1808       if (slash && *(slash + 1) == '/')
1809         start_insert = slash;
1810       else
1811         start_insert = base;
1812
1813       span = start_insert - base;
1814       merge = (char *)xmalloc (span + linklength + 1);
1815       if (span)
1816         memcpy (merge, base, span);
1817       memcpy (merge + span, link, linklength);
1818       merge[span + linklength] = '\0';
1819     }
1820   else if (*link == '/')
1821     {
1822       /* LINK is an absolute path: we need to replace everything
1823          after (and including) the FIRST slash with LINK.
1824
1825          So, if BASE is "http://host/whatever/foo/bar", and LINK is
1826          "/qux/xyzzy", our result should be
1827          "http://host/qux/xyzzy".  */
1828       int span;
1829       const char *slash;
1830       const char *start_insert = NULL; /* for gcc to shut up. */
1831       const char *pos = base;
1832       int seen_slash_slash = 0;
1833       /* We're looking for the first slash, but want to ignore
1834          double slash. */
1835     again:
1836       slash = memchr (pos, '/', end - pos);
1837       if (slash && !seen_slash_slash)
1838         if (*(slash + 1) == '/')
1839           {
1840             pos = slash + 2;
1841             seen_slash_slash = 1;
1842             goto again;
1843           }
1844
1845       /* At this point, SLASH is the location of the first / after
1846          "//", or the first slash altogether.  START_INSERT is the
1847          pointer to the location where LINK will be inserted.  When
1848          examining the last two examples, keep in mind that LINK
1849          begins with '/'. */
1850
1851       if (!slash && !seen_slash_slash)
1852         /* example: "foo" */
1853         /*           ^    */
1854         start_insert = base;
1855       else if (!slash && seen_slash_slash)
1856         /* example: "http://foo" */
1857         /*                     ^ */
1858         start_insert = end;
1859       else if (slash && !seen_slash_slash)
1860         /* example: "foo/bar" */
1861         /*           ^        */
1862         start_insert = base;
1863       else if (slash && seen_slash_slash)
1864         /* example: "http://something/" */
1865         /*                           ^  */
1866         start_insert = slash;
1867
1868       span = start_insert - base;
1869       merge = (char *)xmalloc (span + linklength + 1);
1870       if (span)
1871         memcpy (merge, base, span);
1872       memcpy (merge + span, link, linklength);
1873       merge[span + linklength] = '\0';
1874     }
1875   else
1876     {
1877       /* LINK is a relative URL: we need to replace everything
1878          after last slash (possibly empty) with LINK.
1879
1880          So, if BASE is "whatever/foo/bar", and LINK is "qux/xyzzy",
1881          our result should be "whatever/foo/qux/xyzzy".  */
1882       int need_explicit_slash = 0;
1883       int span;
1884       const char *start_insert;
1885       const char *last_slash = find_last_char (base, end, '/');
1886       if (!last_slash)
1887         {
1888           /* No slash found at all.  Append LINK to what we have,
1889              but we'll need a slash as a separator.
1890
1891              Example: if base == "foo" and link == "qux/xyzzy", then
1892              we cannot just append link to base, because we'd get
1893              "fooqux/xyzzy", whereas what we want is
1894              "foo/qux/xyzzy".
1895
1896              To make sure the / gets inserted, we set
1897              need_explicit_slash to 1.  We also set start_insert
1898              to end + 1, so that the length calculations work out
1899              correctly for one more (slash) character.  Accessing
1900              that character is fine, since it will be the
1901              delimiter, '\0' or '?'.  */
1902           /* example: "foo?..." */
1903           /*               ^    ('?' gets changed to '/') */
1904           start_insert = end + 1;
1905           need_explicit_slash = 1;
1906         }
1907       else if (last_slash && last_slash >= base + 2
1908                && last_slash[-2] == ':' && last_slash[-1] == '/')
1909         {
1910           /* example: http://host"  */
1911           /*                      ^ */
1912           start_insert = end + 1;
1913           need_explicit_slash = 1;
1914         }
1915       else
1916         {
1917           /* example: "whatever/foo/bar" */
1918           /*                        ^    */
1919           start_insert = last_slash + 1;
1920         }
1921
1922       span = start_insert - base;
1923       merge = (char *)xmalloc (span + linklength + 1);
1924       if (span)
1925         memcpy (merge, base, span);
1926       if (need_explicit_slash)
1927         merge[span - 1] = '/';
1928       memcpy (merge + span, link, linklength);
1929       merge[span + linklength] = '\0';
1930     }
1931
1932   return merge;
1933 }
1934 \f
1935 #define APPEND(p, s) do {                       \
1936   int len = strlen (s);                         \
1937   memcpy (p, s, len);                           \
1938   p += len;                                     \
1939 } while (0)
1940
1941 /* Use this instead of password when the actual password is supposed
1942    to be hidden.  We intentionally use a generic string without giving
1943    away the number of characters in the password, like previous
1944    versions did.  */
1945 #define HIDDEN_PASSWORD "*password*"
1946
1947 /* Recreate the URL string from the data in URL.
1948
1949    If HIDE is non-zero (as it is when we're calling this on a URL we
1950    plan to print, but not when calling it to canonicalize a URL for
1951    use within the program), password will be hidden.  Unsafe
1952    characters in the URL will be quoted.  */
1953
1954 char *
1955 url_string (const struct url *url, int hide_password)
1956 {
1957   int size;
1958   char *result, *p;
1959   char *quoted_user = NULL, *quoted_passwd = NULL;
1960
1961   int scheme_port  = supported_schemes[url->scheme].default_port;
1962   char *scheme_str = supported_schemes[url->scheme].leading_string;
1963   int fplen = full_path_length (url);
1964
1965   int brackets_around_host = 0;
1966
1967   assert (scheme_str != NULL);
1968
1969   /* Make sure the user name and password are quoted. */
1970   if (url->user)
1971     {
1972       quoted_user = url_escape_allow_passthrough (url->user);
1973       if (url->passwd)
1974         {
1975           if (hide_password)
1976             quoted_passwd = HIDDEN_PASSWORD;
1977           else
1978             quoted_passwd = url_escape_allow_passthrough (url->passwd);
1979         }
1980     }
1981
1982   if (strchr (url->host, ':'))
1983     brackets_around_host = 1;
1984
1985   size = (strlen (scheme_str)
1986           + strlen (url->host)
1987           + (brackets_around_host ? 2 : 0)
1988           + fplen
1989           + 1);
1990   if (url->port != scheme_port)
1991     size += 1 + numdigit (url->port);
1992   if (quoted_user)
1993     {
1994       size += 1 + strlen (quoted_user);
1995       if (quoted_passwd)
1996         size += 1 + strlen (quoted_passwd);
1997     }
1998
1999   p = result = xmalloc (size);
2000
2001   APPEND (p, scheme_str);
2002   if (quoted_user)
2003     {
2004       APPEND (p, quoted_user);
2005       if (quoted_passwd)
2006         {
2007           *p++ = ':';
2008           APPEND (p, quoted_passwd);
2009         }
2010       *p++ = '@';
2011     }
2012
2013   if (brackets_around_host)
2014     *p++ = '[';
2015   APPEND (p, url->host);
2016   if (brackets_around_host)
2017     *p++ = ']';
2018   if (url->port != scheme_port)
2019     {
2020       *p++ = ':';
2021       p = number_to_string (p, url->port);
2022     }
2023
2024   full_path_write (url, p);
2025   p += fplen;
2026   *p++ = '\0';
2027
2028   assert (p - result == size);
2029
2030   if (quoted_user && quoted_user != url->user)
2031     xfree (quoted_user);
2032   if (quoted_passwd && !hide_password
2033       && quoted_passwd != url->passwd)
2034     xfree (quoted_passwd);
2035
2036   return result;
2037 }
2038 \f
2039 /* Return non-zero if scheme a is similar to scheme b.
2040  
2041    Schemes are similar if they are equal.  If SSL is supported, schemes
2042    are also similar if one is http (SCHEME_HTTP) and the other is https
2043    (SCHEME_HTTPS).  */
2044 int
2045 schemes_are_similar_p (enum url_scheme a, enum url_scheme b)
2046 {
2047   if (a == b)
2048     return 1;
2049 #ifdef HAVE_SSL
2050   if ((a == SCHEME_HTTP && b == SCHEME_HTTPS)
2051       || (a == SCHEME_HTTPS && b == SCHEME_HTTP))
2052     return 1;
2053 #endif
2054   return 0;
2055 }
2056 \f
2057 #if 0
2058 /* Debugging and testing support for path_simplify. */
2059
2060 /* Debug: run path_simplify on PATH and return the result in a new
2061    string.  Useful for calling from the debugger.  */
2062 static char *
2063 ps (char *path)
2064 {
2065   char *copy = xstrdup (path);
2066   path_simplify (copy);
2067   return copy;
2068 }
2069
2070 static void
2071 run_test (char *test, char *expected_result, int expected_change)
2072 {
2073   char *test_copy = xstrdup (test);
2074   int modified = path_simplify (test_copy);
2075
2076   if (0 != strcmp (test_copy, expected_result))
2077     {
2078       printf ("Failed path_simplify(\"%s\"): expected \"%s\", got \"%s\".\n",
2079               test, expected_result, test_copy);
2080     }
2081   if (modified != expected_change)
2082     {
2083       if (expected_change == 1)
2084         printf ("Expected no modification with path_simplify(\"%s\").\n",
2085                 test);
2086       else
2087         printf ("Expected modification with path_simplify(\"%s\").\n",
2088                 test);
2089     }
2090   xfree (test_copy);
2091 }
2092
2093 static void
2094 test_path_simplify (void)
2095 {
2096   static struct {
2097     char *test, *result;
2098     int should_modify;
2099   } tests[] = {
2100     { "",               "",             0 },
2101     { ".",              "",             1 },
2102     { "..",             "",             1 },
2103     { "foo",            "foo",          0 },
2104     { "foo/bar",        "foo/bar",      0 },
2105     { "foo///bar",      "foo/bar",      1 },
2106     { "foo/.",          "foo/",         1 },
2107     { "foo/./",         "foo/",         1 },
2108     { "foo./",          "foo./",        0 },
2109     { "foo/../bar",     "bar",          1 },
2110     { "foo/../bar/",    "bar/",         1 },
2111     { "foo/bar/..",     "foo/",         1 },
2112     { "foo/bar/../x",   "foo/x",        1 },
2113     { "foo/bar/../x/",  "foo/x/",       1 },
2114     { "foo/..",         "",             1 },
2115     { "foo/../..",      "",             1 },
2116     { "a/b/../../c",    "c",            1 },
2117     { "./a/../b",       "b",            1 }
2118   };
2119   int i;
2120
2121   for (i = 0; i < countof (tests); i++)
2122     {
2123       char *test = tests[i].test;
2124       char *expected_result = tests[i].result;
2125       int   expected_change = tests[i].should_modify;
2126       run_test (test, expected_result, expected_change);
2127     }
2128
2129   /* Now run all the tests with a leading slash before the test case,
2130      to prove that the slash is being preserved.  */
2131   for (i = 0; i < countof (tests); i++)
2132     {
2133       char *test, *expected_result;
2134       int expected_change = tests[i].should_modify;
2135
2136       test = xmalloc (1 + strlen (tests[i].test) + 1);
2137       sprintf (test, "/%s", tests[i].test);
2138
2139       expected_result = xmalloc (1 + strlen (tests[i].result) + 1);
2140       sprintf (expected_result, "/%s", tests[i].result);
2141
2142       run_test (test, expected_result, expected_change);
2143
2144       xfree (test);
2145       xfree (expected_result);
2146     }
2147 }
2148 #endif