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 /* Definition of `struct cookie' and the most basic functions. */
53 char *domain; /* domain of the cookie */
54 int port; /* port number */
55 char *path; /* path prefix of the cookie */
56 int secure; /* whether cookie should be
57 transmitted over non-https
59 int permanent; /* whether the cookie should outlive
61 unsigned long expiry_time; /* time when the cookie expires */
62 int discard_requested; /* whether cookie was created to
63 request discarding another
66 char *attr; /* cookie attribute name */
67 char *value; /* cookie attribute value */
69 struct cookie *next; /* used for chaining of cookies in the
73 /* Allocate and return a new, empty cookie structure. */
75 static struct cookie *
78 struct cookie *cookie = xmalloc (sizeof (struct cookie));
79 memset (cookie, '\0', sizeof (struct cookie));
81 /* If we don't know better, assume cookie is non-permanent and valid
82 for the entire session. */
83 cookie->expiry_time = ~0UL;
85 /* Assume default port. */
91 /* Deallocate COOKIE and its components. */
94 delete_cookie (struct cookie *cookie)
96 FREE_MAYBE (cookie->domain);
97 FREE_MAYBE (cookie->path);
98 FREE_MAYBE (cookie->attr);
99 FREE_MAYBE (cookie->value);
103 /* Functions for cookie-specific hash tables. These are regular hash
104 tables, but with case-insensitive test and hash functions. */
106 /* Like string_hash, but produces the same results regardless of the
110 unsigned_string_hash (const void *sv)
113 unsigned const char *x = (unsigned const char *) sv;
118 unsigned char c = TOLOWER (*x);
120 if ((g = h & 0xf0000000) != 0)
121 h = (h ^ (g >> 24)) ^ g;
128 /* Front-end to strcasecmp. */
131 unsigned_string_cmp (const void *s1, const void *s2)
133 return !strcasecmp ((const char *)s1, (const char *)s2);
136 /* Like make_string_hash_table, but uses unsigned_string_hash and
137 unsigned_string_cmp. */
139 static struct hash_table *
140 make_unsigned_string_hash_table (int initial_size)
142 return hash_table_new (initial_size,
143 unsigned_string_hash, unsigned_string_cmp);
146 /* Write "HOST:PORT" to RESULT. RESULT should be a pointer, and the
147 memory for the contents is allocated on the stack. Useful for
148 creating HOST:PORT strings, which are the keys in the hash
151 #define SET_HOSTPORT(host, port, result) do { \
152 int HP_len = strlen (host); \
153 result = alloca (HP_len + 1 + numdigit (port) + 1); \
154 memcpy (result, host, HP_len); \
155 result[HP_len] = ':'; \
156 long_to_string (result + HP_len + 1, port); \
159 /* Find cookie chain that corresponds to DOMAIN (exact) and PORT. */
161 static struct cookie *
162 find_cookie_chain_exact (const char *domain, int port)
165 if (!cookies_hash_table)
167 SET_HOSTPORT (domain, port, key);
168 return hash_table_get (cookies_hash_table, key);
171 /* Functions for storing cookies.
173 All cookies can be referenced through cookies_hash_table. The key
174 in that table is the domain name, and the value is a linked list of
175 all cookies from that domain. Every new cookie is placed on the
178 /* Find and return the cookie whose domain, path, and attribute name
179 correspond to COOKIE. If found, PREVPTR will point to the location
180 of the cookie previous in chain, or NULL if the found cookie is the
183 If no matching cookie is found, return NULL. */
185 static struct cookie *
186 find_matching_cookie (struct cookie *cookie, struct cookie **prevptr)
188 struct cookie *chain, *prev;
190 if (!cookies_hash_table)
193 chain = find_cookie_chain_exact (cookie->domain, cookie->port);
198 for (; chain; prev = chain, chain = chain->next)
199 if (!strcmp (cookie->path, chain->path)
200 && !strcmp (cookie->attr, chain->attr))
211 /* Store COOKIE to memory.
213 This is done by placing COOKIE at the head of its chain. However,
214 if COOKIE matches a cookie already in memory, as determined by
215 find_matching_cookie, the old cookie is unlinked and destroyed.
217 The key of each chain's hash table entry is allocated only the
218 first time; next hash_table_put's reuse the same key. */
221 store_cookie (struct cookie *cookie)
223 struct cookie *chain_head;
227 if (!cookies_hash_table)
228 /* If the hash table is not initialized, do so now, because we'll
229 need to store things. */
230 cookies_hash_table = make_unsigned_string_hash_table (0);
232 /* Initialize hash table key. */
233 SET_HOSTPORT (cookie->domain, cookie->port, hostport);
235 if (hash_table_get_pair (cookies_hash_table, hostport,
236 &chain_key, &chain_head))
238 /* There already exists a chain of cookies with this exact
239 domain. We need to check for duplicates -- if an existing
240 cookie exactly matches our domain, path and name, we replace
243 struct cookie *victim = find_matching_cookie (cookie, &prev);
247 /* Remove VICTIM from the chain. COOKIE will be placed at
251 prev->next = victim->next;
252 cookie->next = chain_head;
256 /* prev is NULL; apparently VICTIM was at the head of
257 the chain. This place will be taken by COOKIE, so
258 all we need to do is: */
259 cookie->next = victim->next;
261 delete_cookie (victim);
262 DEBUGP (("Deleted old cookie (to be replaced.)\n"));
265 cookie->next = chain_head;
269 /* We are now creating the chain. Allocate the string that will
270 be used as a key. It is unsafe to use cookie->domain for
271 that, because it might get deallocated by the above code at
274 chain_key = xstrdup (hostport);
277 hash_table_put (cookies_hash_table, chain_key, cookie);
279 DEBUGP (("\nStored cookie %s %d %s %d %s %s %s\n",
280 cookie->domain, cookie->port, cookie->path, cookie->secure,
281 asctime (localtime ((time_t *)&cookie->expiry_time)),
282 cookie->attr, cookie->value));
285 /* Discard a cookie matching COOKIE's domain, path, and attribute
286 name. This gets called when we encounter a cookie whose expiry
287 date is in the past, or whose max-age is set to 0. The former
288 corresponds to netscape cookie spec, while the latter is specified
292 discard_matching_cookie (struct cookie *cookie)
294 struct cookie *prev, *victim;
296 if (!cookies_hash_table
297 || !hash_table_count (cookies_hash_table))
298 /* No elements == nothing to discard. */
301 victim = find_matching_cookie (cookie, &prev);
305 /* Simply unchain the victim. */
306 prev->next = victim->next;
309 /* VICTIM was head of its chain. We need to place a new
310 cookie at the head. */
313 char *chain_key = NULL;
316 SET_HOSTPORT (victim->domain, victim->port, hostport);
317 res = hash_table_get_pair (cookies_hash_table, hostport,
322 /* VICTIM was the only cookie in the chain. Destroy the
323 chain and deallocate the chain key. */
325 hash_table_remove (cookies_hash_table, hostport);
329 hash_table_put (cookies_hash_table, chain_key, victim->next);
331 delete_cookie (victim);
332 DEBUGP (("Discarded old cookie.\n"));
336 /* Functions for parsing the `Set-Cookie' header, and creating new
337 cookies from the wire. */
340 #define NAME_IS(string_literal) \
341 BOUNDED_EQUAL_NO_CASE (name_b, name_e, string_literal)
343 #define VALUE_EXISTS (value_b && value_e)
345 #define VALUE_NON_EMPTY (VALUE_EXISTS && (value_b != value_e))
347 /* Update the appropriate cookie field. [name_b, name_e) are expected
348 to delimit the attribute name, while [value_b, value_e) (optional)
349 should delimit the attribute value.
351 When called the first time, it will set the cookie's attribute name
352 and value. After that, it will check the attribute name for
353 special fields such as `domain', `path', etc. Where appropriate,
354 it will parse the values of the fields it recognizes and fill the
355 corresponding fields in COOKIE.
357 Returns 1 on success. Returns zero in case a syntax error is
358 found; such a cookie should be discarded. */
361 update_cookie_field (struct cookie *cookie,
362 const char *name_b, const char *name_e,
363 const char *value_b, const char *value_e)
365 assert (name_b != NULL && name_e != NULL);
371 cookie->attr = strdupdelim (name_b, name_e);
372 cookie->value = strdupdelim (value_b, value_e);
376 if (NAME_IS ("domain"))
378 if (!VALUE_NON_EMPTY)
380 FREE_MAYBE (cookie->domain);
381 cookie->domain = strdupdelim (value_b, value_e);
384 else if (NAME_IS ("path"))
386 if (!VALUE_NON_EMPTY)
388 FREE_MAYBE (cookie->path);
389 cookie->path = strdupdelim (value_b, value_e);
392 else if (NAME_IS ("expires"))
397 if (!VALUE_NON_EMPTY)
399 BOUNDED_TO_ALLOCA (value_b, value_e, value_copy);
401 expires = http_atotm (value_copy);
404 cookie->permanent = 1;
405 cookie->expiry_time = (unsigned long)expires;
408 /* Error in expiration spec. Assume default (cookie valid for
409 this session.) #### Should we return 0 and invalidate the
413 /* According to netscape's specification, expiry time in the
414 past means that discarding of a matching cookie is
416 if (cookie->expiry_time < cookies_now)
417 cookie->discard_requested = 1;
421 else if (NAME_IS ("max-age"))
426 if (!VALUE_NON_EMPTY)
428 BOUNDED_TO_ALLOCA (value_b, value_e, value_copy);
430 sscanf (value_copy, "%lf", &maxage);
432 /* something is wrong. */
434 cookie->permanent = 1;
435 cookie->expiry_time = (unsigned long)cookies_now + (unsigned long)maxage;
437 /* According to rfc2109, a cookie with max-age of 0 means that
438 discarding of a matching cookie is requested. */
440 cookie->discard_requested = 1;
444 else if (NAME_IS ("secure"))
446 /* ignore value completely */
451 /* Unrecognized attribute; ignore it. */
457 /* Returns non-zero for characters that are legal in the name of an
460 #define ATTR_NAME_CHAR(c) (ISALNUM (c) || (c) == '-' || (c) == '_')
462 /* Fetch the next character without doing anything special if CH gets
463 set to 0. (The code executed next is expected to handle it.) */
465 #define FETCH1(ch, ptr) do { \
469 /* Like FETCH1, but jumps to `eof' label if CH gets set to 0. */
471 #define FETCH(ch, ptr) do { \
477 /* Parse the contents of the `Set-Cookie' header. The header looks
480 name1=value1; name2=value2; ...
482 Trailing semicolon is optional; spaces are allowed between all
483 tokens. Additionally, values may be quoted.
485 A new cookie is returned upon success, NULL otherwise. The
486 function `update_cookie_field' is used to update the fields of the
487 newly created cookie structure. */
489 static struct cookie *
490 parse_set_cookies (const char *sc)
492 struct cookie *cookie = cookie_new ();
494 enum { S_NAME_PRE, S_NAME, S_NAME_POST,
495 S_VALUE_PRE, S_VALUE, S_VALUE_TRAILSPACE_MAYBE,
496 S_QUOTED_VALUE, S_QUOTED_VALUE_POST,
498 S_DONE, S_ERROR } state = S_NAME_PRE;
503 const char *name_b = NULL, *name_e = NULL;
504 const char *value_b = NULL, *value_e = NULL;
508 while (state != S_DONE && state != S_ERROR)
515 else if (ATTR_NAME_CHAR (c))
522 /* empty attr name not allowed */
526 if (ATTR_NAME_CHAR (c))
528 else if (!c || c == ';' || c == '=' || ISSPACE (c))
539 else if (!c || c == ';')
541 value_b = value_e = NULL;
542 state = S_ATTR_ACTION;
559 state = S_QUOTED_VALUE;
561 else if (c == ';' || c == '\0')
563 value_b = value_e = p - 1;
564 state = S_ATTR_ACTION;
574 if (c == ';' || c == '\0')
578 state = S_ATTR_ACTION;
580 else if (ISSPACE (c))
584 state = S_VALUE_TRAILSPACE_MAYBE;
588 value_e = NULL; /* no trailing space */
592 case S_VALUE_TRAILSPACE_MAYBE:
603 state = S_QUOTED_VALUE_POST;
608 case S_QUOTED_VALUE_POST:
610 state = S_ATTR_ACTION;
611 else if (ISSPACE (c))
618 int legal = update_cookie_field (cookie, name_b, name_e,
623 BOUNDED_TO_ALLOCA (name_b, name_e, name);
624 logprintf (LOG_NOTQUIET,
625 _("Error in Set-Cookie, field `%s'"), name);
640 /* handled by loop condition */
647 delete_cookie (cookie);
648 if (state == S_ERROR)
649 logprintf (LOG_NOTQUIET, _("Error in Set-Cookie, at character `%c'.\n"), c);
655 delete_cookie (cookie);
656 logprintf (LOG_NOTQUIET,
657 _("Error in Set-Cookie: premature end of string.\n"));
661 /* Sanity checks. These are important, otherwise it is possible for
662 mailcious attackers to destroy important cookie information and/or
663 violate your privacy. */
666 #define REQUIRE_DIGITS(p) do { \
669 for (++p; ISDIGIT (*p); p++) \
673 #define REQUIRE_DOT(p) do { \
678 /* Check whether ADDR matches <digits>.<digits>.<digits>.<digits>.
680 We don't want to call network functions like inet_addr() because all
681 we need is a check, preferrably one that is small, fast, and
685 numeric_address_p (const char *addr)
687 const char *p = addr;
689 REQUIRE_DIGITS (p); /* A */
690 REQUIRE_DOT (p); /* . */
691 REQUIRE_DIGITS (p); /* B */
692 REQUIRE_DOT (p); /* . */
693 REQUIRE_DIGITS (p); /* C */
694 REQUIRE_DOT (p); /* . */
695 REQUIRE_DIGITS (p); /* D */
702 /* Check whether COOKIE_DOMAIN is an appropriate domain for HOST.
703 This check is compliant with rfc2109. */
706 check_domain_match (const char *cookie_domain, const char *host)
711 /* Numeric address requires exact match. It also requires HOST to
712 be an IP address. I suppose we *could* resolve HOST with
713 store_hostaddress (it would hit the hash table), but rfc2109
714 doesn't require it, and it doesn't seem very useful, so we
716 if (numeric_address_p (cookie_domain))
717 return !strcmp (cookie_domain, host);
719 /* The domain must contain at least one embedded dot. */
721 const char *rest = cookie_domain;
722 int len = strlen (rest);
724 ++rest, --len; /* ignore first dot */
727 if (rest[len - 1] == '.')
728 --len; /* ignore last dot */
730 if (!memchr (rest, '.', len))
735 /* For the sake of efficiency, check for exact match first. */
736 if (!strcasecmp (cookie_domain, host))
739 /* In rfc2109 terminology, HOST needs domain-match COOKIE_DOMAIN.
740 This means that COOKIE_DOMAIN needs to start with `.' and be an
741 FQDN, and that HOST must end with COOKIE_DOMAIN. */
742 if (*cookie_domain != '.')
745 /* Two proceed, we need to examine two parts of HOST: its head and
746 its tail. Head and tail are defined in terms of the length of
747 the domain, like this:
749 HHHHTTTTTTTTTTTTTTT <- host
750 DDDDDDDDDDDDDDD <- domain
752 That is, "head" is the part of the host before (dlen - hlen), and
753 "tail" is what follows.
755 For the domain to match, two conditions need to be true:
757 1. Tail must equal DOMAIN.
758 2. Head must not contain an embedded dot. */
760 headlen = strlen (host) - strlen (cookie_domain);
763 /* DOMAIN must be a proper subset of HOST. */
765 tail = host + headlen;
768 if (strcasecmp (tail, cookie_domain))
771 /* Test (2) is not part of the "domain-match" itself, but is
772 recommended by rfc2109 for reasons of privacy. */
775 if (memchr (host, '.', headlen))
781 static int path_matches PARAMS ((const char *, const char *));
783 /* Check whether PATH begins with COOKIE_PATH. */
786 check_path_match (const char *cookie_path, const char *path)
788 return path_matches (path, cookie_path);
791 /* Parse the `Set-Cookie' header and, if the cookie is legal, store it
795 set_cookie_header_cb (const char *hdr, void *closure)
797 struct urlinfo *u = (struct urlinfo *)closure;
798 struct cookie *cookie;
800 cookies_now = time (NULL);
802 cookie = parse_set_cookies (hdr);
806 /* Sanitize parts of cookie. */
809 cookie->domain = xstrdup (u->host);
812 if (!check_domain_match (cookie->domain, u->host))
814 DEBUGP (("Attempt to fake the domain: %s, %s\n",
815 cookie->domain, u->host));
820 cookie->path = xstrdup (u->path);
823 if (!check_path_match (cookie->path, u->path))
825 DEBUGP (("Attempt to fake the path: %s, %s\n",
826 cookie->path, u->path));
831 cookie->port = u->port;
833 if (cookie->discard_requested)
835 discard_matching_cookie (cookie);
836 delete_cookie (cookie);
840 store_cookie (cookie);
845 delete_cookie (cookie);
849 /* Support for sending out cookies in HTTP requests, based on
850 previously stored cookies. Entry point is
851 `build_cookies_request'. */
854 /* Count how many times CHR occurs in STRING. */
857 count_char (const char *string, char chr)
861 for (p = string; *p; p++)
867 /* Return the head of the cookie chain that matches HOST. */
869 static struct cookie *
870 find_cookie_chain (const char *host, int port)
874 struct cookie *chain = NULL;
876 if (!cookies_hash_table)
879 SET_HOSTPORT (host, port, hash_key);
882 chain = hash_table_get (cookies_hash_table, hash_key);
886 dot_count = count_char (host, '.');
888 /* Match less and less specific domains. For instance, given
889 fly.srk.fer.hr, we match .srk.fer.hr, then .fer.hr. */
890 while (dot_count-- > 1)
892 /* Note: we operate directly on hash_key (in form host:port)
893 because we don't want to allocate new hash keys in a
895 char *p = strchr (hash_key, '.');
897 chain = hash_table_get (cookies_hash_table, p);
905 /* If FULL_PATH begins with PREFIX, return the length of PREFIX, zero
909 path_matches (const char *full_path, const char *prefix)
911 int len = strlen (prefix);
912 if (strncmp (full_path, prefix, len))
913 /* FULL_PATH doesn't begin with PREFIX. */
916 /* Length of PREFIX determines the quality of the match. */
920 struct weighed_cookie {
921 struct cookie *cookie;
926 goodness_comparator (const void *p1, const void *p2)
928 struct weighed_cookie *wc1 = (struct weighed_cookie *)p1;
929 struct weighed_cookie *wc2 = (struct weighed_cookie *)p2;
930 /* It's goodness2-goodness1 because we want a sort in *decreasing*
931 order of goodness. */
932 return wc2->path_goodness - wc1->path_goodness;
935 /* Build a `Cookies' header for a request that goes to HOST:PORT and
936 requests PATH from the server. Memory is allocated by `malloc',
937 and the caller is responsible for freeing it. If no cookies
938 pertain to this request, i.e. no cookie header should be generated,
942 build_cookies_request (const char *host, int port, const char *path,
943 int connection_secure_p)
945 struct cookie *chain = find_cookie_chain (host, port);
946 struct cookie *cookie;
947 struct weighed_cookie *outgoing;
950 int result_size, pos;
955 cookies_now = time (NULL);
957 /* Count the number of cookies whose path matches. */
960 for (cookie = chain; cookie; cookie = cookie->next)
962 if (cookie->expiry_time < cookies_now)
963 /* Ignore stale cookies. There is no need to unchain the
964 cookie at this point -- Wget is a relatively short-lived
965 application, and stale cookies will not be saved by
968 if (cookie->secure && !connection_secure_p)
969 /* Don't transmit secure cookies over an insecure
972 if (path_matches (path, cookie->path))
976 result_size += strlen (cookie->attr) + 1 + strlen (cookie->value);
982 /* Allocate the array. */
983 outgoing = alloca (count * sizeof (struct weighed_cookie));
985 for (cookie = chain; cookie; cookie = cookie->next)
988 /* #### These two if's are repeated verbatim from the loop
989 above. Should I put them in a separate function? */
990 if (cookie->expiry_time < cookies_now)
992 if (cookie->secure && !connection_secure_p)
993 /* Don't transmit secure cookies over an insecure
996 goodness = path_matches (path, cookie->path);
999 outgoing[i].cookie = cookie;
1000 outgoing[i].path_goodness = goodness;
1003 assert (i == count);
1005 /* Sort the array so that paths that match our path better come
1007 qsort (outgoing, count, sizeof (struct weighed_cookie), goodness_comparator);
1009 /* Allocate output buffer:
1011 name=value pairs -- result_size
1012 "; " separators -- (count - 1) * 2
1013 \r\n line ending -- 2
1014 \0 terminator -- 1 */
1015 result_size = 8 + result_size + (count - 1) * 2 + 2 + 1;
1016 result = xmalloc (result_size);
1018 strcpy (result, "Cookie: ");
1020 for (i = 0; i < count; i++)
1022 struct cookie *c = outgoing[i].cookie;
1023 int namlen = strlen (c->attr);
1024 int vallen = strlen (c->value);
1026 memcpy (result + pos, c->attr, namlen);
1028 result[pos++] = '=';
1029 memcpy (result + pos, c->value, vallen);
1033 result[pos++] = ';';
1034 result[pos++] = ' ';
1037 result[pos++] = '\r';
1038 result[pos++] = '\n';
1039 result[pos++] = '\0';
1040 assert (pos == result_size);
1044 /* Support for loading and saving cookies. The format used for
1045 loading and saving roughly matches the format of `cookies.txt' file
1046 used by Netscape and Mozilla, at least the Unix versions. The
1047 format goes like this:
1049 DOMAIN DOMAIN-FLAG PATH SECURE-FLAG TIMESTAMP ATTR-NAME ATTR-VALUE
1051 DOMAIN -- cookie domain, optionally followed by :PORT
1052 DOMAIN-FLAG -- whether all hosts in the domain match
1054 SECURE-FLAG -- whether cookie requires secure connection
1055 TIMESTAMP -- expiry timestamp, number of seconds since epoch
1056 ATTR-NAME -- name of the cookie attribute
1057 ATTR-VALUE -- value of the cookie attribute (empty if absent)
1059 The fields are separated by TABs (but Wget's loader recognizes any
1060 whitespace). All fields are mandatory, except for ATTR-VALUE. The
1061 `-FLAG' fields are boolean, their legal values being "TRUE" and
1062 "FALSE'. Empty lines, lines consisting of whitespace only, and
1063 comment lines (beginning with # optionally preceded by whitespace)
1066 Example line from cookies.txt (split in two lines for readability):
1068 .google.com TRUE / FALSE 2147368447 \
1069 PREF ID=34bb47565bbcd47b:LD=en:NR=20:TM=985172580:LM=985739012
1071 DOMAIN-FLAG is currently not honored by Wget. The cookies whose
1072 domain begins with `.' are treated as if DOMAIN-FLAG were true,
1073 while all other cookies are treated as if it were FALSE. */
1076 /* If the region [B, E) ends with :<digits>, parse the number, return
1077 it, and store new boundary (location of the `:') to DOMAIN_E_PTR.
1078 If port is not specified, return 0. */
1081 domain_port (const char *domain_b, const char *domain_e,
1082 const char **domain_e_ptr)
1086 const char *colon = memchr (domain_b, ':', domain_e - domain_b);
1089 for (p = colon + 1; p < domain_e && ISDIGIT (*p); p++)
1090 port = 10 * port + (*p - '0');
1092 /* Garbage following port number. */
1094 *domain_e_ptr = colon;
1098 #define SKIP_WS(p) do { \
1099 while (*p && ISSPACE (*p)) \
1103 #define MARK_WORD(p, b, e) do { \
1107 while (*p && !ISSPACE (*p)) \
1114 /* Load cookies from FILE. */
1117 load_cookies (const char *file)
1120 FILE *fp = fopen (file, "r");
1123 logprintf (LOG_NOTQUIET, "Cannot open cookies file `%s': %s\n",
1124 file, strerror (errno));
1127 cookies_now = time (NULL);
1129 for (; ((line = read_whole_line (fp)) != NULL); xfree (line))
1131 struct cookie *cookie;
1136 char *domain_b = NULL, *domain_e = NULL;
1137 char *ignore_b = NULL, *ignore_e = NULL;
1138 char *path_b = NULL, *path_e = NULL;
1139 char *secure_b = NULL, *secure_e = NULL;
1140 char *expires_b = NULL, *expires_e = NULL;
1141 char *name_b = NULL, *name_e = NULL;
1142 char *value_b = NULL, *value_e = NULL;
1146 if (!*p || *p == '#')
1150 MARK_WORD (p, domain_b, domain_e);
1151 MARK_WORD (p, ignore_b, ignore_e);
1152 MARK_WORD (p, path_b, path_e);
1153 MARK_WORD (p, secure_b, secure_e);
1154 MARK_WORD (p, expires_b, expires_e);
1155 MARK_WORD (p, name_b, name_e);
1157 /* Don't use MARK_WORD for value because it may contain
1158 whitespace itself. Instead, . */
1159 MARK_WORD (p, value_b, value_e);
1161 cookie = cookie_new ();
1163 cookie->attr = strdupdelim (name_b, name_e);
1164 cookie->value = strdupdelim (value_b, value_e);
1165 cookie->path = strdupdelim (path_b, path_e);
1167 if (BOUNDED_EQUAL (secure_b, secure_e, "TRUE"))
1170 /* DOMAIN needs special treatment because we might need to
1171 extract the port. */
1172 port = domain_port (domain_b, domain_e, (const char **)&domain_e);
1174 cookie->port = port;
1176 cookie->port = cookie->secure ? DEFAULT_HTTPS_PORT : DEFAULT_HTTP_PORT;
1178 cookie->domain = strdupdelim (domain_b, domain_e);
1180 /* Don't use MARK_WORD for value because it may contain
1181 whitespace itself. Instead, set name_e to the end of line,
1182 modulo trailing space (which includes the NL separator.) */
1185 name_e = p + strlen (p);
1186 while (name_e >= name_b && ISSPACE (*name_e))
1188 if (name_b == name_e)
1189 /* Hmm, should we check for empty value? I guess that's
1190 legal, so I leave it. */
1193 /* safe default in case EXPIRES field is garbled. */
1194 cookie->expiry_time = cookies_now - 1;
1196 /* I don't like changing the line, but it's completely safe.
1197 (line is malloced.) */
1199 sscanf (expires_b, "%lu", &cookie->expiry_time);
1200 if (cookie->expiry_time < cookies_now)
1201 /* ignore stale cookie. */
1203 cookie->permanent = 1;
1205 store_cookie (cookie);
1211 delete_cookie (cookie);
1216 /* Mapper for save_cookies callable by hash_table_map. VALUE points
1217 to the head in a chain of cookies. The function prints the entire
1221 save_cookies_mapper (void *key, void *value, void *arg)
1223 FILE *fp = (FILE *)arg;
1224 char *domain = (char *)key;
1225 struct cookie *chain = (struct cookie *)value;
1226 for (; chain; chain = chain->next)
1228 if (!chain->permanent)
1230 if (chain->expiry_time < cookies_now)
1232 fprintf (fp, "%s\t%s\t%s\t%s\t%lu\t%s\t%s\n",
1233 domain, *domain == '.' ? "TRUE" : "FALSE",
1234 chain->path, chain->secure ? "TRUE" : "FALSE",
1236 chain->attr, chain->value);
1238 return 1; /* stop mapping */
1243 /* Save cookies, in format described above, to FILE. */
1246 save_cookies (const char *file)
1250 if (!cookies_hash_table
1251 || !hash_table_count (cookies_hash_table))
1252 /* no cookies stored; nothing to do. */
1255 cookies_now = time (NULL);
1257 fp = fopen (file, "w");
1260 logprintf (LOG_NOTQUIET, _("Cannot open cookies file `%s': %s\n"),
1261 file, strerror (errno));
1265 fputs ("# HTTP cookie file.\n", fp);
1266 fprintf (fp, "# Generated by Wget on %s.\n", datetime_str (NULL));
1267 fputs ("# Edit at your own risk.\n\n", fp);
1269 hash_table_map (cookies_hash_table, save_cookies_mapper, fp);
1272 logprintf (LOG_NOTQUIET, _("Error writing to `%s': %s\n"),
1273 file, strerror (errno));
1275 if (fclose (fp) < 0)
1276 logprintf (LOG_NOTQUIET, _("Error closing `%s': %s\n"),
1277 file, strerror (errno));
1281 delete_cookie_chain_mapper (void *value, void *key, void *arg_ignored)
1283 char *chain_key = (char *)value;
1284 struct cookie *chain = (struct cookie *)key;
1286 /* Remove the chain from the table and free the key. */
1287 hash_table_remove (cookies_hash_table, chain_key);
1290 /* Then delete all the cookies in the chain. */
1293 struct cookie *next = chain->next;
1294 delete_cookie (chain);
1302 /* Clean up cookie-related data. */
1305 cookies_cleanup (void)
1307 if (!cookies_hash_table)
1309 hash_table_map (cookies_hash_table, delete_cookie_chain_mapper, NULL);
1310 hash_table_destroy (cookies_hash_table);
1311 cookies_hash_table = NULL;