diff options
author | portix <portix@gmx.net> | 2011-11-29 22:48:51 +0100 |
---|---|---|
committer | portix <portix@gmx.net> | 2011-11-29 22:48:51 +0100 |
commit | 452d890acc1ae55390fa55cfbfec07b809225d79 (patch) | |
tree | b65c360282db379bce32d6ddf06487bbd477a025 /src/adblock.c | |
parent | 1b3f2e28a6dbcb3870296d35ab3a7fdd2966dfbe (diff) | |
download | dwb-452d890acc1ae55390fa55cfbfec07b809225d79.zip |
Blocking beforeload events using JavaScriptCore directly instead of using a script.
--HG--
branch : experimental
Diffstat (limited to 'src/adblock.c')
-rw-r--r-- | src/adblock.c | 202 |
1 files changed, 119 insertions, 83 deletions
diff --git a/src/adblock.c b/src/adblock.c index 384af90f..88a939a6 100644 --- a/src/adblock.c +++ b/src/adblock.c @@ -59,28 +59,6 @@ typedef enum _AdblockAttribute { } AdblockAttribute; #define AA_FRAME (AA_SUBDOCUMENT | (AA_SUBDOCUMENT<<ADBLOCK_INVERSE)) -//typedef enum _ThirdParty { -// TP_TRUE, -// TP_FALSE, -// TP_UNKNOWN, -//} ThirdParty; -const static char *adblockscript = "function dwbAdblockBeforeLoad(e){\ - var i=%d; \ - if (e.srcElement instanceof HTMLScriptElement) \ - i |= 1<<0; \ - else if (e.srcElement instanceof HTMLImageElement) \ - i |= 1<<1; \ - else if (e.srcElement instanceof HTMLLinkElement && (e.srcElement.rel == 'stylesheet' || e.srcElement.type == 'text/css')) \ - i |= 1<<2;\ - else if (e.srcElement instanceof HTMLObjectElement || e.srcElement instanceof HTMLEmbedElement) \ - i |= 1<<3;\ - var base = e.srcElement.baseURI;\ - if (base.charAt(base.length-1) == '/' && e.url.charAt(0) == '/') \ - base = base.substring(0, base.length-1);\ - var url = /^https?:\\/\\//.test(e.url) ? e.url : base + e.url;\ - if (%s(i, url, e.srcElement.baseURI)) { e.preventDefault(); }\ - }; window.addEventListener('beforeload', dwbAdblockBeforeLoad, true);"; - typedef struct _AdblockRule { GRegex *pattern; AdblockOption options; @@ -95,6 +73,7 @@ typedef struct _AdblockElementHider { } AdblockElementHider; /*}}}*/ +static JSValueRef adblock_js_callback(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); /* Static variables {{{*/ static GPtrArray *_simple_rules; @@ -230,70 +209,129 @@ adblock_match(GPtrArray *array, const char *uri, const char *uri_host, const cha return match; }/*}}}*//*}}}*/ - -/* LOAD_CALLBACKS {{{*/ /* adblock_js_callback {{{*/ -JSValueRef +static JSValueRef adblock_js_callback(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exception) { - JSValueRef exc = NULL; - char *uri = NULL, *baseuri = NULL; + if (argc != 1 || ! JSValueIsObject(ctx, argv[0])) + return JSValueMakeBoolean(ctx, false); + char *tagname = NULL; + char *baseuri = NULL; + char *tmpuri = NULL; + char *uri = NULL; + char *rel = NULL; + char *type = NULL; SoupURI *suri = NULL, *sbaseuri = NULL; - gboolean ret = false; - gboolean thirdparty; - - if(argc == 3 && JSValueIsNumber(ctx, argv[0])) { - int options = (int)JSValueToNumber(ctx, argv[0], &exc); - if (exc != NULL) - return JSValueMakeBoolean(ctx, false); - - uri = js_value_to_char(ctx, argv[1]); - if (uri == NULL) - return JSValueMakeBoolean(ctx, false); + JSValueRef exc = NULL; + JSObjectRef event = JSValueToObject(ctx, argv[0], &exc); + if (exc != NULL) + return NULL; + + + JSObjectRef srcElement = js_get_object_property(ctx, event, "srcElement"); + if (srcElement == NULL) + return JSValueMakeBoolean(ctx, false); + baseuri = js_get_string_property(ctx, srcElement, "baseURI"); + if (baseuri == NULL) + goto error_out; + tmpuri = js_get_string_property(ctx, event, "url"); + if (tmpuri == NULL) + goto error_out; + + int attributes = (int)js_get_double_property(ctx, function, "attributes"); + + tagname = js_get_string_property(ctx, srcElement, "tagName"); + if (!g_strcmp0(tagname, "IMG")) + attributes |= AA_IMAGE; + else if (!g_strcmp0(tagname, "SCRIPT")) + attributes |= AA_SCRIPT; + else if (!g_strcmp0(tagname, "LINK") ) { + rel = js_get_string_property(ctx, srcElement, "rel"); + type = js_get_string_property(ctx, srcElement, "type"); + if (!g_strcmp0(rel, "stylesheet") || !g_strcmp0(type, "text/css")) { + attributes |= AA_STYLESHEET; + } + FREE(rel); + FREE(type); + } + else if (!g_strcmp0(tagname, "OBJECT") || ! g_strcmp0(tagname, "EMBED")) { + attributes |= AA_OBJECT; + } - baseuri = js_value_to_char(ctx, argv[2]); - if (baseuri == NULL) - goto error_out; + /* Check for relative paths. + * WebKit will only handle http(s), so it is not required to check for other + * schemes + */ + if (! g_regex_match_simple("^https?://", tmpuri, 0, 0)) { + int offset = *tmpuri == '/' && g_str_has_suffix(baseuri, "/") ? 1 : 0; + uri = g_strconcat(baseuri, tmpuri+offset, NULL); + g_free(tmpuri); + } + else + uri = tmpuri; - SoupURI *suri = soup_uri_new(uri); - if (suri == NULL) - goto error_out; - SoupURI *sbaseuri = soup_uri_new(baseuri); - if (sbaseuri == NULL) - goto error_out; + suri = soup_uri_new(uri); + if (suri == NULL) + goto error_out; + sbaseuri = soup_uri_new(baseuri); + if (sbaseuri == NULL) + goto error_out; - const char *host = soup_uri_get_host(suri); - if (host == NULL) - goto error_out; - const char *basehost = soup_uri_get_host(sbaseuri); - if (basehost == NULL) - goto error_out; - - const char *domain = domain_get_base_for_host(host); - const char *basedomain = domain_get_base_for_host(basehost); - thirdparty = g_strcmp0(domain, basedomain); - if (!adblock_match(_exceptions, uri, host, domain, basehost, basedomain, options, thirdparty)) { - if (adblock_match(_rules, uri, host, domain, basehost, basedomain, options, thirdparty)) { - ret = true; + /* FIXME: soup_uri_get_host is just used to get parse the uri */ + const char *host = soup_uri_get_host(suri); + if (host == NULL) + goto error_out; + const char *basehost = soup_uri_get_host(sbaseuri); + if (basehost == NULL) + goto error_out; + + const char *domain = domain_get_base_for_host(host); + const char *basedomain = domain_get_base_for_host(basehost); + gboolean thirdparty = g_strcmp0(domain, basedomain); + if (!adblock_match(_exceptions, uri, host, domain, basehost, basedomain, attributes, thirdparty)) { + if (adblock_match(_rules, uri, host, domain, basehost, basedomain, attributes, thirdparty)) { + JSObjectRef prevent = js_get_object_property(ctx, event, "preventDefault"); + if (prevent) { + JSObjectCallAsFunction(ctx, prevent, event, 0, NULL, NULL); } } } + + error_out: - if (uri != NULL) g_free(uri); - if (baseuri != NULL) g_free(baseuri); - if (suri != NULL) soup_uri_free(suri); - if (sbaseuri != NULL) soup_uri_free(sbaseuri); - return JSValueMakeBoolean(ctx, ret); + if (suri != NULL) soup_uri_free(suri); + if (sbaseuri != NULL) soup_uri_free(sbaseuri); + if (tagname) g_free(tagname); + if (baseuri) g_free(baseuri); + if (uri) g_free(uri); + + + return NULL; }/*}}}*/ +/* LOAD_CALLBACKS {{{*/ +/* js_create_callback {{{*/ +static void +adblock_create_js_callback(WebKitWebFrame *frame, JSObjectCallAsFunctionCallback function, int attr) { + JSContextRef ctx = webkit_web_frame_get_global_context(frame); + JSObjectRef globalObject = JSContextGetGlobalObject(ctx); + JSObjectRef newcall = JSObjectMakeFunctionWithCallback(ctx, NULL, function); + JSStringRef jsattr = JSStringCreateWithUTF8CString("attributes"); + JSObjectSetProperty(ctx, newcall, jsattr, JSValueMakeNumber(ctx, attr), + kJSPropertyAttributeDontDelete | kJSPropertyAttributeDontEnum | kJSPropertyAttributeReadOnly, NULL); + JSStringRelease(jsattr); + JSValueRef val = js_get_object_property(ctx, globalObject, "addEventListener"); + if (val) { + JSStringRef beforeLoadString = JSStringCreateWithUTF8CString("beforeload"); + JSValueRef values[3] = { JSValueMakeString(ctx, beforeLoadString), newcall, JSValueMakeBoolean(ctx, true), }; + JSObjectCallAsFunction(ctx, JSValueToObject(ctx, val, NULL), globalObject, 3, values, NULL); + JSStringRelease(beforeLoadString); + } +}/*}}}*/ /* adblock_frame_load_committed_cb {{{*/ static void adblock_frame_load_committed_cb(WebKitWebFrame *frame, GList *gl) { - const char *name = "dwbGoAndBlockAdsFromThisFrameCallback"; - js_create_callback(frame, name, (JSObjectCallAsFunctionCallback)adblock_js_callback); - char *command = g_strdup_printf(adblockscript, AA_SUBDOCUMENT, name); - dwb_execute_script(frame, command, false); - g_free(command); + adblock_create_js_callback(frame, (JSObjectCallAsFunctionCallback)adblock_js_callback, AA_SUBDOCUMENT); }/*}}}*/ /* adblock_frame_created_cb {{{*/ @@ -302,6 +340,7 @@ adblock_frame_created_cb(WebKitWebView *wv, WebKitWebFrame *frame, GList *gl) { g_signal_connect(frame, "load-committed", G_CALLBACK(adblock_frame_load_committed_cb), gl); }/*}}}*/ +/* adblock_resource_request_cb {{{*/ static void adblock_resource_request_cb(WebKitWebView *wv, WebKitWebFrame *frame, WebKitWebResource *resource, WebKitNetworkRequest *request, @@ -340,9 +379,8 @@ adblock_resource_request_cb(WebKitWebView *wv, WebKitWebFrame *frame, webkit_network_request_set_uri(request, "about:blank"); } } - +}/*}}}*/ -} /* adblock_load_status_cb(WebKitWebView *, GParamSpec *, GList *) {{{*/ static void adblock_load_status_cb(WebKitWebView *wv, GParamSpec *p, GList *gl) { @@ -352,20 +390,16 @@ adblock_load_status_cb(WebKitWebView *wv, GParamSpec *p, GList *gl) { WebKitDOMStyleSheetList *slist = NULL; WebKitDOMStyleSheet *ssheet = NULL; if (status == WEBKIT_LOAD_COMMITTED) { - const char *name = "dwbGoAndBlockAdsFromTheMainFrameCallback"; - js_create_callback(frame, name, (JSObjectCallAsFunctionCallback)adblock_js_callback); - char *command = g_strdup_printf(adblockscript, AA_DOCUMENT, name); - dwb_execute_script(frame, command, false); - g_free(command); + adblock_create_js_callback(frame, (JSObjectCallAsFunctionCallback)adblock_js_callback, AA_DOCUMENT); } else if (status == WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT) { /* Get hostname and base_domain */ - AdblockElementHider *hider; WebKitWebDataSource *datasource = webkit_web_frame_get_data_source(frame); WebKitNetworkRequest *request = webkit_web_data_source_get_request(datasource); SoupMessage *msg = webkit_network_request_get_message(request); - g_return_if_fail(msg != NULL); + if (msg == NULL) + return; SoupURI *suri = soup_message_get_uri(msg); g_return_if_fail(suri != NULL); @@ -375,11 +409,12 @@ adblock_load_status_cb(WebKitWebView *wv, GParamSpec *p, GList *gl) { g_return_if_fail(host != NULL); g_return_if_fail(base_domain != NULL); - GString *css_rule = NULL; - GRegex *regex = NULL; + AdblockElementHider *hider; char *pattern, *escaped, *replaced = NULL; char *tmpreplaced = g_strdup(_css_exceptions->str); - css_rule = g_string_new(NULL); + GString *css_rule = g_string_new(NULL); + GRegex *regex = NULL; + /* get all subdomains */ const char *subdomains[SUBDOMAIN_MAX]; char *nextdot = NULL; @@ -395,6 +430,7 @@ adblock_load_status_cb(WebKitWebView *wv, GParamSpec *p, GList *gl) { } subdomains[uc++] = NULL; + for (int i=0; subdomains[i]; i++) { list = g_hash_table_lookup(_hider_rules, subdomains[i]); if (list) { @@ -423,7 +459,6 @@ adblock_load_status_cb(WebKitWebView *wv, GParamSpec *p, GList *gl) { if (replaced != NULL) { g_string_append(css_rule, replaced); g_string_append_c(css_rule, ','); - g_free(replaced); } /* No exception-exceptions found, so we take all exceptions */ else if (css_rule == NULL || css_rule->len == 0) { @@ -456,6 +491,7 @@ adblock_load_status_cb(WebKitWebView *wv, GParamSpec *p, GList *gl) { g_object_unref(doc); g_string_free(css_rule, true); } + g_free(tmpreplaced); } }/*}}}*//*}}}*/ |