summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJorge Arellano Cid <jcid@dillo.org>2010-01-18 08:55:05 -0300
committerJorge Arellano Cid <jcid@dillo.org>2010-01-18 08:55:05 -0300
commita593fe8b62e148da741e8ce054f4b3bedcf81403 (patch)
tree42c11938246fb6b989c1df0f36794f3759fbb9b7
parent6c118637ea99f74c49803ac528d70a38c54bbd64 (diff)
parentaa10e22a8530fcd4e4b18540a73ffc22c8d4610e (diff)
merge
-rw-r--r--ChangeLog3
-rw-r--r--configure.in1
-rw-r--r--dillorc3
-rw-r--r--doc/Cookies.txt6
-rw-r--r--dpi/cookies.c1072
-rw-r--r--dpid/dpid.c6
-rw-r--r--dw/style.cc2
-rw-r--r--dw/style.hh4
-rw-r--r--dw/table.hh24
-rw-r--r--dw/textblock.cc4
-rw-r--r--src/IO/Makefile.am1
-rw-r--r--src/IO/dpi.c21
-rw-r--r--src/cache.c11
-rw-r--r--src/cookies.c42
-rw-r--r--src/cookies.h3
-rw-r--r--src/css.cc8
-rw-r--r--src/doctree.hh48
-rw-r--r--src/styleengine.cc61
-rw-r--r--src/styleengine.hh20
19 files changed, 649 insertions, 691 deletions
diff --git a/ChangeLog b/ChangeLog
index faebaae0..f5f4ad5b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -16,6 +16,7 @@ dillo-2.2 [??]
- Add support for CSS property list-style-position.
- Support border-width: thin | medium | thick.
- Fix CSS_SHORTHAND_DIRECTIONS case in CssParser.
+ - Add quirk to reset font properties in tables (fixes e.g. gmail).
Patch: Johannes Hofmann
+- Cleaned up system includes in dpid directory.
- Fixed CustProgressBox() for systems without weak symbols.
@@ -56,6 +57,8 @@ dillo-2.2 [??]
- Enable popup menu below bottom of page content (BUG#856).
- Handle JPEGs with CMYK color space.
- Allow keysyms in keysrc.
+ - Explicitly check installation bindir for dpid (BUG 930)
+ - General cookies overhaul.
Patches: corvid
+- Support for the letter-spacing property.
Patch: Johannes Hofmann, corvid
diff --git a/configure.in b/configure.in
index cec040b4..bd4bc80d 100644
--- a/configure.in
+++ b/configure.in
@@ -417,6 +417,7 @@ dnl --------------------
dnl
if test "x$enable_cookies" = "xno" ; then
CFLAGS="$CFLAGS -DDISABLE_COOKIES"
+ CXXFLAGS="$CXXFLAGS -DDISABLE_COOKIES"
fi
if test "x$enable_ipv6" = "xyes" ; then
CFLAGS="$CFLAGS -DENABLE_IPV6"
diff --git a/dillorc b/dillorc
index ce279bf6..33a4a40d 100644
--- a/dillorc
+++ b/dillorc
@@ -114,7 +114,8 @@
# Set the proxy information for http.
# Note that the http_proxy environment variable overrides this setting.
# WARNING: FTP and downloads plugins use wget. To use a proxy with them,
-# you will need to configure wget accordingly.
+# you will need to configure wget accordingly. See
+# http://www.gnu.org/software/wget/manual/html_node/Proxies.html
# http_proxy="http://localhost:8080/"
#(by default, no proxy is used)
diff --git a/doc/Cookies.txt b/doc/Cookies.txt
index c43cacc4..c46e5580 100644
--- a/doc/Cookies.txt
+++ b/doc/Cookies.txt
@@ -1,13 +1,15 @@
Jan 2002, Jörgen Viksell - jorgen.viksell@telia.com,
Jorge Arellano Cid --
-Last update: October 2008
+Last update: January 2010
==================
Cookies in Dillo
==================
-Supported: old Netscape style, RFC 2109, RFC 2965.
+Dillo's cookies implementation is guided by ongoing work by the HTTP State WG
+( http://www.ietf.org/dyn/wg/charter/httpstate-charter ) to specify current
+real-world cookies usage.
Cookies are handled by a dpi (plugin) which shares them between your
instances of Dillo.
diff --git a/dpi/cookies.c b/dpi/cookies.c
index cf0cecf0..207e3bba 100644
--- a/dpi/cookies.c
+++ b/dpi/cookies.c
@@ -13,19 +13,17 @@
*
*/
-/* Handling of cookies takes place here.
- * This implementation aims to follow RFC 2965:
- * http://www.ietf.org/rfc/rfc2965.txt
- */
-
-/*
- * TODO: Cleanup this code. Shorten some functions, order things,
- * add comments, remove leaks, etc.
- */
-
-/* TODO: this server is not assembling the received packets.
- * This means it currently expects dillo to send full dpi tags
- * within the socket; if that fails, everything stops.
+/* 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:
+ * http://www.ietf.org/mail-archive/web/http-state/current/msg00128.html
*/
#ifdef DISABLE_COOKIES
@@ -64,6 +62,7 @@ int main(void)
#define _MSG(...)
#define MSG(...) printf("[cookies dpi]: " __VA_ARGS__)
+#define DILLO_TIME_MAX ((time_t) ((1UL << (sizeof(time_t) * 8 - 1)) - 1))
/*
* a_List_add()
@@ -107,12 +106,9 @@ typedef struct {
char *domain;
char *path;
time_t expires_at;
- uint_t version;
- char *comment;
- char *comment_url;
bool_t secure;
bool_t session_only;
- Dlist *ports;
+ long last_used;
} CookieData_t;
typedef struct {
@@ -133,12 +129,13 @@ static int num_ccontrol = 0;
static int num_ccontrol_max = 1;
static CookieControlAction default_action = COOKIE_DENY;
+static long cookies_use_counter = 0;
static bool_t disabled;
static FILE *file_stream;
-static char *cookies_txt_header_str =
+static const char *const cookies_txt_header_str =
"# HTTP Cookie File\n"
-"# http://wp.netscape.com/newsref/std/cookie_spec.html\n"
-"# This is a generated file! Do not edit.\n\n";
+"# This is a generated file! Do not edit.\n"
+"# [domain TRUE path secure expiry_time name value]\n\n";
/*
@@ -147,12 +144,7 @@ static char *cookies_txt_header_str =
static CookieControlAction Cookies_control_check_domain(const char *domain);
static int Cookie_control_init(void);
-static void Cookies_parse_ports(int url_port, CookieData_t *cookie,
- const char *port_str);
-static char *Cookies_build_ports_str(CookieData_t *cookie);
-static char *Cookies_strip_path(const char *path);
static void Cookies_add_cookie(CookieData_t *cookie);
-static void Cookies_remove_cookie(CookieData_t *cookie);
static int Cookies_cmp(const void *a, const void *b);
/*
@@ -162,7 +154,7 @@ static int Cookie_node_cmp(const void *v1, const void *v2)
{
const CookieNode *n1 = v1, *n2 = v2;
- return strcmp(n1->domain, n2->domain);
+ return dStrcasecmp(n1->domain, n2->domain);
}
/*
@@ -173,7 +165,7 @@ static int Cookie_node_by_domain_cmp(const void *v1, const void *v2)
const CookieNode *node = v1;
const char *domain = v2;
- return strcmp(node->domain, domain);
+ return dStrcasecmp(node->domain, domain);
}
/*
@@ -181,7 +173,7 @@ static int Cookie_node_by_domain_cmp(const void *v1, const void *v2)
* with the optional 'init_str' as its content.
*/
static FILE *Cookies_fopen(const char *filename, const char *mode,
- char *init_str)
+ const char *init_str)
{
FILE *F_in;
int fd, rc;
@@ -220,15 +212,12 @@ static void Cookies_free_cookie(CookieData_t *cookie)
dFree(cookie->value);
dFree(cookie->domain);
dFree(cookie->path);
- dFree(cookie->comment);
- dFree(cookie->comment_url);
- dList_free(cookie->ports);
dFree(cookie);
}
/*
* Initialize the cookies module
- * (The 'disabled' variable is writable only within Cookies_init)
+ * (The 'disabled' variable is writeable only within Cookies_init)
*/
static void Cookies_init()
{
@@ -238,7 +227,6 @@ static void Cookies_init()
#ifndef HAVE_LOCKF
struct flock lck;
#endif
- FILE *old_cookies_file_stream;
/* Default setting */
disabled = TRUE;
@@ -256,7 +244,7 @@ static void Cookies_init()
dFree(filename);
if (!file_stream) {
- MSG("ERROR: Can't open ~/.dillo/cookies.txt, disabling cookies\n");
+ MSG("ERROR: Can't open ~/.dillo/cookies.txt; disabling cookies\n");
return;
}
@@ -272,12 +260,12 @@ static void Cookies_init()
disabled = (fcntl(fileno(file_stream), F_SETLK, &lck) == -1);
#endif
if (disabled) {
- MSG("The cookies file has a file lock: disabling cookies!\n");
+ MSG("The cookies file has a file lock; disabling cookies!\n");
fclose(file_stream);
return;
}
- MSG("Enabling cookies as from cookiesrc...\n");
+ MSG("Enabling cookies as per cookiesrc...\n");
cookies = dList_new(32);
@@ -286,8 +274,7 @@ static void Cookies_init()
line[0] = '\0';
rc = fgets(line, LINE_MAXLEN, file_stream);
if (!rc && ferror(file_stream)) {
- MSG("Cookies1: Error while reading from cookies.txt: %s\n",
- dStrerror(errno));
+ MSG("Error while reading from cookies.txt: %s\n", dStrerror(errno));
break; /* bail out */
}
@@ -300,7 +287,7 @@ static void Cookies_init()
* pieces[0] The domain name
* pieces[1] TRUE/FALSE: is the domain a suffix, or a full domain?
* pieces[2] The path
- * pieces[3] Is the cookie unsecure or secure (TRUE/FALSE)
+ * pieces[3] TRUE/FALSE: is the cookie for secure use only?
* pieces[4] Timestamp of expire date
* pieces[5] Name of the cookie
* pieces[6] Value of the cookie
@@ -312,7 +299,6 @@ static void Cookies_init()
cookie = dNew0(CookieData_t, 1);
cookie->session_only = FALSE;
- cookie->version = 0;
cookie->domain = dStrdup(dStrsep(&line_marker, "\t"));
dStrsep(&line_marker, "\t"); /* we use domain always as sufix */
cookie->path = dStrdup(dStrsep(&line_marker, "\t"));
@@ -323,12 +309,11 @@ static void Cookies_init()
if (piece != NULL)
cookie->expires_at = (time_t) strtol(piece, NULL, 10);
cookie->name = dStrdup(dStrsep(&line_marker, "\t"));
- cookie->value = dStrdup(dStrsep(&line_marker, "\t"));
+ cookie->value = dStrdup(line_marker ? line_marker : "");
if (!cookie->domain || cookie->domain[0] == '\0' ||
!cookie->path || cookie->path[0] != '/' ||
- !cookie->name || cookie->name[0] == '\0' ||
- !cookie->value) {
+ !cookie->name || !cookie->value) {
MSG("Malformed line in cookies.txt file!\n");
Cookies_free_cookie(cookie);
continue;
@@ -346,86 +331,6 @@ static void Cookies_init()
Cookies_add_cookie(cookie);
}
}
-
- filename = dStrconcat(dGethomedir(), "/.dillo/cookies", NULL);
- if ((old_cookies_file_stream = fopen(filename, "r")) != NULL) {
- MSG("WARNING: Reading old cookies file ~/.dillo/cookies too\n");
-
- /* Get all lines in the file */
- while (!feof(old_cookies_file_stream)) {
- line[0] = '\0';
- rc = fgets(line, LINE_MAXLEN, old_cookies_file_stream);
- if (!rc && ferror(old_cookies_file_stream)) {
- MSG("Cookies2: Error while reading from cookies file: %s\n",
- dStrerror(errno));
- break; /* bail out */
- }
-
- /* Remove leading and trailing whitespaces */
- dStrstrip(line);
-
- if (line[0] != '\0') {
- /*
- * Split the row into pieces using a tab as the delimiter.
- * pieces[0] The version this cookie was set as (0 / 1)
- * pieces[1] The domain name
- * pieces[2] A comma separated list of accepted ports
- * pieces[3] The path
- * pieces[4] Is the cookie unsecure or secure (0 / 1)
- * pieces[5] Timestamp of expire date
- * pieces[6] Name of the cookie
- * pieces[7] Value of the cookie
- * pieces[8] Comment
- * pieces[9] Comment url
- */
- CookieControlAction action;
- char *piece;
- char *line_marker = line;
-
- cookie = dNew0(CookieData_t, 1);
-
- cookie->session_only = FALSE;
- piece = dStrsep(&line_marker, "\t");
- if (piece != NULL)
- cookie->version = strtol(piece, NULL, 10);
- cookie->domain = dStrdup(dStrsep(&line_marker, "\t"));
- Cookies_parse_ports(0, cookie, dStrsep(&line_marker, "\t"));
- cookie->path = dStrdup(dStrsep(&line_marker, "\t"));
- piece = dStrsep(&line_marker, "\t");
- if (piece != NULL && piece[0] == '1')
- cookie->secure = TRUE;
- piece = dStrsep(&line_marker, "\t");
- if (piece != NULL)
- cookie->expires_at = (time_t) strtol(piece, NULL, 10);
- cookie->name = dStrdup(dStrsep(&line_marker, "\t"));
- cookie->value = dStrdup(dStrsep(&line_marker, "\t"));
- cookie->comment = dStrdup(dStrsep(&line_marker, "\t"));
- cookie->comment_url = dStrdup(dStrsep(&line_marker, "\t"));
-
- if (!cookie->domain || cookie->domain[0] == '\0' ||
- !cookie->path || cookie->path[0] != '/' ||
- !cookie->name || cookie->name[0] == '\0' ||
- !cookie->value) {
- MSG("Malformed line in cookies file!\n");
- Cookies_free_cookie(cookie);
- continue;
- }
-
- action = Cookies_control_check_domain(cookie->domain);
- if (action == COOKIE_DENY) {
- Cookies_free_cookie(cookie);
- continue;
- } else if (action == COOKIE_ACCEPT_SESSION) {
- cookie->session_only = TRUE;
- }
-
- /* Save cookie in memory */
- Cookies_add_cookie(cookie);
- }
- }
- fclose(old_cookies_file_stream);
- }
- dFree(filename);
}
/*
@@ -436,6 +341,7 @@ static void Cookies_save_and_free()
int i, fd;
CookieNode *node;
CookieData_t *cookie;
+ time_t now;
#ifndef HAVE_LOCKF
struct flock lck;
@@ -444,6 +350,8 @@ static void Cookies_save_and_free()
if (disabled)
return;
+ now = time(NULL);
+
rewind(file_stream);
fd = fileno(file_stream);
if (ftruncate(fd, 0) == -1)
@@ -453,8 +361,7 @@ static void Cookies_save_and_free()
/* Iterate cookies per domain, saving and freeing */
while ((node = dList_nth_data(cookies, 0))) {
for (i = 0; (cookie = dList_nth_data(node->dlist, i)); ++i) {
- if (!cookie->session_only) {
- /* char * ports_str = Cookies_build_ports_str(cookie); */
+ if (!cookie->session_only && (cookie->expires_at > now)) {
fprintf(file_stream, "%s\tTRUE\t%s\t%s\t%ld\t%s\t%s\n",
cookie->domain,
cookie->path,
@@ -462,7 +369,6 @@ static void Cookies_save_and_free()
(long)cookie->expires_at,
cookie->name,
cookie->value);
- /* dFree(ports_str); */
}
Cookies_free_cookie(cookie);
@@ -486,20 +392,19 @@ static void Cookies_save_and_free()
fclose(file_stream);
}
-static char *months[] =
-{ "",
- "Jan", "Feb", "Mar",
- "Apr", "May", "Jun",
- "Jul", "Aug", "Sep",
- "Oct", "Nov", "Dec"
-};
-
/*
* Take a months name and return a number between 1-12.
* E.g. 'April' -> 4
*/
static int Cookies_get_month(const char *month_name)
{
+ static const char *const months[] =
+ { "",
+ "Jan", "Feb", "Mar",
+ "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep",
+ "Oct", "Nov", "Dec"
+ };
int i;
for (i = 1; i <= 12; i++) {
@@ -520,20 +425,29 @@ static int Cookies_get_month(const char *month_name)
* Tue May 21 13:46:22 1991\n
* Tue May 21 13:46:22 1991
*
+ * Let's add:
+ * Mon Jan 11 08:00:00 2010 GMT
+ *
* (return 0 on malformed date string syntax)
+ *
+ * NOTE that the draft spec wants user agents to be more flexible in what
+ * they accept. For now, let's hack in special cases when they're encountered.
+ * Why? Because this function is currently understandable, and I don't want to
+ * abandon that (or at best decrease that -- see section 5.1.1) until there
+ * is known to be good reason.
*/
static time_t Cookies_create_timestamp(const char *expires)
{
time_t ret;
int day, month, year, hour, minutes, seconds;
char *cp;
- char *E_msg =
+ const char *const E_msg =
"Expire date is malformed!\n"
" (should be RFC-1123 | RFC-850 | ANSI asctime)\n"
- " Ignoring cookie: ";
+ " Discarding cookie: ";
cp = strchr(expires, ',');
- if (!cp && (strlen(expires) == 24 || strlen(expires) == 25)) {
+ if (!cp && strlen(expires)>20 && expires[13] == ':' && expires[16] == ':') {
/* Looks like ANSI asctime format... */
cp = (char *)expires;
day = strtol(cp + 8, NULL, 10); /* day */
@@ -583,63 +497,34 @@ static time_t Cookies_create_timestamp(const char *expires)
(minutes * 60) +
seconds);
- MSG("Expires in %ld seconds, at %s",
- (long)ret - time(NULL), ctime(&ret));
+ /* handle overflow */
+ if (year >= 1970 && ret < 0)
+ ret = DILLO_TIME_MAX;
return ret;
}
/*
- * Parse a string containing a list of port numbers.
- */
-static void Cookies_parse_ports(int url_port, CookieData_t *cookie,
- const char *port_str)
-{
- if ((!port_str || !port_str[0]) && url_port != 0) {
- /* There was no list, so only the calling urls port should be allowed. */
- if (!cookie->ports)
- cookie->ports = dList_new(1);
- dList_append(cookie->ports, INT2VOIDP(url_port));
- } else if (port_str[0] == '"' && port_str[1] != '"') {
- char *tok, *str;
- int port;
-
- str = dStrdup(port_str + 1);
- while ((tok = dStrsep(&str, ","))) {
- port = strtol(tok, NULL, 10);
- if (port > 0) {
- if (!cookie->ports)
- cookie->ports = dList_new(1);
- dList_append(cookie->ports, INT2VOIDP(port));
- }
- }
- dFree(str);
- }
-}
-
-/*
- * Build a string of the ports in 'cookie'.
+ * Remove the least recently used cookie in the list.
*/
-static char *Cookies_build_ports_str(CookieData_t *cookie)
+static void Cookies_remove_LRU(Dlist *cookies)
{
- Dstr *dstr;
- char *ret;
- void *data;
- int i;
+ int n = dList_length(cookies);
- dstr = dStr_new("\"");
- for (i = 0; (data = dList_nth_data(cookie->ports, i)); ++i) {
- dStr_sprintfa(dstr, "%d,", VOIDP2INT(data));
- }
- /* Remove any trailing comma */
- if (dstr->len > 1)
- dStr_erase(dstr, dstr->len - 1, 1);
- dStr_append(dstr, "\"");
+ if (n > 0) {
+ int i;
+ CookieData_t *lru = dList_nth_data(cookies, 0);
- ret = dstr->str;
- dStr_free(dstr, FALSE);
+ for (i = 1; i < n; i++) {
+ CookieData_t *curr = dList_nth_data(cookies, i);
- return ret;
+ if (curr->last_used < lru->last_used)
+ lru = curr;
+ }
+ dList_remove(cookies, lru);
+ MSG("removed LRU cookie \'%s=%s\'\n", lru->name, lru->value);
+ Cookies_free_cookie(lru);
+ }
}
static void Cookies_add_cookie(CookieData_t *cookie)
@@ -648,438 +533,461 @@ static void Cookies_add_cookie(CookieData_t *cookie)
CookieData_t *c;
CookieNode *node;
- /* Don't add an expired cookie */
- if (!cookie->session_only && cookie->expires_at < time(NULL)) {
- Cookies_free_cookie(cookie);
- return;
- }
-
node = dList_find_sorted(cookies, cookie->domain,Cookie_node_by_domain_cmp);
domain_cookies = (node) ? node->dlist : NULL;
if (domain_cookies) {
+ /* Remove any cookies with the same name and path */
+ while ((c = dList_find_custom(domain_cookies, cookie, Cookies_cmp))) {
+ dList_remove(domain_cookies, c);
+ Cookies_free_cookie(c);
+ }
+
/* Respect the limit of 20 cookies per domain */
if (dList_length(domain_cookies) >= 20) {
MSG("There are too many cookies for this domain (%s)\n",
cookie->domain);
- Cookies_free_cookie(cookie);
- return;
- }
-
- /* Remove any cookies with the same name and path */
- while ((c = dList_find_custom(domain_cookies, cookie, Cookies_cmp))){
- Cookies_remove_cookie(c);
+ Cookies_remove_LRU(domain_cookies);
}
}
- /* add the cookie into the respective domain list */
- node = dList_find_sorted(cookies, cookie->domain,Cookie_node_by_domain_cmp);
- domain_cookies = (node) ? node->dlist : NULL;
- if (!domain_cookies) {
- domain_cookies = dList_new(5);
- dList_append(domain_cookies, cookie);
- node = dNew(CookieNode, 1);
- node->domain = dStrdup(cookie->domain);
- node->dlist = domain_cookies;
- dList_insert_sorted(cookies, node, Cookie_node_cmp);
+ /* Don't add an expired cookie. Whether expiring now == expired, exactly,
+ * is arguable, but we definitely do not want to add a Max-Age=0 cookie.
+ */
+ if (cookie->expires_at <= time(NULL)) {
+ MSG("Goodbye, expired cookie %s=%s d:%s p:%s\n", cookie->name,
+ cookie->value, cookie->domain, cookie->path);
+ Cookies_free_cookie(cookie);
} else {
- dList_append(domain_cookies, cookie);
+ cookie->last_used = cookies_use_counter++;
+
+ /* add cookie to domain list */
+ if (!domain_cookies) {
+ domain_cookies = dList_new(5);
+ dList_append(domain_cookies, cookie);
+ node = dNew(CookieNode, 1);
+ node->domain = dStrdup(cookie->domain);
+ node->dlist = domain_cookies;
+ dList_insert_sorted(cookies, node, Cookie_node_cmp);
+ } else {
+ dList_append(domain_cookies, cookie);
+ }
+ }
+ if (domain_cookies && (dList_length(domain_cookies) == 0)) {
+ dList_remove(cookies, node);
+ dFree(node->domain);
+ dList_free(domain_cookies);
+ dFree(node);
}
}
/*
- * Remove the cookie from the domain list.
- * If the domain list is empty, remove the node too.
- * Free the cookie.
+ * Return the attribute that is present at *cookie_str.
*/
-static void Cookies_remove_cookie(CookieData_t *cookie)
+static char *Cookies_parse_attr(char **cookie_str)
{
- CookieNode *node;
+ char *str;
+ uint_t len;
- node = dList_find_sorted(cookies, cookie->domain,Cookie_node_by_domain_cmp);
- if (node) {
- dList_remove(node->dlist, cookie);
- if (dList_length(node->dlist) == 0) {
- dList_remove(cookies, node);
- dFree(node->domain);
- dList_free(node->dlist);
- }
- } else {
- MSG("Attempting to remove a cookie that doesn't exist!\n");
- }
+ while (dIsspace(**cookie_str))
+ (*cookie_str)++;
+
+ str = *cookie_str;
+ /* find '=' at end of attr, ';' after attr/val pair, '\0' end of string */
+ len = strcspn(str, "=;");
+ *cookie_str += len;
- Cookies_free_cookie(cookie);
+ while (len && (str[len - 1] == ' ' || str[len - 1] == '\t'))
+ len--;
+ return dStrndup(str, len);
}
/*
- * Return the attribute that is present at *cookie_str. This function
- * will also attempt to advance cookie_str past any equal-sign.
+ * Get the value in *cookie_str.
*/
-static char *Cookies_parse_attr(char **cookie_str)
+static char *Cookies_parse_value(char **cookie_str)
{
- char *str = *cookie_str;
- uint_t i, end = 0;
- bool_t got_attr = FALSE;
-
- for (i = 0; ; i++) {
- switch (str[i]) {
- case ' ':
- case '\t':
- case '=':
- case ';':
- got_attr = TRUE;
- if (end == 0)
- end = i;
- break;
- case ',':
- *cookie_str = str + i;
- return dStrndup(str, i);
- break;
- case '\0':
- if (!got_attr) {
- end = i;
- got_attr = TRUE;
- }
- /* fall through! */
- default:
- if (got_attr) {
- *cookie_str = str + i;
- return dStrndup(str, end);
- }
- break;
- }
- }
+ uint_t len;
+ char *str;
+
+ if (**cookie_str == '=') {
+ (*cookie_str)++;
+ while (dIsspace(**cookie_str))
+ (*cookie_str)++;
- return NULL;
+ str = *cookie_str;
+ /* finds ';' after attr/val pair or '\0' at end of string */
+ len = strcspn(str, ";");
+ *cookie_str += len;
+
+ while (len && (str[len - 1] == ' ' || str[len - 1] == '\t'))
+ len--;
+ } else {
+ str = *cookie_str;
+ len = 0;
+ }
+ return dStrndup(str, len);
}
/*
- * Get the value starting at *cookie_str.
- * broken_syntax: watch out for stupid syntax (comma in unquoted string...)
+ * Advance past any value
*/
-static char *Cookies_parse_value(char **cookie_str,
- bool_t broken_syntax,
- bool_t keep_quotes)
+static void Cookies_eat_value(char **cookie_str)
{
- uint_t i, end;
- char *str = *cookie_str;
-
- for (i = end = 0; !end; ++i) {
- switch (str[i]) {
- case ' ':
- case '\t':
- if (!broken_syntax && str[0] != '\'' && str[0] != '"') {
- *cookie_str = str + i + 1;
- end = 1;
- }
- break;
- case '\'':
- case '"':
- if (i != 0 && str[i] == str[0]) {
- char *tmp = str + i;
-
- while (*tmp != '\0' && *tmp != ';' && *tmp != ',')
- tmp++;
+ if (**cookie_str == '=')
+ *cookie_str += strcspn(*cookie_str, ";");
+}
- *cookie_str = (*tmp == ';') ? tmp + 1 : tmp;
+/*
+ * Handle Expires attribute.
+ * Note that this CAN MODIFY the value string.
+ */
+static time_t Cookies_expires_attr(char *value, const char *server_date)
+{
+ time_t exptime;
- if (keep_quotes)
- i++;
- end = 1;
- }
- break;
- case '\0':
- *cookie_str = str + i;
- end = 1;
- break;
- case ',':
- if (str[0] != '\'' && str[0] != '"' && !broken_syntax) {
- /* A new cookie starts here! */
- *cookie_str = str + i;
- end = 1;
- }
- break;
- case ';':
- if (str[0] != '\'' && str[0] != '"') {
- *cookie_str = str + i + 1;
- end = 1;
+ if (*value == '"' && value[strlen(value) - 1] == '"') {
+ /* In this one case, pay attention to quotes */
+ value[strlen(value) - 1] = '\0';
+ value++;
+ }
+ exptime = Cookies_create_timestamp(value);
+ if (exptime && server_date) {
+ time_t server_time = Cookies_create_timestamp(server_date);
+
+ if (server_time) {
+ time_t now = time(NULL);
+ time_t client_time = exptime + now - server_time;
+
+ if (server_time == exptime) {
+ exptime = now;
+ } else if ((exptime > now) == (client_time > now)) {
+ exptime = client_time;
+ } else {
+ /* Don't want to wrap around at the extremes of representable
+ * values thanks to clock skew.
+ */
+ MSG("At %ld, %ld was trying to turn into %ld\n",
+ (long)now, (long)exptime,
+ (long)client_time);
}
- break;
- default:
- break;
}
}
- /* keep i as an index to the last char */
- --i;
-
- if ((str[0] == '\'' || str[0] == '"') && !keep_quotes) {
- return i > 1 ? dStrndup(str + 1, i - 1) : NULL;
- } else {
- return dStrndup(str, i);
- }
+ return exptime;
}
/*
- * Parse one cookie...
+ * Parse cookie. A cookie might look something like:
+ * "Name=Val; Domain=example.com; Max-Age=3600; HttpOnly"
*/
-static CookieData_t *Cookies_parse_one(int url_port, char **cookie_str)
+static CookieData_t *Cookies_parse(char *cookie_str, const char *server_date)
{
- CookieData_t *cookie;
- char *str = *cookie_str;
- char *attr;
- char *value;
- int num_attr = 0;
+ CookieData_t *cookie = NULL;
+ char *str = cookie_str;
+ bool_t first_attr = TRUE;
bool_t max_age = FALSE;
- bool_t discard = FALSE;
- bool_t error = FALSE;
-
- cookie = dNew0(CookieData_t, 1);
- cookie->session_only = TRUE;
+ bool_t expires = FALSE;
- /* Iterate until there is nothing left of the string OR we come
- * across a comma representing the start of another cookie */
- while (*str != '\0' && *str != ',') {
- if (error) {
- str++;
- continue;
- }
- /* Skip whitespace */
- while (dIsspace(*str))
- str++;
+ /* Iterate until there is nothing left of the string */
+ while (*str) {
+ char *attr;
+ char *value;
/* Get attribute */
attr = Cookies_parse_attr(&str);
- if (!attr) {
- MSG("Cannot parse cookie attribute!\n");
- error = TRUE;
- continue;
- }
/* Get the value for the attribute and store it */
- if (num_attr == 0) {
- /* The first attr, which always is the user supplied attr, may
- * have the same name as an ordinary attr. Hence this workaround. */
- cookie->name = dStrdup(attr);
- cookie->value = Cookies_parse_value(&str, FALSE, TRUE);
+ if (first_attr) {
+ if (!*str && !*attr) {
+ dFree(attr);
+ return NULL;
+ }
+ cookie = dNew0(CookieData_t, 1);
+ /* let's arbitrarily choose a year for now */
+ cookie->expires_at = time(NULL) + 60 * 60 * 24 * 365;
+
+ if (*str != '=') {
+ /* NOTE it seems possible that the Working Group will decide
+ * against allowing nameless cookies.
+ */
+ cookie->name = dStrdup("");
+ cookie->value = attr;
+ } else {
+ cookie->name = dStrdup(attr);
+ cookie->value = Cookies_parse_value(&str);
+ }
} else if (dStrcasecmp(attr, "Path") == 0) {
- value = Cookies_parse_value(&str, FALSE, FALSE);
+ value = Cookies_parse_value(&str);
+ dFree(cookie->path);
cookie->path = value;
} else if (dStrcasecmp(attr, "Domain") == 0) {
- value = Cookies_parse_value(&str, FALSE, FALSE);
+ value = Cookies_parse_value(&str);
+ dFree(cookie->domain);
cookie->domain = value;
- } else if (dStrcasecmp(attr, "Discard") == 0) {
- cookie->session_only = TRUE;
- discard = TRUE;
} else if (dStrcasecmp(attr, "Max-Age") == 0) {
- if (!discard) {
- value = Cookies_parse_value(&str, FALSE, FALSE);
-
- if (value) {
- cookie->expires_at = time(NULL) + strtol(value, NULL, 10);
- cookie->session_only = FALSE;
- max_age = TRUE;
- dFree(value);
- } else {
- MSG("Cannot parse cookie Max-Age value!\n");
- dFree(attr);
- error = TRUE;
- continue;
+ value = Cookies_parse_value(&str);
+ if (isdigit(*value) || *value == '-') {
+ time_t now = time(NULL);
+ long age = strtol(value, NULL, 10);
+
+ cookie->expires_at = now + age;
+ if (age > 0 && cookie->expires_at < 0) {
+ /* handle overflow */
+ cookie->expires_at = DILLO_TIME_MAX;
}
+ expires = max_age = TRUE;
}
- } else if (dStrcasecmp(attr, "Expires") == 0) {
- if (!max_age && !discard) {
- MSG("Old netscape-style cookie...\n");
- value = Cookies_parse_value(&str, TRUE, FALSE);
- if (value) {
- cookie->expires_at = Cookies_create_timestamp(value);
- cookie->session_only = FALSE;
- dFree(value);
- } else {
- MSG("Cannot parse cookie Expires value!\n");
- dFree(attr);
- error = TRUE;
- continue;
- }
- }
- } else if (dStrcasecmp(attr, "Port") == 0) {
- value = Cookies_parse_value(&str, FALSE, TRUE);
- Cookies_parse_ports(url_port, cookie, value);
dFree(value);
- } else if (dStrcasecmp(attr, "Comment") == 0) {
- value = Cookies_parse_value(&str, FALSE, FALSE);
- cookie->comment = value;
- } else if (dStrcasecmp(attr, "CommentURL") == 0) {
- value = Cookies_parse_value(&str, FALSE, FALSE);
- cookie->comment_url = value;
- } else if (dStrcasecmp(attr, "Version") == 0) {
- value = Cookies_parse_value(&str, FALSE, FALSE);
-
- if (value) {
- cookie->version = strtol(value, NULL, 10);
+ } else if (dStrcasecmp(attr, "Expires") == 0) {
+ if (!max_age) {
+ value = Cookies_parse_value(&str);
+ cookie->expires_at = Cookies_expires_attr(value, server_date);
+ expires = TRUE;
dFree(value);
- } else {
- MSG("Cannot parse cookie Version value!\n");
- dFree(attr);
- error = TRUE;
- continue;
+ MSG("Expires in %ld seconds, at %s",
+ (long)cookie->expires_at - time(NULL),
+ ctime(&cookie->expires_at));
+
}
} else if (dStrcasecmp(attr, "Secure") == 0) {
cookie->secure = TRUE;
+ Cookies_eat_value(&str);
} else if (dStrcasecmp(attr, "HttpOnly") == 0) {
- // this case is intentionally left blank, because we do not
- // do client-side scripting (yet).
+ Cookies_eat_value(&str);
} else {
- /* Oops! this can't be good... */
MSG("Cookie contains unknown attribute: '%s'\n", attr);
- dFree(attr);
- error = TRUE;
- continue;
+ Cookies_eat_value(&str);
}
- dFree(attr);
- num_attr++;
- }
-
- *cookie_str = (*str == ',') ? str + 1 : str;
+ if (first_attr)
+ first_attr = FALSE;
+ else
+ dFree(attr);
- if (!error && (!cookie->name || !cookie->value)) {
- MSG("Cookie missing name and/or value!\n");
- error = TRUE;
- }
- if (error) {
- Cookies_free_cookie(cookie);
- cookie = NULL;
+ if (*str == ';')
+ str++;
}
+ cookie->session_only = expires == FALSE;
return cookie;
}
/*
- * Iterate the cookie string until we catch all cookies.
- * Return Value: a list with all the cookies! (or NULL upon error)
+ * Compare cookies by name and path (return 0 if equal)
*/
-static Dlist *Cookies_parse_string(int url_port, char *cookie_string)
+static int Cookies_cmp(const void *a, const void *b)
{
- CookieData_t *cookie;
- Dlist *ret = NULL;
- char *str = cookie_string;
+ const CookieData_t *ca = a, *cb = b;
+ int ret;
- /* The string may contain several cookies separated by comma.
- * We'll iterate until we've caught them all */
- while (*str) {
- cookie = Cookies_parse_one(url_port, &str);
+ if (!(ret = strcmp(ca->name, cb->name)))
+ ret = strcmp(ca->path, cb->path);
+ return ret;
+}
- if (cookie) {
- if (!ret)
- ret = dList_new(4);
- dList_append(ret, cookie);
- } else {
- MSG("Malformed cookie field, ignoring cookie: %s\n", cookie_string);
- }
- }
+/*
+ * Is the domain an IP address?
+ */
+static bool_t Cookies_domain_is_ip(const char *domain)
+{
+ uint_t len;
- return ret;
+ if (!domain)
+ return FALSE;
+
+ len = strlen(domain);
+
+ if (len == strspn(domain, "0123456789.")) {
+ MSG("an IPv4 address\n");
+ return TRUE;
+ }
+ if (*domain == '[' &&
+ (len == strspn(domain, "0123456789abcdefABCDEF:.[]"))) {
+ /* The precise format is shown in section 3.2.2 of rfc 3986 */
+ MSG("an IPv6 address\n");
+ return TRUE;
+ }
+ return FALSE;
}
/*
- * Compare cookies by name and path (return 0 if equal)
+ * Check whether url_path path-matches cookie_path
+ *
+ * Note different user agents apparently vary in path-matching behaviour,
+ * but this is the recommended method at the moment.
*/
-static int Cookies_cmp(const void *a, const void *b)
+static bool_t Cookies_path_matches(const char *url_path,
+ const char *cookie_path)
{
- const CookieData_t *ca = a, *cb = b;
- int ret;
+ bool_t ret = TRUE;
- if (!(ret = strcmp(ca->name, cb->name)))
- ret = strcmp(ca->path, cb->path);
+ if (!url_path || !cookie_path) {
+ ret = FALSE;
+ } else {
+ uint_t c_len = strlen(cookie_path);
+ uint_t u_len = strlen(url_path);
+
+ ret = (!strncmp(cookie_path, url_path, c_len) &&
+ ((c_len == u_len) ||
+ (c_len > 0 && cookie_path[c_len - 1] == '/') ||
+ (url_path[c_len] == '/')));
+ }
return ret;
}
/*
- * Validate cookies domain against some security checks.
+ * If cookie path is not properly set, remedy that.
*/
-static bool_t Cookies_validate_domain(CookieData_t *cookie, char *host,
- char *url_path)
+static void Cookies_validate_path(CookieData_t *cookie, const char *url_path)
{
- int dots, diff, i;
- bool_t is_ip;
-
- /* Make sure that the path is set to something */
if (!cookie->path || cookie->path[0] != '/') {
dFree(cookie->path);
- cookie->path = Cookies_strip_path(url_path);
+
+ if (url_path) {
+ uint_t len = strlen(url_path);
+
+ while (len && url_path[len] != '/')
+ len--;
+ cookie->path = dStrndup(url_path, len ? len : 1);
+ } else {
+ cookie->path = dStrdup("/");
+ }
}
+}
- /* If the server never set a domain, or set one without a leading
- * dot (which isn't allowed), we use the calling URL's hostname. */
- if (cookie->domain == NULL || cookie->domain[0] != '.') {
- dFree(cookie->domain);
- cookie->domain = dStrdup(host);
+/*
+ * Check whether host name A domain-matches host name B.
+ */
+static bool_t Cookies_domain_matches(char *A, char *B)
+{
+ int diff;
+
+ if (!A || !*A || !B || !*B)
+ return FALSE;
+
+ if (*B == '.')
+ B++;
+
+ /* Should we concern ourselves with trailing dots in matching (here or
+ * elsewhere)? The HTTP State people have found that most user agents
+ * don't, so: No.
+ */
+
+ if (!dStrcasecmp(A, B))
return TRUE;
- }
- /* Count the number of dots and also find out if it is an IP-address */
- is_ip = TRUE;
- for (i = 0, dots = 0; cookie->domain[i] != '\0'; i++) {
- if (cookie->domain[i] == '.')
- dots++;
- else if (!isdigit(cookie->domain[i]))
- is_ip = FALSE;
- }
+ if (Cookies_domain_is_ip(B))
+ return FALSE;
+
+ diff = strlen(A) - strlen(B);
- /* A valid domain must have at least two dots in it */
- /* NOTE: this breaks cookies on localhost... */
- if (dots < 2) {
+ if (diff > 0) {
+ /* B is the tail of A, and the match is preceded by a '.' */
+ return (dStrcasecmp(A + diff, B) == 0 && A[diff - 1] == '.');
+ } else {
return FALSE;
}
+}
- /* Now see if the url matches the domain */
- diff = strlen(host) - i;
- if (diff > 0) {
- if (dStrcasecmp(host + diff, cookie->domain))
- return FALSE;
-
- if (!is_ip) {
- /* "x.y.test.com" is not allowed to set cookies for ".test.com";
- * only an url of the form "y.test.com" would be. */
- while ( diff-- )
- if (host[diff] == '.')
- return FALSE;
+/*
+ * Based on the host, how many internal dots do we need in a cookie domain
+ * to make it valid? e.g., "org" is not on the list, so dillo.org is a safe
+ * cookie domain, but "uk" is on the list, so ac.uk is not safe.
+ *
+ * This is imperfect, but it's something. Specifically, checking for these
+ * TLDs is the solution that Konqueror used once upon a time, according to
+ * reports.
+ */
+static uint_t Cookies_internal_dots_required(const char *host)
+{
+ uint_t ret = 1;
+
+ if (host) {
+ int start, after, tld_len;
+
+ /* We may be able to trust the format of the host string more than
+ * I am here. Trailing dots and no dots are real possibilities, though.
+ */
+ after = strlen(host);
+ if (after > 0 && host[after - 1] == '.')
+ after--;
+ start = after;
+ while (start > 0 && host[start - 1] != '.')
+ start--;
+ tld_len = after - start;
+
+ if (tld_len > 0) {
+ /* These TLDs were chosen by examining the current publicsuffix list
+ * in January 2010 and picking out those where it was simplest for
+ * them to describe the situation by beginning with a "*.[tld]" rule.
+ */
+ const char *const tlds[] = {"ar","au","bd","bn","bt","ck","cy","do",
+ "eg","er","et","fj","fk","gt","gu","id",
+ "il","jm","ke","kh","kw","ml","mm","mt",
+ "mz","ni","np","nz","om","pg","py","qa",
+ "sv","tr","uk","uy","ve","ye","yu","za",
+ "zm","zw"};
+ uint_t i, tld_num = sizeof(tlds) / sizeof(tlds[0]);
+
+ for (i = 0; i < tld_num; i++) {
+ if (strlen(tlds[i]) == (uint_t) tld_len &&
+ !dStrncasecmp(tlds[i], host + start, tld_len)) {
+ MSG("TLD code matched %s\n", tlds[i]);
+ ret++;
+ break;
+ }
+ }
}
}
-
- return TRUE;
+ return ret;
}
/*
- * Strip of the filename from a full path
+ * Validate cookies domain against some security checks.
*/
-static char *Cookies_strip_path(const char *path)
+static bool_t Cookies_validate_domain(CookieData_t *cookie, char *host)
{
- char *ret;
- uint_t len;
+ uint_t i, internal_dots;
+
+ if (!cookie->domain) {
+ cookie->domain = dStrdup(host);
+ return TRUE;
+ }
- if (path) {
- len = strlen(path);
+ if (cookie->domain[0] != '.' && !Cookies_domain_is_ip(cookie->domain)) {
+ char *d = dStrconcat(".", cookie->domain, NULL);
+ dFree(cookie->domain);
+ cookie->domain = d;
+ }
- while (len && path[len] != '/')
- len--;
- ret = dStrndup(path, len + 1);
- } else {
- ret = dStrdup("/");
+ if (!Cookies_domain_matches(host, cookie->domain))
+ return FALSE;
+
+ internal_dots = 0;
+ for (i = 1; i < strlen(cookie->domain) - 1; i++) {
+ if (cookie->domain[i] == '.')
+ internal_dots++;
}
- return ret;
+ /* All of this dots business is a weak hack.
+ * TODO: accept the publicsuffix.org list as an optional external file.
+ */
+ if (internal_dots < Cookies_internal_dots_required(host)) {
+ MSG("not enough dots in %s\n", cookie->domain);
+ return FALSE;
+ }
+
+ MSG("host %s and domain %s is all right\n", host, cookie->domain);
+ return TRUE;
}
/*
* Set the value corresponding to the cookie string
*/
static void Cookies_set(char *cookie_string, char *url_host,
- char *url_path, int url_port)
+ char *url_path, char *server_date)
{
CookieControlAction action;
CookieData_t *cookie;
- Dlist *list;
- int i;
if (disabled)
return;
@@ -1090,65 +998,96 @@ static void Cookies_set(char *cookie_string, char *url_host,
return;
}
- if ((list = Cookies_parse_string(url_port, cookie_string))) {
- for (i = 0; (cookie = dList_nth_data(list, i)); ++i) {
- if (Cookies_validate_domain(cookie, url_host, url_path)) {
- if (action == COOKIE_ACCEPT_SESSION)
- cookie->session_only = TRUE;
- Cookies_add_cookie(cookie);
- } else {
- MSG("Rejecting cookie for %s from host %s path %s\n",
- cookie->domain, url_host, url_path);
- Cookies_free_cookie(cookie);
- }
+ MSG("%s SETTING: %s\n", url_host, cookie_string);
+
+ if ((cookie = Cookies_parse(cookie_string, server_date))) {
+ if (Cookies_validate_domain(cookie, url_host)) {
+ Cookies_validate_path(cookie, url_path);
+ if (action == COOKIE_ACCEPT_SESSION)
+ cookie->session_only = TRUE;
+ Cookies_add_cookie(cookie);
+ } else {
+ MSG("Rejecting cookie for domain %s from host %s path %s\n",
+ cookie->domain, url_host, url_path);
+ Cookies_free_cookie(cookie);
}
- dList_free(list);
}
}
/*
- * Compare the cookie with the supplied data to see if it matches
+ * Compare the cookie with the supplied data to see whether it matches
*/
-static bool_t Cookies_match(CookieData_t *cookie, int port,
- const char *path, bool_t is_ssl)
+static bool_t Cookies_match(CookieData_t *cookie, const char *url_path,
+ bool_t is_ssl)
{
- void *data;
- int i;
-
/* Insecure cookies matches both secure and insecure urls, secure
cookies matches only secure urls */
if (cookie->secure && !is_ssl)
return FALSE;
- /* Check that the cookie path is a subpath of the current path */
- if (strncmp(cookie->path, path, strlen(cookie->path)) != 0)
+ if (!Cookies_path_matches(url_path, cookie->path))
return FALSE;
- /* Check if the port of the request URL matches any
- * of those set in the cookie */
- if (cookie->ports) {
- for (i = 0; (data = dList_nth_data(cookie->ports, i)); ++i) {
- if (VOIDP2INT(data) == port)
- return TRUE;
- }
- return FALSE;
- }
-
/* It's a match */
return TRUE;
}
+static void Cookies_add_matching_cookies(const char *domain,
+ const char *url_path,
+ Dlist *matching_cookies,
+ bool_t is_ssl)
+{
+ CookieNode *node = dList_find_sorted(cookies, domain,
+ Cookie_node_by_domain_cmp);
+ if (node) {
+ int i;
+ CookieData_t *cookie;
+ Dlist *domain_cookies = node->dlist;
+
+ for (i = 0; (cookie = dList_nth_data(domain_cookies, i)); ++i) {
+ /* Remove expired cookie. */
+ if (cookie->expires_at < time(NULL)) {
+ MSG("Goodbye, expired cookie %s=%s d:%s p:%s\n", cookie->name,
+ cookie->value, cookie->domain, cookie->path);
+ dList_remove(domain_cookies, cookie);
+ Cookies_free_cookie(cookie);
+ --i; continue;
+ }
+ /* Check if the cookie matches the requesting URL */
+ if (Cookies_match(cookie, url_path, is_ssl)) {
+ int j;
+ CookieData_t *curr;
+ uint_t path_length = strlen(cookie->path);
+
+ cookie->last_used = cookies_use_counter;
+
+ /* Longest cookies go first */
+ for (j = 0;
+ (curr = dList_nth_data(matching_cookies, j)) &&
+ strlen(curr->path) >= path_length;
+ j++) ;
+ dList_insert_pos(matching_cookies, cookie, j);
+ }
+ }
+
+ if (dList_length(domain_cookies) == 0) {
+ dList_remove(cookies, node);
+ dFree(node->domain);
+ dList_free(domain_cookies);
+ dFree(node);
+ }
+ }
+}
+
/*
* Return a string that contains all relevant cookies as headers.
*/
static char *Cookies_get(char *url_host, char *url_path,
- char *url_scheme, int url_port)
+ char *url_scheme)
{
- char *domain_str, *q, *str, *path;
+ char *domain_str, *str;
CookieData_t *cookie;
Dlist *matching_cookies;
- CookieNode *node;
- Dlist *domain_cookies;
bool_t is_ssl;
Dstr *cookie_dstring;
int i;
@@ -1158,64 +1097,45 @@ static char *Cookies_get(char *url_host, char *url_path,
matching_cookies = dList_new(8);
- path = Cookies_strip_path(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, '.')) {
-
- node = dList_find_sorted(cookies, domain_str, Cookie_node_by_domain_cmp);
- domain_cookies = (node) ? node->dlist : NULL;
-
- for (i = 0; (cookie = dList_nth_data(domain_cookies, i)); ++i) {
- /* Remove expired cookie. */
- if (!cookie->session_only && cookie->expires_at < time(NULL)) {
- Cookies_remove_cookie(cookie);
- --i; continue;
- }
- /* Check if the cookie matches the requesting URL */
- if (Cookies_match(cookie, url_port, path, is_ssl)) {
- dList_append(matching_cookies, cookie);
- }
- }
+ Cookies_add_matching_cookies(domain_str, url_path, matching_cookies,
+ is_ssl);
+ }
+ if (!Cookies_domain_is_ip(url_host)) {
+ domain_str = dStrconcat(".", url_host, NULL);
+ Cookies_add_matching_cookies(domain_str, url_path, matching_cookies,
+ is_ssl);
+ dFree(domain_str);
}
/* Found the cookies, now make the string */
cookie_dstring = dStr_new("");
if (dList_length(matching_cookies) > 0) {
- CookieData_t *first_cookie = dList_nth_data(matching_cookies, 0);
dStr_sprintfa(cookie_dstring, "Cookie: ");
- if (first_cookie->version != 0)
- dStr_sprintfa(cookie_dstring, "$Version=\"%d\"; ",
- first_cookie->version);
-
-
for (i = 0; (cookie = dList_nth_data(matching_cookies, i)); ++i) {
- q = (cookie->version == 0 ? "" : "\"");
dStr_sprintfa(cookie_dstring,
- "%s=%s; $Path=%s%s%s; $Domain=%s%s%s",
- cookie->name, cookie->value,
- q, cookie->path, q, q, cookie->domain, q);
- if (cookie->ports) {
- char *ports_str = Cookies_build_ports_str(cookie);
- dStr_sprintfa(cookie_dstring, "; $Port=%s", ports_str);
- dFree(ports_str);
- }
-
+ "%s%s%s",
+ cookie->name, *cookie->name ? "=" : "", cookie->value);
dStr_append(cookie_dstring,
dList_length(matching_cookies) > i + 1 ? "; " : "\r\n");
}
}
dList_free(matching_cookies);
- dFree(path);
str = cookie_dstring->str;
dStr_free(cookie_dstring, FALSE);
+
+ if (*str)
+ cookies_use_counter++;
+
+ MSG("%s GETTING: %s\n", url_host, str);
return str;
}
@@ -1255,7 +1175,7 @@ static int Cookie_control_init(void)
line[0] = '\0';
rc = fgets(line, LINE_MAXLEN, stream);
if (!rc && ferror(stream)) {
- MSG("Cookies3: Error while reading rule from cookiesrc: %s\n",
+ MSG("Error while reading rule from cookiesrc: %s\n",
dStrerror(errno));
break; /* bail out */
}
@@ -1351,8 +1271,8 @@ static CookieControlAction Cookies_control_check_domain(const char *domain)
*/
static int srv_parse_tok(Dsh *sh, ClientInfo *client, char *Buf)
{
- char *p, *cmd, *cookie, *host, *path, *scheme;
- int port, ret = 1;
+ char *cmd, *cookie, *host, *path, *scheme;
+ int ret = 1;
size_t BufSize = strlen(Buf);
cmd = a_Dpip_get_attr_l(Buf, BufSize, "cmd");
@@ -1371,16 +1291,17 @@ static int srv_parse_tok(Dsh *sh, ClientInfo *client, char *Buf)
exit(0);
} else if (cmd && strcmp(cmd, "set_cookie") == 0) {
+ char *date;
+
dFree(cmd);
cookie = a_Dpip_get_attr_l(Buf, BufSize, "cookie");
host = a_Dpip_get_attr_l(Buf, BufSize, "host");
path = a_Dpip_get_attr_l(Buf, BufSize, "path");
- p = a_Dpip_get_attr_l(Buf, BufSize, "port");
- port = strtol(p, NULL, 10);
- dFree(p);
+ date = a_Dpip_get_attr_l(Buf, BufSize, "date");
- Cookies_set(cookie, host, path, port);
+ Cookies_set(cookie, host, path, date);
+ dFree(date);
dFree(path);
dFree(host);
dFree(cookie);
@@ -1391,11 +1312,8 @@ static int srv_parse_tok(Dsh *sh, ClientInfo *client, char *Buf)
scheme = a_Dpip_get_attr_l(Buf, BufSize, "scheme");
host = a_Dpip_get_attr_l(Buf, BufSize, "host");
path = a_Dpip_get_attr_l(Buf, BufSize, "path");
- p = a_Dpip_get_attr_l(Buf, BufSize, "port");
- port = strtol(p, NULL, 10);
- dFree(p);
- cookie = Cookies_get(host, path, scheme, port);
+ cookie = Cookies_get(host, path, scheme);
dFree(scheme);
dFree(path);
dFree(host);
diff --git a/dpid/dpid.c b/dpid/dpid.c
index b5e53d7e..33c6c31c 100644
--- a/dpid/dpid.c
+++ b/dpid/dpid.c
@@ -25,6 +25,7 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
+#include <netinet/tcp.h>
#include <unistd.h>
#include "dpid_common.h"
@@ -519,10 +520,13 @@ int fill_services_list(struct dp *attlist, int numdpis, Dlist **services_list)
*/
static int make_socket_fd()
{
- int ret;
+ int ret, one = 1;
if ((ret = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
ERRMSG("make_socket_fd", "socket", errno);
+ } else {
+ /* avoid delays when sending small pieces of data */
+ setsockopt(ret, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
}
/* set some buffering to increase the transfer's speed */
diff --git a/dw/style.cc b/dw/style.cc
index 6368560f..8d3035d0 100644
--- a/dw/style.cc
+++ b/dw/style.cc
@@ -134,6 +134,7 @@ bool StyleAttrs::equals (object::Object *other) {
whiteSpace == otherAttrs->whiteSpace &&
listStylePosition == otherAttrs->listStylePosition &&
listStyleType == otherAttrs->listStyleType &&
+ cursor == otherAttrs->cursor &&
x_link == otherAttrs->x_link &&
x_img == otherAttrs->x_img &&
x_tooltip == otherAttrs->x_tooltip);
@@ -166,6 +167,7 @@ int StyleAttrs::hashValue () {
whiteSpace +
listStylePosition +
listStyleType +
+ cursor +
x_link +
x_img +
(intptr_t) x_tooltip;
diff --git a/dw/style.hh b/dw/style.hh
index 231f879a..700c56d3 100644
--- a/dw/style.hh
+++ b/dw/style.hh
@@ -81,7 +81,7 @@ namespace core {
* <li> A length refers to an absolute measurement. It is used to
* represent the HTML type %Pixels; and the CSS type \<length\>.
*
- * For CSS lenghts, there are two units: (i) pixels and absolute
+ * For CSS lengths, there are two units: (i) pixels and absolute
* units, which have to be converted to pixels (a pixel is, unlike
* in the CSS specification, treated as absolute unit), and (ii) the
* relative units "em" and "ex" (see below).
@@ -343,7 +343,7 @@ enum WhiteSpace {
* <li> dw::core::style::relLengthVal
* </ul>
*
- * "auto" lenghths are represented as dw::core::style::LENGTH_AUTO.
+ * "auto" lengths are represented as dw::core::style::LENGTH_AUTO.
*/
typedef int Length;
diff --git a/dw/table.hh b/dw/table.hh
index b7264336..87bbaa76 100644
--- a/dw/table.hh
+++ b/dw/table.hh
@@ -14,7 +14,7 @@ namespace dw {
*
* The dw::Table widget is used to render HTML tables.
*
- * Each cell is itself an own widget. Any widget may be used, however, in
+ * Each cell is itself a separate widget. Any widget may be used, however, in
* dillo, only instances of dw::Textblock and dw::TableCell are used as
* children of dw::Table.
*
@@ -25,7 +25,7 @@ namespace dw {
*
* The following diagram shows the dependencies between the different
* functions, which are related to size calculation. Click on the boxes
- * for more informations.
+ * for more information.
*
* \dot
* digraph G {
@@ -128,7 +128,7 @@ namespace dw {
* \f$e_{\hbox{span},i,\min}\f$ (but not \f$e_{\hbox{span},i,\max}\f$)
* are calculated from cells with colspan > 1. (In the following formulas,
* the cell at \f$(i_1, j)\f$ always span from \f$i_1\f$ to \f$i_2\f$.)
- * If the minimal width of the column exeeds the sum of the column minima
+ * If the minimal width of the column exceeds the sum of the column minima
* calculated in the last step:
*
* \f[e_{\hbox{cell},i_1,j,\min} >
@@ -137,7 +137,7 @@ namespace dw {
* then the minimal width of this cell is apportioned to the columns:
*
* <ul>
- * <li> If the minimal width of this cell also exeeds the sum of the
+ * <li> If the minimal width of this cell also exceeds the sum of the
* column maxima:
*
* \f[e_{\hbox{cell},i_1,j,\min} >
@@ -170,11 +170,11 @@ namespace dw {
* \f[ e_{i,\max} =
* \max \{ e_{\hbox{base},i,\max}, e_{i,\min} \} \f]
* For the maxima, there is no \f$e_{\hbox{span},i,\max}\f$, but it has to
- * be assured, that the maximum is always greater or equal than/to the
+ * be assured, that the maximum is always greater than or equal to the
* minimum.
* </ol>
*
- * Generally, if absolute widths are speficied, they are, instead of the
+ * Generally, if absolute widths are specified, they are, instead of the
* results of dw::core::Widget::getExtremes, taken for the minimal and
* maximal width of a cell (minus the box difference, i.e. the difference
* between content size and widget size). If the content width
@@ -199,15 +199,15 @@ namespace dw {
*
* <ul>
* <li> the specified absolute width of the table, when given, or
- * <li> the available width (set by dw::Table::setWidth) times the specifies
- * percentage width pf t(at max 100%), if the latter is given, or
+ * <li> the available width (set by dw::Table::setWidth) times the specified
+ * percentage width of t(at max 100%), if the latter is given, or
* <li> otherwise the available width.
* </ul>
*
* In any case, it is corrected, if it is less than the minimal width
* (but not if it is greater than the maximal width).
*
- * \bug The parantheses is not fully clear, look at the old code.
+ * \bug The parentheses is not fully clear, look at the old code.
*
* Details on differences because of styles are omitted. Below, this
* total width is called \f$W\f$.
@@ -230,7 +230,7 @@ namespace dw {
*
* <li> Then, calculate the sum of the widths, which the columns with
* percentage width specification would allocate, when fully adhering to
- * then:
+ * them:
*
* \f[W_{\hbox{columns}_\%,\hbox{best}} = W \sum w_{i,\%}\f]
*
@@ -274,7 +274,7 @@ namespace dw {
* <h5>Column Widths</h5>
*
* The column widths are now simply calculated by applying the
- * apportenment function.
+ * apportionment function.
*
*
* <h5>Row Heights</h5>
@@ -286,7 +286,7 @@ namespace dw {
* The algorithm described here tends to result in more homogeneous column
* widths.
*
- * The following rule lead to well-defined \f$w_{i}\f$: All columns
+ * The following rule leads to well-defined \f$w_{i}\f$: All columns
* \f$i\f$ have have the same width \f$w\f$, except:
* <ul>
* <li> \f$w < e_{i,\min}\f$, or
diff --git a/dw/textblock.cc b/dw/textblock.cc
index d4cc9734..fae2613a 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -1437,12 +1437,12 @@ int Textblock::findLineIndex (int y)
while ( step > 1 ) {
index = low + step;
if (index <= maxIndex &&
- lineYOffsetWidgetI (index) < y)
+ lineYOffsetWidgetI (index) <= y)
low = index;
step = (step + 1) >> 1;
}
- if (low < maxIndex && lineYOffsetWidgetI (low + 1) < y)
+ if (low < maxIndex && lineYOffsetWidgetI (low + 1) <= y)
low++;
/*
diff --git a/src/IO/Makefile.am b/src/IO/Makefile.am
index 98d8d43a..b168073c 100644
--- a/src/IO/Makefile.am
+++ b/src/IO/Makefile.am
@@ -1,3 +1,4 @@
+AM_CPPFLAGS=-DDILLO_BINDIR='"$(bindir)/"'
AM_CFLAGS = @LIBFLTK_CFLAGS@
AM_CXXFLAGS = @LIBFLTK_CXXFLAGS@
diff --git a/src/IO/dpi.c b/src/IO/dpi.c
index 6491ea27..6f46b2ba 100644
--- a/src/IO/dpi.c
+++ b/src/IO/dpi.c
@@ -30,6 +30,7 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -364,13 +365,17 @@ static int Dpi_start_dpid(void)
Dpi_close_fd(st_pipe[0]);
if (execl(path1, "dpid", (char*)NULL) == -1) {
dFree(path1);
- if (execlp("dpid", "dpid", (char*)NULL) == -1) {
- MSG("Dpi_start_dpid (child): %s\n", dStrerror(errno));
- if (Dpi_blocking_write(st_pipe[1], "ERROR", 5) == -1) {
- MSG("Dpi_start_dpid (child): can't write to pipe.\n");
+ path1 = dStrconcat(DILLO_BINDIR, "dpid", NULL);
+ if (execl(path1, "dpid", (char*)NULL) == -1) {
+ dFree(path1);
+ if (execlp("dpid", "dpid", (char*)NULL) == -1) {
+ MSG("Dpi_start_dpid (child): %s\n", dStrerror(errno));
+ if (Dpi_blocking_write(st_pipe[1], "ERROR", 5) == -1) {
+ MSG("Dpi_start_dpid (child): can't write to pipe.\n");
+ }
+ Dpi_close_fd(st_pipe[1]);
+ _exit (EXIT_FAILURE);
}
- Dpi_close_fd(st_pipe[1]);
- _exit (EXIT_FAILURE);
}
}
} else if (pid < 0) {
@@ -430,9 +435,11 @@ static int Dpi_read_comm_keys(int *port)
*/
static int Dpi_make_socket_fd()
{
- int fd, ret = -1;
+ int fd, one = 1, ret = -1;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
+ /* avoid delays when sending small pieces of data */
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
ret = fd;
}
return ret;
diff --git a/src/cache.c b/src/cache.c
index 3341388c..6df062b3 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -728,15 +728,14 @@ static void Cache_parse_header(CacheEntry_t *entry)
dFree(encoding); /* free Transfer-Encoding */
#ifndef DISABLE_COOKIES
- /* BUG: If a server feels like mixing Set-Cookie2 and Set-Cookie
- * responses which aren't identical, then we have a problem. I don't
- * know if that is a real issue though. */
- if ((Cookies = Cache_parse_multiple_fields(header, "Set-Cookie2")) ||
- (Cookies = Cache_parse_multiple_fields(header, "Set-Cookie"))) {
- a_Cookies_set(Cookies, entry->Url);
+ if ((Cookies = Cache_parse_multiple_fields(header, "Set-Cookie"))) {
+ char *server_date = Cache_parse_field(header, "Date");
+
+ a_Cookies_set(Cookies, entry->Url, server_date);
for (i = 0; (data = dList_nth_data(Cookies, i)); ++i)
dFree(data);
dList_free(Cookies);
+ dFree(server_date);
}
#endif /* !DISABLE_COOKIES */
diff --git a/src/cookies.c b/src/cookies.c
index a25138cd..ea386be5 100644
--- a/src/cookies.c
+++ b/src/cookies.c
@@ -10,10 +10,9 @@
* (at your option) any later version.
*/
-/* Handling of cookies takes place here.
- * This implementation aims to follow RFC 2965:
- * http://www.ietf.org/rfc/rfc2965.txt
- */
+/* Handling of cookies takes place here. */
+
+#include "msg.h"
#ifdef DISABLE_COOKIES
@@ -37,7 +36,6 @@ void a_Cookies_init(void)
#include <ctype.h>
#include <errno.h>
-#include "msg.h"
#include "IO/Url.h"
#include "list.h"
#include "cookies.h"
@@ -138,10 +136,11 @@ void a_Cookies_freeall()
/*
* Set the value corresponding to the cookie string
*/
-void a_Cookies_set(Dlist *cookie_strings, const DilloUrl *set_url)
+void a_Cookies_set(Dlist *cookie_strings, const DilloUrl *set_url,
+ const char *date)
{
CookieControlAction action;
- char *cmd, *cookie_string, *dpip_tag, numstr[16];
+ char *cmd, *cookie_string, *dpip_tag;
const char *path;
int i;
@@ -156,10 +155,14 @@ void a_Cookies_set(Dlist *cookie_strings, const DilloUrl *set_url)
for (i = 0; (cookie_string = dList_nth_data(cookie_strings, i)); ++i) {
path = URL_PATH_(set_url);
- snprintf(numstr, 16, "%d", URL_PORT(set_url));
- cmd = a_Dpip_build_cmd("cmd=%s cookie=%s host=%s path=%s port=%s",
- "set_cookie", cookie_string, URL_HOST_(set_url),
- path ? path : "/", numstr);
+ if (date)
+ cmd = a_Dpip_build_cmd("cmd=%s cookie=%s host=%s path=%s date=%s",
+ "set_cookie", cookie_string,
+ URL_HOST_(set_url), path ? path : "/", date);
+ else
+ cmd = a_Dpip_build_cmd("cmd=%s cookie=%s host=%s path=%s",
+ "set_cookie", cookie_string,
+ URL_HOST_(set_url), path ? path : "/");
_MSG("Cookies.c: a_Cookies_set \n\t \"%s\" \n",cmd );
/* This call is commented because it doesn't guarantee the order
@@ -178,7 +181,7 @@ void a_Cookies_set(Dlist *cookie_strings, const DilloUrl *set_url)
*/
char *a_Cookies_get_query(const DilloUrl *request_url)
{
- char *cmd, *dpip_tag, *query, numstr[16];
+ char *cmd, *dpip_tag, *query;
const char *path;
CookieControlAction action;
@@ -192,10 +195,9 @@ char *a_Cookies_get_query(const DilloUrl *request_url)
}
path = URL_PATH_(request_url);
- snprintf(numstr, 16, "%d", URL_PORT(request_url));
- cmd = a_Dpip_build_cmd("cmd=%s scheme=%s host=%s path=%s port=%s",
+ cmd = a_Dpip_build_cmd("cmd=%s scheme=%s host=%s path=%s",
"get_cookie", URL_SCHEME(request_url),
- URL_HOST(request_url), path ? path : "/", numstr);
+ URL_HOST(request_url), path ? path : "/");
/* Get the answer from cookies.dpi */
_MSG("cookies.c: a_Dpi_send_blocking_cmd cmd = {%s}\n", cmd);
@@ -203,15 +205,11 @@ char *a_Cookies_get_query(const DilloUrl *request_url)
_MSG("cookies.c: after a_Dpi_send_blocking_cmd resp={%s}\n", dpip_tag);
dFree(cmd);
- query = dStrdup("Cookie2: $Version=\"1\"\r\n");
-
if (dpip_tag != NULL) {
- char *cookie = a_Dpip_get_attr(dpip_tag, "cookie");
- char *old_query = query;
- query = dStrconcat(old_query, cookie, NULL);
- dFree(old_query);
+ query = a_Dpip_get_attr(dpip_tag, "cookie");
dFree(dpip_tag);
- dFree(cookie);
+ } else {
+ query = dStrdup("");
}
return query;
}
diff --git a/src/cookies.h b/src/cookies.h
index 6f9f77e0..482aa5ae 100644
--- a/src/cookies.h
+++ b/src/cookies.h
@@ -12,7 +12,8 @@ extern "C" {
# define a_Cookies_freeall() ;
#else
char *a_Cookies_get_query(const DilloUrl *request_url);
- void a_Cookies_set(Dlist *cookie_string, const DilloUrl *set_url);
+ void a_Cookies_set(Dlist *cookie_string, const DilloUrl *set_url,
+ const char *server_date);
void a_Cookies_init( void );
void a_Cookies_freeall( void );
#endif
diff --git a/src/css.cc b/src/css.cc
index 8d8df661..1b81ea7c 100644
--- a/src/css.cc
+++ b/src/css.cc
@@ -584,7 +584,13 @@ void CssContext::buildUserAgentStyle () {
"td, th {border-style: inset; padding: 2px}"
"thead, tbody, tfoot {vertical-align: middle}"
"th {font-weight: bolder; text-align: center}"
- "code, tt, pre, samp, kbd {font-family: monospace}";
+ "code, tt, pre, samp, kbd {font-family: monospace}"
+ /* WORKAROUND: Reset font properties in tables as some
+ * some pages rely on it (e.g. gmail).
+ * http://developer.mozilla.org/En/Fixing_Table_Inheritance_in_Quirks_Mode
+ * has a detailed description of the issue.
+ */
+ "table, caption {font-size: medium; font-weight: normal}";
CssParser::parse (NULL, NULL, this, cssBuf, strlen (cssBuf),
CSS_ORIGIN_USER_AGENT);
diff --git a/src/doctree.hh b/src/doctree.hh
index 30762e44..ef7faa7c 100644
--- a/src/doctree.hh
+++ b/src/doctree.hh
@@ -5,12 +5,20 @@
class DoctreeNode {
public:
+ DoctreeNode *parent;
int num; // unique ascending id
- int depth;
int element;
lout::misc::SimpleVector<char*> *klass;
const char *pseudo;
const char *id;
+
+ DoctreeNode () {
+ parent = NULL;
+ klass = NULL;
+ pseudo = NULL;
+ id = NULL;
+ element = 0;
+ };
};
/**
@@ -23,10 +31,42 @@ class DoctreeNode {
* be extended to a real tree.
*/
class Doctree {
+ private:
+ DoctreeNode *topNode;
+ int num;
+
public:
- virtual ~Doctree () {};
- virtual const DoctreeNode *top () = 0;
- virtual const DoctreeNode *parent (const DoctreeNode *node) = 0;
+ Doctree () {
+ topNode = NULL;
+ num = 0;
+ };
+ ~Doctree () { while (top ()) pop (); };
+ DoctreeNode *push () {
+ DoctreeNode *dn = new DoctreeNode ();
+ dn->parent = topNode;
+ dn->num = num++;
+ topNode = dn;
+ return dn;
+ };
+ void pop () {
+ DoctreeNode *dn = topNode;
+ if (dn) {
+ dFree ((void*) dn->id);
+ if (dn->klass) {
+ for (int i = 0; i < dn->klass->size (); i++)
+ dFree (dn->klass->get(i));
+ delete dn->klass;
+ }
+ topNode = dn->parent;
+ delete dn;
+ }
+ };
+ inline DoctreeNode *top () {
+ return topNode;
+ };
+ inline DoctreeNode *parent (const DoctreeNode *node) {
+ return node->parent;
+ };
};
#endif
diff --git a/src/styleengine.cc b/src/styleengine.cc
index 1ca57054..f0f70bf6 100644
--- a/src/styleengine.cc
+++ b/src/styleengine.cc
@@ -21,14 +21,14 @@ StyleEngine::StyleEngine (dw::core::Layout *layout) {
StyleAttrs style_attrs;
FontAttrs font_attrs;
+ doctree = new Doctree ();
stack = new lout::misc::SimpleVector <Node> (1);
cssContext = new CssContext ();
this->layout = layout;
- num = 0;
importDepth = 0;
stack->increase ();
- Node *n = stack->getRef (stack->size () - 1);
+ Node *n = stack->getRef (stack->size () - 1);
/* Create a dummy font, attribute, and tag for the bottom of the stack. */
font_attrs.name = prefs.font_sans_serif;
@@ -46,21 +46,17 @@ StyleEngine::StyleEngine (dw::core::Layout *layout) {
style_attrs.color = Color::create (layout, 0);
style_attrs.backgroundColor = Color::create (layout, 0xffffff);
- n->num = num++;
n->style = Style::create (layout, &style_attrs);
n->wordStyle = NULL;
- n->element = 0;
- n->id = NULL;
- n->klass = NULL;
- n->pseudo = NULL;
n->styleAttribute = NULL;
n->inheritBackgroundColor = false;
}
StyleEngine::~StyleEngine () {
- while (stack->size () > 0)
- endElement (stack->getRef (stack->size () - 1)->element);
+ while (doctree->top ())
+ endElement (doctree->top ()->element);
delete stack;
+ delete doctree;
delete cssContext;
}
@@ -72,17 +68,14 @@ void StyleEngine::startElement (int element) {
style0 ();
stack->increase ();
- Node *n = stack->getRef (stack->size () - 1);
- n->num = num++;
+ Node *n = stack->getRef (stack->size () - 1);
n->style = NULL;
n->wordStyle = NULL;
- n->depth = stack->size () - 1;
- n->element = element;
- n->id = NULL;
- n->klass = NULL;
- n->pseudo = NULL;
n->styleAttribute = NULL;
n->inheritBackgroundColor = false;
+
+ DoctreeNode *dn = doctree->push ();
+ dn->element = element;
}
void StyleEngine::startElement (const char *tagname) {
@@ -90,9 +83,9 @@ void StyleEngine::startElement (const char *tagname) {
}
void StyleEngine::setId (const char *id) {
- Node *n = stack->getRef (stack->size () - 1);
- assert (n->id == NULL);
- n->id = dStrdup (id);
+ DoctreeNode *dn = doctree->top ();
+ assert (dn->id == NULL);
+ dn->id = dStrdup (id);
};
/**
@@ -121,13 +114,13 @@ static lout::misc::SimpleVector<char *> *splitStr (const char *str, char sep) {
}
void StyleEngine::setClass (const char *klass) {
- Node *n = stack->getRef (stack->size () - 1);
- assert (n->klass == NULL);
- n->klass = splitStr (klass, ' ');
+ DoctreeNode *dn = doctree->top ();
+ assert (dn->klass == NULL);
+ dn->klass = splitStr (klass, ' ');
};
void StyleEngine::setStyle (const char *style) {
- Node *n = stack->getRef (stack->size () - 1);
+ Node *n = stack->getRef (stack->size () - 1);
assert (n->styleAttribute == NULL);
n->styleAttribute = dStrdup (style);
};
@@ -156,16 +149,16 @@ void StyleEngine::inheritBackgroundColor () {
* \brief set the CSS pseudo class :link.
*/
void StyleEngine::setPseudoLink () {
- Node *n = stack->getRef (stack->size () - 1);
- n->pseudo = "link";
+ DoctreeNode *dn = doctree->top ();
+ dn->pseudo = "link";
}
/**
* \brief set the CSS pseudo class :visited.
*/
void StyleEngine::setPseudoVisited () {
- Node *n = stack->getRef (stack->size () - 1);
- n->pseudo = "visited";
+ DoctreeNode *dn = doctree->top ();
+ dn->pseudo = "visited";
}
/**
@@ -173,24 +166,18 @@ void StyleEngine::setPseudoVisited () {
*/
void StyleEngine::endElement (int element) {
assert (stack->size () > 0);
- assert (element == stack->getRef (stack->size () - 1)->element);
+ assert (element == doctree->top ()->element);
- Node *n = stack->getRef (stack->size () - 1);
+ Node *n = stack->getRef (stack->size () - 1);
if (n->style)
n->style->unref ();
if (n->wordStyle)
n->wordStyle->unref ();
- if (n->id)
- dFree ((void*) n->id);
- if (n->klass) {
- for (int i = 0; i < n->klass->size (); i++)
- dFree (n->klass->get(i));
- delete n->klass;
- }
if (n->styleAttribute)
dFree ((void*) n->styleAttribute);
+ doctree->pop ();
stack->setSize (stack->size () - 1);
}
@@ -622,7 +609,7 @@ Style * StyleEngine::style0 (CssPropertyList *nonCssProperties) {
strlen (styleAttribute));
// merge style information
- cssContext->apply (&props, this, styleAttributeProps, nonCssProperties);
+ cssContext->apply (&props, doctree, styleAttributeProps, nonCssProperties);
// apply style
apply (&attrs, &props);
diff --git a/src/styleengine.hh b/src/styleengine.hh
index 8b5dd1fd..66f28cee 100644
--- a/src/styleengine.hh
+++ b/src/styleengine.hh
@@ -17,9 +17,9 @@ class StyleEngine;
* HTML elements and their attributes via the startElement() / endElement()
* methods.
*/
-class StyleEngine : public Doctree {
+class StyleEngine {
private:
- class Node : public DoctreeNode {
+ class Node {
public:
dw::core::style::Style *style;
dw::core::style::Style *wordStyle;
@@ -30,7 +30,7 @@ class StyleEngine : public Doctree {
dw::core::Layout *layout;
lout::misc::SimpleVector <Node> *stack;
CssContext *cssContext;
- int num;
+ Doctree *doctree;
int importDepth;
dw::core::style::Style *style0 (CssPropertyList *nonCssHints = NULL);
@@ -49,24 +49,12 @@ class StyleEngine : public Doctree {
StyleEngine (dw::core::Layout *layout);
~StyleEngine ();
- /* Doctree interface */
- inline const DoctreeNode *top () {
- return stack->getRef (stack->size () - 1);
- };
-
- inline const DoctreeNode *parent (const DoctreeNode *n) {
- if (n->depth > 1)
- return stack->getRef (n->depth - 1);
- else
- return NULL;
- };
-
void parse (DilloHtml *html, DilloUrl *url, const char *buf, int buflen,
CssOrigin origin);
void startElement (int tag);
void startElement (const char *tagname);
void setId (const char *id);
- const char * getId () { return top ()->id; };
+ const char * getId () { return doctree->top ()->id; };
void setClass (const char *klass);
void setStyle (const char *style);
void endElement (int tag);