summaryrefslogtreecommitdiff
path: root/libproxy/modules/pacrunner_webkit.cpp
blob: b9abf348a5013d0d8fa30225913ed488cae591a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*******************************************************************************
 * 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 "../extension_pacrunner.hpp"
using namespace libproxy;

#ifdef __APPLE__
// JavaScriptCore.h requires CoreFoundation
// This is only found on Mac OS X
#include <JavaScriptCore/JavaScriptCore.h>
#else
#include <JavaScriptCore/JavaScript.h>
#endif
#include "pacutils.h"

#ifndef INET_ADDRSTRLEN
#define INET_ADDRSTRLEN 16
#endif

#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif

static char *jstr2str(JSStringRef str, bool release) throw (bad_alloc)
{
	char *tmp = new char[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;
	delete tmp;

	// Try for IPv4
	tmp = new char[INET6_ADDRSTRLEN+1];
	if (getnameinfo(info->ai_addr, info->ai_addrlen,
					tmp, INET6_ADDRSTRLEN+1,
					NULL, 0,
					NI_NUMERICHOST)) {
			freeaddrinfo(info);
			delete tmp;
			return NULL;
		}
	freeaddrinfo(info);

	// Create the return value
	JSStringRef str = JSStringCreateWithUTF8CString(tmp);
	JSValueRef  ret = JSValueMakeString(ctx, str);
	JSStringRelease(str);
	delete 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;
}

class webkit_pacrunner : public pacrunner {
public:
	~webkit_pacrunner() {
		JSGarbageCollect(this->jsctx);
		JSGlobalContextRelease(this->jsctx);
	}

	webkit_pacrunner(string pac, const url& pacurl) throw (bad_alloc) : pacrunner(pac, pacurl) {
		JSStringRef str  = NULL;
		JSObjectRef func = NULL;

		// Create the basic context
		if (!(this->jsctx = JSGlobalContextCreate(NULL))) goto error;

		// Add dnsResolve into the context
		str = JSStringCreateWithUTF8CString("dnsResolve");
		func = JSObjectMakeFunctionWithCallback(this->jsctx, str, dnsResolve);
		JSObjectSetProperty(this->jsctx, JSContextGetGlobalObject(this->jsctx), str, func, kJSPropertyAttributeNone, NULL);
		JSStringRelease(str);

		// Add myIpAddress into the context
		str = JSStringCreateWithUTF8CString("myIpAddress");
		func = JSObjectMakeFunctionWithCallback(this->jsctx, str, myIpAddress);
		JSObjectSetProperty(this->jsctx, JSContextGetGlobalObject(this->jsctx), str, func, kJSPropertyAttributeNone, NULL);
		JSStringRelease(str);

		// Add all other routines into the context
		str = JSStringCreateWithUTF8CString(JAVASCRIPT_ROUTINES);
		if (!JSCheckScriptSyntax(this->jsctx, str, NULL, 0, NULL)) goto error;
		JSEvaluateScript(this->jsctx, str, NULL, NULL, 1, NULL);
		JSStringRelease(str);

		// Add the PAC into the context
		str = JSStringCreateWithUTF8CString(pac.c_str());
		if (!JSCheckScriptSyntax(this->jsctx, str, NULL, 0, NULL)) goto error;
		JSEvaluateScript(this->jsctx, str, NULL, NULL, 1, NULL);
		JSStringRelease(str);
		return;

	error:
		if (str) JSStringRelease(str);
		if (this->jsctx) {
			JSGarbageCollect(this->jsctx);
			JSGlobalContextRelease(this->jsctx);
		}
		throw bad_alloc();
	}

	string run(const url& url_) throw (bad_alloc) {
		JSStringRef str = NULL;
		JSValueRef  val = NULL;
		string      tmp;

		// Run the PAC
		tmp = string("FindProxyForURL(\"") + url_.to_string() + string("\", \"") + url_.get_host() + "\");";
		str = JSStringCreateWithUTF8CString(tmp.c_str());
		if (!str) throw bad_alloc();
		if (!JSCheckScriptSyntax(this->jsctx, str, NULL, 0, NULL))            goto error;
		if (!(val = JSEvaluateScript(this->jsctx, str, NULL, NULL, 1, NULL))) goto error;
		if (!JSValueIsString(this->jsctx, val))                               goto error;
		JSStringRelease(str);

		// Convert the return value to a string
		return jstr2str(JSValueToStringCopy(this->jsctx, val, NULL), true);

	error:
		JSStringRelease(str);
		return "";
	}

private:
	JSGlobalContextRef jsctx;
};

PX_PACRUNNER_MODULE_EZ(webkit, "JSObjectMakeFunctionWithCallback", "webkit");