diff --git a/src/pacparser.c b/src/pacparser.c index f5fed8a..7293ddc 100644 --- a/src/pacparser.c +++ b/src/pacparser.c @@ -217,6 +217,36 @@ dns_resolve_ex(JSContext *ctx, JSValueConst UNUSED(this_val), int UNUSED(argc), return JS_NewString(ctx, ipaddr); } +// Prints space-separated args via the error printer (stderr by default). +static JSValue +js_log_print(JSContext *ctx, int argc, JSValueConst *argv, const char *prefix) +{ + print_error("%s:", prefix); + for (int i = 0; i < argc; i++) { + const char *s = JS_ToCString(ctx, argv[i]); + if (!s) { + print_error("\n"); + return JS_EXCEPTION; + } + print_error(" %s", s); + JS_FreeCString(ctx, s); + } + print_error("\n"); + return JS_UNDEFINED; +} + +static JSValue +pac_alert(JSContext *ctx, JSValueConst UNUSED(this_val), int argc, JSValueConst *argv) +{ + return js_log_print(ctx, argc, argv, "ALERT"); +} + +static JSValue +pac_console_log(JSContext *ctx, JSValueConst UNUSED(this_val), int argc, JSValueConst *argv) +{ + return js_log_print(ctx, argc, argv, "LOG"); +} + // myIpAddress in JS context; not available in core JavaScript. // returns 127.0.0.1 if not able to determine local ip. static JSValue @@ -318,6 +348,13 @@ pacparser_init() JS_SetPropertyStr(ctx, global, "myIpAddressEx", JS_NewCFunction(ctx, my_ip_ex, "myIpAddressEx", 0)); + JS_SetPropertyStr(ctx, global, "alert", + JS_NewCFunction(ctx, pac_alert, "alert", 1)); + JSValue console = JS_NewObject(ctx); + JS_SetPropertyStr(ctx, console, "log", + JS_NewCFunction(ctx, pac_console_log, "log", 1)); + JS_SetPropertyStr(ctx, global, "console", console); + // Evaluate pacUtils. Utility functions required to parse pac files. JSValue result = JS_Eval(ctx, pacUtils, strlen(pacUtils), "pac_utils", JS_EVAL_TYPE_GLOBAL); diff --git a/tests/logging.pac b/tests/logging.pac new file mode 100644 index 0000000..ec9b8cd --- /dev/null +++ b/tests/logging.pac @@ -0,0 +1,7 @@ +// Test PAC file exercising alert() and console.log() debug helpers. +function FindProxyForURL(url, host) { + alert("checking", host); + console.log("url:", url); + console.log("single arg"); + return "DIRECT"; +} diff --git a/tests/runtests.py b/tests/runtests.py index ba48699..4c55191 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -24,6 +24,7 @@ import glob import os import sys +import tempfile def module_path(tests_dir): py_ver = '*'.join([str(x) for x in sys.version_info[0:2]]) @@ -75,6 +76,34 @@ def runtests(pacfile, testdata, tests_dir): pacparser.cleanup() if result != expected_result: raise Exception('Tests failed. Got "%s", expected "%s"' % (result, expected_result)) + + # Logging test: alert() / console.log() should emit to the C library's + # stderr. The extension writes directly via vfprintf, so redirect at the + # file-descriptor level rather than via sys.stderr. + logging_pac = os.path.join(tests_dir, 'logging.pac') + expected_stderr = ('ALERT: checking example.com\n' + 'LOG: url: http://example.com/\n' + 'LOG: single arg\n') + with tempfile.TemporaryFile(mode='w+') as tmp: + saved_fd = os.dup(2) + os.dup2(tmp.fileno(), 2) + try: + pacparser.init() + pacparser.parse_pac_file(logging_pac) + proxy = pacparser.find_proxy('http://example.com/', 'example.com') + pacparser.cleanup() + finally: + sys.stderr.flush() + os.dup2(saved_fd, 2) + os.close(saved_fd) + tmp.seek(0) + actual_stderr = tmp.read() + if proxy != 'DIRECT': + raise Exception('Logging test failed: proxy was "%s", expected "DIRECT"' % proxy) + if actual_stderr != expected_stderr: + raise Exception('Logging test failed: stderr mismatch\nExpected:\n%s\nGot:\n%s' % + (expected_stderr, actual_stderr)) + print('All tests were successful.') diff --git a/tests/runtests.sh b/tests/runtests.sh index 5361aea..63e8aff 100755 --- a/tests/runtests.sh +++ b/tests/runtests.sh @@ -55,4 +55,28 @@ while read line fi done < $testdata + +# Logging tests: verify alert() / console.log() output lands on stderr with +# the expected prefixes, and that the proxy result on stdout is unaffected. +logging_pac=$script_dir/logging.pac +logging_stderr=$(mktemp) +logging_stdout=$($pactester -p $logging_pac -u http://example.com/ -h example.com 2>$logging_stderr) +if [ "$logging_stdout" != "DIRECT" ]; then + echo "Logging test failed: stdout was \"$logging_stdout\", expected \"DIRECT\"" + cat $logging_stderr + rm -f $logging_stderr + exit 1 +fi +expected_stderr=$'ALERT: checking example.com\nLOG: url: http://example.com/\nLOG: single arg' +actual_stderr=$(cat $logging_stderr) +rm -f $logging_stderr +if [ "$actual_stderr" != "$expected_stderr" ]; then + echo "Logging test failed: stderr mismatch" + echo "Expected:" + echo "$expected_stderr" + echo "Got:" + echo "$actual_stderr" + exit 1 +fi + echo "All tests were successful."