[svn] Minor cookie fixes. Published in <sxsheyu9yp6.fsf@florida.arsdigita.de>.

This commit is contained in:
hniksic 2001-05-09 11:15:22 -07:00
parent 105627124e
commit 43ef870bd3
2 changed files with 81 additions and 32 deletions

View File

@ -1,3 +1,13 @@
2001-05-09 Hrvoje Niksic <hniksic@arsdigita.com>
* cookies.c (eliminate_dups): New function.
(build_cookies_request): Use it.
(build_cookies_request): Set chain_store_size after reallocating
all_chains.
(check_domain_match): Annotated for easier future debugging.
(store_cookie): In the debug message, print whether the cookie is
permanent.
2001-05-08 Hrvoje Niksic <hniksic@arsdigita.com> 2001-05-08 Hrvoje Niksic <hniksic@arsdigita.com>
* http.c (http_loop): Reset no_truncate before deciding whether to * http.c (http_loop): Reset no_truncate before deciding whether to

View File

@ -274,8 +274,10 @@ store_cookie (struct cookie *cookie)
hash_table_put (cookies_hash_table, chain_key, cookie); hash_table_put (cookies_hash_table, chain_key, cookie);
DEBUGP (("\nStored cookie %s %d %s %d %s %s %s\n", DEBUGP (("\nStored cookie %s %d %s %s %d %s %s %s\n",
cookie->domain, cookie->port, cookie->path, cookie->secure, cookie->domain, cookie->port, cookie->path,
cookie->permanent ? "permanent" : "nonpermanent",
cookie->secure,
asctime (localtime ((time_t *)&cookie->expiry_time)), asctime (localtime ((time_t *)&cookie->expiry_time)),
cookie->attr, cookie->value)); cookie->attr, cookie->value));
} }
@ -706,6 +708,8 @@ check_domain_match (const char *cookie_domain, const char *host)
int headlen; int headlen;
const char *tail; const char *tail;
DEBUGP (("cdm: 1"));
/* Numeric address requires exact match. It also requires HOST to /* Numeric address requires exact match. It also requires HOST to
be an IP address. I suppose we *could* resolve HOST with be an IP address. I suppose we *could* resolve HOST with
store_hostaddress (it would hit the hash table), but rfc2109 store_hostaddress (it would hit the hash table), but rfc2109
@ -714,6 +718,8 @@ check_domain_match (const char *cookie_domain, const char *host)
if (numeric_address_p (cookie_domain)) if (numeric_address_p (cookie_domain))
return !strcmp (cookie_domain, host); return !strcmp (cookie_domain, host);
DEBUGP ((" 2"));
/* The domain must contain at least one embedded dot. */ /* The domain must contain at least one embedded dot. */
{ {
const char *rest = cookie_domain; const char *rest = cookie_domain;
@ -730,16 +736,22 @@ check_domain_match (const char *cookie_domain, const char *host)
return 0; return 0;
} }
DEBUGP ((" 3"));
/* For the sake of efficiency, check for exact match first. */ /* For the sake of efficiency, check for exact match first. */
if (!strcasecmp (cookie_domain, host)) if (!strcasecmp (cookie_domain, host))
return 1; return 1;
DEBUGP ((" 4"));
/* In rfc2109 terminology, HOST needs domain-match COOKIE_DOMAIN. /* In rfc2109 terminology, HOST needs domain-match COOKIE_DOMAIN.
This means that COOKIE_DOMAIN needs to start with `.' and be an This means that COOKIE_DOMAIN needs to start with `.' and be an
FQDN, and that HOST must end with COOKIE_DOMAIN. */ FQDN, and that HOST must end with COOKIE_DOMAIN. */
if (*cookie_domain != '.') if (*cookie_domain != '.')
return 0; return 0;
DEBUGP ((" 5"));
/* Two proceed, we need to examine two parts of HOST: its head and /* Two proceed, we need to examine two parts of HOST: its head and
its tail. Head and tail are defined in terms of the length of its tail. Head and tail are defined in terms of the length of
the domain, like this: the domain, like this:
@ -762,10 +774,14 @@ check_domain_match (const char *cookie_domain, const char *host)
return 0; return 0;
tail = host + headlen; tail = host + headlen;
DEBUGP ((" 6"));
/* (1) */ /* (1) */
if (strcasecmp (tail, cookie_domain)) if (strcasecmp (tail, cookie_domain))
return 0; return 0;
DEBUGP ((" 7"));
/* Test (2) is not part of the "domain-match" itself, but is /* Test (2) is not part of the "domain-match" itself, but is
recommended by rfc2109 for reasons of privacy. */ recommended by rfc2109 for reasons of privacy. */
@ -773,6 +789,8 @@ check_domain_match (const char *cookie_domain, const char *host)
if (memchr (host, '.', headlen)) if (memchr (host, '.', headlen))
return 0; return 0;
DEBUGP ((" 8"));
return 1; return 1;
} }
@ -978,6 +996,43 @@ equality_comparator (const void *p1, const void *p2)
return namecmp ? namecmp : valuecmp; return namecmp ? namecmp : valuecmp;
} }
/* Eliminate duplicate cookies. "Duplicate cookies" are any two
cookies whose name and value are the same. Whenever a duplicate
pair is found, one of the cookies is removed. */
static int
eliminate_dups (struct weighed_cookie *outgoing, int count)
{
int i;
/* We deploy a simple uniquify algorithm: first sort the array
according to our sort criterion, then uniquify it by comparing
each cookie with its neighbor. */
qsort (outgoing, count, sizeof (struct weighed_cookie), equality_comparator);
for (i = 0; i < count - 1; i++)
{
struct cookie *c1 = outgoing[i].cookie;
struct cookie *c2 = outgoing[i + 1].cookie;
if (!strcmp (c1->attr, c2->attr) && !strcmp (c1->value, c2->value))
{
/* c1 and c2 are the same; get rid of c2. */
if (count > i + 1)
/* move all ptrs from positions [i + 1, count) to i. */
memmove (outgoing + i, outgoing + i + 1,
(count - (i + 1)) * sizeof (struct weighed_cookie));
/* We decrement i to counter the ++i above. Remember that
we've just removed the element in front of us; we need to
remain in place to check whether outgoing[i] matches what
used to be outgoing[i + 2]. */
--i;
--count;
}
}
return count;
}
/* Comparator used for sorting by quality. */ /* Comparator used for sorting by quality. */
static int static int
@ -997,11 +1052,11 @@ goodness_comparator (const void *p1, const void *p2)
return dgdiff ? dgdiff : pgdiff; return dgdiff ? dgdiff : pgdiff;
} }
/* Build a `Cookies' header for a request that goes to HOST:PORT and /* Build a `Cookie' header for a request that goes to HOST:PORT and
requests PATH from the server. Memory is allocated by `malloc', requests PATH from the server. The resulting string is allocated
and the caller is responsible for freeing it. If no cookies with `malloc', and the caller is responsible for freeing it. If no
pertain to this request, i.e. no cookie header should be generated, cookies pertain to this request, i.e. no cookie header should be
NULL is returned. */ generated, NULL is returned. */
char * char *
build_cookies_request (const char *host, int port, const char *path, build_cookies_request (const char *host, int port, const char *path,
@ -1023,9 +1078,11 @@ build_cookies_request (const char *host, int port, const char *path,
if (chain_count > chain_store_size) if (chain_count > chain_store_size)
{ {
/* It's extremely unlikely that more than 20 chains will ever /* It's extremely unlikely that more than 20 chains will ever
match. But in this case it's easy to not have the match. But since find_matching_chains reports the exact size
limitation, so we don't. */ it needs, it's easy to not have the limitation, so we
don't. */
all_chains = alloca (chain_count * sizeof (struct cookie *)); all_chains = alloca (chain_count * sizeof (struct cookie *));
chain_store_size = chain_count;
goto again; goto again;
} }
@ -1047,6 +1104,8 @@ build_cookies_request (const char *host, int port, const char *path,
/* Allocate the array. */ /* Allocate the array. */
outgoing = alloca (count * sizeof (struct weighed_cookie)); outgoing = alloca (count * sizeof (struct weighed_cookie));
/* Fill the array with all the matching cookies from all the
matching chains. */
ocnt = 0; ocnt = 0;
for (i = 0; i < chain_count; i++) for (i = 0; i < chain_count; i++)
for (cookie = all_chains[i]; cookie; cookie = cookie->next) for (cookie = all_chains[i]; cookie; cookie = cookie->next)
@ -1062,28 +1121,8 @@ build_cookies_request (const char *host, int port, const char *path,
assert (ocnt == count); assert (ocnt == count);
/* Eliminate duplicate cookies; that is, those whose name and value /* Eliminate duplicate cookies; that is, those whose name and value
are the same. We do it by first sorting the array, and then are the same. */
uniq'ing it. */ count = eliminate_dups (outgoing, count);
qsort (outgoing, count, sizeof (struct weighed_cookie), equality_comparator);
for (i = 0; i < count - 1; i++)
{
struct cookie *c1 = outgoing[i].cookie;
struct cookie *c2 = outgoing[i + 1].cookie;
if (!strcmp (c1->attr, c2->attr) && !strcmp (c1->value, c2->value))
{
/* c1 and c2 are the same; get rid of c2. */
if (count > i + 1)
/* move all ptrs from positions [i + 1, count) to i. */
memmove (outgoing + i, outgoing + i + 1,
(count - (i + 1)) * sizeof (struct weighed_cookie));
/* We decrement i to counter the ++i above. Remember that
we've just removed the element in front of us; we need to
remain in place to check whether outgoing[i] what used to
be outgoing[i + 2]. */
--i;
--count;
}
}
/* Sort the array so that best-matching domains come first, and /* Sort the array so that best-matching domains come first, and
that, within one domain, best-matching paths come first. */ that, within one domain, best-matching paths come first. */
@ -1192,7 +1231,7 @@ domain_port (const char *domain_b, const char *domain_e,
++p; \ ++p; \
} while (0) } while (0)
#define SET_WORD_BOUNDARIES(p, b, e) do { \ #define SET_WORD_BOUNDARIES(p, b, e) do { \
SKIP_WS (p); \ SKIP_WS (p); \
b = p; \ b = p; \
/* skip non-ws */ \ /* skip non-ws */ \