@@ -224,6 +224,44 @@ int SelectALPNCallback(
224224unsigned int inlen,
225225void * arg){
226226 TLSWrap* w = static_cast <TLSWrap*>(arg);
227+ if (w->alpn_callback_enabled_ ){
228+ Environment* env = w->env ();
229+ HandleScope handle_scope (env->isolate ());
230+
231+ Local<Value> callback_arg =
232+ Buffer::Copy (env, reinterpret_cast <const char *>(in), inlen)
233+ .ToLocalChecked ();
234+
235+ MaybeLocal<Value> maybe_callback_result =
236+ w->MakeCallback (env->alpn_callback_string (), 1 , &callback_arg);
237+
238+ if (UNLIKELY (maybe_callback_result.IsEmpty ())){
239+ // Implies the callback didn't return, because some exception was thrown
240+ // during processing, e.g. if callback returned an invalid ALPN value.
241+ return SSL_TLSEXT_ERR_ALERT_FATAL;
242+ }
243+
244+ Local<Value> callback_result = maybe_callback_result.ToLocalChecked ();
245+
246+ if (callback_result->IsUndefined ()){
247+ // If you set an ALPN callback, but you return undefined for an ALPN
248+ // request, you're rejecting all proposed ALPN protocols, and so we send
249+ // a fatal alert:
250+ return SSL_TLSEXT_ERR_ALERT_FATAL;
251+ }
252+
253+ CHECK (callback_result->IsNumber ());
254+ unsigned int result_int = callback_result.As <v8::Number>()->Value ();
255+
256+ // The callback returns an offset into the given buffer, for the selected
257+ // protocol that should be returned. We then set outlen & out to point
258+ // to the selected input length & value directly:
259+ *outlen = *(in + result_int);
260+ *out = (in + result_int + 1 );
261+
262+ return SSL_TLSEXT_ERR_OK;
263+ }
264+
227265const std::vector<unsigned char >& alpn_protos = w->alpn_protos_ ;
228266
229267if (alpn_protos.empty ()) return SSL_TLSEXT_ERR_NOACK;
@@ -1249,6 +1287,15 @@ void TLSWrap::OnClientHelloParseEnd(void* arg){
12491287 c->Cycle ();
12501288}
12511289
1290+ void TLSWrap::EnableALPNCb (const FunctionCallbackInfo<Value>& args){
1291+ TLSWrap* wrap;
1292+ ASSIGN_OR_RETURN_UNWRAP (&wrap, args.Holder ());
1293+ wrap->alpn_callback_enabled_ = true ;
1294+
1295+ SSL* ssl = wrap->ssl_ .get ();
1296+ SSL_CTX_set_alpn_select_cb (SSL_get_SSL_CTX (ssl), SelectALPNCallback, wrap);
1297+ }
1298+
12521299void TLSWrap::GetServername (const FunctionCallbackInfo<Value>& args){
12531300 Environment* env = Environment::GetCurrent (args);
12541301
@@ -2069,6 +2116,7 @@ void TLSWrap::Initialize(
20692116SetProtoMethod (isolate, t, " certCbDone" , CertCbDone);
20702117SetProtoMethod (isolate, t, " destroySSL" , DestroySSL);
20712118SetProtoMethod (isolate, t, " enableCertCb" , EnableCertCb);
2119+ SetProtoMethod (isolate, t, " enableALPNCb" , EnableALPNCb);
20722120SetProtoMethod (isolate, t, " endParser" , EndParser);
20732121SetProtoMethod (isolate, t, " enableKeylogCallback" , EnableKeylogCallback);
20742122SetProtoMethod (isolate, t, " enableSessionCallbacks" , EnableSessionCallbacks);
@@ -2138,6 +2186,7 @@ void TLSWrap::RegisterExternalReferences(ExternalReferenceRegistry* registry){
21382186 registry->Register (CertCbDone);
21392187 registry->Register (DestroySSL);
21402188 registry->Register (EnableCertCb);
2189+ registry->Register (EnableALPNCb);
21412190 registry->Register (EndParser);
21422191 registry->Register (EnableKeylogCallback);
21432192 registry->Register (EnableSessionCallbacks);
0 commit comments