httpd-bugs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
Subject DO NOT REPLY [Bug 11475] - usertrack can read Cookie2 header but spec says it doesn't contain cookies
Date Wed, 07 Aug 2002 15:59:23 GMT

usertrack can read Cookie2 header but spec says it doesn't contain cookies

------- Additional Comments From  2002-08-07 15:59 -------
Looking at the spot_cookie() code a bit more, I'm also suspicious that it may
be confused by both RFC 2965-style cookies (which can have quoted-string
values, with escaped characters).

Further, I think it will also be confused just by old-style cookies where
the string "Apache" (or whatever the cookie name it's looking for is) appears
in a cookie name or value somewhere before the actual cookie name/value pair
in the header.  For example, I suspect "Apache2=foo; Apache=bar" or
"foo=Apache; Apache=bar" would both cause the apr_strstr_c() call to find
the first, incorrect, occurance of "Apache".  Or, if the client has two valid
"Apache" cookies for the server, with different paths, it may send them both,
with the more-specific path first ... but since we always set the path=/, our
cookie will be the last one, not the first one.

if ((value = ap_strstr_c(cookie, dcfg->cookie_name))) {
    char *cookiebuf, *cookieend;

    value += strlen(dcfg->cookie_name) + 1;  /* Skip over the '=' */
    cookiebuf = apr_pstrdup(r->pool, value);
    cookieend = strchr(cookiebuf, ';');
    if (cookieend)
        *cookieend = '\0';      /* Ignore anything after a ; */

I don't know if this helps or not, but since I don't have time right now to
implement a complete fix, I will attach a file that parses a Cookie: header
into an APR hash of cookies, where each hash value is an APR array of
"string" structures.  The first structure in an array is the first cookie
we found with the given name (the name is the hash key that points to the
array), which should be the most-specific cookie of that name, assuming the
client is working correctly.  The last structure in an array is the last
cookie -- which is the one mod_usertrack would want, because it would have
to be the path=/ cookie.

The "string" structure contains both the string itself, null-terminated, and
the string length, which is useful for avoiding additional strlen() calls.
The cookie_get() function returns the string of the first cookie, or NULL
if there is more than one cookie with the same name.  This obviously isn't
useful for the mod_usertrack situation, where we want the last cookie in
an array.  For that, you want to do something like (assuming you know
there's at each one element in the array):

/**** DEBUG: watch out for nelts == 0 !! ****/
string = ((struct string*) val_arr->elts) + val_arr->nelts - 1;
str = string->ptr;
str_len = string->str_len;

When parsing the Cookie: header, if a $Version=1 cookie is detected
at the start (or some legal RFC 2965 variation), then the code parses
according to RFCs 2965 and 2616 (mostly); otherwise, it parses according
to the old Netscape specification.

When parsing in RFC 2965-mode, cookie names are flattened to lowercase,
since the spec calls for case-insensitive cookie names.  Quoted strings
are de-quoted and escaped characters in quoted strings are un-escaped
(except for some dubious values that RFC 2616 allows).  Unquoted cookie
values must be RFC 2616 tokens, and all cookie names must be tokens as well.
Both commas and semicolons are legal delimiters.

When parsing in Netscape-mode, cookie names and values are not altered,
except that we ignore internal whitespace and commas, because the spec
doesn't allow those at all.  Only semicolons are legal delimiters.

In general, high-bit-set octets and ASCII control characters are
stripped out, despite what RFC 2616 allows, because -- well, because
applications really shouldn't be using such stuff in an HTTP header,
should they?

The code also imposes its own #defined limits on name and value lengths.
This probably overkill given that the header is normally limited to
about 8 Kb by the DEFAULT_LIMIT_REQUEST_FIELDSIZE #define, but this
code came from another application where we didn't have such external

Plus, it's worth noting that both the Netscape and RFC 2965
specs allow clients to send 20 cookies where each one's name/value
pair is 4 Kb ... but any application that actually relied on that many
large cookies would cause Apache errors for its clients, once they
exceeded the 8 Kb header limit.  Maybe someday Cookie: headers should
be allowed to exceed the DEFAULT_LIMIT_REQUEST_FIELDSIZE?  Or else,
at least a warning about this conflict with the specs should maybe go
in the docs.

The code tries hard to avoid excess strlen()-type calls and multiple
passes over the data.  Although it would be more elegant to allocate
key[] and val[] buffers off the stack for the maximum, dump characters
into them as we find them, and then apr_palloc() just enough space
for the resultant strings, that requires at least two passes over
all the data.

Instead, this code starts by allocating a small buf_size buffer
from apr_palloc(), and then, once it's filled up, allocating double
that amount of space for the next buffer.  The doubling continues
until a reasonable maximum is reached that can always contain the
largest string we need to handle (ideally, several large strings).
This does involve memcpy() calls when we have to reallocate in the
middle of a name or value, and some wasted space, but we should
avoid a full 2* pass over all the data, and not waste too much more
space than we need.  Like I said, it's a bit of overkill just for
the Cookie: header, but I had the code on hand.

The attached code should compile, but it differs slightly from
our actual implementation usage, so I can't guarantee that it's

Perhaps something like this might form part of an APR-util cookie
library?  Or not ...

To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message