aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcorvid <corvid@lavabit.com>2010-03-22 17:30:34 +0000
committercorvid <corvid@lavabit.com>2010-03-22 17:30:34 +0000
commiteecb359024409cf7110bef25a35e958db3cc1acb (patch)
tree28c8539b440d2f762015a9a6452969c96c6c8b06
parente86dd0113bb24d5a9e1f584a716342fd5a964937 (diff)
cookies use host-only as in draft spec
Behaviour should be quite similar to before, but it'll be easier for someone else to understand if it matches the spec's way of doing things more closely.
-rw-r--r--dpi/cookies.c90
-rw-r--r--test/cookies.c37
2 files changed, 93 insertions, 34 deletions
diff --git a/dpi/cookies.c b/dpi/cookies.c
index 7eac107f..f0abfa0a 100644
--- a/dpi/cookies.c
+++ b/dpi/cookies.c
@@ -16,10 +16,6 @@
/* This is written to follow the HTTP State Working Group's
* draft-ietf-httpstate-cookie-01.txt.
*
- * We depart from the draft spec's domain format in that, rather than
- * using a host-only flag, we continue to use the .domain notation
- * internally to indicate cookies that may also be returned to subdomains.
- *
* Info on cookies in the wild:
* http://www.ietf.org/mail-archive/web/http-state/current/msg00078.html
* And dates specifically:
@@ -107,6 +103,7 @@ typedef struct {
char *domain;
char *path;
time_t expires_at;
+ bool_t host_only;
bool_t secure;
bool_t session_only;
long last_used;
@@ -138,7 +135,7 @@ static FILE *file_stream;
static const char *const cookies_txt_header_str =
"# HTTP Cookie File\n"
"# This is a generated file! Do not edit.\n"
-"# [domain TRUE path secure expiry_time name value]\n\n";
+"# [domain subdomains path secure expiry_time name value]\n\n";
/* The epoch is Jan 1, 1970. When there is difficulty in representing future
* dates, use the (by far) most likely last representable time in Jan 19, 2038.
@@ -284,7 +281,9 @@ static void Cookies_load_cookies(FILE *stream)
cookie->session_only = FALSE;
cookie->domain = dStrdup(dStrsep(&line_marker, "\t"));
- dStrsep(&line_marker, "\t"); /* we use domain always as sufix */
+ piece = dStrsep(&line_marker, "\t");
+ if (piece != NULL && piece[0] == 'F')
+ cookie->host_only = TRUE;
cookie->path = dStrdup(dStrsep(&line_marker, "\t"));
piece = dStrsep(&line_marker, "\t");
if (piece != NULL && piece[0] == 'T')
@@ -414,8 +413,9 @@ static void Cookies_save_and_free()
while ((node = dList_nth_data(domains, 0))) {
for (i = 0; (cookie = dList_nth_data(node->cookies, i)); ++i) {
if (!cookie->session_only && difftime(cookie->expires_at, now) > 0) {
- fprintf(file_stream, "%s\tTRUE\t%s\t%s\t%ld\t%s\t%s\n",
+ fprintf(file_stream, "%s\t%s\t%s\t%s\t%ld\t%s\t%s\n",
cookie->domain,
+ cookie->host_only ? "FALSE" : "TRUE",
cookie->path,
cookie->secure ? "TRUE" : "FALSE",
(long)difftime(cookie->expires_at, cookies_epoch_time),
@@ -622,7 +622,7 @@ static void Cookies_add_cookie(CookieData_t *cookie)
domain_cookies = (node) ? node->cookies : NULL;
if (domain_cookies) {
- /* Remove any cookies with the same name and path */
+ /* Remove any cookies with the same name, path, and host-only values. */
while ((c = dList_find_custom(domain_cookies, cookie, Cookies_cmp))) {
dList_remove(domain_cookies, c);
dList_remove_fast(all_cookies, c);
@@ -893,16 +893,15 @@ static CookieData_t *Cookies_parse(char *cookie_str, const char *server_date)
}
/*
- * Compare cookies by name and path (return 0 if equal)
+ * Compare cookies by host_only, name, and path. Return 0 if equal.
*/
static int Cookies_cmp(const void *a, const void *b)
{
const CookieData_t *ca = a, *cb = b;
- int ret;
- if (!(ret = strcmp(ca->name, cb->name)))
- ret = strcmp(ca->path, cb->path);
- return ret;
+ return (ca->host_only != cb->host_only) ||
+ (strcmp(ca->name, cb->name) != 0) ||
+ (strcmp(ca->path, cb->path) != 0);
}
/*
@@ -1071,15 +1070,10 @@ static bool_t Cookies_validate_domain(CookieData_t *cookie, char *host)
if (!cookie->domain) {
cookie->domain = dStrdup(host);
+ cookie->host_only = TRUE;
return TRUE;
}
- if (cookie->domain[0] != '.' && !Cookies_domain_is_ip(cookie->domain)) {
- char *d = dStrconcat(".", cookie->domain, NULL);
- dFree(cookie->domain);
- cookie->domain = d;
- }
-
if (!Cookies_domain_matches(host, cookie->domain))
return FALSE;
@@ -1145,8 +1139,11 @@ static int Cookies_set(char *cookie_string, char *url_host,
* Compare the cookie with the supplied data to see whether it matches
*/
static bool_t Cookies_match(CookieData_t *cookie, const char *url_path,
- bool_t is_ssl)
+ bool_t host_only_val, bool_t is_ssl)
{
+ if (cookie->host_only != host_only_val)
+ return FALSE;
+
/* Insecure cookies matches both secure and insecure urls, secure
cookies matches only secure urls */
if (cookie->secure && !is_ssl)
@@ -1161,6 +1158,7 @@ static bool_t Cookies_match(CookieData_t *cookie, const char *url_path,
static void Cookies_add_matching_cookies(const char *domain,
const char *url_path,
+ bool_t host_only_val,
Dlist *matching_cookies,
bool_t is_ssl)
{
@@ -1182,7 +1180,7 @@ static void Cookies_add_matching_cookies(const char *domain,
--i; continue;
}
/* Check if the cookie matches the requesting URL */
- if (Cookies_match(cookie, url_path, is_ssl)) {
+ if (Cookies_match(cookie, url_path, host_only_val, is_ssl)) {
int j;
CookieData_t *curr;
uint_t path_length = strlen(cookie->path);
@@ -1212,7 +1210,8 @@ static char *Cookies_get(char *url_host, char *url_path,
char *domain_str, *str;
CookieData_t *cookie;
Dlist *matching_cookies;
- bool_t is_ssl;
+ bool_t is_ssl, is_ip_addr, host_only_val;
+
Dstr *cookie_dstring;
int i;
@@ -1224,18 +1223,47 @@ static char *Cookies_get(char *url_host, char *url_path,
/* Check if the protocol is secure or not */
is_ssl = (!dStrcasecmp(url_scheme, "https"));
- for (domain_str = (char *) url_host;
- domain_str != NULL && *domain_str;
- domain_str = strchr(domain_str+1, '.')) {
- Cookies_add_matching_cookies(domain_str, url_path, matching_cookies,
- is_ssl);
- }
- if (!Cookies_domain_is_ip(url_host)) {
+ is_ip_addr = Cookies_domain_is_ip(url_host);
+
+ /* If a cookie is set that lacks a Domain attribute, its domain is set to
+ * the server's host and the host_only flag is set for that cookie. Such a
+ * cookie can only be sent back to that host. Cookies with Domain attrs do
+ * not have the host_only flag set, and may be sent to subdomains. Domain
+ * attrs can have leading dots, which should be ignored for matching
+ * purposes.
+ */
+ host_only_val = FALSE;
+ if (!is_ip_addr) {
+ /* e.g., sub.example.com set a cookie with domain ".sub.example.com". */
domain_str = dStrconcat(".", url_host, NULL);
- Cookies_add_matching_cookies(domain_str, url_path, matching_cookies,
- is_ssl);
+ Cookies_add_matching_cookies(domain_str, url_path, host_only_val,
+ matching_cookies, is_ssl);
dFree(domain_str);
}
+ host_only_val = TRUE;
+ /* e.g., sub.example.com set a cookie with no domain attribute. */
+ Cookies_add_matching_cookies(url_host, url_path, host_only_val,
+ matching_cookies, is_ssl);
+ host_only_val = FALSE;
+ /* e.g., sub.example.com set a cookie with domain "sub.example.com". */
+ Cookies_add_matching_cookies(url_host, url_path, host_only_val,
+ matching_cookies, is_ssl);
+
+ if (!is_ip_addr) {
+ for (domain_str = strchr(url_host+1, '.');
+ domain_str != NULL && *domain_str;
+ domain_str = strchr(domain_str+1, '.')) {
+ /* e.g., sub.example.com set a cookie with domain ".example.com". */
+ Cookies_add_matching_cookies(domain_str, url_path, host_only_val,
+ matching_cookies, is_ssl);
+ if (domain_str[1]) {
+ domain_str++;
+ /* e.g., sub.example.com set a cookie with domain "example.com".*/
+ Cookies_add_matching_cookies(domain_str, url_path, host_only_val,
+ matching_cookies, is_ssl);
+ }
+ }
+ }
/* Found the cookies, now make the string */
cookie_dstring = dStr_new("");
diff --git a/test/cookies.c b/test/cookies.c
index 0d8d3db1..d3ff7ae6 100644
--- a/test/cookies.c
+++ b/test/cookies.c
@@ -832,17 +832,41 @@ int main()
expect(__LINE__, "Cookie: name=val\r\n", "http", "dotdomain.org", "/");
expect(__LINE__, "Cookie: name=val\r\n", "http", "www.dotdomain.org", "/");
+ /* HOST_ONLY */
+ a_Cookies_set("name=val; domain=.hostonly.org", "hostonly.org", "/", NULL);
+ a_Cookies_set("name2=val2", "hostonly.org", "/", NULL);
+ a_Cookies_set("name3=val3; domain=hostonly.org", "hostonly.org", "/", NULL);
+ expect(__LINE__, "Cookie: name=val; name2=val2; name3=val3\r\n", "http",
+ "hostonly.org", "/");
+ a_Cookies_set("name=new; domain=.hostonly.org", "hostonly.org", "/", NULL);
+ expect(__LINE__, "Cookie: name=new; name2=val2; name3=val3\r\n", "http",
+ "hostonly.org", "/");
+ a_Cookies_set("name2=new2", "hostonly.org", "/", NULL);
+ expect(__LINE__, "Cookie: name=new; name2=new2; name3=val3\r\n", "http",
+ "hostonly.org", "/");
+ a_Cookies_set("name3=new3; domain=hostonly.org", "hostonly.org", "/", NULL);
+ expect(__LINE__, "Cookie: name=new; name2=new2; name3=new3\r\n", "http",
+ "hostonly.org", "/");
+
/* SUBDOMAIN */
a_Cookies_set("name=val; domain=www.subdomain.com", "subdomain.com", "/",
NULL);
+ a_Cookies_set("name=val; domain=.www.subdomain.com", "subdomain.com", "/",
+ NULL);
expect(__LINE__, "", "http", "subdomain.com", "/");
expect(__LINE__, "", "http", "www.subdomain.com", "/");
/* SUPERDOMAIN(?) */
- a_Cookies_set("name=val; domain=supdomain.com", "www.supdomain.com", "/",
+ a_Cookies_set("name=val; domain=.supdomain.com", "www.supdomain.com", "/",
NULL);
- expect(__LINE__, "Cookie: name=val\r\n", "http", "www.supdomain.com", "/");
- expect(__LINE__, "Cookie: name=val\r\n", "http", "supdomain.com", "/");
+ a_Cookies_set("name2=val2; domain=supdomain.com", "www.supdomain.com", "/",
+ NULL);
+ expect(__LINE__, "Cookie: name=val; name2=val2\r\n", "http",
+ "sub2.sub.supdomain.com", "/");
+ expect(__LINE__, "Cookie: name=val; name2=val2\r\n", "http",
+ "www.supdomain.com", "/");
+ expect(__LINE__, "Cookie: name=val; name2=val2\r\n", "http",
+ "supdomain.com", "/");
/* UNRELATED */
a_Cookies_set("name=val; domain=another.com", "unrelated.com", "/", NULL);
@@ -857,6 +881,13 @@ int main()
a_Cookies_set("name=val; domain=another.com", "verybadguys.com", "/", NULL);
expect(__LINE__, "", "http", "another.com", "/");
+ a_Cookies_set("name=val; domain=similar.com", "imilar.com", "/", NULL);
+ a_Cookies_set("name2=val2; domain=similar.com", "ssimilar.com", "/", NULL);
+ a_Cookies_set("name3=val3; domain=.similar.com", "imilar.com", "/", NULL);
+ a_Cookies_set("name4=val4; domain=.similar.com", "timilar.com", "/", NULL);
+ a_Cookies_set("name4=val4; domain=.similar.com", "tiimilar.com", "/", NULL);
+ expect(__LINE__, "", "http", "similar.com", "/");
+
/* SECURE */
a_Cookies_set("name=val; secure", "secure.com", "/", NULL);
expect(__LINE__, "", "http", "secure.com", "/");