ASF Bugzilla – Attachment 2624 Details for
Bug 11475
usertrack can read Cookie2 header but spec says it doesn't contain cookies
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
Netscape and RFC 2695 compliant cookie parser
cookie.c (text/plain), 9.98 KB, created by
Chris Darroch
on 2002-08-07 16:01:06 UTC
(
hide
)
Description:
Netscape and RFC 2695 compliant cookie parser
Filename:
MIME Type:
Creator:
Chris Darroch
Created:
2002-08-07 16:01:06 UTC
Size:
9.98 KB
patch
obsolete
>/* Author: Chris Darroch <chrisd@pearsoncmg.com> > * Date: August 7, 2002 > */ > >#include "httpd.h" /* request_rec, etc. */ >#include "http_log.h" /* ap_log_rerror(), etc. */ > >#include "apr_hash.h" /* apr_hash_t, etc. */ >#include "apr_pools.h" /* apr_pool_t, etc. */ > >#define APR_WANT_MEMFUNC /* memcpy(), etc. */ >#define APR_WANT_STRFUNC /* strncmp(), etc. */ >#include "apr_want.h" > > >/* COOKIE_MAX_KEY_LEN and COOKIE_MAX_VAL_LEN should be divisible by 8. > * > * COOKIE_MAX_ALLOC_SIZE should contain at a minimum enough space for > * COOKIE_MAX_VAL_LEN + 1 trailing null. > * > * The Cookie header string is limited by DEFAULT_LIMIT_REQUEST_FIELDSIZE to > * 8190+2 and may be further restricted by the run-time LimitRequestFieldSize > * directive. > */ > >#define COOKIE_MAX_NUM_KEYS 64 >#define COOKIE_MAX_KEY_LEN 64 >#define COOKIE_MAX_VAL_LEN 4096 >#define COOKIE_MIN_ALLOC_SIZE \ > ((COOKIE_MAX_KEY_LEN + COOKIE_MAX_VAL_LEN) / 8 + 1) >#define COOKIE_MAX_ALLOC_SIZE (COOKIE_MIN_ALLOC_SIZE * 16) > > >struct string >{ > const char *ptr; > int len; >}; > > >/* private globals */ > >/* This bitmap contains 1 for disallowed character values. > * Character values 0-7 map to the first bitmap byte. > * Character value 0 maps to the lowest-order bit of the first bitmap byte, and > * character value 7 maps to the highest-order bit of the first bitmap byte. > */ > >static const unsigned char cookie_invalid_token[16] = >{ > 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x93, 0x00, 0xFC, > 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xA8 >}; > > >static apr_status_t cookie_parse_header(apr_pool_t *p, const char *header, > apr_hash_t *cookies); > > >/* Used to return a single cookie value. */ > >const char *cookie_get(apr_hash_t *cookies, > const char *key, const int key_len, > int *val_len_ptr) >{ > apr_array_header_t *val_arr; > > > if((val_arr = (apr_array_header_t*) apr_hash_get(cookies, > (const void*) key, (apr_ssize_t) key_len)) == NULL) > { > return NULL; > } > > if(val_arr->nelts > 1) > return NULL; > > if(val_len_ptr != NULL) > *val_len_ptr = ((struct string*) val_arr->elts)->len; > > return ((struct string*) val_arr->elts)->ptr; >} > >/* Used to parse cookie headers and values. */ > >apr_status_t cookie_parse(request_rec *r, apr_hash_t **cookies_ptr) >{ > apr_hash_t *cookies; > const char *header; > apr_status_t status; > > > *cookies_ptr = cookies = apr_hash_make(r->pool); > > /* Contrary to mod_usertrack's implication, only the Cookie > * header contains cookie attribute/value pairs, not the Cookie2 header. > */ > > if((header = apr_table_get(r->headers_in, "Cookie")) == NULL) > return APR_SUCCESS; > > if(status = cookie_parse_header(r->pool, header, cookies)) > { > ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, > "unable to parse cookie header"); > > return status; > } > > return APR_SUCCESS; >} > >static apr_status_t cookie_parse_header(apr_pool_t *p, const char *header, > apr_hash_t *cookies) >{ > char *buf, *attr, *key, *val; > apr_size_t buf_size = COOKIE_MIN_ALLOC_SIZE; > int buf_len = 0, key_len = 0, val_len; > int is_key = 1, quote_flag = 0, read_flag = 1; > int key_num = 0; > int version = 0; > const char *s = header; > register unsigned char c; > > > if((key = buf = (char*) apr_palloc(p, COOKIE_MIN_ALLOC_SIZE)) == NULL) > return APR_ENOMEM; > > > /* We look for an initial $Version cookie, and, if its value is > * "1" or greater, we treat the header according to RFCs 2965 and 2616: > * cookie names must be tokens, cookie values may be quoted, > * quoted cookie values may contain escaped characters, and commas > * are allowed as delimiters. > * > * We ignore cookies with names that begin with a dollar sign > * when parsing a header according to RFC 2965. > * > * For simplicity, we allow lonely CR and LF characters in whitespace, > * which isn't exactly what RFC 2616 specifies. We also simply ignore > * whitespace in cookie names, and don't allow escaped nulls or > * non-ASCII characters or non-whitespace control characters > * in quoted value strings. > * > * When parsing a header according to the original Netscape specification, > * we support only semicolons as delimiters, and restrict cookie names > * and values to ASCII characters, excluding control characters, > * whitespace, commas, and semicolons. We also do not allow equals signs > * in cookie names. This is somewhat more strict than actually specified, > * but the specificiation is inexact, and we want to be careful. > */ > > while(c = (unsigned char) *s++) > { > if(c == 9 || c == 10 || c == 13 || c == ' ') > continue; > > if(is_key) > { > if(read_flag) > { > if(c == '$' && strncasecmp(s, "Version", 7) != 0) > break; > > s += 7; > read_flag = 0; > } > else > { > if(c != '=') > break; > > is_key = 0; > read_flag = 1; > } > } > else > { > if(read_flag) > { > if(c != '1') > { > if(c != '"') > break; > > if(strncmp(s, "1\"", 2) == 0) > s += 2; > else if(strncmp(s, "\\1\"", 3) == 0) > s += 3; > else > break; > } > > read_flag = 0; > } > else > { > if(c == ',' || c == ';') > { > version = 1; > > header = s; > } > > break; > } > } > } > > > is_key = 1; > read_flag = 0; > > s = header; > > while(c = (unsigned char) *s++) > { > /* until we decide what character set to use to interpret these */ > > if(c & 0x80) > continue; > > if((version == 0 && c == ';') || > (version > 0 && quote_flag != 2 && (c == ',' || c == ';'))) > { > if(key_len > 0) > { > apr_array_header_t *val_arr; > struct string *string; > > > if(is_key) > { > val = buf; > val_len = 0; > } > > *buf++ = 0; > > if(++buf_len >= buf_size) > { > if(buf_size < COOKIE_MAX_ALLOC_SIZE) > buf_size *= 2; > if((buf = (char*) apr_palloc(p, buf_size)) == NULL) > return APR_ENOMEM; > buf_len = 0; > } > > val_arr = (apr_array_header_t*) apr_hash_get(cookies, > (const void*) key, (apr_ssize_t) key_len); > > if(val_arr == NULL) > { > val_arr = apr_array_make(p, 1, sizeof(struct string)); > apr_hash_set(cookies, > (const void*) key, (apr_ssize_t) key_len, > (const void*) val_arr); > } > > string = (struct string*) apr_array_push(val_arr); > string->ptr = val; > string->len = val_len; > > key = buf; > key_len = 0; > is_key = 1; > > if(++key_num == COOKIE_MAX_NUM_KEYS) > break; > } > > if(version > 0) > { > quote_flag = 0; > read_flag = 0; > } > > continue; > } > > if(c == '=' && is_key) > { > if(key_len > 0) > { > val = buf; > val_len = 0; > is_key = 0; > } > > continue; > } > > if(quote_flag == 2) > { > if(c == '"') > { > ++quote_flag; > > continue; > } > else if(c == '\\') > { > /* Despite RFC 2616, we disallow escaped nulls. */ > > if(*s) > c = (unsigned char) *s++; > } > } > > if((is_key && key_len >= COOKIE_MAX_KEY_LEN) || > (!is_key && val_len >= COOKIE_MAX_VAL_LEN)) > { > continue; > } > > > if(is_key) > { > if(version == 0) > { > if(c <= ' ' || c == ',' || c == 127) > continue; > } > else > { > if((cookie_invalid_token[c >> 3] >> (c & 0x07)) & 0x01) > continue; > else if(key_len == 0 && !read_flag && > (read_flag = (c == '$') + 1) == 2) > { > continue; > } > else if(c >= 'A' && c <= 'Z') > c |= 0x20; > } > } > else > { > if(version == 0) > { > if(c <= ' ' || c == ',' || c == 127) > continue; > } > else > { > if(quote_flag == 3) > continue; > else if(val_len == 0 && !quote_flag && > (quote_flag = (c == '"') + 1) == 2) > { > continue; > } > else if(quote_flag == 2) > { > /* This handles both escaped and non-escaped characters > * in quoted values. > * > * RFC 2616 requires us to disallow non-escaped > * non-whitespace control characters, and escaped > * characters > 127. We also choose to disallow > * escaped non-whitespace control characters. > */ > > if(c < ' ' && c != 9 && c != 10 && c != 13) > continue; > else if(c >= 127) > continue; > } > else if((cookie_invalid_token[c >> 3] >> (c & 0x07)) & 0x01) > { > if(!quote_flag) > ++quote_flag; > > continue; > } > } > } > > if(read_flag == 2) > continue; > > > *buf++ = c; > > if(is_key) > ++key_len; > else > ++val_len; > > if(++buf_len >= buf_size) > { > if(buf_size < COOKIE_MAX_ALLOC_SIZE) > buf_size *= 2; > if((buf = (char*) apr_palloc(p, buf_size)) == NULL) > return APR_ENOMEM; > > if(is_key) > { > memcpy(buf, key, key_len); > key = buf; > buf_len = key_len; > } > else > { > memcpy(buf, val, val_len); > val = buf; > buf_len = val_len; > } > > buf += buf_len; > } > } > > > if(key_len > 0) > { > apr_array_header_t *val_arr; > struct string *string; > > > val_arr = (apr_array_header_t*) apr_hash_get(cookies, > (const void*) key, (apr_ssize_t) key_len); > > if(val_arr == NULL) > { > val_arr = apr_array_make(p, 1, sizeof(struct string)); > apr_hash_set(cookies, > (const void*) key, (apr_ssize_t) key_len, > (const void*) val_arr); > } > > if(is_key) > { > val = buf; > val_len = 0; > } > > *buf++ = 0; > > string = (struct string*) apr_array_push(val_arr); > string->ptr = val; > string->len = val_len; > } > > > return OK; >} > > >/**** DEBUG: Here are some tests for use with this code: > **** > **** Cookie: $VERsion = "1" , a=a, a= c; d="123; e=def""xx"x, y="ab\12\"asd\éqwe > **** > **** Cookie: $version=1; ::$$xx=123 , $foo=bar, foo$bar=123, ($)=1, (x$)=2 > **** > **** Cookie: $version=1; ::$$xx=123 , $foo=bar, foo$bar=123, ($)=1, (x$)=2, ABC$$def="\"ABC=$$ asd \"asd,a,;asd"(")$abc==123; xxx=yyy > **** > **** Cookie: $version = "1" , XYZ=123, xyz=546; xéa\"1$foo=\"asd; \"123\"="\"\$\xx" > ****/
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 11475
: 2624