r2631 jmb - in /branches/jmb/cookies: content/urldb.c content/urldb.h desktop/netsurf.c
by netsurf@semichrome.net
Author: jmb
Date: Mon Jun 19 22:09:10 2006
New Revision: 2631
URL: http://svn.semichrome.net?rev=2631&view=rev
Log:
Use regex to match expires avpair.
Modified:
branches/jmb/cookies/content/urldb.c
branches/jmb/cookies/content/urldb.h
branches/jmb/cookies/desktop/netsurf.c
Modified: branches/jmb/cookies/content/urldb.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.c?rev=2631&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.c (original)
+++ branches/jmb/cookies/content/urldb.c Mon Jun 19 22:09:10 2006
@@ -266,6 +266,24 @@
#define COOKIE_FILE_VERSION 100
#define URL_FILE_VERSION 106
+
+regex_t expires_re;
+
+/**
+ * Initialise URL database code
+ *
+ * This should be called before any other urldb functions
+ */
+void urldb_init(void)
+{
+ regcomp_wrapper(&expires_re, "[a-zA-Z]{3},[[:space:]]" // "Wdy, "
+ "[0-9]{2}[[:space:]-]" // "DD[ -]"
+ "[a-zA-Z]{3}[[:space:]-]" // "MMM[ -]"
+ "[0-9]{4}[[:space:]]" // "YYYY "
+ "[0-9]{2}(:[0-9]{2}){2}" // "HH:MM:SS"
+ "[[:space:]]GMT", // " GMT"
+ REG_EXTENDED);
+}
/**
* Import an URL database from file, replacing any existing database
@@ -2526,31 +2544,15 @@
comma = strchr(cur, ',');
if (comma) {
/* Check for Expires avpair: Wdy, DD-Mon-YYYY HH:MM:SS GMT */
- /* Irritatingly, we can't suppress assignment as it results
- * in a return value of 0. Therefore we simply provide a
- * scratch buffer for sscanf to write to.
- * Additionally, date parts of the form "DD Mon YYYY" have
- * been seen in the wild, so we accept them too even though
- * they're not strictly correct - it's more important to
- * match something that looks like an Expires avpair than
- * be strict here (as we're simply looking for the end of
- * the cookie declaration) */
- char buf[12];
- if (sscanf(comma - 3,
- "%3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz], "
- "%2[0123456789]%1[ -]"
- "%3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz]"
- "%1[ -]%4[0123456789] "
- "%2[0123456789]:%2[0123456789]:"
- "%2[0123456789] GMT",
- buf, buf, buf, buf, buf,
- buf, buf, buf, buf) == 9) {
+ /* Date parts of the form "DD Mon YYYY" have been seen in
+ * the wild, so we accept them too even though they're not
+ * strictly correct - it's more important to match something
+ * that looks like an Expires avpair than be strict here (as
+ * we're simply looking for the end of the cookie
+ * declaration) */
+ if (regexec(&expires_re, comma - 3, 0, NULL, 0) == 0) {
/* Part of Expires avpair => look for next comma */
comma = strchr(comma + 1, ',');
- } else {
- LOG(("sscanf failed"));
}
}
@@ -2629,23 +2631,11 @@
comma = strchr(cur, ',');
if (comma) {
/* Check if it's an Expires avpair */
- char buf[12];
- if (sscanf(comma - 3,
- "%3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz], "
- "%2[0123456789]%1[ -]"
- "%3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz]"
- "%1[ -]%4[0123456789] "
- "%2[0123456789]:%2[0123456789]:"
- "%2[0123456789] GMT",
- buf, buf, buf, buf, buf,
- buf, buf, buf, buf) == 9) {
+ if (regexec(&expires_re, comma - 3, 0,
+ NULL, 0) == 0) {
/* Part of Expires avpair =>
* look for next comma */
comma = strchr(comma + 1, ',');
- } else {
- LOG(("sscanf failed"));
}
}
if (!comma)
Modified: branches/jmb/cookies/content/urldb.h
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.h?rev=2631&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.h (original)
+++ branches/jmb/cookies/content/urldb.h Mon Jun 19 22:09:10 2006
@@ -24,6 +24,9 @@
};
struct bitmap;
+
+/* Initialisation */
+void urldb_init(void);
/* Persistence support */
void urldb_load(const char *filename);
Modified: branches/jmb/cookies/desktop/netsurf.c
URL: http://svn.semichrome.net/branches/jmb/cookies/desktop/netsurf.c?rev=2631...
==============================================================================
--- branches/jmb/cookies/desktop/netsurf.c (original)
+++ branches/jmb/cookies/desktop/netsurf.c Mon Jun 19 22:09:10 2006
@@ -15,6 +15,7 @@
#include "netsurf/utils/config.h"
#include "netsurf/content/fetch.h"
#include "netsurf/content/fetchcache.h"
+#include "netsurf/content/urldb.h"
#include "netsurf/desktop/netsurf.h"
#include "netsurf/desktop/browser.h"
#include "netsurf/desktop/gui.h"
@@ -77,6 +78,7 @@
lib_init();
url_init();
+ urldb_init();
gui_init(argc, argv);
setlocale(LC_ALL, "");
fetch_init();
16 years, 7 months
r2630 jmb - /branches/jmb/cookies/content/fetch.c
by netsurf@semichrome.net
Author: jmb
Date: Mon Jun 19 12:35:05 2006
New Revision: 2630
URL: http://svn.semichrome.net?rev=2630&view=rev
Log:
Lose commented out old curl cookie calls
Modified:
branches/jmb/cookies/content/fetch.c
Modified: branches/jmb/cookies/content/fetch.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/fetch.c?rev=2630&r...
==============================================================================
--- branches/jmb/cookies/content/fetch.c (original)
+++ branches/jmb/cookies/content/fetch.c Mon Jun 19 12:35:05 2006
@@ -640,15 +640,7 @@
f->cookie_string = urldb_get_cookie(f->url, f->referer);
if (f->cookie_string)
SETOPT(CURLOPT_COOKIE, f->cookie_string);
-// if (option_cookie_file)
-// SETOPT(CURLOPT_COOKIEFILE, option_cookie_file);
-// if (option_cookie_jar)
-// SETOPT(CURLOPT_COOKIEJAR, option_cookie_jar);
- }
-// else {
-// SETOPT(CURLOPT_COOKIEFILE, 0);
-// SETOPT(CURLOPT_COOKIEJAR, 0);
-// }
+ }
#ifdef WITH_AUTH
if ((auth = urldb_get_auth_details(f->url)) != NULL) {
SETOPT(CURLOPT_HTTPAUTH, CURLAUTH_ANY);
16 years, 7 months
r2629 jmb - /branches/jmb/cookies/content/urldb.c
by netsurf@semichrome.net
Author: jmb
Date: Mon Jun 19 12:30:24 2006
New Revision: 2629
URL: http://svn.semichrome.net?rev=2629&view=rev
Log:
Fix stupidity in Cookie file parser (it failed to skip to the next
input line after parsing the version string)
Modified:
branches/jmb/cookies/content/urldb.c
Modified: branches/jmb/cookies/content/urldb.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.c?rev=2629&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.c (original)
+++ branches/jmb/cookies/content/urldb.c Mon Jun 19 12:30:24 2006
@@ -3078,6 +3078,8 @@
LOG(("Unknown Cookie file version"));
break;
}
+
+ continue;
} else if (file_version == 0) {
/* Haven't yet seen version; skip this input */
continue;
16 years, 7 months
r2628 jmb - /branches/jmb/cookies/content/urldb.c
by netsurf@semichrome.net
Author: jmb
Date: Mon Jun 19 12:18:23 2006
New Revision: 2628
URL: http://svn.semichrome.net?rev=2628&view=rev
Log:
Fix exact path handling to consider correct cookie chain
Fix duplicate cookie sending for directories
Don't send $Version for old-style cookies
Modified:
branches/jmb/cookies/content/urldb.c
Modified: branches/jmb/cookies/content/urldb.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.c?rev=2628&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.c (original)
+++ branches/jmb/cookies/content/urldb.c Mon Jun 19 12:18:23 2006
@@ -2328,7 +2328,7 @@
continue;
/* Consider all cookies associated with this exact path */
- for (c = p->cookies; c; c = c->next) {
+ for (c = q->cookies; c; c = c->next) {
if (c->expires != 1 && c->expires < now)
/* cookie has expired => ignore */
continue;
@@ -2354,6 +2354,10 @@
}
// LOG(("%s", ret));
+
+ if (strlen(p->segment) == 0)
+ /* We're a directory; skip parent */
+ p = p->parent->parent;
/* Now consider cookies whose paths prefix-match ours */
for (; p; p = p->parent) {
@@ -2363,40 +2367,31 @@
if (strlen(q->segment) > 0)
continue;
- if (q->cookies) {
- for (c = q->cookies; c; c = c->next) {
-// LOG(("%p: %s=%s", c,
-// c->name, c->value));
- if (c->expires != 1 &&
- c->expires < now)
- /* cookie has expired
- * => ignore */
- continue;
-
- if (c->secure && strcasecmp(
- q->scheme, "https"))
- /* Secure cookie for
- * insecure server
- * => ignore */
- continue;
-
- if (!urldb_concat_cookie(c,
- &ret_used,
- &ret_alloc, &ret)) {
- free(path);
- free(ret);
- return NULL;
- }
-
- if (c->version <
- (unsigned int)
- version)
- version = c->version;
-
- c->last_used = now;
-
- count++;
+ for (c = q->cookies; c; c = c->next) {
+// LOG(("%p: %s=%s", c, c->name, c->value));
+ if (c->expires != 1 && c->expires < now)
+ /* cookie has expired => ignore */
+ continue;
+
+ if (c->secure && strcasecmp(
+ q->scheme, "https"))
+ /* Secure cookie for insecure server
+ * => ignore */
+ continue;
+
+ if (!urldb_concat_cookie(c, &ret_used,
+ &ret_alloc, &ret)) {
+ free(path);
+ free(ret);
+ return NULL;
}
+
+ if (c->version < (unsigned int) version)
+ version = c->version;
+
+ c->last_used = now;
+
+ count++;
}
}
@@ -2454,13 +2449,24 @@
/* and build output string */
{
- char *temp = malloc(12 + ret_used);
+ char *temp;
+ if (version > 0)
+ temp = malloc(12 + ret_used);
+ else
+ temp = malloc(ret_used);
if (!temp) {
free(path);
free(ret);
return NULL;
}
- sprintf(temp, "$Version=%d%s", version, ret);
+
+ if (version > 0)
+ sprintf(temp, "$Version=%d%s", version, ret);
+ else {
+ /* Old-style cookies => no version & skip "; " */
+ sprintf(temp, "%s", ret + 2);
+ }
+
free(path);
free(ret);
ret = temp;
16 years, 7 months
r2627 jmb - /branches/jmb/cookies/content/urldb.c
by netsurf@semichrome.net
Author: jmb
Date: Mon Jun 19 11:45:52 2006
New Revision: 2627
URL: http://svn.semichrome.net?rev=2627&view=rev
Log:
Special case max-age=0 (cookie deletion request)
Modified:
branches/jmb/cookies/content/urldb.c
Modified: branches/jmb/cookies/content/urldb.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.c?rev=2627&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.c (original)
+++ branches/jmb/cookies/content/urldb.c Mon Jun 19 11:45:52 2006
@@ -2756,8 +2756,13 @@
break;
}
} else if (strcasecmp(n, "Max-Age") == 0) {
+ int temp = atoi(v);
had_max_age = true;
- max_age = time(NULL) + atoi(v);
+ if (temp == 0)
+ /* Special case - 0 means delete */
+ max_age = 0;
+ else
+ max_age = time(NULL) + temp;
} else if (!c->path &&
strcasecmp(n, "Path") == 0) {
c->path_from_set = true;
16 years, 7 months
r2626 jmb - /branches/jmb/cookies/content/urldb.c
by netsurf@semichrome.net
Author: jmb
Date: Mon Jun 19 11:34:17 2006
New Revision: 2626
URL: http://svn.semichrome.net?rev=2626&view=rev
Log:
Reinstate FQDN check ($4.3.2:iv)
Modified:
branches/jmb/cookies/content/urldb.c
Modified: branches/jmb/cookies/content/urldb.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.c?rev=2626&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.c (original)
+++ branches/jmb/cookies/content/urldb.c Mon Jun 19 11:34:17 2006
@@ -2606,12 +2606,12 @@
goto error;
}
- /* Ensure H contains no dots - wrong */
-// for (int i = 0; i < (hlen - dlen); i++)
-// if (host[i] == '.') {
-// urldb_free_cookie(c);
-// goto error;
-// }
+ /* Ensure H contains no dots */
+ for (int i = 0; i < (hlen - dlen); i++)
+ if (host[i] == '.') {
+ urldb_free_cookie(c);
+ goto error;
+ }
}
/* Now insert into database */
16 years, 7 months
r2625 jmb - /branches/jmb/cookies/content/urldb.c
by netsurf@semichrome.net
Author: jmb
Date: Sun Jun 18 23:57:39 2006
New Revision: 2625
URL: http://svn.semichrome.net?rev=2625&view=rev
Log:
Consider all matching paths on a host, regardless of differing URL schemes.
Obey secure cookie flag.
Modified:
branches/jmb/cookies/content/urldb.c
Modified: branches/jmb/cookies/content/urldb.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.c?rev=2625&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.c (original)
+++ branches/jmb/cookies/content/urldb.c Sun Jun 18 23:57:39 2006
@@ -2316,58 +2316,87 @@
now = time(NULL);
- /* Consider all cookies associated with this exact path */
- for (c = p->cookies; c; c = c->next) {
- if (c->expires != 1 && c->expires < now)
- /* cookie has expired => ignore */
+ if (p->prev) {
+ for (q = p->prev; q && q->prev; q = q->prev)
+ ; /* do nothing */
+ } else {
+ q = p;
+ }
+
+ for (; q; q = q->next) {
+ if (strcmp(q->segment, p->segment))
continue;
- if (!urldb_concat_cookie(c, &ret_used, &ret_alloc, &ret)) {
- free(path);
- free(ret);
- return NULL;
- }
-
- if (c->version < (unsigned int)version)
- version = c->version;
-
- c->last_used = now;
-
- count++;
+ /* Consider all cookies associated with this exact path */
+ for (c = p->cookies; c; c = c->next) {
+ if (c->expires != 1 && c->expires < now)
+ /* cookie has expired => ignore */
+ continue;
+
+ if (c->secure && strcasecmp(q->scheme, "https"))
+ /* secure cookie for insecure host. ignore */
+ continue;
+
+ if (!urldb_concat_cookie(c, &ret_used,
+ &ret_alloc, &ret)) {
+ free(path);
+ free(ret);
+ return NULL;
+ }
+
+ if (c->version < (unsigned int)version)
+ version = c->version;
+
+ c->last_used = now;
+
+ count++;
+ }
}
// LOG(("%s", ret));
/* Now consider cookies whose paths prefix-match ours */
for (; p; p = p->parent) {
- /* Find parent directory's path entry */
- /** \todo Do we want to use path entries
- * on all schemes or just the current one? */
- for (q = p->children; q; q = q->next)
- if (strlen(q->segment) == 0 &&
- strcasecmp(q->scheme, scheme) == 0)
- break;
-
- if (q && q->cookies) {
- for (c = q->cookies; c; c = c->next) {
-// LOG(("%p: %s=%s", c, c->name, c->value));
- if (c->expires != 1 && c->expires < now)
- /* cookie has expired => ignore */
- continue;
-
- if (!urldb_concat_cookie(c, &ret_used,
- &ret_alloc, &ret)) {
- free(path);
- free(ret);
- return NULL;
+ /* Find parent directory's path entry(ies) */
+ /* There are potentially multiple due to differing schemes */
+ for (q = p->children; q; q = q->next) {
+ if (strlen(q->segment) > 0)
+ continue;
+
+ if (q->cookies) {
+ for (c = q->cookies; c; c = c->next) {
+// LOG(("%p: %s=%s", c,
+// c->name, c->value));
+ if (c->expires != 1 &&
+ c->expires < now)
+ /* cookie has expired
+ * => ignore */
+ continue;
+
+ if (c->secure && strcasecmp(
+ q->scheme, "https"))
+ /* Secure cookie for
+ * insecure server
+ * => ignore */
+ continue;
+
+ if (!urldb_concat_cookie(c,
+ &ret_used,
+ &ret_alloc, &ret)) {
+ free(path);
+ free(ret);
+ return NULL;
+ }
+
+ if (c->version <
+ (unsigned int)
+ version)
+ version = c->version;
+
+ c->last_used = now;
+
+ count++;
}
-
- if (c->version < (unsigned int)version)
- version = c->version;
-
- c->last_used = now;
-
- count++;
}
}
@@ -2392,6 +2421,10 @@
/* Ensure cookie path is a prefix of the resource */
if (strncmp(c->path, path, strlen(c->path)) != 0)
/* paths don't match => ignore */
+ continue;
+
+ if (c->secure && strcasecmp(scheme, "https"))
+ /* secure cookie for insecure host. ignore */
continue;
if (!urldb_concat_cookie(c, &ret_used, &ret_alloc,
16 years, 7 months
r2624 jmb - in /branches/jmb/cookies: content/urldb.c content/urldb.h riscos/gui.c
by netsurf@semichrome.net
Author: jmb
Date: Sun Jun 18 22:17:48 2006
New Revision: 2624
URL: http://svn.semichrome.net?rev=2624&view=rev
Log:
Cookie persistence support
Modified:
branches/jmb/cookies/content/urldb.c
branches/jmb/cookies/content/urldb.h
branches/jmb/cookies/riscos/gui.c
Modified: branches/jmb/cookies/content/urldb.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.c?rev=2624&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.c (original)
+++ branches/jmb/cookies/content/urldb.c Sun Jun 18 22:17:48 2006
@@ -241,9 +241,13 @@
/* Cookies */
static struct cookie *urldb_parse_cookie(const char *url,
const char *cookie);
+static bool urldb_insert_cookie(struct cookie *c, const char *scheme,
+ const char *url);
static void urldb_free_cookie(struct cookie *c);
static bool urldb_concat_cookie(struct cookie *c, int *used,
int *alloc, char **buf);
+static void urldb_save_cookie_hosts(FILE *fp, struct host_part *parent);
+static void urldb_save_cookie_paths(FILE *fp, struct path_data *parent);
/** Root database handle */
static struct host_part db_root;
@@ -260,6 +264,9 @@
&empty, &empty, &empty
};
+#define COOKIE_FILE_VERSION 100
+#define URL_FILE_VERSION 106
+
/**
* Import an URL database from file, replacing any existing database
*
@@ -294,7 +301,7 @@
LOG(("Unsupported URL file version."));
return;
}
- if (version > 106) {
+ if (version > URL_FILE_VERSION) {
LOG(("Unknown URL file version."));
return;
}
@@ -490,7 +497,7 @@
}
/* file format version number */
- fprintf(fp, "106\n");
+ fprintf(fp, "%d\n", URL_FILE_VERSION);
for (i = 0; i != NUM_SEARCH_TREES; i++) {
urldb_save_search_tree(search_trees[i], fp);
@@ -2275,6 +2282,7 @@
int ret_alloc = 4096, ret_used = 1;
char *path;
char *ret;
+ char *scheme;
time_t now;
url_func_result res;
@@ -2291,6 +2299,8 @@
p = urldb_find_url(url);
if (!p)
return NULL;
+
+ scheme = p->scheme;
ret = malloc(ret_alloc);
if (!ret)
@@ -2331,8 +2341,11 @@
/* Now consider cookies whose paths prefix-match ours */
for (; p; p = p->parent) {
/* Find parent directory's path entry */
+ /** \todo Do we want to use path entries
+ * on all schemes or just the current one? */
for (q = p->children; q; q = q->next)
- if (strlen(q->segment) == 0)
+ if (strlen(q->segment) == 0 &&
+ strcasecmp(q->scheme, scheme) == 0)
break;
if (q && q->cookies) {
@@ -2484,9 +2497,15 @@
* be strict here (as we're simply looking for the end of
* the cookie declaration) */
char buf[12];
- if (sscanf(comma - 3, "%3[A-Za-z], "
- "%2[0-9]%1[ -]%3[A-Za-z]%1[ -]%4[0-9] "
- "%2[0-9]:%2[0-9]:%2[0-9] GMT",
+ if (sscanf(comma - 3,
+ "%3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz], "
+ "%2[0123456789]%1[ -]"
+ "%3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz]"
+ "%1[ -]%4[0123456789] "
+ "%2[0123456789]:%2[0123456789]:"
+ "%2[0123456789] GMT",
buf, buf, buf, buf, buf,
buf, buf, buf, buf) == 9) {
/* Part of Expires avpair => look for next comma */
@@ -2502,9 +2521,7 @@
}
do {
- struct cookie *c, *d;
- const struct host_part *h;
- struct path_data *p;
+ struct cookie *c;
char *dot;
snprintf(cookie, sizeof cookie, "%.*s", comma - cur, cur);
@@ -2534,7 +2551,7 @@
/* Domain match fetch host with cookie domain */
if (strcasecmp(host, c->domain) != 0) {
- int hlen, dlen, i;
+ int hlen, dlen;
if (host[0] >= '0' && host[0] <= '9') {
/* IP address, so no partial match */
@@ -2557,7 +2574,7 @@
}
/* Ensure H contains no dots - wrong */
-// for (i = 0; i < (hlen - dlen); i++)
+// for (int i = 0; i < (hlen - dlen); i++)
// if (host[i] == '.') {
// urldb_free_cookie(c);
// goto error;
@@ -2565,87 +2582,8 @@
}
/* Now insert into database */
- if (c->domain[0] == '.') {
- h = urldb_search_find(
- search_trees[tolower(c->domain[1]) - 'a' +
- ST_DN],
- c->domain + 1);
- if (!h) {
- h = urldb_add_host(c->domain + 1);
- if (!h) {
- urldb_free_cookie(c);
- goto error;
- }
- }
-
- p = &h->paths;
- } else {
- if (c->domain[0] >= '0' && c->domain[0] <= '9')
- h = urldb_search_find(search_trees[ST_IP],
- c->domain);
- else
- h = urldb_search_find(search_trees[
- tolower(c->domain[0]) -
- 'a' + ST_DN],
- c->domain);
-
- if (!h) {
- h = urldb_add_host(c->domain);
- if (!h) {
- urldb_free_cookie(c);
- goto error;
- }
- }
-
- /* find path */
- p = urldb_add_path(scheme, 0, h,
- c->path, NULL, urlt);
- if (!p) {
- urldb_free_cookie(c);
- goto error;
- }
- }
-
- /* add cookie */
- for (d = p->cookies; d; d = d->next) {
- if (!strcmp(d->domain, c->domain) &&
- !strcmp(d->path, c->path) &&
- !strcmp(d->name, c->name))
- break;
- }
-
- if (d) {
- if (c->expires == 0) {
- /* remove cookie */
- if (d->next)
- d->next->prev = d->prev;
- if (d->prev)
- d->prev->next = d->next;
- else
- p->cookies = d->next;
- urldb_free_cookie(d);
- urldb_free_cookie(c);
- } else {
- /* replace d with c */
- c->prev = d->prev;
- c->next = d->next;
- if (c->next)
- c->next->prev = c;
- if (c->prev)
- c->prev->next = c;
- else
- p->cookies = c;
- urldb_free_cookie(d);
-// LOG(("%p: %s=%s", c, c->name, c->value));
- }
- } else {
- c->prev = NULL;
- c->next = p->cookies;
- if (p->cookies)
- p->cookies->prev = c;
- p->cookies = c;
-// LOG(("%p: %s=%s", c, c->name, c->value));
- }
+ if (!urldb_insert_cookie(c, scheme, urlt))
+ goto error;
cur = comma + 1;
if (cur < end) {
@@ -2653,11 +2591,15 @@
if (comma) {
/* Check if it's an Expires avpair */
char buf[12];
- if (sscanf(comma - 3, "%3[A-Za-z], "
- "%2[0-9]%1[ -]%3[A-Za-z]"
- "%1[ -]%4[0-9] "
- "%2[0-9]:%2[0-9]:%2[0-9] "
- "GMT",
+ if (sscanf(comma - 3,
+ "%3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz], "
+ "%2[0123456789]%1[ -]"
+ "%3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz]"
+ "%1[ -]%4[0123456789] "
+ "%2[0123456789]:%2[0123456789]:"
+ "%2[0123456789] GMT",
buf, buf, buf, buf, buf,
buf, buf, buf, buf) == 9) {
/* Part of Expires avpair =>
@@ -2703,6 +2645,8 @@
time_t max_age = 0, expires = 0;
bool had_max_age = false, had_expires = false;
url_func_result res;
+
+ assert(url && cookie);
c = calloc(1, sizeof(struct cookie));
if (!c)
@@ -2869,12 +2813,113 @@
}
/**
+ * Insert a cookie into the database
+ *
+ * \param c The cookie to insert
+ * \param scheme URL scheme associated with cookie path
+ * \param url URL (sans fragment) associated with cookie
+ * \return true on success, false on memory exhaustion (c will be freed)
+ */
+bool urldb_insert_cookie(struct cookie *c, const char *scheme,
+ const char *url)
+{
+ struct cookie *d;
+ const struct host_part *h;
+ struct path_data *p;
+
+ assert(c && scheme && url);
+
+ if (c->domain[0] == '.') {
+ h = urldb_search_find(
+ search_trees[tolower(c->domain[1]) - 'a' + ST_DN],
+ c->domain + 1);
+ if (!h) {
+ h = urldb_add_host(c->domain + 1);
+ if (!h) {
+ urldb_free_cookie(c);
+ return false;
+ }
+ }
+
+ p = &h->paths;
+ } else {
+ if (c->domain[0] >= '0' && c->domain[0] <= '9')
+ h = urldb_search_find(search_trees[ST_IP], c->domain);
+ else
+ h = urldb_search_find(search_trees[
+ tolower(c->domain[0]) - 'a' + ST_DN],
+ c->domain);
+
+ if (!h) {
+ h = urldb_add_host(c->domain);
+ if (!h) {
+ urldb_free_cookie(c);
+ return false;
+ }
+ }
+
+ /* find path */
+ p = urldb_add_path(scheme, 0, h,
+ c->path, NULL, url);
+ if (!p) {
+ urldb_free_cookie(c);
+ return false;
+ }
+ }
+
+ /* add cookie */
+ for (d = p->cookies; d; d = d->next) {
+ if (!strcmp(d->domain, c->domain) &&
+ !strcmp(d->path, c->path) &&
+ !strcmp(d->name, c->name))
+ break;
+ }
+
+ if (d) {
+ if (c->expires == 0) {
+ /* remove cookie */
+ if (d->next)
+ d->next->prev = d->prev;
+ if (d->prev)
+ d->prev->next = d->next;
+ else
+ p->cookies = d->next;
+ urldb_free_cookie(d);
+ urldb_free_cookie(c);
+ } else {
+ /* replace d with c */
+ c->prev = d->prev;
+ c->next = d->next;
+ if (c->next)
+ c->next->prev = c;
+ if (c->prev)
+ c->prev->next = c;
+ else
+ p->cookies = c;
+ urldb_free_cookie(d);
+// LOG(("%p: %s=%s", c, c->name, c->value));
+ }
+ } else {
+ c->prev = NULL;
+ c->next = p->cookies;
+ if (p->cookies)
+ p->cookies->prev = c;
+ p->cookies = c;
+// LOG(("%p: %s=%s", c, c->name, c->value));
+ }
+
+ return true;
+}
+
+/**
* Free a cookie
*
* \param c The cookie to free
*/
void urldb_free_cookie(struct cookie *c)
{
+ assert(c);
+
free(c->comment);
free(c->domain);
free(c->path);
@@ -2894,7 +2939,11 @@
*/
bool urldb_concat_cookie(struct cookie *c, int *used, int *alloc, char **buf)
{
- int clen = 2 + strlen(c->name) + 1 + strlen(c->value) +
+ int clen;
+
+ assert(c && used && alloc && buf && *buf);
+
+ clen = 2 + strlen(c->name) + 1 + strlen(c->value) +
(c->path_from_set ?
8 + strlen(c->path) : 0) +
(c->domain_from_set ?
@@ -2924,6 +2973,222 @@
return true;
}
+/**
+ * Load a cookie file into the database
+ *
+ * \param filename File to load
+ */
+void urldb_load_cookies(const char *filename)
+{
+ FILE *fp;
+ char s[16*1024];
+ int file_version = 0;
+
+ assert(filename);
+
+ fp = fopen(filename, "r");
+ if (!fp)
+ return;
+
+#define FIND_WS { \
+ for (; *p && !isspace(*p) && !iscntrl(*p); p++) \
+ ; /* do nothing */ \
+ if (p >= end) { \
+ LOG(("Overran input")); \
+ continue; \
+ } \
+ *p++ = '\0'; \
+}
+
+#define SKIP_WS { \
+ for (; *p && isspace(*p); p++) \
+ ; /* do nothing */ \
+ if (p >= end) { \
+ LOG(("Overran input")); \
+ continue; \
+ } \
+}
+
+ while (fgets(s, sizeof s, fp)) {
+ char *p = s, *end = 0,
+ *domain, *path, *name, *value, *scheme, *url,
+ *comment;
+ int version, domain_specified, path_specified,
+ secure, no_destroy;
+ time_t expires, last_used;
+
+ if(s[0] == 0 || s[0] == '#')
+ /* Skip blank lines or comments */
+ continue;
+
+ s[strlen(s) - 1] = '\0'; /* lose terminating newline */
+ end = s + strlen(s);
+
+ /* Look for file version first
+ * (all input is ignored until this is read)
+ */
+ if (strncasecmp(s, "Version:", 8) == 0) {
+ FIND_WS; SKIP_WS; file_version = atoi(p);
+
+ if (file_version != COOKIE_FILE_VERSION) {
+ LOG(("Unknown Cookie file version"));
+ break;
+ }
+ } else if (file_version == 0) {
+ /* Haven't yet seen version; skip this input */
+ continue;
+ }
+
+ /* One cookie/line */
+
+ /* Parse input */
+ FIND_WS; version = atoi(s);
+ SKIP_WS; domain = p; FIND_WS;
+ SKIP_WS; domain_specified = atoi(p); FIND_WS;
+ SKIP_WS; path = p; FIND_WS;
+ SKIP_WS; path_specified = atoi(p); FIND_WS;
+ SKIP_WS; secure = atoi(p); FIND_WS;
+ SKIP_WS; expires = (time_t)atoi(p); FIND_WS;
+ SKIP_WS; last_used = (time_t)atoi(p); FIND_WS;
+ SKIP_WS; no_destroy = atoi(p); FIND_WS;
+ SKIP_WS; name = p; FIND_WS;
+ SKIP_WS; value = p; FIND_WS;
+ SKIP_WS; scheme = p; FIND_WS;
+ SKIP_WS; url = p; FIND_WS;
+
+ /* Comment may have no content, so don't
+ * use macros as they'll break */
+ for (; *p && isspace(*p); p++)
+ ; /* do nothing */
+ comment = p;
+
+ assert(p <= end);
+
+ /* Now create cookie */
+ struct cookie *c = malloc(sizeof(struct cookie));
+ if (!c)
+ break;
+
+ c->name = strdup(name);
+ c->value = strdup(value);
+ c->comment = strdup(comment);
+ c->domain_from_set = domain_specified;
+ c->domain = strdup(domain);
+ c->path_from_set = path_specified;
+ c->path = strdup(path);
+ c->expires = expires;
+ c->last_used = last_used;
+ c->secure = secure;
+ c->version = version;
+ c->no_destroy = no_destroy;
+
+ if (!(c->name && c->value && c->comment &&
+ c->domain && c->path)) {
+ urldb_free_cookie(c);
+ break;
+ }
+
+ /* And insert it into database */
+ if (!urldb_insert_cookie(c, scheme, url)) {
+ /* Cookie freed for us */
+ break;
+ }
+ }
+
+#undef SKIP_WS
+#undef FIND_WS
+
+ fclose(fp);
+}
+
+/**
+ * Save persistent cookies to file
+ *
+ * \param filename Path to save to
+ */
+void urldb_save_cookies(const char *filename)
+{
+ FILE *fp;
+
+ assert(filename);
+
+ fp = fopen(filename, "w");
+ if (!fp)
+ return;
+
+ fprintf(fp, "# >%s\n", filename);
+ fprintf(fp, "# NetSurf cookies file.\n"
+ "#\n"
+ "# Lines starting with a '#' are comments, "
+ "blank lines are ignored.\n"
+ "#\n"
+ "# All lines prior to \"Version: %d\" are discarded.\n"
+ "#\n"
+ "# Version\tDomain\tDomain from Set-Cookie\tPath\t"
+ "Path from Set-Cookie\tSecure\tExpires\tLast used\t"
+ "No destroy\tName\tValue\tScheme\tURL\tComment\n",
+ COOKIE_FILE_VERSION);
+ fprintf(fp, "Version: %d\n", COOKIE_FILE_VERSION);
+
+
+ urldb_save_cookie_hosts(fp, &db_root);
+
+ fclose(fp);
+}
+
+/**
+ * Save a host subtree's cookies
+ *
+ * \param fp File pointer to write to
+ * \param parent Parent host
+ */
+void urldb_save_cookie_hosts(FILE *fp, struct host_part *parent)
+{
+ assert(fp && parent);
+
+ urldb_save_cookie_paths(fp, &parent->paths);
+
+ for (struct host_part *h = parent->children; h; h = h->next)
+ urldb_save_cookie_hosts(fp, h);
+}
+
+/**
+ * Save a path subtree's cookies
+ *
+ * \param fp File pointer to write to
+ * \param parent Parent path
+ */
+void urldb_save_cookie_paths(FILE *fp, struct path_data *parent)
+{
+ time_t now = time(NULL);
+
+ assert(fp && parent);
+
+ if (parent->cookies) {
+ for (struct cookie *c = parent->cookies; c; c = c->next) {
+
+ if (c->expires < now)
+ /* Skip expired cookies */
+ continue;
+
+ fprintf(fp, "%d\t%s\t%d\t%s\t%d\t%d\t%d\t%d\t%d\t"
+ "%s\t%s\t%s\t%s\t%s\n",
+ c->version, c->domain,
+ c->domain_from_set, c->path,
+ c->path_from_set, c->secure,
+ (int)c->expires, (int)c->last_used,
+ c->no_destroy, c->name, c->value,
+ parent->scheme ? parent->scheme
+ : "unused",
+ parent->url ? parent->url : "unused",
+ c->comment ? c->comment : "");
+ }
+ }
+
+ for (struct path_data *p = parent->children; p; p = p->next)
+ urldb_save_cookie_paths(fp, p);
+}
+
#ifdef TEST
int main(void)
Modified: branches/jmb/cookies/content/urldb.h
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.h?rev=2624&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.h (original)
+++ branches/jmb/cookies/content/urldb.h Sun Jun 18 22:17:48 2006
@@ -69,5 +69,7 @@
/* Cookies */
bool urldb_set_cookie(const char *header, const char *url);
char *urldb_get_cookie(const char *url, const char *referer);
+void urldb_load_cookies(const char *filename);
+void urldb_save_cookies(const char *filename);
#endif
Modified: branches/jmb/cookies/riscos/gui.c
URL: http://svn.semichrome.net/branches/jmb/cookies/riscos/gui.c?rev=2624&r1=2...
==============================================================================
--- branches/jmb/cookies/riscos/gui.c (original)
+++ branches/jmb/cookies/riscos/gui.c Sun Jun 18 22:17:48 2006
@@ -367,6 +367,7 @@
bitmap_initialise_memory();
urldb_load(option_url_path);
+ urldb_load_cookies(option_cookie_file);
nsdir_temp = getenv("NetSurf$Dir");
if (!nsdir_temp)
@@ -724,6 +725,7 @@
void gui_quit(void)
{
bitmap_quit();
+ urldb_save_cookies(option_cookie_jar);
urldb_save(option_url_save);
ro_gui_window_quit();
ro_gui_global_history_save();
16 years, 7 months
r2623 jmb - /branches/jmb/cookies/content/urldb.c
by netsurf@semichrome.net
Author: jmb
Date: Sat Jun 17 16:26:11 2006
New Revision: 2623
URL: http://svn.semichrome.net?rev=2623&view=rev
Log:
Fix domain cookies
Modified:
branches/jmb/cookies/content/urldb.c
Modified: branches/jmb/cookies/content/urldb.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.c?rev=2623&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.c (original)
+++ branches/jmb/cookies/content/urldb.c Sat Jun 17 16:26:11 2006
@@ -2376,8 +2376,8 @@
/* cookie has expired => ignore */
continue;
- if (strncmp(c->path, path, strlen(c->path)) != 0 ||
- strlen(c->path) <= strlen(path))
+ /* Ensure cookie path is a prefix of the resource */
+ if (strncmp(c->path, path, strlen(c->path)) != 0)
/* paths don't match => ignore */
continue;
16 years, 7 months
r2622 jmb - in /branches/jmb/cookies: ./ content/fetch.c content/urldb.c content/urldb.h utils/url.c utils/url.h
by netsurf@semichrome.net
Author: jmb
Date: Sat Jun 17 11:14:32 2006
New Revision: 2622
URL: http://svn.semichrome.net?rev=2622&view=rev
Log:
Branch cookies work.
Added:
branches/jmb/cookies/
- copied from r2621, trunk/netsurf/
Modified:
branches/jmb/cookies/content/fetch.c
branches/jmb/cookies/content/urldb.c
branches/jmb/cookies/content/urldb.h
branches/jmb/cookies/utils/url.c
branches/jmb/cookies/utils/url.h
Modified: branches/jmb/cookies/content/fetch.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/fetch.c?rev=2622&r...
==============================================================================
--- branches/jmb/cookies/content/fetch.c (original)
+++ branches/jmb/cookies/content/fetch.c Sat Jun 17 11:14:32 2006
@@ -70,6 +70,7 @@
char *host; /**< Host part of URL. */
char *location; /**< Response Location header, or 0. */
unsigned long content_length; /**< Response Content-Length, or 0. */
+ char *cookie_string; /**< Cookie string for this fetch */
char *realm; /**< HTTP Auth Realm */
char *post_urlenc; /**< Url encoded POST string, or 0. */
struct curl_httppost *post_multipart; /**< Multipart post data, or 0. */
@@ -356,6 +357,7 @@
fetch->host = host;
fetch->location = 0;
fetch->content_length = 0;
+ fetch->cookie_string = 0;
fetch->realm = 0;
fetch->post_urlenc = 0;
fetch->post_multipart = 0;
@@ -635,14 +637,18 @@
SETOPT(CURLOPT_HTTPGET, 1L);
}
if (f->cookies) {
- if (option_cookie_file)
- SETOPT(CURLOPT_COOKIEFILE, option_cookie_file);
- if (option_cookie_jar)
- SETOPT(CURLOPT_COOKIEJAR, option_cookie_jar);
- } else {
- SETOPT(CURLOPT_COOKIEFILE, 0);
- SETOPT(CURLOPT_COOKIEJAR, 0);
- }
+ f->cookie_string = urldb_get_cookie(f->url, f->referer);
+ if (f->cookie_string)
+ SETOPT(CURLOPT_COOKIE, f->cookie_string);
+// if (option_cookie_file)
+// SETOPT(CURLOPT_COOKIEFILE, option_cookie_file);
+// if (option_cookie_jar)
+// SETOPT(CURLOPT_COOKIEJAR, option_cookie_jar);
+ }
+// else {
+// SETOPT(CURLOPT_COOKIEFILE, 0);
+// SETOPT(CURLOPT_COOKIEJAR, 0);
+// }
#ifdef WITH_AUTH
if ((auth = urldb_get_auth_details(f->url)) != NULL) {
SETOPT(CURLOPT_HTTPAUTH, CURLAUTH_ANY);
@@ -771,6 +777,7 @@
free(f->host);
free(f->referer);
free(f->location);
+ free(f->cookie_string);
free(f->realm);
if (f->headers)
curl_slist_free_all(f->headers);
@@ -1175,6 +1182,10 @@
f->cachedata.last_modified =
curl_getdate(&data[i], NULL);
}
+ } else if (11 < size && strncasecmp(data, "Set-Cookie:", 11) == 0) {
+ /* extract Set-Cookie header */
+ SKIP_ST(11);
+ urldb_set_cookie(&data[i], f->url);
}
return size;
Modified: branches/jmb/cookies/content/urldb.c
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.c?rev=2622&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.c (original)
+++ branches/jmb/cookies/content/urldb.c Sat Jun 17 11:14:32 2006
@@ -77,6 +77,9 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
+
+#include <curl/curl.h>
+
#include "netsurf/image/bitmap.h"
#include "netsurf/content/urldb.h"
#include "netsurf/desktop/options.h"
@@ -92,7 +95,11 @@
char *name; /**< Cookie name */
char *value; /**< Cookie value */
char *comment; /**< Cookie comment */
- time_t expires; /**< Expiry timestamp, or 0 for session */
+ bool domain_from_set; /**< Domain came from Set-Cookie: header */
+ char *domain; /**< Domain */
+ bool path_from_set; /**< Path came from Set-Cookie: header */
+ char *path; /**< Path */
+ time_t expires; /**< Expiry timestamp, or 1 for session */
time_t last_used; /**< Last used time */
bool secure; /**< Only send for HTTPS requests */
enum { COOKIE_NETSCAPE = 0,
@@ -102,6 +109,7 @@
bool no_destroy; /**< Never destroy this cookie,
* unless it's expired */
+ struct cookie *prev; /**< Previous in list */
struct cookie *next; /**< Next in list */
};
@@ -229,6 +237,13 @@
const char *b);
static int urldb_search_match_prefix(const struct host_part *a,
const char *b);
+
+/* Cookies */
+static struct cookie *urldb_parse_cookie(const char *url,
+ const char *cookie);
+static void urldb_free_cookie(struct cookie *c);
+static bool urldb_concat_cookie(struct cookie *c, int *used,
+ int *alloc, char **buf);
/** Root database handle */
static struct host_part db_root;
@@ -2242,6 +2257,674 @@
return root;
}
+/**
+ * Retrieve cookies for an URL
+ *
+ * \param url URL being fetched
+ * \param referer Referring resource, or NULL
+ * \return Cookies string for libcurl (on heap), or NULL on error/no cookies
+ *
+ * \todo Handle unvalidated fetches
+ */
+char *urldb_get_cookie(const char *url, const char *referer)
+{
+ const struct path_data *p, *q;
+ const struct host_part *h;
+ struct cookie *c;
+ int count = 0, version = COOKIE_RFC2965;
+ int ret_alloc = 4096, ret_used = 1;
+ char *path;
+ char *ret;
+ time_t now;
+ url_func_result res;
+
+ assert(url);
+
+// LOG(("%s : %s", url, referer));
+
+// if (referer)
+// /* No unvalidated fetches for now */
+// return NULL;
+
+ urldb_add_url(url);
+
+ p = urldb_find_url(url);
+ if (!p)
+ return NULL;
+
+ ret = malloc(ret_alloc);
+ if (!ret)
+ return NULL;
+
+ ret[0] = '\0';
+
+ res = url_path(url, &path);
+ if (res != URL_FUNC_OK) {
+ free(ret);
+ return NULL;
+ }
+
+ now = time(NULL);
+
+ /* Consider all cookies associated with this exact path */
+ for (c = p->cookies; c; c = c->next) {
+ if (c->expires != 1 && c->expires < now)
+ /* cookie has expired => ignore */
+ continue;
+
+ if (!urldb_concat_cookie(c, &ret_used, &ret_alloc, &ret)) {
+ free(path);
+ free(ret);
+ return NULL;
+ }
+
+ if (c->version < (unsigned int)version)
+ version = c->version;
+
+ c->last_used = now;
+
+ count++;
+ }
+
+// LOG(("%s", ret));
+
+ /* Now consider cookies whose paths prefix-match ours */
+ for (; p; p = p->parent) {
+ /* Find parent directory's path entry */
+ for (q = p->children; q; q = q->next)
+ if (strlen(q->segment) == 0)
+ break;
+
+ if (q && q->cookies) {
+ for (c = q->cookies; c; c = c->next) {
+// LOG(("%p: %s=%s", c, c->name, c->value));
+ if (c->expires != 1 && c->expires < now)
+ /* cookie has expired => ignore */
+ continue;
+
+ if (!urldb_concat_cookie(c, &ret_used,
+ &ret_alloc, &ret)) {
+ free(path);
+ free(ret);
+ return NULL;
+ }
+
+ if (c->version < (unsigned int)version)
+ version = c->version;
+
+ c->last_used = now;
+
+ count++;
+ }
+ }
+
+ if (!p->parent) {
+ /* No parent, so bail here. This can't go in the
+ * loop exit condition as we want to process the
+ * top-level node, too */
+ break;
+ }
+ }
+
+// LOG(("%s", ret));
+
+ /* Finally consider domain cookies for hosts which domain match ours */
+ for (h = (const struct host_part *)p; h && h != &db_root;
+ h = h->parent) {
+ for (c = h->paths.cookies; c; c = c->next) {
+ if (c->expires != 1 && c->expires < now)
+ /* cookie has expired => ignore */
+ continue;
+
+ if (strncmp(c->path, path, strlen(c->path)) != 0 ||
+ strlen(c->path) <= strlen(path))
+ /* paths don't match => ignore */
+ continue;
+
+ if (!urldb_concat_cookie(c, &ret_used, &ret_alloc,
+ &ret)) {
+ free(path);
+ free(ret);
+ return NULL;
+ }
+
+ if (c->version < (unsigned int)version)
+ version = c->version;
+
+ c->last_used = now;
+
+ count++;
+ }
+ }
+
+// LOG(("%s", ret));
+
+ if (count == 0) {
+ /* No cookies found */
+ free(path);
+ free(ret);
+ return NULL;
+ }
+
+ /* and build output string */
+ {
+ char *temp = malloc(12 + ret_used);
+ if (!temp) {
+ free(path);
+ free(ret);
+ return NULL;
+ }
+ sprintf(temp, "$Version=%d%s", version, ret);
+ free(path);
+ free(ret);
+ ret = temp;
+ }
+
+ return ret;
+}
+
+/**
+ * Parse Set-Cookie header and insert cookie(s) into database
+ *
+ * \param header Header to parse, with Set-Cookie: stripped
+ * \param url URL being fetched
+ * \return true on success, false otherwise
+ */
+bool urldb_set_cookie(const char *header, const char *url)
+{
+ char cookie[8192];
+ const char *cur = header, *comma, *end;
+ char *path, *host, *scheme, *urlt;
+ url_func_result res;
+
+ assert(url && header);
+
+// LOG(("'%s' : '%s'", url, header));
+
+ /* strip fragment */
+ urlt = strdup(url);
+ scheme = strchr(urlt, '#');
+ if (scheme)
+ *scheme = '\0';
+
+ res = url_scheme(url, &scheme);
+ if (res != URL_FUNC_OK) {
+ free(urlt);
+ return false;
+ }
+
+ res = url_path(url, &path);
+ if (res != URL_FUNC_OK) {
+ free(scheme);
+ free(urlt);
+ return false;
+ }
+
+ res = url_host(url, &host);
+ if (res != URL_FUNC_OK) {
+ free(path);
+ free(scheme);
+ free(urlt);
+ return false;
+ }
+
+ end = cur + strlen(cur) - 2 /* Trailing CRLF */;
+
+ /* Find comma, if any */
+ comma = strchr(cur, ',');
+ if (comma) {
+ /* Check for Expires avpair: Wdy, DD-Mon-YYYY HH:MM:SS GMT */
+ /* Irritatingly, we can't suppress assignment as it results
+ * in a return value of 0. Therefore we simply provide a
+ * scratch buffer for sscanf to write to.
+ * Additionally, date parts of the form "DD Mon YYYY" have
+ * been seen in the wild, so we accept them too even though
+ * they're not strictly correct - it's more important to
+ * match something that looks like an Expires avpair than
+ * be strict here (as we're simply looking for the end of
+ * the cookie declaration) */
+ char buf[12];
+ if (sscanf(comma - 3, "%3[A-Za-z], "
+ "%2[0-9]%1[ -]%3[A-Za-z]%1[ -]%4[0-9] "
+ "%2[0-9]:%2[0-9]:%2[0-9] GMT",
+ buf, buf, buf, buf, buf,
+ buf, buf, buf, buf) == 9) {
+ /* Part of Expires avpair => look for next comma */
+ comma = strchr(comma + 1, ',');
+ } else {
+ LOG(("sscanf failed"));
+ }
+ }
+
+ if (!comma) {/* Yes, if; not else - Expires check may modify comma */
+ /* No comma => 1 cookie in this header */
+ comma = end;
+ }
+
+ do {
+ struct cookie *c, *d;
+ const struct host_part *h;
+ struct path_data *p;
+ char *dot;
+
+ snprintf(cookie, sizeof cookie, "%.*s", comma - cur, cur);
+
+ c = urldb_parse_cookie(url, cookie);
+ if (!c) {
+ /* failed => stop parsing */
+ goto error;
+ }
+
+ /* validate cookie */
+
+ /* Cookie path must be a prefix of URL path */
+ if (strncmp(c->path, path, strlen(c->path)) != 0 ||
+ strlen(c->path) > strlen(path)) {
+ urldb_free_cookie(c);
+ goto error;
+ }
+
+ /* Cookie domain must contain embedded dots */
+ dot = strchr(c->domain + 1, '.');
+ if (!dot || *(dot + 1) == '\0') {
+ /* no embedded dots */
+ urldb_free_cookie(c);
+ goto error;
+ }
+
+ /* Domain match fetch host with cookie domain */
+ if (strcasecmp(host, c->domain) != 0) {
+ int hlen, dlen, i;
+
+ if (host[0] >= '0' && host[0] <= '9') {
+ /* IP address, so no partial match */
+ urldb_free_cookie(c);
+ goto error;
+ }
+
+ hlen = strlen(host);
+ dlen = strlen(c->domain);
+
+ if (hlen <= dlen) {
+ /* Partial match not possible */
+ urldb_free_cookie(c);
+ goto error;
+ }
+
+ if (strcasecmp(host + (hlen - dlen), c->domain)) {
+ urldb_free_cookie(c);
+ goto error;
+ }
+
+ /* Ensure H contains no dots - wrong */
+// for (i = 0; i < (hlen - dlen); i++)
+// if (host[i] == '.') {
+// urldb_free_cookie(c);
+// goto error;
+// }
+ }
+
+ /* Now insert into database */
+ if (c->domain[0] == '.') {
+ h = urldb_search_find(
+ search_trees[tolower(c->domain[1]) - 'a' +
+ ST_DN],
+ c->domain + 1);
+ if (!h) {
+ h = urldb_add_host(c->domain + 1);
+ if (!h) {
+ urldb_free_cookie(c);
+ goto error;
+ }
+ }
+
+ p = &h->paths;
+ } else {
+ if (c->domain[0] >= '0' && c->domain[0] <= '9')
+ h = urldb_search_find(search_trees[ST_IP],
+ c->domain);
+ else
+ h = urldb_search_find(search_trees[
+ tolower(c->domain[0]) -
+ 'a' + ST_DN],
+ c->domain);
+
+ if (!h) {
+ h = urldb_add_host(c->domain);
+ if (!h) {
+ urldb_free_cookie(c);
+ goto error;
+ }
+ }
+
+ /* find path */
+ p = urldb_add_path(scheme, 0, h,
+ c->path, NULL, urlt);
+ if (!p) {
+ urldb_free_cookie(c);
+ goto error;
+ }
+ }
+
+ /* add cookie */
+ for (d = p->cookies; d; d = d->next) {
+ if (!strcmp(d->domain, c->domain) &&
+ !strcmp(d->path, c->path) &&
+ !strcmp(d->name, c->name))
+ break;
+ }
+
+ if (d) {
+ if (c->expires == 0) {
+ /* remove cookie */
+ if (d->next)
+ d->next->prev = d->prev;
+ if (d->prev)
+ d->prev->next = d->next;
+ else
+ p->cookies = d->next;
+ urldb_free_cookie(d);
+ urldb_free_cookie(c);
+ } else {
+ /* replace d with c */
+ c->prev = d->prev;
+ c->next = d->next;
+ if (c->next)
+ c->next->prev = c;
+ if (c->prev)
+ c->prev->next = c;
+ else
+ p->cookies = c;
+ urldb_free_cookie(d);
+// LOG(("%p: %s=%s", c, c->name, c->value));
+ }
+ } else {
+ c->prev = NULL;
+ c->next = p->cookies;
+ if (p->cookies)
+ p->cookies->prev = c;
+ p->cookies = c;
+// LOG(("%p: %s=%s", c, c->name, c->value));
+ }
+
+ cur = comma + 1;
+ if (cur < end) {
+ comma = strchr(cur, ',');
+ if (comma) {
+ /* Check if it's an Expires avpair */
+ char buf[12];
+ if (sscanf(comma - 3, "%3[A-Za-z], "
+ "%2[0-9]%1[ -]%3[A-Za-z]"
+ "%1[ -]%4[0-9] "
+ "%2[0-9]:%2[0-9]:%2[0-9] "
+ "GMT",
+ buf, buf, buf, buf, buf,
+ buf, buf, buf, buf) == 9) {
+ /* Part of Expires avpair =>
+ * look for next comma */
+ comma = strchr(comma + 1, ',');
+ } else {
+ LOG(("sscanf failed"));
+ }
+ }
+ if (!comma)
+ comma = end;
+ }
+ } while (comma && cur < end);
+
+ free(host);
+ free(path);
+ free(scheme);
+ free(urlt);
+
+ return true;
+
+error:
+ free(host);
+ free(path);
+ free(scheme);
+ free(urlt);
+
+ return false;
+}
+
+/**
+ * Parse a cookie
+ *
+ * \param url URL being fetched
+ * \param cookie Cookie string
+ * \return Pointer to cookie structure (on heap, caller frees) or NULL
+ */
+struct cookie *urldb_parse_cookie(const char *url, const char *cookie)
+{
+ struct cookie *c;
+ char name[1024], value[4096];
+ const char *cur = cookie, *semi, *end;
+ time_t max_age = 0, expires = 0;
+ bool had_max_age = false, had_expires = false;
+ url_func_result res;
+
+ c = calloc(1, sizeof(struct cookie));
+ if (!c)
+ return NULL;
+
+ end = cur + strlen(cur);
+
+ /* Find semicolon */
+ semi = strchr(cur, ';');
+ if (!semi)
+ semi = end;
+
+ /* process name-value pairs */
+ do {
+ char *equals = strchr(cur, '=');
+ int vlen;
+
+ name[0] = value[0] = '\0';
+
+ if (equals && equals < semi) {
+ char *n, *v;
+ /* name = value */
+ if (sscanf(cur, "%1023[^=]=%4095[^;]",
+ name, value) != 2)
+ break;
+
+ /* Strip whitespace from start of name */
+ for (n = name; *n; n++) {
+ if (*n != ' ' && *n != '\t')
+ break;
+ }
+
+ /* Strip whitespace from end of name */
+ for (vlen = strlen(name); vlen; vlen--) {
+ if (name[vlen] == ' ' || name[vlen] == '\t')
+ name[vlen] = '\0';
+ else
+ break;
+ }
+
+ /* Strip whitespace from start of value */
+ for (v = value; *v; v++) {
+ if (*v != ' ' && *v != '\t')
+ break;
+ }
+ /* Strip quote from start of value */
+ if (*v == '"')
+ v++;
+
+ /* Strip whitespace from end of value */
+ for (vlen = strlen(value); vlen; vlen--) {
+ if (value[vlen] == ' ' ||
+ value[vlen] == '\t')
+ value[vlen] = '\0';
+ else
+ break;
+ }
+ /* Strip quote from end of value */
+ if (value[vlen] == '"')
+ value[vlen] = '\0';
+
+ if (!c->comment &&
+ strcasecmp(n, "Comment") == 0) {
+ c->comment = strdup(v);
+ if (!c->comment)
+ break;
+ } else if (!c->domain &&
+ strcasecmp(n, "Domain") == 0) {
+ if (v[0] == '.') {
+ /* Domain must start with a dot */
+ c->domain_from_set = true;
+ c->domain = strdup(v);
+ if (!c->domain)
+ break;
+ }
+ } else if (strcasecmp(n, "Max-Age") == 0) {
+ had_max_age = true;
+ max_age = time(NULL) + atoi(v);
+ } else if (!c->path &&
+ strcasecmp(n, "Path") == 0) {
+ c->path_from_set = true;
+ c->path = strdup(v);
+ if (!c->path)
+ break;
+ } else if (strcasecmp(n, "Version") == 0) {
+ c->version = atoi(v);
+ } else if (strcasecmp(n, "Expires") == 0) {
+ had_expires = true;
+ expires = curl_getdate(v, NULL);
+ } else if (!c->name) {
+ c->name = strdup(n);
+ c->value = strdup(v);
+ if (!c->name || !c->value)
+ break;
+ }
+ } else {
+ char *n;
+
+ /* name */
+ if (sscanf(cur, "%1023[^;] ", name) != 1)
+ break;
+
+ /* Strip whitespace from start of name */
+ for (n = name; *n; n++) {
+ if (*n != ' ' && *n != '\t')
+ break;
+ }
+
+ /* Strip whitespace from end of name */
+ for (vlen = strlen(name); vlen; vlen--) {
+ if (name[vlen] == ' ' || name[vlen] == '\t')
+ name[vlen] = '\0';
+ else
+ break;
+ }
+
+ if (strcasecmp(n, "Secure") == 0)
+ c->secure = true;
+ }
+
+ cur = semi + 1;
+ if (cur < end) {
+ semi = strchr(cur, ';');
+ if (!semi)
+ semi = end;
+ }
+ } while(semi && cur < end);
+
+ if (cur < end) {
+ /* parsing failed */
+ urldb_free_cookie(c);
+ return NULL;
+ }
+
+ /* Now fix-up default values */
+ if (!c->domain) {
+ res = url_host(url, &c->domain);
+ if (res != URL_FUNC_OK) {
+ urldb_free_cookie(c);
+ return NULL;
+ }
+ }
+
+ if (!c->path) {
+ res = url_path(url, &c->path);
+ if (res != URL_FUNC_OK) {
+ urldb_free_cookie(c);
+ return NULL;
+ }
+ }
+
+ if (had_max_age && had_expires) {
+ /* Max age takes precedence iff version 1 or later */
+ c->expires =
+ c->version == COOKIE_NETSCAPE ? expires : max_age;
+ } else if (had_max_age) {
+ c->expires = max_age;
+ } else if (had_expires) {
+ c->expires = expires;
+ } else
+ c->expires = 1;
+
+ return c;
+}
+
+/**
+ * Free a cookie
+ *
+ * \param c The cookie to free
+ */
+void urldb_free_cookie(struct cookie *c)
+{
+ free(c->comment);
+ free(c->domain);
+ free(c->path);
+ free(c->name);
+ free(c->value);
+ free(c);
+}
+
+/**
+ * Concatenate a cookie into the provided buffer
+ *
+ * \param c Cookie to concatenate
+ * \param used Pointer to amount of buffer used (updated)
+ * \param alloc Pointer to allocated size of buffer (updated)
+ * \param buf Pointer to Pointer to buffer (updated)
+ * \return true on success, false on memory exhaustion
+ */
+bool urldb_concat_cookie(struct cookie *c, int *used, int *alloc, char **buf)
+{
+ int clen = 2 + strlen(c->name) + 1 + strlen(c->value) +
+ (c->path_from_set ?
+ 8 + strlen(c->path) : 0) +
+ (c->domain_from_set ?
+ 10 + strlen(c->domain) : 0);
+
+ if (*used + clen >= *alloc) {
+ char *temp = realloc(*buf, *alloc + 4096);
+ if (!temp) {
+ return false;
+ }
+ *buf = temp;
+ *alloc += 4096;
+ }
+
+ /** \todo Quote value strings iff version > 0 */
+ sprintf(*buf + *used - 1, "; %s=%s%s%s%s%s",
+ c->name, c->value,
+ (c->path_from_set ? "; $Path=" : "" ),
+ (c->path_from_set ? c->path : "" ),
+// (c->path_from_set ? "\"" : ""),
+ (c->domain_from_set ? "; $Domain=" : ""),
+ (c->domain_from_set ? c->domain : "")
+// ,(c->domain_from_set ? "\"" : "")
+ );
+ *used += clen;
+
+ return true;
+}
+
+
#ifdef TEST
int main(void)
{
Modified: branches/jmb/cookies/content/urldb.h
URL: http://svn.semichrome.net/branches/jmb/cookies/content/urldb.h?rev=2622&r...
==============================================================================
--- branches/jmb/cookies/content/urldb.h (original)
+++ branches/jmb/cookies/content/urldb.h Sat Jun 17 11:14:32 2006
@@ -66,4 +66,8 @@
/* Debug */
void urldb_dump(void);
+/* Cookies */
+bool urldb_set_cookie(const char *header, const char *url);
+char *urldb_get_cookie(const char *url, const char *referer);
+
#endif
Modified: branches/jmb/cookies/utils/url.c
URL: http://svn.semichrome.net/branches/jmb/cookies/utils/url.c?rev=2622&r1=26...
==============================================================================
--- branches/jmb/cookies/utils/url.c (original)
+++ branches/jmb/cookies/utils/url.c Sat Jun 17 11:14:32 2006
@@ -677,6 +677,58 @@
/**
+ * Extract path segment from an URL
+ *
+ * \param url an absolute URL
+ * \param result pointer to pointer to buffer to hold result
+ * \return URL_FUNC_OK on success
+ */
+
+url_func_result url_path(const char *url, char **result)
+{
+ int m, path_len = 0;
+ regmatch_t match[10];
+
+ (*result) = 0;
+
+ m = regexec(&url_re, url, 10, match, 0);
+ if (m) {
+ LOG(("url '%s' failed to match regex", url));
+ return URL_FUNC_FAILED;
+ }
+ if (match[URL_RE_SCHEME].rm_so == -1 ||
+ match[URL_RE_AUTHORITY].rm_so == -1)
+ return URL_FUNC_FAILED;
+
+ if (match[URL_RE_PATH].rm_so != -1)
+ path_len = match[URL_RE_PATH].rm_eo -
+ match[URL_RE_PATH].rm_so;
+
+ (*result) = malloc((path_len ? path_len : 1) + 1);
+ if (!(*result)) {
+ LOG(("malloc failed"));
+ return URL_FUNC_NOMEM;
+ }
+
+ m = 0;
+ if (path_len > 1) {
+ strncpy((*result), url + match[URL_RE_PATH].rm_so,
+ path_len);
+ for (; path_len != 0 && (*result)[m + path_len - 1] != '/';
+ path_len--)
+ /* do nothing */;
+ m += path_len;
+ }
+ else
+ (*result)[m++] = '/';
+
+ (*result)[m] = '\0';
+
+ return URL_FUNC_OK;
+}
+
+
+/**
* Attempt to find a nice filename for a URL.
*
* \param url an absolute URL
Modified: branches/jmb/cookies/utils/url.h
URL: http://svn.semichrome.net/branches/jmb/cookies/utils/url.h?rev=2622&r1=26...
==============================================================================
--- branches/jmb/cookies/utils/url.h (original)
+++ branches/jmb/cookies/utils/url.h Sat Jun 17 11:14:32 2006
@@ -30,6 +30,7 @@
url_func_result url_canonical_root(const char *url, char **result);
url_func_result url_strip_lqf(const char *url, char **result);
url_func_result url_plq(const char *url, char **result);
+url_func_result url_path(const char *url, char **result);
char *path_to_url(const char *path);
char *url_to_path(const char *url);
16 years, 7 months