From 55090f5226ad2fd474b5352f399a4d8c912a2a02 Mon Sep 17 00:00:00 2001 From: npmccallum Date: Thu, 5 Jun 2008 20:11:40 +0000 Subject: add webkit javascript plugin git-svn-id: http://libproxy.googlecode.com/svn/branches/libproxy-0.2@233 c587cffe-e639-0410-9787-d7902ae8ed56 --- configure.ac | 28 ++++++- src/plugins/Makefile.am | 10 +++ src/plugins/webkit.c | 209 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 src/plugins/webkit.c diff --git a/configure.ac b/configure.ac index 41ad5c1..efe5f88 100644 --- a/configure.ac +++ b/configure.ac @@ -15,8 +15,10 @@ AC_PROG_MAKE_SET PKG_CHECK_MODULES(x11, x11, have_x11=yes, have_x11=no) PKG_CHECK_MODULES(xmu, xmu, have_xmu=yes, have_xmu=no) PKG_CHECK_MODULES(gconf, gconf-2.0, have_gconf=yes, have_gconf=no) +PKG_CHECK_MODULES(webkit, webkit-1.0, have_webkit=yes, have_webkit=no) PKG_CHECK_MODULES(mozjs, xulrunner-js, have_mozjs=yes, - [PKG_CHECK_MODULES(mozjs, firefox-js, have_mozjs=yes, have_mozjs=no)]) + [PKG_CHECK_MODULES(mozjs, firefox-js, have_mozjs=yes, + [PKG_CHECK_MODULES(mozjs, mozilla-js, have_mozjs=yes, have_mozjs=no)])]) PKG_CHECK_MODULES(NetworkManager, NetworkManager, have_networkmanager=yes, have_networkmanager=no) @@ -84,6 +86,27 @@ else fi AM_CONDITIONAL([WITH_KDE], [test x$with_kde = xyes]) +# WebKit Javascript +AC_ARG_WITH([webkit], + [AS_HELP_STRING([--with-webkit], + [build WebKit JavaScriptCore PAC runner plugin @<:@automatic@:>@])], + [], + [test x$have_webkit == xyes && with_webkit=yes]) +if test x$with_webkit = xyes; then + if test x$have_webkit == xyes; then + WEBKIT_CFLAGS="$webkit_CFLAGS" + WEBKIT_LIBS="$webkit_LIBS" + AC_SUBST(WEBKIT_CFLAGS) + AC_SUBST(WEBKIT_LIBS) + else + echo "WebKit JavaScriptCore plugin requires: WebKit!" + exit 1 + fi +else + with_webkit=no +fi +AM_CONDITIONAL([WITH_WEBKIT], [test x$with_webkit = xyes]) + # Mozilla Javascript AC_ARG_WITH([mozjs], [AS_HELP_STRING([--with-mozjs], @@ -153,7 +176,7 @@ AC_C_CONST AC_TYPE_SIZE_T PLUGINDIR=$libdir/$PACKAGE_NAME/$PACKAGE_VERSION/plugins AC_SUBST(PLUGINDIR) -CFLAGS="-std=c99 $CFLAGS -DPLUGINDIR=\\\"$PLUGINDIR\\\" -DSYSCONFDIR=\\\"$sysconfdir\\\" -D_POSIX_C_SOURCE=1" +CFLAGS="-g -std=c99 $CFLAGS -DPLUGINDIR=\\\"$PLUGINDIR\\\" -DSYSCONFDIR=\\\"$sysconfdir\\\" -D_POSIX_C_SOURCE=1" ### Checks for library functions. AC_FUNC_MALLOC @@ -172,6 +195,7 @@ echo -e "\t\tenvvar : $with_envvar" echo -e "\t\tfile : $with_file" echo -e "\t\tgnome : $with_gnome" echo -e "\t\tkde : $with_kde" +echo -e "\t\twebkit : $with_webkit" echo -e "\t\tmozjs : $with_mozjs" echo -e "\t\tnetworkmanager : $with_networkmanager" echo 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/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 + * + * 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 +#include +#include +#include +#include +#include +#define __USE_BSD +#include + +#include +#include + +#include +#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); +} -- cgit v1.2.1