@@ -57,8 +57,40 @@ using v8::String;
5757using v8::Undefined;
5858using v8::Value;
5959
60+ using TryCatchScope = node::errors::TryCatchScope;
61+
6062namespace quic {
6163
64+ QuicCallbackScope::QuicCallbackScope (QuicSession* session)
65+ : session_(session),
66+ private_ (new InternalCallbackScope(
67+ session->env (),
68+ session->object(),
69+ {
70+ session->get_async_id (),
71+ session->get_trigger_async_id ()
72+ })),
73+ try_catch_(session->env ()->isolate()) {
74+ try_catch_.SetVerbose (true );
75+ }
76+
77+ QuicCallbackScope::~QuicCallbackScope () {
78+ Environment* env = session_->env ();
79+ if (UNLIKELY (try_catch_.HasCaught ())) {
80+ session_->crypto_context ()->set_in_client_hello (false );
81+ session_->crypto_context ()->set_in_ocsp_request (false );
82+ if (!try_catch_.HasTerminated () && env->can_call_into_js ()) {
83+ session_->set_last_error ({
84+ QUIC_ERROR_SESSION,
85+ uint64_t {NGTCP2_INTERNAL_ERROR}
86+ });
87+ session_->Close ();
88+ CHECK (session_->is_destroyed ());
89+ }
90+ private_->MarkAsFailed ();
91+ }
92+ }
93+
6294typedef ssize_t (*ngtcp2_close_fn)(
6395 ngtcp2_conn* conn,
6496 ngtcp2_path* path,
@@ -393,53 +425,59 @@ void JSQuicSessionListener::OnClientHello(
393425 HandleScope scope (env->isolate ());
394426 Context::Scope context_scope (env->context ());
395427
428+ // Why this instead of using MakeCallback? We need to catch any
429+ // errors that happen both when preparing the arguments and
430+ // invoking the callback so that we can properly signal a failure
431+ // to the peer.
432+ QuicCallbackScope cb_scope (session ());
433+
396434 Local<Array> ciphers;
397435 Local<Value> alpn_string = Undefined (env->isolate ());
398436 Local<Value> servername = Undefined (env->isolate ());
399437
400- // TODO(@jasnell): Need to decide how to handle the possible
401- // ToLocal failures more gracefully than crashing.
402-
403- CHECK (session ()->crypto_context ()->hello_ciphers ().ToLocal (&ciphers));
404-
405- if (alpn != nullptr )
406- CHECK (String::NewFromUtf8 (env->isolate (), alpn).ToLocal (&alpn_string));
407-
408- if (server_name != nullptr )
409- CHECK (String::NewFromUtf8 (env->isolate (), server_name)
410- .ToLocal (&servername));
411-
412- Local<Value> argv[] = {
413- alpn_string,
414- servername,
415- ciphers
416- };
438+ if (session ()->crypto_context ()->hello_ciphers ().ToLocal (&ciphers) &&
439+ (alpn == nullptr ||
440+ String::NewFromUtf8 (env->isolate (), alpn).ToLocal (&alpn_string)) &&
441+ (server_name == nullptr ||
442+ String::NewFromUtf8 (env->isolate (), server_name).ToLocal (&servername))) {
443+ Local<Value> argv[] = {
444+ alpn_string,
445+ servername,
446+ ciphers
447+ };
417448
418- // Grab a shared pointer to this to prevent the QuicSession
419- // from being freed while the MakeCallback is running.
420- BaseObjectPtr<QuicSession> ptr (session ());
421- session ()->MakeCallback (
422- env->quic_on_session_client_hello_function (),
423- arraysize (argv), argv);
449+ // Grab a shared pointer to this to prevent the QuicSession
450+ // from being freed while the MakeCallback is running.
451+ BaseObjectPtr<QuicSession> ptr (session ());
452+ env->quic_on_session_client_hello_function ()->Call (
453+ env->context (),
454+ session ()->object (),
455+ arraysize (argv),
456+ argv);
457+ }
424458}
425459
426460void JSQuicSessionListener::OnCert (const char * server_name) {
427461 Environment* env = session ()->env ();
428462 HandleScope handle_scope (env->isolate ());
429463 Context::Scope context_scope (env->context ());
430464
465+ QuicCallbackScope cb_scope (session ());
466+
431467 Local<Value> servername = Undefined (env->isolate ());
432- if (server_name != nullptr ) {
433- servername = OneByteString (
434- env->isolate (),
435- server_name,
436- strlen (server_name));
437- }
438468
439- // Grab a shared pointer to this to prevent the QuicSession
440- // from being freed while the MakeCallback is running.
441469 BaseObjectPtr<QuicSession> ptr (session ());
442- session ()->MakeCallback (env->quic_on_session_cert_function (), 1 , &servername);
470+ if (server_name == nullptr ||
471+ String::NewFromUtf8 (
472+ env->isolate (),
473+ server_name,
474+ v8::NewStringType::kNormal ,
475+ strlen (server_name)).ToLocal (&servername)) {
476+ env->quic_on_session_cert_function ()->Call (
477+ env->context (),
478+ session ()->object (),
479+ 1 , &servername);
480+ }
443481}
444482
445483void JSQuicSessionListener::OnStreamHeaders (
@@ -2913,11 +2951,12 @@ int QuicSession::OnReceiveCryptoData(
29132951 return NGTCP2_ERR_CALLBACK_FAILURE;
29142952
29152953 QuicSession::NgCallbackScope callback_scope (session);
2916- return session->crypto_context ()->Receive (
2954+ int ret = session->crypto_context ()->Receive (
29172955 crypto_level,
29182956 offset,
29192957 data,
29202958 datalen);
2959+ return ret == 0 ? 0 : NGTCP2_ERR_CALLBACK_FAILURE;
29212960}
29222961
29232962// Called by ngtcp2 for both client and server connections
0 commit comments