summaryrefslogtreecommitdiff
path: root/libproxy/modules/pacrunner_duktape.cpp
blob: 8288e131f5b0751b4efede1693c6f8cba14a61d0 (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
/*******************************************************************************
 * libproxy - A library for proxy configuration
 * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com>
 * Copyright (C) 2021 Zhaofeng Li <hello@zhaofeng.li>
 *
 * 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"
#include <unistd.h> // gethostname
using namespace libproxy;

#include <duktape.h>
#include "pacutils.h"

static duk_ret_t dnsResolve(duk_context *ctx) {
	if (duk_get_top(ctx) != 1) {
		// Invalid number of arguments
		return 0;
	}

	// We do not need to free the string - It's managed by Duktape.
	const char *hostname = duk_get_string(ctx, 0);
	if (!hostname) {
		return 0;
	}

	// Look it up
	struct addrinfo *info;
	if (getaddrinfo(hostname, NULL, NULL, &info)) {
		return 0;
	}

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

	// Create the return value
	duk_push_string(ctx, tmp);
	return 1;
}

static duk_ret_t myIpAddress(duk_context *ctx) {
	char hostname[1024];
	hostname[sizeof(hostname) - 1] = '\0';

	if (!gethostname(hostname, sizeof(hostname) - 1)) {
		duk_push_string(ctx, hostname);
		return dnsResolve(ctx);
	}

	return duk_error(ctx, DUK_ERR_ERROR, "Unable to find hostname!");
}

class duktape_pacrunner : public pacrunner {
public:
	duktape_pacrunner(string pac, const url& pacurl) : pacrunner(pac, pacurl) {
		this->ctx = duk_create_heap_default();
		if (!this->ctx) goto error;
		duk_push_c_function(this->ctx, dnsResolve, 1);
		duk_put_global_string(this->ctx, "dnsResolve");

		duk_push_c_function(this->ctx, myIpAddress, 1);
		duk_put_global_string(this->ctx, "myIpAddress");

		// Add other routines
		duk_push_string(this->ctx, JAVASCRIPT_ROUTINES);
		if (duk_peval_noresult(this->ctx)) {
			goto error;
		}

		// Add the PAC into the context
		duk_push_string(this->ctx, pac.c_str());
		if (duk_peval_noresult(this->ctx)) {
			goto error;
		}

		return;
	error:
		duk_destroy_heap(this->ctx);
		throw bad_alloc();
	}

	~duktape_pacrunner() {
		duk_destroy_heap(this->ctx);
	}

	string run(const url& url_) override {
		string url = url_.to_string();
		string host = url_.get_host();

		duk_get_global_string(this->ctx, "FindProxyForURL");
		duk_push_string(this->ctx, url.c_str());
		duk_push_string(this->ctx, host.c_str());
		duk_int_t result = duk_pcall(this->ctx, 2);

		if (result == 0) {
			// Success
			const char *proxy = duk_get_string(this->ctx, 0);
			if (!proxy) {
				duk_pop(this->ctx);
				return "";
			}
			string proxyString = string(proxy);
			duk_pop(this->ctx);
			return proxyString;
		} else {
			// Something happened. The top of the stack is an error.
			duk_pop(this->ctx);
			return "";
		}
	}

private:
	duk_context *ctx;
};

PX_PACRUNNER_MODULE_EZ(duktape, "duk_create_heap_default", "duktape");