@@ -57,8 +57,40 @@ using v8::String;
57
57
using v8::Undefined;
58
58
using v8::Value;
59
59
60
+ using TryCatchScope = node::errors::TryCatchScope;
61
+
60
62
namespace quic {
61
63
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
+
62
94
typedef ssize_t (*ngtcp2_close_fn)(
63
95
ngtcp2_conn* conn,
64
96
ngtcp2_path* path,
@@ -393,53 +425,59 @@ void JSQuicSessionListener::OnClientHello(
393
425
HandleScope scope (env->isolate ());
394
426
Context::Scope context_scope (env->context ());
395
427
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
+
396
434
Local<Array> ciphers;
397
435
Local<Value> alpn_string = Undefined (env->isolate ());
398
436
Local<Value> servername = Undefined (env->isolate ());
399
437
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
+ };
417
448
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
+ }
424
458
}
425
459
426
460
void JSQuicSessionListener::OnCert (const char * server_name) {
427
461
Environment* env = session ()->env ();
428
462
HandleScope handle_scope (env->isolate ());
429
463
Context::Scope context_scope (env->context ());
430
464
465
+ QuicCallbackScope cb_scope (session ());
466
+
431
467
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
- }
438
468
439
- // Grab a shared pointer to this to prevent the QuicSession
440
- // from being freed while the MakeCallback is running.
441
469
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
+ }
443
481
}
444
482
445
483
void JSQuicSessionListener::OnStreamHeaders (
@@ -2913,11 +2951,12 @@ int QuicSession::OnReceiveCryptoData(
2913
2951
return NGTCP2_ERR_CALLBACK_FAILURE;
2914
2952
2915
2953
QuicSession::NgCallbackScope callback_scope (session);
2916
- return session->crypto_context ()->Receive (
2954
+ int ret = session->crypto_context ()->Receive (
2917
2955
crypto_level,
2918
2956
offset,
2919
2957
data,
2920
2958
datalen);
2959
+ return ret == 0 ? 0 : NGTCP2_ERR_CALLBACK_FAILURE;
2921
2960
}
2922
2961
2923
2962
// Called by ngtcp2 for both client and server connections
0 commit comments