1 /* Support for cookies.
2 Copyright (C) 2001 Free Software Foundation, Inc.
4 This file is part of Wget.
6 This program 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.
11 This program 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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* Written by Hrvoje Niksic. Parts are loosely inspired by cookie
21 code submitted by Tomasz Wegrzanowski. */
41 /* Hash table that maps domain names to cookie chains. */
43 static struct hash_table *cookies_hash_table;
45 /* This should be set by entry points in this file, so the low-level
46 functions don't need to call time() all the time. */
48 static time_t cookies_now;
50 /* This should *really* be in a .h file! */
51 time_t http_atotm PARAMS ((char *));
54 /* Definition of `struct cookie' and the most basic functions. */
57 char *domain; /* domain of the cookie */
58 int port; /* port number */
59 char *path; /* path prefix of the cookie */
60 int secure; /* whether cookie should be
61 transmitted over non-https
63 int permanent; /* whether the cookie should outlive
65 unsigned long expiry_time; /* time when the cookie expires */
66 int discard_requested; /* whether cookie was created to
67 request discarding another
70 char *attr; /* cookie attribute name */
71 char *value; /* cookie attribute value */
73 struct cookie *next; /* used for chaining of cookies in the
77 /* Allocate and return a new, empty cookie structure. */
79 static struct cookie *
82 struct cookie *cookie = xmalloc (sizeof (struct cookie));
83 memset (cookie, '\0', sizeof (struct cookie));
85 /* If we don't know better, assume cookie is non-permanent and valid
86 for the entire session. */
87 cookie->expiry_time = ~0UL;
89 /* Assume default port. */
95 /* Deallocate COOKIE and its components. */
98 delete_cookie (struct cookie *cookie)
100 FREE_MAYBE (cookie->domain);
101 FREE_MAYBE (cookie->path);
102 FREE_MAYBE (cookie->attr);
103 FREE_MAYBE (cookie->value);
107 /* Functions for cookie-specific hash tables. These are regular hash
108 tables, but with case-insensitive test and hash functions. */
110 /* Like string_hash, but produces the same results regardless of the
114 unsigned_string_hash (const void *sv)
117 unsigned const char *x = (unsigned const char *) sv;
122 unsigned char c = TOLOWER (*x);
124 if ((g = h & 0xf0000000) != 0)
125 h = (h ^ (g >> 24)) ^ g;
132 /* Front-end to strcasecmp. */
135 unsigned_string_cmp (const void *s1, const void *s2)
137 return !strcasecmp ((const char *)s1, (const char *)s2);
140 /* Like make_string_hash_table, but uses unsigned_string_hash and
141 unsigned_string_cmp. */
143 static struct hash_table *
144 make_unsigned_string_hash_table (int initial_size)
146 return hash_table_new (initial_size,
147 unsigned_string_hash, unsigned_string_cmp);
150 /* Write "HOST:PORT" to RESULT. RESULT should be a pointer, and the
151 memory for the contents is allocated on the stack. Useful for
152 creating HOST:PORT strings, which are the keys in the hash
155 #define SET_HOSTPORT(host, port, result) do { \
156 int HP_len = strlen (host); \
157 result = alloca (HP_len + 1 + numdigit (port) + 1); \
158 memcpy (result, host, HP_len); \
159 result[HP_len] = ':'; \
160 long_to_string (result + HP_len + 1, port); \
163 /* Find cookie chain that corresponds to DOMAIN (exact) and PORT. */
165 static struct cookie *
166 find_cookie_chain_exact (const char *domain, int port)
169 if (!cookies_hash_table)
171 SET_HOSTPORT (domain, port, key);
172 return hash_table_get (cookies_hash_table, key);
175 /* Functions for storing cookies.
177 All cookies can be referenced through cookies_hash_table. The key
178 in that table is the domain name, and the value is a linked list of
179 all cookies from that domain. Every new cookie is placed on the
182 /* Find and return the cookie whose domain, path, and attribute name
183 correspond to COOKIE. If found, PREVPTR will point to the location
184 of the cookie previous in chain, or NULL if the found cookie is the
187 If no matching cookie is found, return NULL. */
189 static struct cookie *
190 find_matching_cookie (struct cookie *cookie, struct cookie **prevptr)
192 struct cookie *chain, *prev;
194 if (!cookies_hash_table)
197 chain = find_cookie_chain_exact (cookie->domain, cookie->port);
202 for (; chain; prev = chain, chain = chain->next)
203 if (!strcmp (cookie->path, chain->path)
204 && !strcmp (cookie->attr, chain->attr))
215 /* Store COOKIE to memory.
217 This is done by placing COOKIE at the head of its chain. However,
218 if COOKIE matches a cookie already in memory, as determined by
219 find_matching_cookie, the old cookie is unlinked and destroyed.
221 The key of each chain's hash table entry is allocated only the
222 first time; next hash_table_put's reuse the same key. */
225 store_cookie (struct cookie *cookie)
227 struct cookie *chain_head;
231 if (!cookies_hash_table)
232 /* If the hash table is not initialized, do so now, because we'll
233 need to store things. */
234 cookies_hash_table = make_unsigned_string_hash_table (0);
236 /* Initialize hash table key. */
237 SET_HOSTPORT (cookie->domain, cookie->port, hostport);
239 if (hash_table_get_pair (cookies_hash_table, hostport,
240 &chain_key, &chain_head))
242 /* There already exists a chain of cookies with this exact
243 domain. We need to check for duplicates -- if an existing
244 cookie exactly matches our domain, path and name, we replace
247 struct cookie *victim = find_matching_cookie (cookie, &prev);
251 /* Remove VICTIM from the chain. COOKIE will be placed at
255 prev->next = victim->next;
256 cookie->next = chain_head;
260 /* prev is NULL; apparently VICTIM was at the head of
261 the chain. This place will be taken by COOKIE, so
262 all we need to do is: */
263 cookie->next = victim->next;
265 delete_cookie (victim);
266 DEBUGP (("Deleted old cookie (to be replaced.)\n"));
269 cookie->next = chain_head;
273 /* We are now creating the chain. Allocate the string that will
274 be used as a key. It is unsafe to use cookie->domain for
275 that, because it might get deallocated by the above code at
278 chain_key = xstrdup (hostport);
281 hash_table_put (cookies_hash_table, chain_key, cookie);
283 DEBUGP (("\nStored cookie %s %d %s %d %s %s %s\n",
284 cookie->domain, cookie->port, cookie->path, cookie->secure,
285 asctime (localtime ((time_t *)&cookie->expiry_time)),
286 cookie->attr, cookie->value));
289 /* Discard a cookie matching COOKIE's domain, path, and attribute
290 name. This gets called when we encounter a cookie whose expiry
291 date is in the past, or whose max-age is set to 0. The former
292 corresponds to netscape cookie spec, while the latter is specified
296 discard_matching_cookie (struct cookie *cookie)
298 struct cookie *prev, *victim;
300 if (!cookies_hash_table
301 || !hash_table_count (cookies_hash_table))
302 /* No elements == nothing to discard. */
305 victim = find_matching_cookie (cookie, &prev);
309 /* Simply unchain the victim. */
310 prev->next = victim->next;
313 /* VICTIM was head of its chain. We need to place a new
314 cookie at the head. */
317 char *chain_key = NULL;
320 SET_HOSTPORT (victim->domain, victim->port, hostport);
321 res = hash_table_get_pair (cookies_hash_table, hostport,
326 /* VICTIM was the only cookie in the chain. Destroy the
327 chain and deallocate the chain key. */
329 hash_table_remove (cookies_hash_table, hostport);
333 hash_table_put (cookies_hash_table, chain_key, victim->next);
335 delete_cookie (victim);
336 DEBUGP (("Discarded old cookie.\n"));
340 /* Functions for parsing the `Set-Cookie' header, and creating new
341 cookies from the wire. */
344 #define NAME_IS(string_literal) \
345 BOUNDED_EQUAL_NO_CASE (name_b, name_e, string_literal)
347 #define VALUE_EXISTS (value_b && value_e)
349 #define VALUE_NON_EMPTY (VALUE_EXISTS && (value_b != value_e))
351 /* Update the appropriate cookie field. [name_b, name_e) are expected
352 to delimit the attribute name, while [value_b, value_e) (optional)
353 should delimit the attribute value.
355 When called the first time, it will set the cookie's attribute name
356 and value. After that, it will check the attribute name for
357 special fields such as `domain', `path', etc. Where appropriate,
358 it will parse the values of the fields it recognizes and fill the
359 corresponding fields in COOKIE.
361 Returns 1 on success. Returns zero in case a syntax error is
362 found; such a cookie should be discarded. */
365 update_cookie_field (struct cookie *cookie,
366 const char *name_b, const char *name_e,
367 const char *value_b, const char *value_e)
369 assert (name_b != NULL && name_e != NULL);
375 cookie->attr = strdupdelim (name_b, name_e);
376 cookie->value = strdupdelim (value_b, value_e);
380 if (NAME_IS ("domain"))
382 if (!VALUE_NON_EMPTY)
384 FREE_MAYBE (cookie->domain);
385 cookie->domain = strdupdelim (value_b, value_e);
388 else if (NAME_IS ("path"))
390 if (!VALUE_NON_EMPTY)
392 FREE_MAYBE (cookie->path);
393 cookie->path = strdupdelim (value_b, value_e);
396 else if (NAME_IS ("expires"))
401 if (!VALUE_NON_EMPTY)
403 BOUNDED_TO_ALLOCA (value_b, value_e, value_copy);
405 expires = http_atotm (value_copy);
408 cookie->permanent = 1;
409 cookie->expiry_time = (unsigned long)expires;
412 /* Error in expiration spec. Assume default (cookie valid for
413 this session.) #### Should we return 0 and invalidate the
417 /* According to netscape's specification, expiry time in the
418 past means that discarding of a matching cookie is
420 if (cookie->expiry_time < cookies_now)
421 cookie->discard_requested = 1;
425 else if (NAME_IS ("max-age"))
430 if (!VALUE_NON_EMPTY)
432 BOUNDED_TO_ALLOCA (value_b, value_e, value_copy);
434 sscanf (value_copy, "%lf", &maxage);
436 /* something is wrong. */
438 cookie->permanent = 1;
439 cookie->expiry_time = (unsigned long)cookies_now + (unsigned long)maxage;
441 /* According to rfc2109, a cookie with max-age of 0 means that
442 discarding of a matching cookie is requested. */
444 cookie->discard_requested = 1;
448 else if (NAME_IS ("secure"))
450 /* ignore value completely */
455 /* Unrecognized attribute; ignore it. */
461 /* Returns non-zero for characters that are legal in the name of an
464 #define ATTR_NAME_CHAR(c) (ISALNUM (c) || (c) == '-' || (c) == '_')
466 /* Fetch the next character without doing anything special if CH gets
467 set to 0. (The code executed next is expected to handle it.) */
469 #define FETCH1(ch, ptr) do { \
473 /* Like FETCH1, but jumps to `eof' label if CH gets set to 0. */
475 #define FETCH(ch, ptr) do { \
481 /* Parse the contents of the `Set-Cookie' header. The header looks
484 name1=value1; name2=value2; ...
486 Trailing semicolon is optional; spaces are allowed between all
487 tokens. Additionally, values may be quoted.
489 A new cookie is returned upon success, NULL otherwise. The
490 function `update_cookie_field' is used to update the fields of the
491 newly created cookie structure. */
493 static struct cookie *
494 parse_set_cookies (const char *sc)
496 struct cookie *cookie = cookie_new ();
498 enum { S_NAME_PRE, S_NAME, S_NAME_POST,
499 S_VALUE_PRE, S_VALUE, S_VALUE_TRAILSPACE_MAYBE,
500 S_QUOTED_VALUE, S_QUOTED_VALUE_POST,
502 S_DONE, S_ERROR } state = S_NAME_PRE;
507 const char *name_b = NULL, *name_e = NULL;
508 const char *value_b = NULL, *value_e = NULL;
512 while (state != S_DONE && state != S_ERROR)
519 else if (ATTR_NAME_CHAR (c))
526 /* empty attr name not allowed */
530 if (ATTR_NAME_CHAR (c))
532 else if (!c || c == ';' || c == '=' || ISSPACE (c))
543 else if (!c || c == ';')
545 value_b = value_e = NULL;
546 state = S_ATTR_ACTION;
563 state = S_QUOTED_VALUE;
565 else if (c == ';' || c == '\0')
567 value_b = value_e = p - 1;
568 state = S_ATTR_ACTION;
578 if (c == ';' || c == '\0')
582 state = S_ATTR_ACTION;
584 else if (ISSPACE (c))
588 state = S_VALUE_TRAILSPACE_MAYBE;
592 value_e = NULL; /* no trailing space */
596 case S_VALUE_TRAILSPACE_MAYBE:
607 state = S_QUOTED_VALUE_POST;
612 case S_QUOTED_VALUE_POST:
614 state = S_ATTR_ACTION;
615 else if (ISSPACE (c))
622 int legal = update_cookie_field (cookie, name_b, name_e,
627 BOUNDED_TO_ALLOCA (name_b, name_e, name);
628 logprintf (LOG_NOTQUIET,
629 _("Error in Set-Cookie, field `%s'"), name);
644 /* handled by loop condition */
651 delete_cookie (cookie);
652 if (state == S_ERROR)
653 logprintf (LOG_NOTQUIET, _("Syntax error in Set-Cookie at character `%c'.\n"), c);
659 delete_cookie (cookie);
660 logprintf (LOG_NOTQUIET,
661 _("Syntax error in Set-Cookie: premature end of string.\n"));
665 /* Sanity checks. These are important, otherwise it is possible for
666 mailcious attackers to destroy important cookie information and/or
667 violate your privacy. */
670 #define REQUIRE_DIGITS(p) do { \
673 for (++p; ISDIGIT (*p); p++) \
677 #define REQUIRE_DOT(p) do { \
682 /* Check whether ADDR matches <digits>.<digits>.<digits>.<digits>.
684 We don't want to call network functions like inet_addr() because all
685 we need is a check, preferrably one that is small, fast, and
689 numeric_address_p (const char *addr)
691 const char *p = addr;
693 REQUIRE_DIGITS (p); /* A */
694 REQUIRE_DOT (p); /* . */
695 REQUIRE_DIGITS (p); /* B */
696 REQUIRE_DOT (p); /* . */
697 REQUIRE_DIGITS (p); /* C */
698 REQUIRE_DOT (p); /* . */
699 REQUIRE_DIGITS (p); /* D */
706 /* Check whether COOKIE_DOMAIN is an appropriate domain for HOST.
707 This check is compliant with rfc2109. */
710 check_domain_match (const char *cookie_domain, const char *host)
715 /* Numeric address requires exact match. It also requires HOST to
716 be an IP address. I suppose we *could* resolve HOST with
717 store_hostaddress (it would hit the hash table), but rfc2109
718 doesn't require it, and it doesn't seem very useful, so we
720 if (numeric_address_p (cookie_domain))
721 return !strcmp (cookie_domain, host);
723 /* The domain must contain at least one embedded dot. */
725 const char *rest = cookie_domain;
726 int len = strlen (rest);
728 ++rest, --len; /* ignore first dot */
731 if (rest[len - 1] == '.')
732 --len; /* ignore last dot */
734 if (!memchr (rest, '.', len))
739 /* For the sake of efficiency, check for exact match first. */
740 if (!strcasecmp (cookie_domain, host))
743 /* In rfc2109 terminology, HOST needs domain-match COOKIE_DOMAIN.
744 This means that COOKIE_DOMAIN needs to start with `.' and be an
745 FQDN, and that HOST must end with COOKIE_DOMAIN. */
746 if (*cookie_domain != '.')
749 /* Two proceed, we need to examine two parts of HOST: its head and
750 its tail. Head and tail are defined in terms of the length of
751 the domain, like this:
753 HHHHTTTTTTTTTTTTTTT <- host
754 DDDDDDDDDDDDDDD <- domain
756 That is, "head" is the part of the host before (dlen - hlen), and
757 "tail" is what follows.
759 For the domain to match, two conditions need to be true:
761 1. Tail must equal DOMAIN.
762 2. Head must not contain an embedded dot. */
764 headlen = strlen (host) - strlen (cookie_domain);
767 /* DOMAIN must be a proper subset of HOST. */
769 tail = host + headlen;
772 if (strcasecmp (tail, cookie_domain))
775 /* Test (2) is not part of the "domain-match" itself, but is
776 recommended by rfc2109 for reasons of privacy. */
779 if (memchr (host, '.', headlen))
785 static int path_matches PARAMS ((const char *, const char *));
787 /* Check whether PATH begins with COOKIE_PATH. */
790 check_path_match (const char *cookie_path, const char *path)
792 return path_matches (path, cookie_path);
795 /* Parse the `Set-Cookie' header and, if the cookie is legal, store it
799 set_cookie_header_cb (const char *hdr, void *closure)
801 struct urlinfo *u = (struct urlinfo *)closure;
802 struct cookie *cookie;
804 cookies_now = time (NULL);
806 cookie = parse_set_cookies (hdr);
810 /* Sanitize parts of cookie. */
813 cookie->domain = xstrdup (u->host);
816 if (!check_domain_match (cookie->domain, u->host))
818 DEBUGP (("Attempt to fake the domain: %s, %s\n",
819 cookie->domain, u->host));
824 cookie->path = xstrdup (u->path);
827 if (!check_path_match (cookie->path, u->path))
829 DEBUGP (("Attempt to fake the path: %s, %s\n",
830 cookie->path, u->path));
835 cookie->port = u->port;
837 if (cookie->discard_requested)
839 discard_matching_cookie (cookie);
840 delete_cookie (cookie);
844 store_cookie (cookie);
849 delete_cookie (cookie);
853 /* Support for sending out cookies in HTTP requests, based on
854 previously stored cookies. Entry point is
855 `build_cookies_request'. */
858 /* Count how many times CHR occurs in STRING. */
861 count_char (const char *string, char chr)
865 for (p = string; *p; p++)
871 /* Store CHAIN to STORE if there is room in STORE. If not, inrecement
872 COUNT anyway, so that when the function is done, we end up with the
873 exact count of how much place we actually need. */
875 #define STORE_CHAIN(st_chain, st_store, st_size, st_count) do { \
876 if (st_count < st_size) \
877 store[st_count] = st_chain; \
881 /* Store cookie chains that match HOST, PORT. Since more than one
882 chain can match, the matches are written to STORE. No more than
883 SIZE matches are written; if more matches are present, return the
884 number of chains that would have been written. */
887 find_matching_chains (const char *host, int port,
888 struct cookie *store[], int size)
890 struct cookie *chain;
895 if (!cookies_hash_table)
898 SET_HOSTPORT (host, port, hash_key);
901 chain = hash_table_get (cookies_hash_table, hash_key);
903 STORE_CHAIN (chain, store, size, count);
905 dot_count = count_char (host, '.');
907 /* Match less and less specific domains. For instance, given
908 fly.srk.fer.hr, we match .srk.fer.hr, then .fer.hr. */
909 while (dot_count-- > 1)
911 /* Note: we operate directly on hash_key (in form host:port)
912 because we don't want to allocate new hash keys in a
914 char *p = strchr (hash_key, '.');
916 chain = hash_table_get (cookies_hash_table, p);
918 STORE_CHAIN (chain, store, size, count);
924 /* If FULL_PATH begins with PREFIX, return the length of PREFIX, zero
928 path_matches (const char *full_path, const char *prefix)
930 int len = strlen (prefix);
931 if (strncmp (full_path, prefix, len))
932 /* FULL_PATH doesn't begin with PREFIX. */
935 /* Length of PREFIX determines the quality of the match. */
940 matching_cookie (const struct cookie *cookie, const char *path,
941 int connection_secure_p, int *path_goodness)
945 if (cookie->expiry_time < cookies_now)
946 /* Ignore stale cookies. There is no need to unchain the cookie
947 at this point -- Wget is a relatively short-lived application,
948 and stale cookies will not be saved by `save_cookies'. */
950 if (cookie->secure && !connection_secure_p)
951 /* Don't transmit secure cookies over an insecure connection. */
953 pg = path_matches (path, cookie->path);
958 /* If the caller requested path_goodness, we return it. This is
959 an optimization, so that the caller doesn't need to call
960 path_matches() again. */
965 struct weighed_cookie {
966 struct cookie *cookie;
971 /* Comparator used for uniquifying the list. */
974 equality_comparator (const void *p1, const void *p2)
976 struct weighed_cookie *wc1 = (struct weighed_cookie *)p1;
977 struct weighed_cookie *wc2 = (struct weighed_cookie *)p2;
979 int namecmp = strcmp (wc1->cookie->attr, wc2->cookie->attr);
980 int valuecmp = strcmp (wc1->cookie->value, wc2->cookie->value);
982 /* We only really care whether both name and value are equal. We
983 return them in this order only for consistency... */
984 return namecmp ? namecmp : valuecmp;
987 /* Comparator used for sorting by quality. */
990 goodness_comparator (const void *p1, const void *p2)
992 struct weighed_cookie *wc1 = (struct weighed_cookie *)p1;
993 struct weighed_cookie *wc2 = (struct weighed_cookie *)p2;
995 /* Subtractions take `wc2' as the first argument becauase we want a
996 sort in *decreasing* order of goodness. */
997 int dgdiff = wc2->domain_goodness - wc1->domain_goodness;
998 int pgdiff = wc2->path_goodness - wc1->path_goodness;
1000 /* Sort by domain goodness; if these are the same, sort by path
1001 goodness. (The sorting order isn't really specified; maybe it
1002 should be the other way around.) */
1003 return dgdiff ? dgdiff : pgdiff;
1006 /* Build a `Cookies' header for a request that goes to HOST:PORT and
1007 requests PATH from the server. Memory is allocated by `malloc',
1008 and the caller is responsible for freeing it. If no cookies
1009 pertain to this request, i.e. no cookie header should be generated,
1010 NULL is returned. */
1013 build_cookies_request (const char *host, int port, const char *path,
1014 int connection_secure_p)
1016 struct cookie *chain_default_store[20];
1017 struct cookie **all_chains = chain_default_store;
1018 int chain_store_size = ARRAY_SIZE (chain_default_store);
1021 struct cookie *cookie;
1022 struct weighed_cookie *outgoing;
1025 int result_size, pos;
1028 chain_count = find_matching_chains (host, port, all_chains, chain_store_size);
1029 if (chain_count > chain_store_size)
1031 /* It's extremely unlikely that more than 20 chains will ever
1032 match. But in this case it's easy to not have the
1033 limitation, so we don't. */
1034 all_chains = alloca (chain_count * sizeof (struct cookie *));
1041 cookies_now = time (NULL);
1043 /* Count the number of cookies whose path matches. */
1045 for (i = 0; i < chain_count; i++)
1046 for (cookie = all_chains[i]; cookie; cookie = cookie->next)
1047 if (matching_cookie (cookie, path, connection_secure_p, NULL))
1050 /* No matching cookies. */
1053 /* Allocate the array. */
1054 outgoing = alloca (count * sizeof (struct weighed_cookie));
1057 for (i = 0; i < chain_count; i++)
1058 for (cookie = all_chains[i]; cookie; cookie = cookie->next)
1061 if (!matching_cookie (cookie, path, connection_secure_p, &pg))
1063 outgoing[ocnt].cookie = cookie;
1064 outgoing[ocnt].domain_goodness = strlen (cookie->domain);
1065 outgoing[ocnt].path_goodness = pg;
1068 assert (ocnt == count);
1070 /* Eliminate duplicate cookies; that is, those whose name and value
1071 are the same. We do it by first sorting the array, and then
1073 qsort (outgoing, count, sizeof (struct weighed_cookie), equality_comparator);
1074 for (i = 0; i < count - 1; i++)
1076 struct cookie *c1 = outgoing[i].cookie;
1077 struct cookie *c2 = outgoing[i + 1].cookie;
1078 if (!strcmp (c1->attr, c2->attr) && !strcmp (c1->value, c2->value))
1080 /* c1 and c2 are the same; get rid of c2. */
1082 /* move all ptrs from positions [i + 1, count) to i. */
1083 memmove (outgoing + i, outgoing + i + 1,
1084 (count - (i + 1)) * sizeof (struct weighed_cookie));
1085 /* We decrement i to counter the ++i above. Remember that
1086 we've just removed the element in front of us; we need to
1087 remain in place to check whether outgoing[i] what used to
1088 be outgoing[i + 2]. */
1094 /* Sort the array so that best-matching domains come first, and
1095 that, within one domain, best-matching paths come first. */
1096 qsort (outgoing, count, sizeof (struct weighed_cookie), goodness_comparator);
1098 /* Count the space the name=value pairs will take. */
1100 for (i = 0; i < count; i++)
1102 struct cookie *c = outgoing[i].cookie;
1104 result_size += strlen (c->attr) + 1 + strlen (c->value);
1107 /* Allocate output buffer:
1109 name=value pairs -- result_size
1110 "; " separators -- (count - 1) * 2
1111 \r\n line ending -- 2
1112 \0 terminator -- 1 */
1113 result_size = 8 + result_size + (count - 1) * 2 + 2 + 1;
1114 result = xmalloc (result_size);
1116 strcpy (result, "Cookie: ");
1118 for (i = 0; i < count; i++)
1120 struct cookie *c = outgoing[i].cookie;
1121 int namlen = strlen (c->attr);
1122 int vallen = strlen (c->value);
1124 memcpy (result + pos, c->attr, namlen);
1126 result[pos++] = '=';
1127 memcpy (result + pos, c->value, vallen);
1131 result[pos++] = ';';
1132 result[pos++] = ' ';
1135 result[pos++] = '\r';
1136 result[pos++] = '\n';
1137 result[pos++] = '\0';
1138 assert (pos == result_size);
1142 /* Support for loading and saving cookies. The format used for
1143 loading and saving roughly matches the format of `cookies.txt' file
1144 used by Netscape and Mozilla, at least the Unix versions. The
1145 format goes like this:
1147 DOMAIN DOMAIN-FLAG PATH SECURE-FLAG TIMESTAMP ATTR-NAME ATTR-VALUE
1149 DOMAIN -- cookie domain, optionally followed by :PORT
1150 DOMAIN-FLAG -- whether all hosts in the domain match
1152 SECURE-FLAG -- whether cookie requires secure connection
1153 TIMESTAMP -- expiry timestamp, number of seconds since epoch
1154 ATTR-NAME -- name of the cookie attribute
1155 ATTR-VALUE -- value of the cookie attribute (empty if absent)
1157 The fields are separated by TABs (but Wget's loader recognizes any
1158 whitespace). All fields are mandatory, except for ATTR-VALUE. The
1159 `-FLAG' fields are boolean, their legal values being "TRUE" and
1160 "FALSE'. Empty lines, lines consisting of whitespace only, and
1161 comment lines (beginning with # optionally preceded by whitespace)
1164 Example line from cookies.txt (split in two lines for readability):
1166 .google.com TRUE / FALSE 2147368447 \
1167 PREF ID=34bb47565bbcd47b:LD=en:NR=20:TM=985172580:LM=985739012
1169 DOMAIN-FLAG is currently not honored by Wget. The cookies whose
1170 domain begins with `.' are treated as if DOMAIN-FLAG were true,
1171 while all other cookies are treated as if it were FALSE. */
1174 /* If the region [B, E) ends with :<digits>, parse the number, return
1175 it, and store new boundary (location of the `:') to DOMAIN_E_PTR.
1176 If port is not specified, return 0. */
1179 domain_port (const char *domain_b, const char *domain_e,
1180 const char **domain_e_ptr)
1184 const char *colon = memchr (domain_b, ':', domain_e - domain_b);
1187 for (p = colon + 1; p < domain_e && ISDIGIT (*p); p++)
1188 port = 10 * port + (*p - '0');
1190 /* Garbage following port number. */
1192 *domain_e_ptr = colon;
1196 #define SKIP_WS(p) do { \
1197 while (*p && ISSPACE (*p)) \
1201 #define MARK_WORD(p, b, e) do { \
1205 while (*p && !ISSPACE (*p)) \
1212 /* Load cookies from FILE. */
1215 load_cookies (const char *file)
1218 FILE *fp = fopen (file, "r");
1221 logprintf (LOG_NOTQUIET, "Cannot open cookies file `%s': %s\n",
1222 file, strerror (errno));
1225 cookies_now = time (NULL);
1227 for (; ((line = read_whole_line (fp)) != NULL); xfree (line))
1229 struct cookie *cookie;
1234 char *domain_b = NULL, *domain_e = NULL;
1235 char *ignore_b = NULL, *ignore_e = NULL;
1236 char *path_b = NULL, *path_e = NULL;
1237 char *secure_b = NULL, *secure_e = NULL;
1238 char *expires_b = NULL, *expires_e = NULL;
1239 char *name_b = NULL, *name_e = NULL;
1240 char *value_b = NULL, *value_e = NULL;
1244 if (!*p || *p == '#')
1248 MARK_WORD (p, domain_b, domain_e);
1249 MARK_WORD (p, ignore_b, ignore_e);
1250 MARK_WORD (p, path_b, path_e);
1251 MARK_WORD (p, secure_b, secure_e);
1252 MARK_WORD (p, expires_b, expires_e);
1253 MARK_WORD (p, name_b, name_e);
1255 /* Don't use MARK_WORD for value because it may contain
1256 whitespace itself. Instead, . */
1257 MARK_WORD (p, value_b, value_e);
1259 cookie = cookie_new ();
1261 cookie->attr = strdupdelim (name_b, name_e);
1262 cookie->value = strdupdelim (value_b, value_e);
1263 cookie->path = strdupdelim (path_b, path_e);
1265 if (BOUNDED_EQUAL (secure_b, secure_e, "TRUE"))
1268 /* DOMAIN needs special treatment because we might need to
1269 extract the port. */
1270 port = domain_port (domain_b, domain_e, (const char **)&domain_e);
1272 cookie->port = port;
1274 cookie->port = cookie->secure ? DEFAULT_HTTPS_PORT : DEFAULT_HTTP_PORT;
1276 cookie->domain = strdupdelim (domain_b, domain_e);
1278 /* Don't use MARK_WORD for value because it may contain
1279 whitespace itself. Instead, set name_e to the end of line,
1280 modulo trailing space (which includes the NL separator.) */
1283 name_e = p + strlen (p);
1284 while (name_e >= name_b && ISSPACE (*name_e))
1286 if (name_b == name_e)
1287 /* Hmm, should we check for empty value? I guess that's
1288 legal, so I leave it. */
1291 /* safe default in case EXPIRES field is garbled. */
1292 cookie->expiry_time = cookies_now - 1;
1294 /* I don't like changing the line, but it's completely safe.
1295 (line is malloced.) */
1297 sscanf (expires_b, "%lu", &cookie->expiry_time);
1298 if (cookie->expiry_time < cookies_now)
1299 /* ignore stale cookie. */
1301 cookie->permanent = 1;
1303 store_cookie (cookie);
1309 delete_cookie (cookie);
1314 /* Mapper for save_cookies callable by hash_table_map. VALUE points
1315 to the head in a chain of cookies. The function prints the entire
1319 save_cookies_mapper (void *key, void *value, void *arg)
1321 FILE *fp = (FILE *)arg;
1322 char *domain = (char *)key;
1323 struct cookie *chain = (struct cookie *)value;
1324 for (; chain; chain = chain->next)
1326 if (!chain->permanent)
1328 if (chain->expiry_time < cookies_now)
1330 fprintf (fp, "%s\t%s\t%s\t%s\t%lu\t%s\t%s\n",
1331 domain, *domain == '.' ? "TRUE" : "FALSE",
1332 chain->path, chain->secure ? "TRUE" : "FALSE",
1334 chain->attr, chain->value);
1336 return 1; /* stop mapping */
1341 /* Save cookies, in format described above, to FILE. */
1344 save_cookies (const char *file)
1348 if (!cookies_hash_table
1349 || !hash_table_count (cookies_hash_table))
1350 /* no cookies stored; nothing to do. */
1353 DEBUGP (("Saving cookies to %s.\n", file));
1355 cookies_now = time (NULL);
1357 fp = fopen (file, "w");
1360 logprintf (LOG_NOTQUIET, _("Cannot open cookies file `%s': %s\n"),
1361 file, strerror (errno));
1365 fputs ("# HTTP cookie file.\n", fp);
1366 fprintf (fp, "# Generated by Wget on %s.\n", datetime_str (NULL));
1367 fputs ("# Edit at your own risk.\n\n", fp);
1369 hash_table_map (cookies_hash_table, save_cookies_mapper, fp);
1372 logprintf (LOG_NOTQUIET, _("Error writing to `%s': %s\n"),
1373 file, strerror (errno));
1375 if (fclose (fp) < 0)
1376 logprintf (LOG_NOTQUIET, _("Error closing `%s': %s\n"),
1377 file, strerror (errno));
1379 DEBUGP (("Done saving cookies.\n", file));
1383 delete_cookie_chain_mapper (void *value, void *key, void *arg_ignored)
1385 char *chain_key = (char *)value;
1386 struct cookie *chain = (struct cookie *)key;
1388 /* Remove the chain from the table and free the key. */
1389 hash_table_remove (cookies_hash_table, chain_key);
1392 /* Then delete all the cookies in the chain. */
1395 struct cookie *next = chain->next;
1396 delete_cookie (chain);
1404 /* Clean up cookie-related data. */
1407 cookies_cleanup (void)
1409 if (!cookies_hash_table)
1411 hash_table_map (cookies_hash_table, delete_cookie_chain_mapper, NULL);
1412 hash_table_destroy (cookies_hash_table);
1413 cookies_hash_table = NULL;