diff -r e820d7cb2be7 src/cache.c --- a/src/cache.c Sun Dec 27 20:35:17 2009 +0000 +++ b/src/cache.c Mon Dec 28 01:54:09 2009 +0000 @@ -937,7 +937,7 @@ NewUrl = a_Url_new(URL_STR_(entry->Location), URL_STR_(entry->Url)); if (entry->Flags & CA_TempRedirect) a_Url_set_flags(NewUrl, URL_FLAGS(NewUrl) | URL_E2EQuery); - a_Nav_push(bw, NewUrl); + a_Nav_push(bw, NewUrl, entry->Url); a_Url_free(NewUrl); } else { /* Sub entity redirection (most probably an image) */ diff -r e820d7cb2be7 src/capi.c --- a/src/capi.c Sun Dec 27 20:35:17 2009 +0000 +++ b/src/capi.c Mon Dec 28 01:54:09 2009 +0000 @@ -15,6 +15,7 @@ * to get the requests served. Kind of a broker. */ +#include /* isalpha */ #include #include "msg.h" @@ -313,6 +314,86 @@ } /* + * When dillo wants to open an URL, this can be either due to user action + * (e.g., typing in an URL, clicking a link), or automatic (HTTP header + * indicates redirection, META HTML tag with refresh attribute and 0 delay, + * and images and stylesheets on an HTML page when autoloading is enabled). + * + * For a user request, the action will be permitted. + * For an automatic request, permission to load depends on the filter set + * by the user. + */ +static bool_t Capi_filters_allow(const DilloUrl *wanted, + const DilloUrl *requester) +{ + bool_t ret; + + if (requester == NULL) { + /* request made by user */ + ret = TRUE; + } else { + switch (prefs.filter_auto_requests) { + case PREFS_FILTER_SAME_HOST: + ret = dStrcasecmp(URL_HOST(wanted), URL_HOST(requester)) == 0; + break; + case PREFS_FILTER_SAME_DOMAIN: + { + const char *req_host = URL_HOST(requester), + *want_host = URL_HOST(wanted); + uint_t req_hostlen = strlen(req_host); + + MSG("Capi_filters_allow:\n%s\n%s\n", req_host, want_host); + if (req_hostlen > 0 && !isalpha(req_host[req_hostlen - 1])) { + /* for IP addrs, match fully */ + ret = dStrcasecmp(req_host, want_host) == 0; + } else { + /* For hostnames, let's say for now that if you have two dots, + * we'll ignore everything through the first dot, e.g., + * 'www.dillo.org' => 'dillo.org' + * + * TODO: it sounds like requiring a third dot would be best for + * ai,au,bd,bh,ck,eg,et,fk,il,in,kh,kr,mk,mt,na,np,nz,pg,pk,qa, + * sa,sb,sg,sv,ua,ug,uk,uy,vn,za,zw, name + */ + uint_t want_hostlen; + char *dot = strchr(req_host, '.'); + + if (dot && strchr(dot + 1, '.')) { + req_hostlen -= dot + 1 - req_host; + req_host = dot + 1; + } + want_hostlen = strlen(want_host); + + if (want_hostlen < req_hostlen) { + ret = FALSE; + } else { + if (want_hostlen > req_hostlen && + want_host[want_hostlen - req_hostlen - 1] == '.') { + /* If the longer, leading portion of the host ends with + * a dot, trim it off, e.g., 'hg.dillo.org' => 'dillo.org' + * but 'hgdillo.org' would be unchanged. + */ + want_host += want_hostlen - req_hostlen; + } + ret = dStrcasecmp(req_host, want_host) == 0; + } + } + if (ret) + MSG("ALLOW\n"); + else + MSG("BLOCK\n"); + break; + } + case PREFS_FILTER_ALLOW_ALL: + default: + ret = TRUE; + break; + } + } + return ret; +} + +/* * Most used function for requesting a URL. * TODO: clean up the ad-hoc bindings with an API that allows dynamic * addition of new plugins. @@ -328,6 +409,9 @@ const char *scheme = URL_SCHEME(web->url); int safe = 0, ret = 0, use_cache = 0; + dReturn_val_if_fail((a_Capi_get_flags(web->url) & CAPI_IsCached) || + Capi_filters_allow(web->url, web->requester), 0); + /* reload test */ reload = (!(a_Capi_get_flags(web->url) & CAPI_IsCached) || (URL_FLAGS(web->url) & URL_E2EQuery)); diff -r e820d7cb2be7 src/html.cc --- a/src/html.cc Sun Dec 27 20:35:17 2009 +0000 +++ b/src/html.cc Mon Dec 28 01:54:09 2009 +0000 @@ -105,8 +105,8 @@ const char *attrname, int tag_parsing_flags); static int Html_write_raw(DilloHtml *html, char *buf, int bufsize, int Eof); -static void Html_load_image(BrowserWindow *bw, DilloUrl *url, - DilloImage *image); +static bool Html_load_image(BrowserWindow *bw, DilloUrl *url, + const DilloUrl *requester, DilloImage *image); static void Html_callback(int Op, CacheClient_t *Client); static void Html_tag_cleanup_at_close(DilloHtml *html, int TagIdx); @@ -654,12 +654,21 @@ { dReturn_if_fail (bw->nav_expecting == FALSE); + /* If the user asked for a specific URL, the user (NULL) is the requester, + * but if the user just asked for all URLs, use the page URL as the + * requester. If the possible patterns become more complex, it might be + * good to have the caller supply the requester instead. + */ + const DilloUrl *requester = pattern ? NULL : this->page_url; + for (int i = 0; i < images->size(); i++) { if (images->get(i)->image) { if ((!pattern) || (!a_Url_cmp(images->get(i)->url, pattern))) { - Html_load_image(bw, images->get(i)->url, images->get(i)->image); - a_Image_unref (images->get(i)->image); - images->get(i)->image = NULL; // web owns it now + if (Html_load_image(bw, images->get(i)->url, requester, + images->get(i)->image)) { + a_Image_unref (images->get(i)->image); + images->get(i)->image = NULL; // web owns it now + } } } } @@ -2086,9 +2095,10 @@ load_now = prefs.load_images || (a_Capi_get_flags_with_redirection(url) & CAPI_IsCached); - Html_add_new_htmlimage(html, &url, load_now ? NULL : Image); + bool loading = false; if (load_now) - Html_load_image(html->bw, url, Image); + loading = Html_load_image(html->bw, url, html->page_url, Image); + Html_add_new_htmlimage(html, &url, loading ? NULL : Image); dFree(tooltip_str); dFree(width_ptr); @@ -2100,13 +2110,13 @@ /* * Tell cache to retrieve image */ -static void Html_load_image(BrowserWindow *bw, DilloUrl *url, - DilloImage *Image) +static bool Html_load_image(BrowserWindow *bw, DilloUrl *url, + const DilloUrl *requester, DilloImage *Image) { DilloWeb *Web; int ClientKey; /* Fill a Web structure for the cache query */ - Web = a_Web_new(url); + Web = a_Web_new(url, requester); Web->bw = bw; Web->Image = Image; a_Image_ref(Image); @@ -2116,6 +2126,7 @@ a_Bw_add_client(bw, ClientKey, 0); a_Bw_add_url(bw, url); } + return ClientKey != 0; } /* @@ -2924,7 +2935,7 @@ } else { /* Fill a Web structure for the cache query */ int ClientKey; - DilloWeb *Web = a_Web_new(url); + DilloWeb *Web = a_Web_new(url, html->page_url); Web->bw = html->bw; if ((ClientKey = a_Capi_open_url(Web, Html_css_load_callback, NULL))) { ++html->bw->NumPendingStyleSheets; diff -r e820d7cb2be7 src/nav.c --- a/src/nav.c Sun Dec 27 20:35:17 2009 +0000 +++ b/src/nav.c Mon Dec 28 01:54:09 2009 +0000 @@ -191,7 +191,8 @@ * This function requests the page's root-URL; images and related stuff * are fetched directly by the HTML module. */ -static void Nav_open_url(BrowserWindow *bw, const DilloUrl *url, int offset) +static void Nav_open_url(BrowserWindow *bw, const DilloUrl *url, + const DilloUrl *requester, int offset) { DilloUrl *old_url; bool_t MustLoad, ForceReload, Repush, IgnoreScroll; @@ -232,7 +233,7 @@ // a_Menu_pagemarks_new(bw); - Web = a_Web_new(url); + Web = a_Web_new(url, requester); Web->bw = bw; Web->flags |= WEB_RootUrl; if ((ClientKey = a_Capi_open_url(Web, NULL, NULL)) != 0) { @@ -341,7 +342,8 @@ * - Set bw to expect the URL data * - Ask the cache to feed back the requested URL (via Nav_open_url) */ -void a_Nav_push(BrowserWindow *bw, const DilloUrl *url) +void a_Nav_push(BrowserWindow *bw, const DilloUrl *url, + const DilloUrl *requester) { dReturn_if_fail (bw != NULL); @@ -353,7 +355,7 @@ a_Nav_cancel_expect(bw); bw->nav_expect_url = a_Url_dup(url); bw->nav_expecting = TRUE; - Nav_open_url(bw, url, 0); + Nav_open_url(bw, url, requester, 0); } /* @@ -370,7 +372,7 @@ a_Url_set_flags(url, URL_FLAGS(url) | URL_ReloadFromCache); bw->nav_expect_url = a_Url_dup(url); bw->nav_expecting = TRUE; - Nav_open_url(bw, url, 0); + Nav_open_url(bw, url, NULL, 0); a_Url_free(url); } } @@ -407,7 +409,7 @@ if (bw->meta_refresh_status == 2) { Nav_stack_move_ptr(bw, -1); - a_Nav_push(bw, bw->meta_refresh_url); + a_Nav_push(bw, bw->meta_refresh_url,a_History_get_url(NAV_TOP_UIDX(bw))); } a_Url_free(bw->meta_refresh_url); bw->meta_refresh_url = NULL; @@ -441,7 +443,7 @@ a_Nav_cancel_expect(bw); if (--idx >= 0){ a_UIcmd_set_msg(bw, ""); - Nav_open_url(bw, a_History_get_url(NAV_UIDX(bw,idx)), -1); + Nav_open_url(bw, a_History_get_url(NAV_UIDX(bw,idx)), NULL, -1); } } @@ -455,7 +457,7 @@ a_Nav_cancel_expect(bw); if (++idx < a_Nav_stack_size(bw)) { a_UIcmd_set_msg(bw, ""); - Nav_open_url(bw, a_History_get_url(NAV_UIDX(bw,idx)), +1); + Nav_open_url(bw, a_History_get_url(NAV_UIDX(bw,idx)), NULL, +1); } } @@ -464,7 +466,7 @@ */ void a_Nav_home(BrowserWindow *bw) { - a_Nav_push(bw, prefs.home); + a_Nav_push(bw, prefs.home, NULL); } /* @@ -496,7 +498,7 @@ a_Url_set_flags(r_url, URL_FLAGS(r_url) & ~URL_SpamSafe); bw->nav_expect_url = r_url; bw->nav_expecting = TRUE; - Nav_open_url(bw, r_url, 0); + Nav_open_url(bw, r_url, NULL, 0); } } } @@ -523,7 +525,7 @@ a_UIcmd_open_url_nw(bw, a_History_get_url(NAV_UIDX(bw,idx))); } else { a_Nav_cancel_expect(bw); - Nav_open_url(bw, a_History_get_url(NAV_UIDX(bw,idx)), offset); + Nav_open_url(bw, a_History_get_url(NAV_UIDX(bw,idx)), NULL, offset); a_UIcmd_set_buttons_sens(bw); } } @@ -560,7 +562,7 @@ void a_Nav_save_url(BrowserWindow *bw, const DilloUrl *url, const char *filename) { - DilloWeb *Web = a_Web_new(url); + DilloWeb *Web = a_Web_new(url, NULL); Web->bw = bw; Web->filename = dStrdup(filename); Web->flags |= WEB_Download; diff -r e820d7cb2be7 src/nav.h --- a/src/nav.h Sun Dec 27 20:35:17 2009 +0000 +++ b/src/nav.h Mon Dec 28 01:54:09 2009 +0000 @@ -14,7 +14,8 @@ #endif /* __cplusplus */ void a_Nav_redirection0(BrowserWindow *bw, const DilloUrl *new_url); -void a_Nav_push(BrowserWindow *bw, const DilloUrl *url); +void a_Nav_push(BrowserWindow *bw, const DilloUrl *url, + const DilloUrl *requester); void a_Nav_repush(BrowserWindow *bw); void a_Nav_back(BrowserWindow *bw); void a_Nav_forw(BrowserWindow *bw); diff -r e820d7cb2be7 src/prefs.c --- a/src/prefs.c Sun Dec 27 20:35:17 2009 +0000 +++ b/src/prefs.c Mon Dec 28 01:54:09 2009 +0000 @@ -39,6 +39,7 @@ prefs.buffered_drawing = 1; prefs.contrast_visited_color = TRUE; prefs.enterpress_forces_submit = FALSE; + prefs.filter_auto_requests = PREFS_FILTER_ALLOW_ALL; prefs.focus_new_tab = TRUE; prefs.font_cursive = dStrdup(PREFS_FONT_CURSIVE); prefs.font_factor = 1.0; diff -r e820d7cb2be7 src/prefs.h --- a/src/prefs.h Sun Dec 27 20:35:17 2009 +0000 +++ b/src/prefs.h Mon Dec 28 01:54:09 2009 +0000 @@ -26,6 +26,10 @@ /* Panel sizes */ enum { P_tiny = 0, P_small, P_medium, P_large }; +enum {PREFS_FILTER_ALLOW_ALL, + PREFS_FILTER_SAME_HOST, + PREFS_FILTER_SAME_DOMAIN}; + typedef struct _DilloPrefs DilloPrefs; struct _DilloPrefs { @@ -69,6 +73,7 @@ bool_t load_images; bool_t load_stylesheets; bool_t parse_embedded_css; + int filter_auto_requests; int32_t buffered_drawing; char *font_serif; char *font_sans_serif; diff -r e820d7cb2be7 src/prefsparser.cc --- a/src/prefsparser.cc Sun Dec 27 20:35:17 2009 +0000 +++ b/src/prefsparser.cc Mon Dec 28 01:54:09 2009 +0000 @@ -26,6 +26,7 @@ PREFS_INT32, PREFS_DOUBLE, PREFS_GEOMETRY, + PREFS_FILTER, PREFS_PANEL_SIZE } PrefType_t; @@ -50,6 +51,7 @@ { "contrast_visited_color", &prefs.contrast_visited_color, PREFS_BOOL }, { "enterpress_forces_submit", &prefs.enterpress_forces_submit, PREFS_BOOL }, + { "filter_auto_requests", &prefs.filter_auto_requests, PREFS_FILTER }, { "focus_new_tab", &prefs.focus_new_tab, PREFS_BOOL }, { "font_cursive", &prefs.font_cursive, PREFS_STRING }, { "font_factor", &prefs.font_factor, PREFS_DOUBLE }, @@ -136,6 +138,17 @@ a_Misc_parse_geometry(value, &prefs.xpos, &prefs.ypos, &prefs.width, &prefs.height); break; + case PREFS_FILTER: + if (!dStrcasecmp(value, "same_host")) + prefs.filter_auto_requests = PREFS_FILTER_SAME_HOST; + else if (!dStrcasecmp(value, "same_domain")) + prefs.filter_auto_requests = PREFS_FILTER_SAME_DOMAIN; + else { + if (dStrcasecmp(value, "allow_all")) + MSG_WARN("prefs: unrecognized value for filter_auto_requests\n"); + prefs.filter_auto_requests = PREFS_FILTER_ALLOW_ALL; + } + break; case PREFS_PANEL_SIZE: if (!dStrcasecmp(value, "tiny")) prefs.panel_size = P_tiny; diff -r e820d7cb2be7 src/uicmd.cc --- a/src/uicmd.cc Sun Dec 27 20:35:17 2009 +0000 +++ b/src/uicmd.cc Mon Dec 28 01:54:09 2009 +0000 @@ -616,7 +616,7 @@ */ void a_UIcmd_open_url(BrowserWindow *bw, const DilloUrl *url) { - a_Nav_push(bw, url); + a_Nav_push(bw, url, NULL); a_UIcmd_focus_main_area(bw); } @@ -626,7 +626,7 @@ * Location if we don't yet have an URL, main otherwise. */ if (url) { - a_Nav_push(new_bw, url); + a_Nav_push(new_bw, url, NULL); BW2UI(new_bw)->focus_main(); } else { BW2UI(new_bw)->focus_location(); @@ -840,7 +840,7 @@ if (name) { url = a_Url_new(name, "file:"); - a_Nav_push((BrowserWindow*)vbw, url); + a_Nav_push((BrowserWindow*)vbw, url, NULL); a_Url_free(url); dFree(name); } @@ -931,7 +931,7 @@ void a_UIcmd_book(void *vbw) { DilloUrl *url = a_Url_new("dpi:/bm/", NULL); - a_Nav_push((BrowserWindow*)vbw, url); + a_Nav_push((BrowserWindow*)vbw, url, NULL); a_Url_free(url); } diff -r e820d7cb2be7 src/web.cc --- a/src/web.cc Sun Dec 27 20:35:17 2009 +0000 +++ b/src/web.cc Mon Dec 28 01:54:09 2009 +0000 @@ -103,12 +103,13 @@ /* * Allocate and set safe values for a DilloWeb structure */ -DilloWeb* a_Web_new(const DilloUrl *url) +DilloWeb* a_Web_new(const DilloUrl *url, const DilloUrl *requester) { DilloWeb *web= dNew(DilloWeb, 1); _MSG(" a_Web_new: ValidWebs ==> %d\n", dList_length(ValidWebs)); web->url = a_Url_dup(url); + web->requester = a_Url_dup(requester); web->bw = NULL; web->flags = 0; web->Image = NULL; @@ -136,6 +137,7 @@ { if (!web) return; a_Url_free(web->url); + a_Url_free(web->requester); a_Image_unref(web->Image); dFree(web->filename); dList_remove(ValidWebs, (void *)web); diff -r e820d7cb2be7 src/web.hh --- a/src/web.hh Sun Dec 27 20:35:17 2009 +0000 +++ b/src/web.hh Mon Dec 28 01:54:09 2009 +0000 @@ -22,6 +22,8 @@ struct _DilloWeb { DilloUrl *url; /* Requested URL */ + DilloUrl *requester; /* URL that caused this request, or + * NULL if user-initiated. */ BrowserWindow *bw; /* The requesting browser window [reference] */ int flags; /* Additional info */ @@ -34,7 +36,7 @@ }; void a_Web_init(void); -DilloWeb* a_Web_new (const DilloUrl* url); +DilloWeb* a_Web_new (const DilloUrl* url, const DilloUrl *requester); int a_Web_valid(DilloWeb *web); void a_Web_free (DilloWeb*); int a_Web_dispatch_by_type (const char *Type, DilloWeb *web,