--- cache.c.orig Wed Oct 27 10:04:18 2004 +++ cache.c Wed Oct 27 15:05:33 2004 @@ -34,6 +34,7 @@ #include "misc.h" #define NULLKey 0 +#define LINE_MAXLEN 4096 #define DEBUG_LEVEL 5 #include "debug.h" @@ -57,6 +58,16 @@ typedef struct { ChainLink *CCCAnswer; /* CCC link for answering branch */ } CacheData_t; +typedef enum { + CACHE_ACCEPT, + CACHE_ACCEPT_SESSION, + CACHE_DENY +} CacheControlAction; + +typedef struct { + CacheControlAction action; + char *domain; +} CacheControl; /* * Local data @@ -73,6 +84,11 @@ static GSList *ClientQueue = NULL; static GSList *DelayedQueue = NULL; static guint DelayedQueueIdleId = 0; +/* Variables for access control */ +static CacheControl *ccontrol = NULL; +static int num_ccontrol = 0; +static int num_ccontrol_max = 1; +static CacheControlAction default_action = CACHE_DENY; /* * Forward declarations @@ -81,6 +97,12 @@ static void Cache_process_queue(CacheDat static void Cache_delayed_process_queue(CacheData_t *entry); static void Cache_stop_client(gint Key, gint force); +/* these should be moved */ +static FILE *Cache_fopen(const char *filename, gchar *init_str); +static int Cache_control_init(void); +static CacheControlAction Cache_control_check_domain(const char *domain); +static CacheControlAction Cache_control_check(const DilloUrl *url); + /* * Determine if two hash entries are equal (used by GHashTable) */ @@ -110,6 +132,15 @@ static guint Cache_url_hash(gconstpointe void a_Cache_init(void) { CacheHash = g_hash_table_new(Cache_url_hash, Cache_hash_entry_equal); + + /* Read and parse the cache control file (cacherc) */ + if (Cache_control_init() != 0) { + DEBUG_MSG(10, "Cache control disable, all pages will be cached.\n"); + return; + } + + DEBUG_MSG(10, "Enabling cache control as from cacherc...\n"); + return; } /* Client operations ------------------------------------------------------ */ @@ -367,12 +398,21 @@ static gint Cache_open_url(DilloWeb *Web _MSG("Cache_open_url: %s %sFOUND\n", URL_STR(Url), entry ? "" : "NOT "); - if ( entry ) { - /* URL is cached: feed our client with cached data */ + if ( entry && (!(entry->Flags & CA_NoCache))) { + /* URL is cached and set to use cache: feed our client with cached data */ ClientKey = Cache_client_enqueue(entry->Url, Web, Call, CbData); Cache_delayed_process_queue(entry); } else { + if ( entry && (entry->Flags & CA_NoCache)) { + /* URL is cached, but set to not cache, check for access */ + if (!Cache_control_check(Url)) { + DEBUG_MSG(10, "Caching is disabled for this page\n"); + Cache_prepare_reload(Url); + } else { + DEBUG_MSG(10, "Page requested no caching, but lacks access in cacherc.\n"); + } + } /* URL not cached: create an entry, send our client to the queue, * and open a new connection */ entry = Cache_entry_add(Url); @@ -1149,4 +1189,169 @@ void a_Cache_freeall(void) NULL); /* Remove the cache hash */ g_hash_table_destroy(CacheHash); +} + +/* + * set the CA_NoCache flag for this URL + */ +void a_Cache_set_nocache_flag(DilloUrl *Url) +{ + CacheData_t *entry = Cache_entry_search(Url); + entry->Flags |= CA_NoCache; +} + +/* ------------------------------------------------------------- + * Access control routines + * ------------------------------------------------------------- */ + +/* + * Return a file pointer. If the file doesn't exist, try to create it, + * with the optional 'init_str' as its content. + */ +static FILE *Cache_fopen(const char *filename, gchar *init_str) +{ + FILE *F_in; + int fd; + + if ((F_in = fopen(filename, "r+")) == NULL) { + /* Create the file */ + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd != -1) { + if (init_str) + write(fd, init_str, strlen(init_str)); + close(fd); + + DEBUG_MSG(10, "Cache: Created file: %s\n", filename); + F_in = Cache_fopen(filename, NULL); + } else { + DEBUG_MSG(10, "Cache: Could not create file: %s!\n", filename); + } + } + + /* set close on exec */ + fcntl(fileno(F_in), F_SETFD, FD_CLOEXEC | fcntl(fileno(F_in), F_GETFD)); + + return F_in; +} + +/* + * Get the cache control rules (from cacherc). + * Return value: + * 0 = Parsed OK, with no-cache enabled + * 1 = Parsed OK, with no-cache disabled + * 2 = Can't open the control file + */ +static int Cache_control_init(void) +{ + CacheControl cc; + FILE *stream; + char *filename; + char line[LINE_MAXLEN]; + char domain[LINE_MAXLEN]; + char rule[LINE_MAXLEN]; + int i, j; + gboolean enabled = FALSE; + + /* Get a file pointer */ + filename = a_Misc_prepend_user_home(".dillo/cacherc"); + stream = Cache_fopen(filename, "DEFAULT DENY\n"); + g_free(filename); + + if (!stream) + return 2; + + /* Get all lines in the file */ + while (!feof(stream)) { + line[0] = '\0'; + fgets(line, LINE_MAXLEN, stream); + + /* Remove leading and trailing whitespaces */ + g_strstrip(line); + + if (line[0] != '\0' && line[0] != '#') { + i = 0; + j = 0; + + /* Get the domain */ + while (!isspace(line[i])) + domain[j++] = line[i++]; + domain[j] = '\0'; + + /* Skip past whitespaces */ + i++; + while (isspace(line[i])) + i++; + + /* Get the rule */ + j = 0; + while (line[i] != '\0' && !isspace(line[i])) + rule[j++] = line[i++]; + rule[j] = '\0'; + + if (g_strcasecmp(rule, "ACCEPT") == 0) + cc.action = CACHE_ACCEPT; + else if (g_strcasecmp(rule, "ACCEPT_SESSION") == 0) + cc.action = CACHE_ACCEPT_SESSION; + else if (g_strcasecmp(rule, "DENY") == 0) + cc.action = CACHE_DENY; + else { + MSG("Cache: rule '%s' for domain '%s' is not recognised.\n", + rule, domain); + continue; + } + + cc.domain = g_strdup(domain); + if (g_strcasecmp(cc.domain, "DEFAULT") == 0) { + /* Set the default action */ + default_action = cc.action; + g_free(cc.domain); + } else { + a_List_add(ccontrol, num_ccontrol, num_ccontrol_max); + ccontrol[num_ccontrol++] = cc; + } + + if (cc.action != CACHE_DENY) + enabled = TRUE; + } + } + + fclose(stream); + + return (enabled ? 0 : 1); +} + +/* + * Check the rules for an appropriate action for this domain + */ +static CacheControlAction Cache_control_check_domain(const char *domain) +{ + int i, diff; + + for (i = 0; i < num_ccontrol; i++) { + if (ccontrol[i].domain[0] == '.') { + diff = strlen(domain) - strlen(ccontrol[i].domain); + if (diff >= 0) { + if (g_strcasecmp(domain + diff, ccontrol[i].domain) != 0) + continue; + } else { + continue; + } + } else { + if (g_strcasecmp(domain, ccontrol[i].domain) != 0) + continue; + } + + /* If we got here we have a match */ + return( ccontrol[i].action ); + } + + return default_action; +} + +/* + * Same as the above except it takes an URL + */ +static CacheControlAction Cache_control_check(const DilloUrl *url) +{ + return Cache_control_check_domain(URL_HOST(url)); } --- cache.h.orig Wed Oct 27 10:10:19 2004 +++ cache.h Wed Oct 27 15:06:26 2004 @@ -26,6 +26,7 @@ #define CA_Stopped (256) /* True if the entry has been stopped */ #define CA_MsgErased (512) /* Used to erase the bw's status bar */ #define CA_RedirectLoop (1024) /* Redirect loop */ +#define CA_NoCache (2048) /* Do not cache this page */ /* * Callback type for cache clients @@ -55,6 +56,7 @@ gint a_Cache_get_buf(const DilloUrl *Url void a_Cache_freeall(void); void a_Cache_null_client(int Op, CacheClient_t *Client); void a_Cache_stop_client(gint Key); +void a_Cache_set_nocache_flag(DilloUrl *Url); #endif /* __CACHE_H__ */ --- html.c.orig Wed Oct 27 09:03:32 2004 +++ html.c Wed Oct 27 15:06:40 2004 @@ -3088,27 +3088,33 @@ static void Html_tag_open_meta(DilloHtml } if ((equiv = Html_get_attr(html, tag, tagsize, "http-equiv")) && - !g_strcasecmp(equiv, "refresh") && (content = Html_get_attr(html, tag, tagsize, "content"))) { - /* Get delay, if present, and make a message with it */ - if ((delay = strtol(content, NULL, 0))) - g_snprintf(delay_str, 64, " after %d second%s.", - delay, (delay > 1) ? "s" : ""); - else - sprintf(delay_str, "."); + if (!g_strcasecmp(equiv, "refresh")) { + /* Get delay, if present, and make a message with it */ + if ((delay = strtol(content, NULL, 0))) + g_snprintf(delay_str, 64, " after %d second%s.", + delay, (delay > 1) ? "s" : ""); + else + sprintf(delay_str, "."); - /* Skip to anything after "URL=" */ - while (*content && *(content++) != '='); + /* Skip to anything after "URL=" */ + while (*content && *(content++) != '='); - /* Send a custom HTML message */ - html_msg = g_strdup_printf(meta_template, content, delay_str); - { - DilloHtmlProcessingState SaveFlags = html->InFlags; - Html_write_raw(html, html_msg, strlen(html_msg), 0); - html->InFlags = SaveFlags; + /* Send a custom HTML message */ + html_msg = g_strdup_printf(meta_template, content, delay_str); + { + DilloHtmlProcessingState SaveFlags = html->InFlags; + Html_write_raw(html, html_msg, strlen(html_msg), 0); + html->InFlags = SaveFlags; + } + g_free(html_msg); + } + + /* check to see if there is a request to not cache the page */ + if (!g_strcasecmp(content, "no-cache")) { + a_Cache_set_nocache_flag(html->linkblock->base_url); } - g_free(html_msg); } }