diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/Makefile.am | 10 | ||||
-rw-r--r-- | src/plugins/mozjs.c | 189 | ||||
-rw-r--r-- | src/plugins/networkmanager.c | 4 | ||||
-rw-r--r-- | src/plugins/webkit.c | 209 |
4 files changed, 336 insertions, 76 deletions
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 5e5d18c..9a561ea 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -14,6 +14,9 @@ endif if WITH_KDE plugin_LTLIBRARIES += kde.la endif +if WITH_WEBKIT +plugin_LTLIBRARIES += webkit.la +endif if WITH_MOZJS plugin_LTLIBRARIES += mozjs.la endif @@ -45,6 +48,13 @@ kde_la_CFLAGS = -I$(top_srcdir)/src/lib @KDE_CFLAGS@ kde_la_LIBADD = ../lib/libproxy.la kde_la_LDFLAGS = -module -avoid-version @KDE_LIBS@ +# WebKit (JavaScriptCore) based PAC runner +webkit_la_SOURCES = webkit.c +webkit_la_CFLAGS = -I$(top_srcdir)/src/lib @WEBKIT_CFLAGS@ +webkit_la_LIBADD = ../lib/libproxy.la +webkit_la_LDFLAGS = -module -avoid-version @WEBKIT_LIBS@ +nodist_webkit_la_SOURCES = pacutils.h + # Mozilla (Spidermonkey) based PAC runner mozjs_la_SOURCES = mozjs.c mozjs_la_CFLAGS = -I$(top_srcdir)/src/lib @MOZJS_CFLAGS@ diff --git a/src/plugins/mozjs.c b/src/plugins/mozjs.c index 5f89672..88c8180 100644 --- a/src/plugins/mozjs.c +++ b/src/plugins/mozjs.c @@ -36,38 +36,34 @@ static JSBool dnsResolve(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, // Get hostname argument char *tmp = px_strdup(JS_GetStringBytes(JS_ValueToString(cx, argv[0]))); + // Set the default return value + *rval = JSVAL_NULL; + // Look it up - struct addrinfo *info; + struct addrinfo *info = NULL; if (getaddrinfo(tmp, NULL, NULL, &info)) - goto error; + goto out; + + // Allocate the IP address px_free(tmp); + tmp = px_malloc0(INET6_ADDRSTRLEN+1); - // Try for IPv4 - tmp = px_malloc0(INET_ADDRSTRLEN+1); - if (inet_ntop(info->ai_family, + // Try for IPv4 and IPv6 + if (!inet_ntop(info->ai_family, &((struct sockaddr_in *) info->ai_addr)->sin_addr, tmp, INET_ADDRSTRLEN+1) > 0) - { - JSString *ip = JS_NewString(cx, tmp, strlen(tmp)); - *rval = STRING_TO_JSVAL(ip); - return true; - } - - // Try for IPv6 - px_free(tmp); - tmp = px_malloc0(INET6_ADDRSTRLEN+1); - if (inet_ntop(info->ai_family, - &((struct sockaddr_in6 *) info->ai_addr)->sin6_addr, - tmp, INET6_ADDRSTRLEN+1) > 0) - { - JSString *ip = JS_NewString(cx, tmp, strlen(tmp)); - *rval = STRING_TO_JSVAL(ip); - return true; - } + if (!inet_ntop(info->ai_family, + &((struct sockaddr_in6 *) info->ai_addr)->sin6_addr, + tmp, INET6_ADDRSTRLEN+1) > 0) + goto out; + + // We succeeded + *rval = STRING_TO_JSVAL(JS_NewString(cx, tmp, strlen(tmp))); + tmp = NULL; - error: + out: + if (info) freeaddrinfo(info); px_free(tmp); - *rval = JSVAL_NULL; return true; } @@ -83,72 +79,115 @@ static JSBool myIpAddress(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return true; } +typedef struct { + JSRuntime *run; + JSContext *ctx; + JSClass *cls; + char *pac; +} ctxStore; + +static void ctxs_free(ctxStore *self) +{ + if (!self) return; + if (self->ctx) JS_DestroyContext(self->ctx); + if (self->run) JS_DestroyRuntime(self->run); + if (self->cls) px_free(self->cls); + px_free(self->pac); + px_free(self); +} + +static ctxStore *ctxs_new(pxPAC *pac) +{ + JSObject *global = NULL; + jsval rval; + + // Create the basic context + ctxStore *self = px_malloc0(sizeof(ctxStore)); + + // Setup Javascript global class + self->cls = px_malloc0(sizeof(JSClass)); + self->cls->name = "global"; + self->cls->flags = 0; + self->cls->addProperty = JS_PropertyStub; + self->cls->delProperty = JS_PropertyStub; + self->cls->getProperty = JS_PropertyStub; + self->cls->setProperty = JS_PropertyStub; + self->cls->enumerate = JS_EnumerateStub; + self->cls->resolve = JS_ResolveStub; + self->cls->convert = JS_ConvertStub; + self->cls->finalize = JS_FinalizeStub; + + // Initialize Javascript runtime environment + if (!(self->run = JS_NewRuntime(1024 * 1024))) goto error; + if (!(self->ctx = JS_NewContext(self->run, 1024 * 1024))) goto error; + if (!(global = JS_NewObject(self->ctx, self->cls, NULL, NULL))) goto error; + JS_InitStandardClasses(self->ctx, global); + + // Define Javascript functions + JS_DefineFunction(self->ctx, global, "dnsResolve", dnsResolve, 1, 0); + JS_DefineFunction(self->ctx, global, "myIpAddress", myIpAddress, 0, 0); + JS_EvaluateScript(self->ctx, global, JAVASCRIPT_ROUTINES, + strlen(JAVASCRIPT_ROUTINES), "pacutils.js", 0, &rval); + + // Add PAC to the environment + JS_EvaluateScript(self->ctx, global, px_pac_to_string(pac), + strlen(px_pac_to_string(pac)), + px_url_to_string((pxURL *) px_pac_get_url(pac)), + 0, &rval); + + // Save the pac + self->pac = px_strdup(px_pac_to_string(pac)); + return self; + +error: + ctxs_free(self); + return NULL; +} + char *mozjs_pacrunner(pxProxyFactory *self, pxPAC *pac, pxURL *url) { - JSRuntime *runtime = NULL; - JSContext *context = NULL; - JSObject *global = NULL; - jsval rval; - char *answer = NULL; - // Make sure we have the pac file and url if (!pac) return NULL; if (!url) return NULL; if (!px_pac_to_string(pac) && !px_pac_reload(pac)) return NULL; - - // Setup Javascript global class - JSClass *global_class = px_malloc0(sizeof(JSClass)); - global_class->name = "global"; - global_class->flags = 0; - global_class->addProperty = JS_PropertyStub; - global_class->delProperty = JS_PropertyStub; - global_class->getProperty = JS_PropertyStub; - global_class->setProperty = JS_PropertyStub; - global_class->enumerate = JS_EnumerateStub; - global_class->resolve = JS_ResolveStub; - global_class->convert = JS_ConvertStub; - global_class->finalize = JS_FinalizeStub; - - // Initialize Javascript runtime environment - if (!(runtime = JS_NewRuntime(1024 * 1024))) goto out; - if (!(context = JS_NewContext(runtime, 1024 * 1024))) goto out; - if (!(global = JS_NewObject(context, global_class, NULL, NULL))) goto out; - JS_InitStandardClasses(context, global); - - // Define Javascript functions - JS_DefineFunction(context, global, "dnsResolve", dnsResolve, 1, 0); - JS_DefineFunction(context, global, "myIpAddress", myIpAddress, 0, 0); - JS_EvaluateScript(context, global, JAVASCRIPT_ROUTINES, - strlen(JAVASCRIPT_ROUTINES), "pacutils.js", 0, &rval); - - // Add PAC to the environment - JS_EvaluateScript(context, JS_GetGlobalObject(context), - px_pac_to_string(pac), strlen(px_pac_to_string(pac)), - px_url_to_string((pxURL *) px_pac_get_url(pac)), 0, &rval); + + // Get the cached context + ctxStore *ctxs = px_proxy_factory_misc_get(self, "mozjs"); + + // If there is a cached context, make sure it is the same pac + if (ctxs && strcmp(ctxs->pac, px_pac_to_string(pac))) + { + ctxs_free(ctxs); + ctxs = NULL; + } + + // If no context exists (or if the pac was changed), create one + if (!ctxs) + { + if ((ctxs = ctxs_new(pac))) + px_proxy_factory_misc_set(self, "mozjs", ctxs); + else + return NULL; + } // Build arguments to the FindProxyForURL() function char *tmpurl = px_strdup(px_url_to_string(url)); char *tmphost = px_strdup(px_url_get_host(url)); - jsval val[2] = { - STRING_TO_JSVAL(JS_NewString(context, tmpurl, strlen(tmpurl))), - STRING_TO_JSVAL(JS_NewString(context, tmphost, strlen(tmphost))) + jsval args[2] = { + STRING_TO_JSVAL(JS_NewString(ctxs->ctx, tmpurl, strlen(tmpurl))), + STRING_TO_JSVAL(JS_NewString(ctxs->ctx, tmphost, strlen(tmphost))) }; // Find the proxy (call FindProxyForURL()) - JSBool result = JS_CallFunctionName(context, JS_GetGlobalObject(context), - "FindProxyForURL", 2, val, &rval); - if (!result) goto out; - answer = px_strdup(JS_GetStringBytes(JS_ValueToString(context, rval))); + jsval rval; + JSBool result = JS_CallFunctionName(ctxs->ctx, JS_GetGlobalObject(ctxs->ctx), "FindProxyForURL", 2, args, &rval); + if (!result) return NULL; + char *answer = px_strdup(JS_GetStringBytes(JS_ValueToString(ctxs->ctx, rval))); if (!answer || !strcmp(answer, "undefined")) { px_free(answer); - answer = NULL; + return NULL; } - - out: - if (context) JS_DestroyContext(context); - if (runtime) JS_DestroyRuntime(runtime); - px_free(global_class); - return answer; + return answer; } bool on_proxy_factory_instantiate(pxProxyFactory *self) @@ -159,4 +198,6 @@ bool on_proxy_factory_instantiate(pxProxyFactory *self) void on_proxy_factory_destantiate(pxProxyFactory *self) { px_proxy_factory_pac_runner_set(self, NULL); + ctxs_free(px_proxy_factory_misc_get(self, "mozjs")); + px_proxy_factory_misc_set(self, "mozjs", NULL); } diff --git a/src/plugins/networkmanager.c b/src/plugins/networkmanager.c index fca92d6..e7c8360 100644 --- a/src/plugins/networkmanager.c +++ b/src/plugins/networkmanager.c @@ -84,13 +84,13 @@ nm_on_get_proxy(pxProxyFactory *self) bool on_proxy_factory_instantiate(pxProxyFactory *self) { - px_proxy_factory_on_get_proxies_add(self, nm_on_get_proxy); + px_proxy_factory_on_get_proxy_add(self, nm_on_get_proxy); } void on_proxy_factory_destantiate(pxProxyFactory *self) { - px_proxy_factory_on_get_proxies_del(self, nm_on_get_proxy); + px_proxy_factory_on_get_proxy_del(self, nm_on_get_proxy); DBusConnection *conn = px_proxy_factory_misc_get(self, "networkmanager"); if (conn) { diff --git a/src/plugins/webkit.c b/src/plugins/webkit.c new file mode 100644 index 0000000..859c618 --- /dev/null +++ b/src/plugins/webkit.c @@ -0,0 +1,209 @@ +/******************************************************************************* + * libproxy - A library for proxy configuration + * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + ******************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <arpa/inet.h> +#define __USE_BSD +#include <unistd.h> + +#include <misc.h> +#include <proxy_factory.h> + +#include <JavaScriptCore/JavaScript.h> +#include "pacutils.h" + +static char *jstr2str(JSStringRef str, bool release) +{ + char *tmp = px_malloc0(JSStringGetMaximumUTF8CStringSize(str)+1); + JSStringGetUTF8CString(str, tmp, JSStringGetMaximumUTF8CStringSize(str)+1); + if (release) JSStringRelease(str); + return tmp; +} + +static JSValueRef dnsResolve(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception) +{ + if (argc != 1) return NULL; + if (!JSValueIsString(ctx, argv[0])) return NULL; + + // Get hostname argument + char *tmp = jstr2str(JSValueToStringCopy(ctx, argv[0], NULL), true); + + // Look it up + struct addrinfo *info; + if (getaddrinfo(tmp, NULL, NULL, &info)) + return NULL; + px_free(tmp); + + // Try for IPv4 + tmp = px_malloc0(INET6_ADDRSTRLEN+1); + if (!inet_ntop(info->ai_family, + &((struct sockaddr_in *) info->ai_addr)->sin_addr, + tmp, INET_ADDRSTRLEN+1) > 0) + // Try for IPv6 + if (!inet_ntop(info->ai_family, + &((struct sockaddr_in6 *) info->ai_addr)->sin6_addr, + tmp, INET6_ADDRSTRLEN+1) > 0) + { + freeaddrinfo(info); + px_free(tmp); + return NULL; + } + freeaddrinfo(info); + + // Create the return value + JSStringRef str = JSStringCreateWithUTF8CString(tmp); + JSValueRef ret = JSValueMakeString(ctx, str); + JSStringRelease(str); + px_free(tmp); + + return ret; +} + +static JSValueRef myIpAddress(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception) +{ + char hostname[1024]; + if (!gethostname(hostname, 1023)) { + JSStringRef str = JSStringCreateWithUTF8CString(hostname); + JSValueRef val = JSValueMakeString(ctx, str); + JSStringRelease(str); + JSValueRef ip = dnsResolve(ctx, func, self, 1, &val, NULL); + return ip; + } + return NULL; +} + +typedef struct { + JSGlobalContextRef ctx; + char *pac; +} ctxStore; + +static void ctxs_free(ctxStore *self) +{ + if (!self) return; + JSGlobalContextRelease(self->ctx); + JSGarbageCollect(self->ctx); + px_free(self->pac); + px_free(self); +} + +static ctxStore *ctxs_new(pxPAC *pac) +{ + JSStringRef str = NULL; + JSObjectRef func = NULL; + + // Create the basic context + ctxStore *self = px_malloc0(sizeof(ctxStore)); + self->pac = px_strdup(px_pac_to_string(pac)); + if (!(self->ctx = JSGlobalContextCreate(NULL))) goto error; + + // Add dnsResolve into the context + str = JSStringCreateWithUTF8CString("dnsResolve"); + func = JSObjectMakeFunctionWithCallback(self->ctx, str, dnsResolve); + JSObjectSetProperty(self->ctx, JSContextGetGlobalObject(self->ctx), str, func, kJSPropertyAttributeNone, NULL); + JSStringRelease(str); + + // Add myIpAddress into the context + str = JSStringCreateWithUTF8CString("myIpAddress"); + func = JSObjectMakeFunctionWithCallback(self->ctx, str, myIpAddress); + JSObjectSetProperty(self->ctx, JSContextGetGlobalObject(self->ctx), str, func, kJSPropertyAttributeNone, NULL); + JSStringRelease(str); + + // Add all other routines into the context + str = JSStringCreateWithUTF8CString(JAVASCRIPT_ROUTINES); + if (!JSCheckScriptSyntax(self->ctx, str, NULL, 0, NULL)) goto error; + JSEvaluateScript(self->ctx, str, NULL, NULL, 1, NULL); + JSStringRelease(str); + + // Add the PAC into the context + str = JSStringCreateWithUTF8CString(self->pac); + if (!JSCheckScriptSyntax(self->ctx, str, NULL, 0, NULL)) goto error; + JSEvaluateScript(self->ctx, str, NULL, NULL, 1, NULL); + JSStringRelease(str); + + return self; + +error: + if (str) JSStringRelease(str); + ctxs_free(self); + return NULL; +} + +char *webkit_pacrunner(pxProxyFactory *self, pxPAC *pac, pxURL *url) +{ + JSStringRef str = NULL; + JSValueRef val = NULL; + char *tmp = NULL; + + // Make sure we have the pac file and url + if (!pac) return NULL; + if (!url) return NULL; + if (!px_pac_to_string(pac) && !px_pac_reload(pac)) return NULL; + + // Get the cached context + ctxStore *ctxs = px_proxy_factory_misc_get(self, "webkit"); + + // If there is a cached context, make sure it is the same pac + if (ctxs && strcmp(ctxs->pac, px_pac_to_string(pac))) + { + ctxs_free(ctxs); + ctxs = NULL; + } + + // If no context exists (or if the pac was changed), create one + if (!ctxs) + { + if ((ctxs = ctxs_new(pac))) + px_proxy_factory_misc_set(self, "webkit", ctxs); + else + return NULL; + } + + // Run the PAC + tmp = px_strcat("FindProxyForURL(\"", px_url_to_string(url), "\", \"", px_url_get_host(url), "\");", NULL); + str = JSStringCreateWithUTF8CString(tmp); + px_free(tmp); tmp = NULL; + if (!JSCheckScriptSyntax(ctxs->ctx, str, NULL, 0, NULL)) goto error; + if (!(val = JSEvaluateScript(ctxs->ctx, str, NULL, NULL, 1, NULL))) goto error; + if (!JSValueIsString(ctxs->ctx, val)) goto error; + JSStringRelease(str); + + // Convert the return value to a string + return jstr2str(JSValueToStringCopy(ctxs->ctx, val, NULL), true); + +error: + if (str) JSStringRelease(str); + ctxs_free(ctxs); + return tmp; +} + +bool on_proxy_factory_instantiate(pxProxyFactory *self) +{ + return px_proxy_factory_pac_runner_set(self, webkit_pacrunner); +} + +void on_proxy_factory_destantiate(pxProxyFactory *self) +{ + px_proxy_factory_pac_runner_set(self, NULL); + ctxs_free(px_proxy_factory_misc_get(self, "webkit")); + px_proxy_factory_misc_set(self, "webkit", NULL); +} |