| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8dd48c9 commit d049919
16 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -77,6 +77,12 @@ added: v0.3.1 | |||
| 77 | 77 | * `timeout` {number} Specifies the number of milliseconds to execute `code` | |
| 78 | 78 | before terminating execution. If execution is terminated, an [`Error`][] | |
| 79 | 79 | will be thrown. | |
| 80 | + * `breakOnSigint`: if `true`, the execution will be terminated when | ||
| 81 | + `SIGINT` (Ctrl+C) is received. Existing handlers for the | ||
| 82 | + event that have been attached via `process.on("SIGINT")` will be disabled | ||
| 83 | + during script execution, but will continue to work after that. | ||
| 84 | + If execution is terminated, an [`Error`][] will be thrown. | ||
| 85 | + | ||
| 80 | 86 | ||
| 81 | 87 | Runs the compiled code contained by the `vm.Script` object within the given | |
| 82 | 88 | `contextifiedSandbox` and returns the result. Running code does not have access | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -13,6 +13,29 @@ const Script = binding.ContextifyScript; | |||
| 13 | 13 | // - isContext(sandbox) | |
| 14 | 14 | // From this we build the entire documented API. | |
| 15 | 15 | ||
| 16 | + const realRunInThisContext = Script.prototype.runInThisContext; | ||
| 17 | + const realRunInContext = Script.prototype.runInContext; | ||
| 18 | + | ||
| 19 | + Script.prototype.runInThisContext = function(options) { | ||
| 20 | + if (options && options.breakOnSigint) { | ||
| 21 | + return sigintHandlersWrap(() => { | ||
| 22 | + return realRunInThisContext.call(this, options); | ||
| 23 | + }); | ||
| 24 | + } else { | ||
| 25 | + return realRunInThisContext.call(this, options); | ||
| 26 | + } | ||
| 27 | + }; | ||
| 28 | + | ||
| 29 | + Script.prototype.runInContext = function(contextifiedSandbox, options) { | ||
| 30 | + if (options && options.breakOnSigint) { | ||
| 31 | + return sigintHandlersWrap(() => { | ||
| 32 | + return realRunInContext.call(this, contextifiedSandbox, options); | ||
| 33 | + }); | ||
| 34 | + } else { | ||
| 35 | + return realRunInContext.call(this, contextifiedSandbox, options); | ||
| 36 | + } | ||
| 37 | + }; | ||
| 38 | + | ||
| 16 | 39 | Script.prototype.runInNewContext = function(sandbox, options) { | |
| 17 | 40 | var context = exports.createContext(sandbox); | |
| 18 | 41 | return this.runInContext(context, options); | |
@@ -55,3 +78,27 @@ exports.runInThisContext = function(code, options) { | |||
| 55 | 78 | }; | |
| 56 | 79 | ||
| 57 | 80 | exports.isContext = binding.isContext; | |
| 81 | + | ||
| 82 | + // Remove all SIGINT listeners and re-attach them after the wrapped function | ||
| 83 | + // has executed, so that caught SIGINT are handled by the listeners again. | ||
| 84 | + function sigintHandlersWrap(fn) { | ||
| 85 | + // Using the internal list here to make sure `.once()` wrappers are used, | ||
| 86 | + // not the original ones. | ||
| 87 | + let sigintListeners = process._events.SIGINT; | ||
| 88 | + if (!Array.isArray(sigintListeners)) | ||
| 89 | + sigintListeners = sigintListeners ? [sigintListeners] : []; | ||
| 90 | + else | ||
| 91 | + sigintListeners = sigintListeners.slice(); | ||
| 92 | + | ||
| 93 | + process.removeAllListeners('SIGINT'); | ||
| 94 | + | ||
| 95 | + try { | ||
| 96 | + return fn(); | ||
| 97 | + } finally { | ||
| 98 | + // Add using the public methods so that the `newListener` handler of | ||
| 99 | + // process can re-attach the listeners. | ||
| 100 | + for (const listener of sigintListeners) { | ||
| 101 | + process.addListener('SIGINT', listener); | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3317,7 +3317,7 @@ static void AtExit() { | |||
| 3317 | 3317 | } | |
| 3318 | 3318 | ||
| 3319 | 3319 | ||
| 3320 | - static void SignalExit(int signo) { | ||
| 3320 | + void SignalExit(int signo) { | ||
| 3321 | 3321 | uv_tty_reset_mode(); | |
| 3322 | 3322 | #ifdef __FreeBSD__ | |
| 3323 | 3323 | // FreeBSD has a nasty bug, see RegisterSignalHandler for details | |
@@ -3819,9 +3819,9 @@ static void EnableDebugSignalHandler(int signo) { | |||
| 3819 | 3819 | } | |
| 3820 | 3820 | ||
| 3821 | 3821 | ||
| 3822 | - static void RegisterSignalHandler(int signal, | ||
| 3823 | - void (*handler)(int signal), | ||
| 3824 | - bool reset_handler = false) { | ||
| 3822 | + void RegisterSignalHandler(int signal, | ||
| 3823 | + void (*handler)(int signal), | ||
| 3824 | + bool reset_handler) { | ||
| 3825 | 3825 | struct sigaction sa; | |
| 3826 | 3826 | memset(&sa, 0, sizeof(sa)); | |
| 3827 | 3827 | sa.sa_handler = handler; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -553,14 +553,15 @@ class ContextifyScript : public BaseObject { | |||
| 553 | 553 | TryCatch try_catch(args.GetIsolate()); | |
| 554 | 554 | uint64_t timeout = GetTimeoutArg(args, 0); | |
| 555 | 555 | bool display_errors = GetDisplayErrorsArg(args, 0); | |
| 556 | + bool break_on_sigint = GetBreakOnSigintArg(args, 0); | ||
| 556 | 557 | if (try_catch.HasCaught()) { | |
| 557 | 558 | try_catch.ReThrow(); | |
| 558 | 559 | return; | |
| 559 | 560 | } | |
| 560 | 561 | ||
| 561 | 562 | // Do the eval within this context | |
| 562 | 563 | Environment* env = Environment::GetCurrent(args); | |
| 563 | - EvalMachine(env, timeout, display_errors, args, try_catch); | ||
| 564 | + EvalMachine(env, timeout, display_errors, break_on_sigint, args, try_catch); | ||
| 564 | 565 | } | |
| 565 | 566 | ||
| 566 | 567 | // args: sandbox, [options] | |
@@ -569,6 +570,7 @@ class ContextifyScript : public BaseObject { | |||
| 569 | 570 | ||
| 570 | 571 | int64_t timeout; | |
| 571 | 572 | bool display_errors; | |
| 573 | + bool break_on_sigint; | ||
| 572 | 574 | ||
| 573 | 575 | // Assemble arguments | |
| 574 | 576 | if (!args[0]->IsObject()) { | |
@@ -581,6 +583,7 @@ class ContextifyScript : public BaseObject { | |||
| 581 | 583 | TryCatch try_catch(env->isolate()); | |
| 582 | 584 | timeout = GetTimeoutArg(args, 1); | |
| 583 | 585 | display_errors = GetDisplayErrorsArg(args, 1); | |
| 586 | + break_on_sigint = GetBreakOnSigintArg(args, 1); | ||
| 584 | 587 | if (try_catch.HasCaught()) { | |
| 585 | 588 | try_catch.ReThrow(); | |
| 586 | 589 | return; | |
@@ -605,6 +608,7 @@ class ContextifyScript : public BaseObject { | |||
| 605 | 608 | if (EvalMachine(contextify_context->env(), | |
| 606 | 609 | timeout, | |
| 607 | 610 | display_errors, | |
| 611 | + break_on_sigint, | ||
| 608 | 612 | args, | |
| 609 | 613 | try_catch)) { | |
| 610 | 614 | contextify_context->CopyProperties(); | |
@@ -653,6 +657,23 @@ class ContextifyScript : public BaseObject { | |||
| 653 | 657 | True(env->isolate())); | |
| 654 | 658 | } | |
| 655 | 659 | ||
| 660 | + static bool GetBreakOnSigintArg(const FunctionCallbackInfo<Value>& args, | ||
| 661 | + const int i) { | ||
| 662 | + if (args[i]->IsUndefined() || args[i]->IsString()) { | ||
| 663 | + return false; | ||
| 664 | + } | ||
| 665 | + if (!args[i]->IsObject()) { | ||
| 666 | + Environment::ThrowTypeError(args.GetIsolate(), | ||
| 667 | + "options must be an object"); | ||
| 668 | + return false; | ||
| 669 | + } | ||
| 670 | + | ||
| 671 | + Local<String> key = FIXED_ONE_BYTE_STRING(args.GetIsolate(), | ||
| 672 | + "breakOnSigint"); | ||
| 673 | + Local<Value> value = args[i].As<Object>()->Get(key); | ||
| 674 | + return value->IsTrue(); | ||
| 675 | + } | ||
| 676 | + | ||
| 656 | 677 | static int64_t GetTimeoutArg(const FunctionCallbackInfo<Value>& args, | |
| 657 | 678 | const int i) { | |
| 658 | 679 | if (args[i]->IsUndefined() || args[i]->IsString()) { | |
@@ -798,6 +819,7 @@ class ContextifyScript : public BaseObject { | |||
| 798 | 819 | static bool EvalMachine(Environment* env, | |
| 799 | 820 | const int64_t timeout, | |
| 800 | 821 | const bool display_errors, | |
| 822 | + const bool break_on_sigint, | ||
| 801 | 823 | const FunctionCallbackInfo<Value>& args, | |
| 802 | 824 | TryCatch& try_catch) { | |
| 803 | 825 | if (!ContextifyScript::InstanceOf(env, args.Holder())) { | |
@@ -813,16 +835,30 @@ class ContextifyScript : public BaseObject { | |||
| 813 | 835 | Local<Script> script = unbound_script->BindToCurrentContext(); | |
| 814 | 836 | ||
| 815 | 837 | Local<Value> result; | |
| 816 | - if (timeout != -1) { | ||
| 838 | + bool timed_out = false; | ||
| 839 | + if (break_on_sigint && timeout != -1) { | ||
| 817 | 840 | Watchdog wd(env->isolate(), timeout); | |
| 841 | + SigintWatchdog swd(env->isolate()); | ||
| 818 | 842 | result = script->Run(); | |
| 843 | + timed_out = wd.HasTimedOut(); | ||
| 844 | + } else if (break_on_sigint) { | ||
| 845 | + SigintWatchdog swd(env->isolate()); | ||
| 846 | + result = script->Run(); | ||
| 847 | + } else if (timeout != -1) { | ||
| 848 | + Watchdog wd(env->isolate(), timeout); | ||
| 849 | + result = script->Run(); | ||
| 850 | + timed_out = wd.HasTimedOut(); | ||
| 819 | 851 | } else { | |
| 820 | 852 | result = script->Run(); | |
| 821 | 853 | } | |
| 822 | 854 | ||
| 823 | 855 | if (try_catch.HasCaught() && try_catch.HasTerminated()) { | |
| 824 | 856 | env->isolate()->CancelTerminateExecution(); | |
| 825 | - env->ThrowError("Script execution timed out."); | ||
| 857 | + if (timed_out) { | ||
| 858 | + env->ThrowError("Script execution timed out."); | ||
| 859 | + } else { | ||
| 860 | + env->ThrowError("Script execution interrupted."); | ||
| 861 | + } | ||
| 826 | 862 | try_catch.ReThrow(); | |
| 827 | 863 | return false; | |
| 828 | 864 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -99,6 +99,13 @@ void GetSockOrPeerName(const v8::FunctionCallbackInfo<v8::Value>& args) { | |||
| 99 | 99 | args.GetReturnValue().Set(err); | |
| 100 | 100 | } | |
| 101 | 101 | ||
| 102 | + void SignalExit(int signo); | ||
| 103 | + #ifdef __POSIX__ | ||
| 104 | + void RegisterSignalHandler(int signal, | ||
| 105 | + void (*handler)(int signal), | ||
| 106 | + bool reset_handler = false); | ||
| 107 | + #endif | ||
| 108 | + | ||
| 102 | 109 | #ifdef _WIN32 | |
| 103 | 110 | // emulate snprintf() on windows, _snprintf() doesn't zero-terminate the buffer | |
| 104 | 111 | // on overflow... | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,5 @@ | |||
| 1 | 1 | #include "node.h" | |
| 2 | + #include "node_watchdog.h" | ||
| 2 | 3 | #include "v8.h" | |
| 3 | 4 | #include "env.h" | |
| 4 | 5 | #include "env-inl.h" | |
@@ -88,6 +89,20 @@ static void SetHiddenValue(const FunctionCallbackInfo<Value>& args) { | |||
| 88 | 89 | } | |
| 89 | 90 | ||
| 90 | 91 | ||
| 92 | + void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) { | ||
| 93 | + int ret = SigintWatchdogHelper::GetInstance()->Start(); | ||
| 94 | + if (ret != 0) { | ||
| 95 | + Environment* env = Environment::GetCurrent(args); | ||
| 96 | + env->ThrowErrnoException(ret, "StartSigintWatchdog"); | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + | ||
| 101 | + void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) { | ||
| 102 | + bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop(); | ||
| 103 | + args.GetReturnValue().Set(had_pending_signals); | ||
| 104 | + } | ||
| 105 | + | ||
| 91 | 106 | void Initialize(Local<Object> target, | |
| 92 | 107 | Local<Value> unused, | |
| 93 | 108 | Local<Context> context) { | |
@@ -100,6 +115,9 @@ void Initialize(Local<Object> target, | |||
| 100 | 115 | env->SetMethod(target, "getHiddenValue", GetHiddenValue); | |
| 101 | 116 | env->SetMethod(target, "setHiddenValue", SetHiddenValue); | |
| 102 | 117 | env->SetMethod(target, "getProxyDetails", GetProxyDetails); | |
| 118 | + | ||
| 119 | + env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog); | ||
| 120 | + env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog); | ||
| 103 | 121 | } | |
| 104 | 122 | ||
| 105 | 123 | } // namespace util | |
| Back | FazBrowse Home | New Git URL |
0 commit comments