]> sjero.net Git - wget/blob - src/cookies.c
[svn] Remove K&R support.
[wget] / src / cookies.c
1 /* Support for cookies.
2    Copyright (C) 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or (at
9 your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 /* Written by Hrvoje Niksic.  Parts are loosely inspired by the
31    cookie patch submitted by Tomasz Wegrzanowski.
32
33    This implements the client-side cookie support, as specified
34    (loosely) by Netscape's "preliminary specification", currently
35    available at:
36
37        http://wp.netscape.com/newsref/std/cookie_spec.html
38
39    rfc2109 is not supported because of its incompatibilities with the
40    above widely-used specification.  rfc2965 is entirely ignored,
41    since popular client software doesn't implement it, and even the
42    sites that do send Set-Cookie2 also emit Set-Cookie for
43    compatibility.  */
44
45 #include <config.h>
46
47 #include <stdio.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <assert.h>
51 #include <errno.h>
52 #include <time.h>
53
54 #include "wget.h"
55 #include "utils.h"
56 #include "hash.h"
57 #include "cookies.h"
58
59 /* This should *really* be in a .h file!  */
60 time_t http_atotm (const char *);
61 \f
62 /* Declarations of `struct cookie' and the most basic functions. */
63
64 /* Cookie jar serves as cookie storage and a means of retrieving
65    cookies efficiently.  All cookies with the same domain are stored
66    in a linked list called "chain".  A cookie chain can be reached by
67    looking up the domain in the cookie jar's chains_by_domain table.
68
69    For example, to reach all the cookies under google.com, one must
70    execute hash_table_get(jar->chains_by_domain, "google.com").  Of
71    course, when sending a cookie to `www.google.com', one must search
72    for cookies that belong to either `www.google.com' or `google.com'
73    -- but the point is that the code doesn't need to go through *all*
74    the cookies.  */
75
76 struct cookie_jar {
77   /* Cookie chains indexed by domain.  */
78   struct hash_table *chains;
79
80   int cookie_count;             /* number of cookies in the jar. */
81 };
82
83 /* Value set by entry point functions, so that the low-level
84    routines don't need to call time() all the time.  */
85 time_t cookies_now;
86
87 struct cookie_jar *
88 cookie_jar_new (void)
89 {
90   struct cookie_jar *jar = xnew (struct cookie_jar);
91   jar->chains = make_nocase_string_hash_table (0);
92   jar->cookie_count = 0;
93   return jar;
94 }
95
96 struct cookie {
97   char *domain;                 /* domain of the cookie */
98   int port;                     /* port number */
99   char *path;                   /* path prefix of the cookie */
100
101   int secure;                   /* whether cookie should be
102                                    transmitted over non-https
103                                    connections. */
104   int domain_exact;             /* whether DOMAIN must match as a
105                                    whole. */
106
107   int permanent;                /* whether the cookie should outlive
108                                    the session. */
109   time_t expiry_time;           /* time when the cookie expires, 0
110                                    means undetermined. */
111
112   int discard_requested;        /* whether cookie was created to
113                                    request discarding another
114                                    cookie. */
115
116   char *attr;                   /* cookie attribute name */
117   char *value;                  /* cookie attribute value */
118
119   struct cookie *next;          /* used for chaining of cookies in the
120                                    same domain. */
121 };
122
123 #define PORT_ANY (-1)
124
125 /* Allocate and return a new, empty cookie structure. */
126
127 static struct cookie *
128 cookie_new (void)
129 {
130   struct cookie *cookie = xnew0 (struct cookie);
131
132   /* Both cookie->permanent and cookie->expiry_time are now 0.  This
133      means that the cookie doesn't expire, but is only valid for this
134      session (i.e. not written out to disk).  */
135
136   cookie->port = PORT_ANY;
137   return cookie;
138 }
139
140 /* Non-zero if the cookie has expired.  Assumes cookies_now has been
141    set by one of the entry point functions.  */
142
143 static int
144 cookie_expired_p (const struct cookie *c)
145 {
146   return c->expiry_time != 0 && c->expiry_time < cookies_now;
147 }
148
149 /* Deallocate COOKIE and its components. */
150
151 static void
152 delete_cookie (struct cookie *cookie)
153 {
154   xfree_null (cookie->domain);
155   xfree_null (cookie->path);
156   xfree_null (cookie->attr);
157   xfree_null (cookie->value);
158   xfree (cookie);
159 }
160 \f
161 /* Functions for storing cookies.
162
163    All cookies can be reached beginning with jar->chains.  The key in
164    that table is the domain name, and the value is a linked list of
165    all cookies from that domain.  Every new cookie is placed on the
166    head of the list.  */
167
168 /* Find and return a cookie in JAR whose domain, path, and attribute
169    name correspond to COOKIE.  If found, PREVPTR will point to the
170    location of the cookie previous in chain, or NULL if the found
171    cookie is the head of a chain.
172
173    If no matching cookie is found, return NULL. */
174
175 static struct cookie *
176 find_matching_cookie (struct cookie_jar *jar, struct cookie *cookie,
177                       struct cookie **prevptr)
178 {
179   struct cookie *chain, *prev;
180
181   chain = hash_table_get (jar->chains, cookie->domain);
182   if (!chain)
183     goto nomatch;
184
185   prev = NULL;
186   for (; chain; prev = chain, chain = chain->next)
187     if (0 == strcmp (cookie->path, chain->path)
188         && 0 == strcmp (cookie->attr, chain->attr)
189         && cookie->port == chain->port)
190       {
191         *prevptr = prev;
192         return chain;
193       }
194
195  nomatch:
196   *prevptr = NULL;
197   return NULL;
198 }
199
200 /* Store COOKIE to the jar.
201
202    This is done by placing COOKIE at the head of its chain.  However,
203    if COOKIE matches a cookie already in memory, as determined by
204    find_matching_cookie, the old cookie is unlinked and destroyed.
205
206    The key of each chain's hash table entry is allocated only the
207    first time; next hash_table_put's reuse the same key.  */
208
209 static void
210 store_cookie (struct cookie_jar *jar, struct cookie *cookie)
211 {
212   struct cookie *chain_head;
213   char *chain_key;
214
215   if (hash_table_get_pair (jar->chains, cookie->domain,
216                            &chain_key, &chain_head))
217     {
218       /* A chain of cookies in this domain already exists.  Check for
219          duplicates -- if an extant cookie exactly matches our domain,
220          port, path, and name, replace it.  */
221       struct cookie *prev;
222       struct cookie *victim = find_matching_cookie (jar, cookie, &prev);
223
224       if (victim)
225         {
226           /* Remove VICTIM from the chain.  COOKIE will be placed at
227              the head. */
228           if (prev)
229             {
230               prev->next = victim->next;
231               cookie->next = chain_head;
232             }
233           else
234             {
235               /* prev is NULL; apparently VICTIM was at the head of
236                  the chain.  This place will be taken by COOKIE, so
237                  all we need to do is:  */
238               cookie->next = victim->next;
239             }
240           delete_cookie (victim);
241           --jar->cookie_count;
242           DEBUGP (("Deleted old cookie (to be replaced.)\n"));
243         }
244       else
245         cookie->next = chain_head;
246     }
247   else
248     {
249       /* We are now creating the chain.  Use a copy of cookie->domain
250          as the key for the life-time of the chain.  Using
251          cookie->domain would be unsafe because the life-time of the
252          chain may exceed the life-time of the cookie.  (Cookies may
253          be deleted from the chain by this very function.)  */
254       cookie->next = NULL;
255       chain_key = xstrdup (cookie->domain);
256     }
257
258   hash_table_put (jar->chains, chain_key, cookie);
259   ++jar->cookie_count;
260
261 #ifdef ENABLE_DEBUG
262   if (opt.debug)
263     {
264       time_t exptime = cookie->expiry_time;
265       DEBUGP (("\nStored cookie %s %d%s %s <%s> <%s> [expiry %s] %s %s\n",
266                cookie->domain, cookie->port,
267                cookie->port == PORT_ANY ? " (ANY)" : "",
268                cookie->path,
269                cookie->permanent ? "permanent" : "session",
270                cookie->secure ? "secure" : "insecure",
271                cookie->expiry_time ? datetime_str (&exptime) : "none",
272                cookie->attr, cookie->value));
273     }
274 #endif
275 }
276
277 /* Discard a cookie matching COOKIE's domain, port, path, and
278    attribute name.  This gets called when we encounter a cookie whose
279    expiry date is in the past, or whose max-age is set to 0.  The
280    former corresponds to netscape cookie spec, while the latter is
281    specified by rfc2109.  */
282
283 static void
284 discard_matching_cookie (struct cookie_jar *jar, struct cookie *cookie)
285 {
286   struct cookie *prev, *victim;
287
288   if (!hash_table_count (jar->chains))
289     /* No elements == nothing to discard. */
290     return;
291
292   victim = find_matching_cookie (jar, cookie, &prev);
293   if (victim)
294     {
295       if (prev)
296         /* Simply unchain the victim. */
297         prev->next = victim->next;
298       else
299         {
300           /* VICTIM was head of its chain.  We need to place a new
301              cookie at the head.  */
302           char *chain_key = NULL;
303           int res;
304
305           res = hash_table_get_pair (jar->chains, victim->domain,
306                                      &chain_key, NULL);
307           assert (res != 0);
308           if (!victim->next)
309             {
310               /* VICTIM was the only cookie in the chain.  Destroy the
311                  chain and deallocate the chain key.  */
312               hash_table_remove (jar->chains, victim->domain);
313               xfree (chain_key);
314             }
315           else
316             hash_table_put (jar->chains, chain_key, victim->next);
317         }
318       delete_cookie (victim);
319       DEBUGP (("Discarded old cookie.\n"));
320     }
321 }
322 \f
323 /* Functions for parsing the `Set-Cookie' header, and creating new
324    cookies from the wire.  */
325
326 #define NAME_IS(string_literal)                                 \
327   BOUNDED_EQUAL_NO_CASE (name_b, name_e, string_literal)
328
329 #define VALUE_EXISTS (value_b && value_e)
330
331 #define VALUE_NON_EMPTY (VALUE_EXISTS && (value_b != value_e))
332
333 /* Update the appropriate cookie field.  [name_b, name_e) are expected
334    to delimit the attribute name, while [value_b, value_e) (optional)
335    should delimit the attribute value.
336
337    When called the first time, it will set the cookie's attribute name
338    and value.  After that, it will check the attribute name for
339    special fields such as `domain', `path', etc.  Where appropriate,
340    it will parse the values of the fields it recognizes and fill the
341    corresponding fields in COOKIE.
342
343    Returns 1 on success.  Returns zero in case a syntax error is
344    found; such a cookie should be discarded.  */
345
346 static int
347 update_cookie_field (struct cookie *cookie,
348                      const char *name_b, const char *name_e,
349                      const char *value_b, const char *value_e)
350 {
351   assert (name_b != NULL && name_e != NULL);
352
353   if (!cookie->attr)
354     {
355       if (!VALUE_EXISTS)
356         return 0;
357       cookie->attr = strdupdelim (name_b, name_e);
358       cookie->value = strdupdelim (value_b, value_e);
359       return 1;
360     }
361
362   if (NAME_IS ("domain"))
363     {
364       if (!VALUE_NON_EMPTY)
365         return 0;
366       xfree_null (cookie->domain);
367       /* Strictly speaking, we should set cookie->domain_exact if the
368          domain doesn't begin with a dot.  But many sites set the
369          domain to "foo.com" and expect "subhost.foo.com" to get the
370          cookie, and it apparently works.  */
371       if (*value_b == '.')
372         ++value_b;
373       cookie->domain = strdupdelim (value_b, value_e);
374       return 1;
375     }
376   else if (NAME_IS ("path"))
377     {
378       if (!VALUE_NON_EMPTY)
379         return 0;
380       xfree_null (cookie->path);
381       cookie->path = strdupdelim (value_b, value_e);
382       return 1;
383     }
384   else if (NAME_IS ("expires"))
385     {
386       char *value_copy;
387       time_t expires;
388
389       if (!VALUE_NON_EMPTY)
390         return 0;
391       BOUNDED_TO_ALLOCA (value_b, value_e, value_copy);
392
393       expires = http_atotm (value_copy);
394       if (expires != (time_t) -1)
395         {
396           cookie->permanent = 1;
397           cookie->expiry_time = expires;
398         }
399       else
400         /* Error in expiration spec.  Assume default (cookie doesn't
401            expire, but valid only for this session.)  */
402         ;
403
404       /* According to netscape's specification, expiry time in the
405          past means that discarding of a matching cookie is
406          requested.  */
407       if (cookie->expiry_time < cookies_now)
408         cookie->discard_requested = 1;
409
410       return 1;
411     }
412   else if (NAME_IS ("max-age"))
413     {
414       double maxage = -1;
415       char *value_copy;
416
417       if (!VALUE_NON_EMPTY)
418         return 0;
419       BOUNDED_TO_ALLOCA (value_b, value_e, value_copy);
420
421       sscanf (value_copy, "%lf", &maxage);
422       if (maxage == -1)
423         /* something went wrong. */
424         return 0;
425       cookie->permanent = 1;
426       cookie->expiry_time = cookies_now + maxage;
427
428       /* According to rfc2109, a cookie with max-age of 0 means that
429          discarding of a matching cookie is requested.  */
430       if (maxage == 0)
431         cookie->discard_requested = 1;
432
433       return 1;
434     }
435   else if (NAME_IS ("secure"))
436     {
437       /* ignore value completely */
438       cookie->secure = 1;
439       return 1;
440     }
441   else
442     /* Unrecognized attribute; ignore it. */
443     return 1;
444 }
445
446 #undef NAME_IS
447
448 /* Returns non-zero for characters that are legal in the name of an
449    attribute.  This used to allow only alphanumerics, '-', and '_',
450    but we need to be more lenient because a number of sites wants to
451    use weirder attribute names.  rfc2965 "informally specifies"
452    attribute name (token) as "a sequence of non-special, non-white
453    space characters".  So we allow everything except the stuff we know
454    could harm us.  */
455
456 #define ATTR_NAME_CHAR(c) ((c) > 32 && (c) < 127        \
457                            && (c) != '"' && (c) != '='  \
458                            && (c) != ';' && (c) != ',')
459
460 /* Parse the contents of the `Set-Cookie' header.  The header looks
461    like this:
462
463    name1=value1; name2=value2; ...
464
465    Trailing semicolon is optional; spaces are allowed between all
466    tokens.  Additionally, values may be quoted.
467
468    A new cookie is returned upon success, NULL otherwise.  The
469    specified CALLBACK function (normally `update_cookie_field' is used
470    to update the fields of the newly created cookie structure.  */
471
472 static struct cookie *
473 parse_set_cookies (const char *sc,
474                    int (*callback) (struct cookie *,
475                                     const char *, const char *,
476                                     const char *, const char *),
477                    int silent)
478 {
479   struct cookie *cookie = cookie_new ();
480
481   /* #### Hand-written DFAs are no fun to debug.  We'de be better off
482      to rewrite this as an inline parser.  */
483
484   enum { S_START, S_NAME, S_NAME_POST,
485          S_VALUE_PRE, S_VALUE, S_QUOTED_VALUE, S_VALUE_TRAILSPACE,
486          S_ATTR_ACTION, S_DONE, S_ERROR
487   } state = S_START;
488
489   const char *p = sc;
490   char c;
491
492   const char *name_b  = NULL, *name_e  = NULL;
493   const char *value_b = NULL, *value_e = NULL;
494
495   c = *p;
496
497   while (state != S_DONE && state != S_ERROR)
498     {
499       switch (state)
500         {
501         case S_START:
502           if (!c)
503             state = S_DONE;
504           else if (ISSPACE (c))
505             /* Strip all whitespace preceding the name. */
506             c = *++p;
507           else if (ATTR_NAME_CHAR (c))
508             {
509               name_b = p;
510               state = S_NAME;
511             }
512           else
513             /* empty attr name not allowed */
514             state = S_ERROR;
515           break;
516         case S_NAME:
517           if (!c || c == ';' || c == '=' || ISSPACE (c))
518             {
519               name_e = p;
520               state = S_NAME_POST;
521             }
522           else if (ATTR_NAME_CHAR (c))
523             c = *++p;
524           else
525             state = S_ERROR;
526           break;
527         case S_NAME_POST:
528           if (!c || c == ';')
529             {
530               value_b = value_e = NULL;
531               if (c == ';')
532                 c = *++p;
533               state = S_ATTR_ACTION;
534             }
535           else if (c == '=')
536             {
537               c = *++p;
538               state = S_VALUE_PRE;
539             }
540           else if (ISSPACE (c))
541             /* Ignore space and keep the state. */
542             c = *++p;
543           else
544             state = S_ERROR;
545           break;
546         case S_VALUE_PRE:
547           if (!c || c == ';')
548             {
549               value_b = value_e = p;
550               if (c == ';')
551                 c = *++p;
552               state = S_ATTR_ACTION;
553             }
554           else if (c == '"')
555             {
556               c = *++p;
557               value_b = p;
558               state = S_QUOTED_VALUE;
559             }
560           else if (ISSPACE (c))
561             c = *++p;
562           else
563             {
564               value_b = p;
565               value_e = NULL;
566               state = S_VALUE;
567             }
568           break;
569         case S_VALUE:
570           if (!c || c == ';' || ISSPACE (c))
571             {
572               value_e = p;
573               state = S_VALUE_TRAILSPACE;
574             }
575           else
576             {
577               value_e = NULL;   /* no trailing space */
578               c = *++p;
579             }
580           break;
581         case S_QUOTED_VALUE:
582           if (c == '"')
583             {
584               value_e = p;
585               c = *++p;
586               state = S_VALUE_TRAILSPACE;
587             }
588           else if (!c)
589             state = S_ERROR;
590           else
591             c = *++p;
592           break;
593         case S_VALUE_TRAILSPACE:
594           if (c == ';')
595             {
596               c = *++p;
597               state = S_ATTR_ACTION;
598             }
599           else if (!c)
600             state = S_ATTR_ACTION;
601           else if (ISSPACE (c))
602             c = *++p;
603           else
604             state = S_VALUE;
605           break;
606         case S_ATTR_ACTION:
607           {
608             int legal = callback (cookie, name_b, name_e, value_b, value_e);
609             if (!legal)
610               {
611                 if (!silent)
612                   {
613                     char *name;
614                     BOUNDED_TO_ALLOCA (name_b, name_e, name);
615                     logprintf (LOG_NOTQUIET,
616                                _("Error in Set-Cookie, field `%s'"),
617                                escnonprint (name));
618                   }
619                 state = S_ERROR;
620                 break;
621               }
622             state = S_START;
623           }
624           break;
625         case S_DONE:
626         case S_ERROR:
627           /* handled by loop condition */
628           break;
629         }
630     }
631   if (state == S_DONE)
632     return cookie;
633
634   delete_cookie (cookie);
635   if (state != S_ERROR)
636     abort ();
637
638   if (!silent)
639     logprintf (LOG_NOTQUIET,
640                _("Syntax error in Set-Cookie: %s at position %d.\n"),
641                escnonprint (sc), p - sc);
642   return NULL;
643 }
644 \f
645 /* Sanity checks.  These are important, otherwise it is possible for
646    mailcious attackers to destroy important cookie information and/or
647    violate your privacy.  */
648
649
650 #define REQUIRE_DIGITS(p) do {                  \
651   if (!ISDIGIT (*p))                            \
652     return 0;                                   \
653   for (++p; ISDIGIT (*p); p++)                  \
654     ;                                           \
655 } while (0)
656
657 #define REQUIRE_DOT(p) do {                     \
658   if (*p++ != '.')                              \
659     return 0;                                   \
660 } while (0)
661
662 /* Check whether ADDR matches <digits>.<digits>.<digits>.<digits>.
663
664    We don't want to call network functions like inet_addr() because
665    all we need is a check, preferrably one that is small, fast, and
666    well-defined.  */
667
668 static int
669 numeric_address_p (const char *addr)
670 {
671   const char *p = addr;
672
673   REQUIRE_DIGITS (p);           /* A */
674   REQUIRE_DOT (p);              /* . */
675   REQUIRE_DIGITS (p);           /* B */
676   REQUIRE_DOT (p);              /* . */
677   REQUIRE_DIGITS (p);           /* C */
678   REQUIRE_DOT (p);              /* . */
679   REQUIRE_DIGITS (p);           /* D */
680
681   if (*p != '\0')
682     return 0;
683   return 1;
684 }
685
686 /* Check whether COOKIE_DOMAIN is an appropriate domain for HOST.
687    Originally I tried to make the check compliant with rfc2109, but
688    the sites deviated too often, so I had to fall back to "tail
689    matching", as defined by the original Netscape's cookie spec.  */
690
691 static int
692 check_domain_match (const char *cookie_domain, const char *host)
693 {
694   DEBUGP (("cdm: 1"));
695
696   /* Numeric address requires exact match.  It also requires HOST to
697      be an IP address.  */
698   if (numeric_address_p (cookie_domain))
699     return 0 == strcmp (cookie_domain, host);
700
701   DEBUGP ((" 2"));
702
703   /* For the sake of efficiency, check for exact match first. */
704   if (0 == strcasecmp (cookie_domain, host))
705     return 1;
706
707   DEBUGP ((" 3"));
708
709   /* HOST must match the tail of cookie_domain. */
710   if (!match_tail (host, cookie_domain, 1))
711     return 0;
712
713   /* We know that COOKIE_DOMAIN is a subset of HOST; however, we must
714      make sure that somebody is not trying to set the cookie for a
715      subdomain shared by many entities.  For example, "company.co.uk"
716      must not be allowed to set a cookie for ".co.uk".  On the other
717      hand, "sso.redhat.de" should be able to set a cookie for
718      ".redhat.de".
719
720      The only marginally sane way to handle this I can think of is to
721      reject on the basis of the length of the second-level domain name
722      (but when the top-level domain is unknown), with the assumption
723      that those of three or less characters could be reserved.  For
724      example:
725
726           .co.org -> works because the TLD is known
727            .co.uk -> doesn't work because "co" is only two chars long
728           .com.au -> doesn't work because "com" is only 3 chars long
729           .cnn.uk -> doesn't work because "cnn" is also only 3 chars long (ugh)
730           .cnn.de -> doesn't work for the same reason (ugh!!)
731          .abcd.de -> works because "abcd" is 4 chars long
732       .img.cnn.de -> works because it's not trying to set the 2nd level domain
733        .cnn.co.uk -> works for the same reason
734
735     That should prevent misuse, while allowing reasonable usage.  If
736     someone knows of a better way to handle this, please let me
737     know.  */
738   {
739     const char *p = cookie_domain;
740     int dccount = 1;            /* number of domain components */
741     int ldcl  = 0;              /* last domain component length */
742     int nldcl = 0;              /* next to last domain component length */
743     int out;
744     if (*p == '.')
745       /* Ignore leading period in this calculation. */
746       ++p;
747     DEBUGP ((" 4"));
748     for (out = 0; !out; p++)
749       switch (*p)
750         {
751         case '\0':
752           out = 1;
753           break;
754         case '.':
755           if (ldcl == 0)
756             /* Empty domain component found -- the domain is invalid. */
757             return 0;
758           if (*(p + 1) == '\0')
759             {
760               /* Tolerate trailing '.' by not treating the domain as
761                  one ending with an empty domain component.  */
762               out = 1;
763               break;
764             }
765           nldcl = ldcl;
766           ldcl  = 0;
767           ++dccount;
768           break;
769         default:
770           ++ldcl;
771         }
772
773     DEBUGP ((" 5"));
774
775     if (dccount < 2)
776       return 0;
777
778     DEBUGP ((" 6"));
779
780     if (dccount == 2)
781       {
782         int i;
783         int known_toplevel = 0;
784         static const char *known_toplevel_domains[] = {
785           ".com", ".edu", ".net", ".org", ".gov", ".mil", ".int"
786         };
787         for (i = 0; i < countof (known_toplevel_domains); i++)
788           if (match_tail (cookie_domain, known_toplevel_domains[i], 1))
789             {
790               known_toplevel = 1;
791               break;
792             }
793         if (!known_toplevel && nldcl <= 3)
794           return 0;
795       }
796   }
797
798   DEBUGP ((" 7"));
799
800   /* Don't allow the host "foobar.com" to set a cookie for domain
801      "bar.com".  */
802   if (*cookie_domain != '.')
803     {
804       int dlen = strlen (cookie_domain);
805       int hlen = strlen (host);
806       /* cookie host:    hostname.foobar.com */
807       /* desired domain:             bar.com */
808       /* '.' must be here in host-> ^        */
809       if (hlen > dlen && host[hlen - dlen - 1] != '.')
810         return 0;
811     }
812
813   DEBUGP ((" 8"));
814
815   return 1;
816 }
817
818 static int path_matches (const char *, const char *);
819
820 /* Check whether PATH begins with COOKIE_PATH. */
821
822 static int
823 check_path_match (const char *cookie_path, const char *path)
824 {
825   return path_matches (path, cookie_path);
826 }
827 \f
828 /* Process the HTTP `Set-Cookie' header.  This results in storing the
829    cookie or discarding a matching one, or ignoring it completely, all
830    depending on the contents.  */
831
832 void
833 cookie_handle_set_cookie (struct cookie_jar *jar,
834                           const char *host, int port,
835                           const char *path, const char *set_cookie)
836 {
837   struct cookie *cookie;
838   cookies_now = time (NULL);
839
840   cookie = parse_set_cookies (set_cookie, update_cookie_field, 0);
841   if (!cookie)
842     goto out;
843
844   /* Sanitize parts of cookie. */
845
846   if (!cookie->domain)
847     {
848     copy_domain:
849       /* If the domain was not provided, we use the one we're talking
850          to, and set exact match.  */
851       cookie->domain = xstrdup (host);
852       cookie->domain_exact = 1;
853       /* Set the port, but only if it's non-default. */
854       if (port != 80 && port != 443)
855         cookie->port = port;
856     }
857   else
858     {
859       if (!check_domain_match (cookie->domain, host))
860         {
861           logprintf (LOG_NOTQUIET,
862                      _("Cookie coming from %s attempted to set domain to %s\n"),
863                      escnonprint (host), escnonprint (cookie->domain));
864           xfree (cookie->domain);
865           goto copy_domain;
866         }
867     }
868
869   if (!cookie->path)
870     {
871       /* The cookie doesn't set path: set it to the URL path, sans the
872          file part ("/dir/file" truncated to "/dir/").  */
873       char *trailing_slash = strrchr (path, '/');
874       if (trailing_slash)
875         cookie->path = strdupdelim (path, trailing_slash + 1);
876       else
877         /* no slash in the string -- can this even happen? */
878         cookie->path = xstrdup (path);
879     }
880   else
881     {
882       /* The cookie sets its own path; verify that it is legal. */
883       if (!check_path_match (cookie->path, path))
884         {
885           DEBUGP (("Attempt to fake the path: %s, %s\n",
886                    cookie->path, path));
887           goto out;
888         }
889     }
890
891   /* Now store the cookie, or discard an existing cookie, if
892      discarding was requested.  */
893
894   if (cookie->discard_requested)
895     {
896       discard_matching_cookie (jar, cookie);
897       goto out;
898     }
899
900   store_cookie (jar, cookie);
901   return;
902
903  out:
904   if (cookie)
905     delete_cookie (cookie);
906 }
907 \f
908 /* Support for sending out cookies in HTTP requests, based on
909    previously stored cookies.  Entry point is
910    `build_cookies_request'.  */
911    
912 /* Return a count of how many times CHR occurs in STRING. */
913
914 static int
915 count_char (const char *string, char chr)
916 {
917   const char *p;
918   int count = 0;
919   for (p = string; *p; p++)
920     if (*p == chr)
921       ++count;
922   return count;
923 }
924
925 /* Find the cookie chains whose domains match HOST and store them to
926    DEST.
927
928    A cookie chain is the head of a list of cookies that belong to a
929    host/domain.  Given HOST "img.search.xemacs.org", this function
930    will return the chains for "img.search.xemacs.org",
931    "search.xemacs.org", and "xemacs.org" -- those of them that exist
932    (if any), that is.
933
934    DEST should be large enough to accept (in the worst case) as many
935    elements as there are domain components of HOST.  */
936
937 static int
938 find_chains_of_host (struct cookie_jar *jar, const char *host,
939                      struct cookie *dest[])
940 {
941   int dest_count = 0;
942   int passes, passcnt;
943
944   /* Bail out quickly if there are no cookies in the jar.  */
945   if (!hash_table_count (jar->chains))
946     return 0;
947
948   if (numeric_address_p (host))
949     /* If host is an IP address, only check for the exact match. */
950     passes = 1;
951   else
952     /* Otherwise, check all the subdomains except the top-level (last)
953        one.  As a domain with N components has N-1 dots, the number of
954        passes equals the number of dots.  */
955     passes = count_char (host, '.');
956
957   passcnt = 0;
958
959   /* Find chains that match HOST, starting with exact match and
960      progressing to less specific domains.  For instance, given HOST
961      fly.srk.fer.hr, first look for fly.srk.fer.hr's chain, then
962      srk.fer.hr's, then fer.hr's.  */
963   while (1)
964     {
965       struct cookie *chain = hash_table_get (jar->chains, host);
966       if (chain)
967         dest[dest_count++] = chain;
968       if (++passcnt >= passes)
969         break;
970       host = strchr (host, '.') + 1;
971     }
972
973   return dest_count;
974 }
975
976 /* If FULL_PATH begins with PREFIX, return the length of PREFIX, zero
977    otherwise.  */
978
979 static int
980 path_matches (const char *full_path, const char *prefix)
981 {
982   int len;
983
984   if (*prefix != '/')
985     /* Wget's HTTP paths do not begin with '/' (the URL code treats it
986        as a mere separator, inspired by rfc1808), but the '/' is
987        assumed when matching against the cookie stuff.  */
988     return 0;
989
990   ++prefix;
991   len = strlen (prefix);
992
993   if (0 != strncmp (full_path, prefix, len))
994     /* FULL_PATH doesn't begin with PREFIX. */
995     return 0;
996
997   /* Length of PREFIX determines the quality of the match. */
998   return len + 1;
999 }
1000
1001 /* Return non-zero iff COOKIE matches the provided parameters of the
1002    URL being downloaded: HOST, PORT, PATH, and SECFLAG.
1003
1004    If PATH_GOODNESS is non-NULL, store the "path goodness" value
1005    there.  That value is a measure of how closely COOKIE matches PATH,
1006    used for ordering cookies.  */
1007
1008 static int
1009 cookie_matches_url (const struct cookie *cookie,
1010                     const char *host, int port, const char *path,
1011                     int secflag, int *path_goodness)
1012 {
1013   int pg;
1014
1015   if (cookie_expired_p (cookie))
1016     /* Ignore stale cookies.  Don't bother unchaining the cookie at
1017        this point -- Wget is a relatively short-lived application, and
1018        stale cookies will not be saved by `save_cookies'.  On the
1019        other hand, this function should be as efficient as
1020        possible.  */
1021     return 0;
1022
1023   if (cookie->secure && !secflag)
1024     /* Don't transmit secure cookies over insecure connections.  */
1025     return 0;
1026   if (cookie->port != PORT_ANY && cookie->port != port)
1027     return 0;
1028
1029   /* If exact domain match is required, verify that cookie's domain is
1030      equal to HOST.  If not, assume success on the grounds of the
1031      cookie's chain having been found by find_chains_of_host.  */
1032   if (cookie->domain_exact
1033       && 0 != strcasecmp (host, cookie->domain))
1034     return 0;
1035
1036   pg = path_matches (path, cookie->path);
1037   if (!pg)
1038     return 0;
1039
1040   if (path_goodness)
1041     /* If the caller requested path_goodness, we return it.  This is
1042        an optimization, so that the caller doesn't need to call
1043        path_matches() again.  */
1044     *path_goodness = pg;
1045   return 1;
1046 }
1047
1048 /* A structure that points to a cookie, along with the additional
1049    information about the cookie's "goodness".  This allows us to sort
1050    the cookies when returning them to the server, as required by the
1051    spec.  */
1052
1053 struct weighed_cookie {
1054   struct cookie *cookie;
1055   int domain_goodness;
1056   int path_goodness;
1057 };
1058
1059 /* Comparator used for uniquifying the list. */
1060
1061 static int
1062 equality_comparator (const void *p1, const void *p2)
1063 {
1064   struct weighed_cookie *wc1 = (struct weighed_cookie *)p1;
1065   struct weighed_cookie *wc2 = (struct weighed_cookie *)p2;
1066
1067   int namecmp  = strcmp (wc1->cookie->attr, wc2->cookie->attr);
1068   int valuecmp = strcmp (wc1->cookie->value, wc2->cookie->value);
1069
1070   /* We only really care whether both name and value are equal.  We
1071      return them in this order only for consistency...  */
1072   return namecmp ? namecmp : valuecmp;
1073 }
1074
1075 /* Eliminate duplicate cookies.  "Duplicate cookies" are any two
1076    cookies with the same attr name and value.  Whenever a duplicate
1077    pair is found, one of the cookies is removed.  */
1078
1079 static int
1080 eliminate_dups (struct weighed_cookie *outgoing, int count)
1081 {
1082   struct weighed_cookie *h;     /* hare */
1083   struct weighed_cookie *t;     /* tortoise */
1084   struct weighed_cookie *end = outgoing + count;
1085
1086   /* We deploy a simple uniquify algorithm: first sort the array
1087      according to our sort criteria, then copy it to itself, comparing
1088      each cookie to its neighbor and ignoring the duplicates.  */
1089
1090   qsort (outgoing, count, sizeof (struct weighed_cookie), equality_comparator);
1091
1092   /* "Hare" runs through all the entries in the array, followed by
1093      "tortoise".  If a duplicate is found, the hare skips it.
1094      Non-duplicate entries are copied to the tortoise ptr.  */
1095
1096   for (h = t = outgoing; h < end; h++)
1097     {
1098       if (h != end - 1)
1099         {
1100           struct cookie *c0 = h[0].cookie;
1101           struct cookie *c1 = h[1].cookie;
1102           if (!strcmp (c0->attr, c1->attr) && !strcmp (c0->value, c1->value))
1103             continue;           /* ignore the duplicate */
1104         }
1105
1106       /* If the hare has advanced past the tortoise (because of
1107          previous dups), make sure the values get copied.  Otherwise,
1108          no copying is necessary.  */
1109       if (h != t)
1110         *t++ = *h;
1111       else
1112         t++;
1113     }
1114   return t - outgoing;
1115 }
1116
1117 /* Comparator used for sorting by quality. */
1118
1119 static int
1120 goodness_comparator (const void *p1, const void *p2)
1121 {
1122   struct weighed_cookie *wc1 = (struct weighed_cookie *)p1;
1123   struct weighed_cookie *wc2 = (struct weighed_cookie *)p2;
1124
1125   /* Subtractions take `wc2' as the first argument becauase we want a
1126      sort in *decreasing* order of goodness.  */
1127   int dgdiff = wc2->domain_goodness - wc1->domain_goodness;
1128   int pgdiff = wc2->path_goodness - wc1->path_goodness;
1129
1130   /* Sort by domain goodness; if these are the same, sort by path
1131      goodness.  (The sorting order isn't really specified; maybe it
1132      should be the other way around.)  */
1133   return dgdiff ? dgdiff : pgdiff;
1134 }
1135
1136 /* Generate a `Cookie' header for a request that goes to HOST:PORT and
1137    requests PATH from the server.  The resulting string is allocated
1138    with `malloc', and the caller is responsible for freeing it.  If no
1139    cookies pertain to this request, i.e. no cookie header should be
1140    generated, NULL is returned.  */
1141
1142 char *
1143 cookie_header (struct cookie_jar *jar, const char *host,
1144                int port, const char *path, int secflag)
1145 {
1146   struct cookie **chains;
1147   int chain_count;
1148
1149   struct cookie *cookie;
1150   struct weighed_cookie *outgoing;
1151   int count, i, ocnt;
1152   char *result;
1153   int result_size, pos;
1154
1155   /* First, find the cookie chains whose domains match HOST. */
1156
1157   /* Allocate room for find_chains_of_host to write to.  The number of
1158      chains can at most equal the number of subdomains, hence
1159      1+<number of dots>.  */
1160   chains = alloca_array (struct cookie *, 1 + count_char (host, '.'));
1161   chain_count = find_chains_of_host (jar, host, chains);
1162
1163   /* No cookies for this host. */
1164   if (!chain_count)
1165     return NULL;
1166
1167   cookies_now = time (NULL);
1168
1169   /* Now extract from the chains those cookies that match our host
1170      (for domain_exact cookies), port (for cookies with port other
1171      than PORT_ANY), etc.  See matching_cookie for details.  */
1172
1173   /* Count the number of matching cookies. */
1174   count = 0;
1175   for (i = 0; i < chain_count; i++)
1176     for (cookie = chains[i]; cookie; cookie = cookie->next)
1177       if (cookie_matches_url (cookie, host, port, path, secflag, NULL))
1178         ++count;
1179   if (!count)
1180     return NULL;                /* no cookies matched */
1181
1182   /* Allocate the array. */
1183   outgoing = alloca_array (struct weighed_cookie, count);
1184
1185   /* Fill the array with all the matching cookies from the chains that
1186      match HOST. */
1187   ocnt = 0;
1188   for (i = 0; i < chain_count; i++)
1189     for (cookie = chains[i]; cookie; cookie = cookie->next)
1190       {
1191         int pg;
1192         if (!cookie_matches_url (cookie, host, port, path, secflag, &pg))
1193           continue;
1194         outgoing[ocnt].cookie = cookie;
1195         outgoing[ocnt].domain_goodness = strlen (cookie->domain);
1196         outgoing[ocnt].path_goodness   = pg;
1197         ++ocnt;
1198       }
1199   assert (ocnt == count);
1200
1201   /* Eliminate duplicate cookies; that is, those whose name and value
1202      are the same.  */
1203   count = eliminate_dups (outgoing, count);
1204
1205   /* Sort the array so that best-matching domains come first, and
1206      that, within one domain, best-matching paths come first. */
1207   qsort (outgoing, count, sizeof (struct weighed_cookie), goodness_comparator);
1208
1209   /* Count the space the name=value pairs will take. */
1210   result_size = 0;
1211   for (i = 0; i < count; i++)
1212     {
1213       struct cookie *c = outgoing[i].cookie;
1214       /* name=value */
1215       result_size += strlen (c->attr) + 1 + strlen (c->value);
1216     }
1217
1218   /* Allocate output buffer:
1219      name=value pairs -- result_size
1220      "; " separators  -- (count - 1) * 2
1221      \0 terminator    -- 1 */
1222   result_size = result_size + (count - 1) * 2 + 1;
1223   result = xmalloc (result_size);
1224   pos = 0;
1225   for (i = 0; i < count; i++)
1226     {
1227       struct cookie *c = outgoing[i].cookie;
1228       int namlen = strlen (c->attr);
1229       int vallen = strlen (c->value);
1230
1231       memcpy (result + pos, c->attr, namlen);
1232       pos += namlen;
1233       result[pos++] = '=';
1234       memcpy (result + pos, c->value, vallen);
1235       pos += vallen;
1236       if (i < count - 1)
1237         {
1238           result[pos++] = ';';
1239           result[pos++] = ' ';
1240         }
1241     }
1242   result[pos++] = '\0';
1243   assert (pos == result_size);
1244   return result;
1245 }
1246 \f
1247 /* Support for loading and saving cookies.  The format used for
1248    loading and saving should be the format of the `cookies.txt' file
1249    used by Netscape and Mozilla, at least the Unix versions.
1250    (Apparently IE can export cookies in that format as well.)  The
1251    format goes like this:
1252
1253        DOMAIN DOMAIN-FLAG PATH SECURE-FLAG TIMESTAMP ATTR-NAME ATTR-VALUE
1254
1255      DOMAIN      -- cookie domain, optionally followed by :PORT
1256      DOMAIN-FLAG -- whether all hosts in the domain match
1257      PATH        -- cookie path
1258      SECURE-FLAG -- whether cookie requires secure connection
1259      TIMESTAMP   -- expiry timestamp, number of seconds since epoch
1260      ATTR-NAME   -- name of the cookie attribute
1261      ATTR-VALUE  -- value of the cookie attribute (empty if absent)
1262
1263    The fields are separated by TABs.  All fields are mandatory, except
1264    for ATTR-VALUE.  The `-FLAG' fields are boolean, their legal values
1265    being "TRUE" and "FALSE'.  Empty lines, lines consisting of
1266    whitespace only, and comment lines (beginning with # optionally
1267    preceded by whitespace) are ignored.
1268
1269    Example line from cookies.txt (split in two lines for readability):
1270
1271        .google.com      TRUE    /       FALSE   2147368447      \
1272        PREF     ID=34bb47565bbcd47b:LD=en:NR=20:TM=985172580:LM=985739012
1273
1274 */
1275
1276 /* If the region [B, E) ends with :<digits>, parse the number, return
1277    it, and store new boundary (location of the `:') to DOMAIN_E_PTR.
1278    If port is not specified, return 0.  */
1279
1280 static int
1281 domain_port (const char *domain_b, const char *domain_e,
1282              const char **domain_e_ptr)
1283 {
1284   int port = 0;
1285   const char *p;
1286   const char *colon = memchr (domain_b, ':', domain_e - domain_b);
1287   if (!colon)
1288     return 0;
1289   for (p = colon + 1; p < domain_e && ISDIGIT (*p); p++)
1290     port = 10 * port + (*p - '0');
1291   if (p < domain_e)
1292     /* Garbage following port number. */
1293     return 0;
1294   *domain_e_ptr = colon;
1295   return port;
1296 }
1297
1298 #define GET_WORD(p, b, e) do {                  \
1299   b = p;                                        \
1300   while (*p && *p != '\t')                      \
1301     ++p;                                        \
1302   e = p;                                        \
1303   if (b == e || !*p)                            \
1304     goto next;                                  \
1305   ++p;                                          \
1306 } while (0)
1307
1308 /* Load cookies from FILE.  */
1309
1310 void
1311 cookie_jar_load (struct cookie_jar *jar, const char *file)
1312 {
1313   char *line;
1314   FILE *fp = fopen (file, "r");
1315   if (!fp)
1316     {
1317       logprintf (LOG_NOTQUIET, _("Cannot open cookies file `%s': %s\n"),
1318                  file, strerror (errno));
1319       return;
1320     }
1321   cookies_now = time (NULL);
1322
1323   for (; ((line = read_whole_line (fp)) != NULL); xfree (line))
1324     {
1325       struct cookie *cookie;
1326       char *p = line;
1327
1328       double expiry;
1329       int port;
1330
1331       char *domain_b  = NULL, *domain_e  = NULL;
1332       char *domflag_b = NULL, *domflag_e = NULL;
1333       char *path_b    = NULL, *path_e    = NULL;
1334       char *secure_b  = NULL, *secure_e  = NULL;
1335       char *expires_b = NULL, *expires_e = NULL;
1336       char *name_b    = NULL, *name_e    = NULL;
1337       char *value_b   = NULL, *value_e   = NULL;
1338
1339       /* Skip leading white-space. */
1340       while (*p && ISSPACE (*p))
1341         ++p;
1342       /* Ignore empty lines.  */
1343       if (!*p || *p == '#')
1344         continue;
1345
1346       GET_WORD (p, domain_b,  domain_e);
1347       GET_WORD (p, domflag_b, domflag_e);
1348       GET_WORD (p, path_b,    path_e);
1349       GET_WORD (p, secure_b,  secure_e);
1350       GET_WORD (p, expires_b, expires_e);
1351       GET_WORD (p, name_b,    name_e);
1352
1353       /* Don't use GET_WORD for value because it ends with newline,
1354          not TAB.  */
1355       value_b = p;
1356       value_e = p + strlen (p);
1357       if (value_e > value_b && value_e[-1] == '\n')
1358         --value_e;
1359       if (value_e > value_b && value_e[-1] == '\r')
1360         --value_e;
1361       /* Empty values are legal (I think), so don't bother checking. */
1362
1363       cookie = cookie_new ();
1364
1365       cookie->attr    = strdupdelim (name_b, name_e);
1366       cookie->value   = strdupdelim (value_b, value_e);
1367       cookie->path    = strdupdelim (path_b, path_e);
1368       cookie->secure  = BOUNDED_EQUAL (secure_b, secure_e, "TRUE");
1369
1370       /* Curl source says, quoting Andre Garcia: "flag: A TRUE/FALSE
1371          value indicating if all machines within a given domain can
1372          access the variable.  This value is set automatically by the
1373          browser, depending on the value set for the domain."  */
1374       cookie->domain_exact = !BOUNDED_EQUAL (domflag_b, domflag_e, "TRUE");
1375
1376       /* DOMAIN needs special treatment because we might need to
1377          extract the port.  */
1378       port = domain_port (domain_b, domain_e, (const char **)&domain_e);
1379       if (port)
1380         cookie->port = port;
1381
1382       if (*domain_b == '.')
1383         ++domain_b;             /* remove leading dot internally */
1384       cookie->domain  = strdupdelim (domain_b, domain_e);
1385
1386       /* safe default in case EXPIRES field is garbled. */
1387       expiry = (double)cookies_now - 1;
1388
1389       /* I don't like changing the line, but it's safe here.  (line is
1390          malloced.)  */
1391       *expires_e = '\0';
1392       sscanf (expires_b, "%lf", &expiry);
1393
1394       if (expiry == 0)
1395         {
1396           /* EXPIRY can be 0 for session cookies saved because the
1397              user specified `--keep-session-cookies' in the past.
1398              They remain session cookies, and will be saved only if
1399              the user has specified `keep-session-cookies' again.  */
1400         }
1401       else
1402         {
1403           if (expiry < cookies_now)
1404             goto abort_cookie;  /* ignore stale cookie. */
1405           cookie->expiry_time = expiry;
1406           cookie->permanent = 1;
1407         }
1408
1409       store_cookie (jar, cookie);
1410
1411     next:
1412       continue;
1413
1414     abort_cookie:
1415       delete_cookie (cookie);
1416     }
1417   fclose (fp);
1418 }
1419
1420 /* Mapper for save_cookies callable by hash_table_map.  VALUE points
1421    to the head in a chain of cookies.  The function prints the entire
1422    chain.  */
1423
1424 static int
1425 save_cookies_mapper (void *key, void *value, void *arg)
1426 {
1427   FILE *fp = (FILE *)arg;
1428   char *domain = (char *)key;
1429   struct cookie *cookie = (struct cookie *)value;
1430   for (; cookie; cookie = cookie->next)
1431     {
1432       if (!cookie->permanent && !opt.keep_session_cookies)
1433         continue;
1434       if (cookie_expired_p (cookie))
1435         continue;
1436       if (!cookie->domain_exact)
1437         fputc ('.', fp);
1438       fputs (domain, fp);
1439       if (cookie->port != PORT_ANY)
1440         fprintf (fp, ":%d", cookie->port);
1441       fprintf (fp, "\t%s\t%s\t%s\t%.0f\t%s\t%s\n",
1442                cookie->domain_exact ? "FALSE" : "TRUE",
1443                cookie->path, cookie->secure ? "TRUE" : "FALSE",
1444                (double)cookie->expiry_time,
1445                cookie->attr, cookie->value);
1446       if (ferror (fp))
1447         return 1;               /* stop mapping */
1448     }
1449   return 0;
1450 }
1451
1452 /* Save cookies, in format described above, to FILE. */
1453
1454 void
1455 cookie_jar_save (struct cookie_jar *jar, const char *file)
1456 {
1457   FILE *fp;
1458
1459   DEBUGP (("Saving cookies to %s.\n", file));
1460
1461   cookies_now = time (NULL);
1462
1463   fp = fopen (file, "w");
1464   if (!fp)
1465     {
1466       logprintf (LOG_NOTQUIET, _("Cannot open cookies file `%s': %s\n"),
1467                  file, strerror (errno));
1468       return;
1469     }
1470
1471   fputs ("# HTTP cookie file.\n", fp);
1472   fprintf (fp, "# Generated by Wget on %s.\n", datetime_str (&cookies_now));
1473   fputs ("# Edit at your own risk.\n\n", fp);
1474
1475   hash_table_map (jar->chains, save_cookies_mapper, fp);
1476
1477   if (ferror (fp))
1478     logprintf (LOG_NOTQUIET, _("Error writing to `%s': %s\n"),
1479                file, strerror (errno));
1480   if (fclose (fp) < 0)
1481     logprintf (LOG_NOTQUIET, _("Error closing `%s': %s\n"),
1482                file, strerror (errno));
1483
1484   DEBUGP (("Done saving cookies.\n"));
1485 }
1486 \f
1487 /* Destroy all the elements in the chain and unhook it from the cookie
1488    jar.  This is written in the form of a callback to hash_table_map
1489    and used by cookie_jar_delete to delete all the cookies in a
1490    jar.  */
1491
1492 static int
1493 nuke_cookie_chain (void *value, void *key, void *arg)
1494 {
1495   char *chain_key = (char *)value;
1496   struct cookie *chain = (struct cookie *)key;
1497   struct cookie_jar *jar = (struct cookie_jar *)arg;
1498
1499   /* Remove the chain from the table and free the key. */
1500   hash_table_remove (jar->chains, chain_key);
1501   xfree (chain_key);
1502
1503   /* Then delete all the cookies in the chain. */
1504   while (chain)
1505     {
1506       struct cookie *next = chain->next;
1507       delete_cookie (chain);
1508       chain = next;
1509     }
1510
1511   /* Keep mapping. */
1512   return 0;
1513 }
1514
1515 /* Clean up cookie-related data. */
1516
1517 void
1518 cookie_jar_delete (struct cookie_jar *jar)
1519 {
1520   hash_table_map (jar->chains, nuke_cookie_chain, jar);
1521   hash_table_destroy (jar->chains);
1522   xfree (jar);
1523 }
1524 \f
1525 /* Test cases.  Currently this is only tests parse_set_cookies.  To
1526    use, recompile Wget with -DTEST_COOKIES and call test_cookies()
1527    from main.  */
1528
1529 #ifdef TEST_COOKIES
1530 int test_count;
1531 char *test_results[10];
1532
1533 static int test_parse_cookies_callback (struct cookie *ignored,
1534                                         const char *nb, const char *ne,
1535                                         const char *vb, const char *ve)
1536 {
1537   test_results[test_count++] = strdupdelim (nb, ne);
1538   test_results[test_count++] = strdupdelim (vb, ve);
1539   return 1;
1540 }
1541
1542 void
1543 test_cookies (void)
1544 {
1545   /* Tests expected to succeed: */
1546   static struct {
1547     char *data;
1548     char *results[10];
1549   } tests_succ[] = {
1550     { "", {NULL} },
1551     { "arg=value", {"arg", "value", NULL} },
1552     { "arg1=value1;arg2=value2", {"arg1", "value1", "arg2", "value2", NULL} },
1553     { "arg1=value1; arg2=value2", {"arg1", "value1", "arg2", "value2", NULL} },
1554     { "arg1=value1;  arg2=value2;", {"arg1", "value1", "arg2", "value2", NULL} },
1555     { "arg1=value1;  arg2=value2;  ", {"arg1", "value1", "arg2", "value2", NULL} },
1556     { "arg1=\"value1\"; arg2=\"\"", {"arg1", "value1", "arg2", "", NULL} },
1557     { "arg=", {"arg", "", NULL} },
1558     { "arg1=; arg2=", {"arg1", "", "arg2", "", NULL} },
1559     { "arg1 = ; arg2= ", {"arg1", "", "arg2", "", NULL} },
1560   };
1561
1562   /* Tests expected to fail: */
1563   static char *tests_fail[] = {
1564     ";",
1565     "arg=\"unterminated",
1566     "=empty-name",
1567     "arg1=;=another-empty-name",
1568   };
1569   int i;
1570
1571   for (i = 0; i < countof (tests_succ); i++)
1572     {
1573       int ind;
1574       char *data = tests_succ[i].data;
1575       char **expected = tests_succ[i].results;
1576       struct cookie *c;
1577
1578       test_count = 0;
1579       c = parse_set_cookies (data, test_parse_cookies_callback, 1);
1580       if (!c)
1581         {
1582           printf ("NULL cookie returned for valid data: %s\n", data);
1583           continue;
1584         }
1585
1586       for (ind = 0; ind < test_count; ind += 2)
1587         {
1588           if (!expected[ind])
1589             break;
1590           if (0 != strcmp (expected[ind], test_results[ind]))
1591             printf ("Invalid name %d for '%s' (expected '%s', got '%s')\n",
1592                     ind / 2 + 1, data, expected[ind], test_results[ind]);
1593           if (0 != strcmp (expected[ind + 1], test_results[ind + 1]))
1594             printf ("Invalid value %d for '%s' (expected '%s', got '%s')\n",
1595                     ind / 2 + 1, data, expected[ind + 1], test_results[ind + 1]);
1596         }
1597       if (ind < test_count || expected[ind])
1598         printf ("Unmatched number of results: %s\n", data);
1599     }
1600
1601   for (i = 0; i < countof (tests_fail); i++)
1602     {
1603       struct cookie *c;
1604       char *data = tests_fail[i];
1605       test_count = 0;
1606       c = parse_set_cookies (data, test_parse_cookies_callback, 1);
1607       if (c)
1608         printf ("Failed to report error on invalid data: %s\n", data);
1609     }
1610 }
1611 #endif /* TEST_COOKIES */