@@ -78,6 +78,7 @@ const uint32_t kOnHeadersComplete = 1;
7878const uint32_t kOnBody = 2 ;
7979const uint32_t kOnMessageComplete = 3 ;
8080const uint32_t kOnExecute = 4 ;
81+ const uint32_t kOnTimeout = 5 ;
8182// Any more fields than this will be flushed into JS
8283const size_t kMaxHeaderFieldsCount = 32 ;
8384
@@ -185,6 +186,7 @@ class Parser : public AsyncWrap, public StreamListener {
185186 num_fields_ = num_values_ = 0 ;
186187 url_.Reset ();
187188 status_message_.Reset ();
189+ header_parsing_start_time_ = uv_hrtime ();
188190 return 0 ;
189191 }
190192
@@ -518,9 +520,16 @@ class Parser : public AsyncWrap, public StreamListener {
518520 Environment* env = Environment::GetCurrent (args);
519521 bool lenient = args[2 ]->IsTrue ();
520522
523+ uint64_t headers_timeout = 0 ;
524+
521525 CHECK (args[0 ]->IsInt32 ());
522526 CHECK (args[1 ]->IsObject ());
523527
528+ if (args.Length () > 3 ) {
529+ CHECK (args[3 ]->IsInt32 ());
530+ headers_timeout = args[3 ].As <Int32>()->Value ();
531+ }
532+
524533 parser_type_t type =
525534 static_cast <parser_type_t >(args[0 ].As <Int32>()->Value ());
526535
@@ -537,7 +546,7 @@ class Parser : public AsyncWrap, public StreamListener {
537546
538547 parser->set_provider_type (provider);
539548 parser->AsyncReset (args[1 ].As <Object>());
540- parser->Init (type, lenient);
549+ parser->Init (type, lenient, headers_timeout );
541550 }
542551
543552 template <bool should_pause>
@@ -645,6 +654,24 @@ class Parser : public AsyncWrap, public StreamListener {
645654 if (ret.IsEmpty ())
646655 return ;
647656
657+ // check header parsing time
658+ if (header_parsing_start_time_ != 0 && headers_timeout_ != 0 ) {
659+ uint64_t now = uv_hrtime ();
660+ uint64_t parsing_time = (now - header_parsing_start_time_) / 1e6 ;
661+
662+ if (parsing_time > headers_timeout_) {
663+ Local<Value> cb =
664+ object ()->Get (env ()->context (), kOnTimeout ).ToLocalChecked ();
665+
666+ if (!cb->IsFunction ())
667+ return ;
668+
669+ MakeCallback (cb.As <Function>(), 0 , nullptr );
670+
671+ return ;
672+ }
673+ }
674+
648675 Local<Value> cb =
649676 object ()->Get (env ()->context (), kOnExecute ).ToLocalChecked ();
650677
@@ -821,7 +848,7 @@ class Parser : public AsyncWrap, public StreamListener {
821848 }
822849
823850
824- void Init (parser_type_t type, bool lenient) {
851+ void Init (parser_type_t type, bool lenient, uint64_t headers_timeout ) {
825852#ifdef NODE_EXPERIMENTAL_HTTP
826853 llhttp_init (&parser_, type, &settings);
827854 llhttp_set_lenient (&parser_, lenient);
@@ -836,6 +863,8 @@ class Parser : public AsyncWrap, public StreamListener {
836863 num_values_ = 0 ;
837864 have_flushed_ = false ;
838865 got_exception_ = false ;
866+ header_parsing_start_time_ = 0 ;
867+ headers_timeout_ = headers_timeout;
839868 }
840869
841870
@@ -884,6 +913,8 @@ class Parser : public AsyncWrap, public StreamListener {
884913 bool pending_pause_ = false ;
885914 uint64_t header_nread_ = 0 ;
886915#endif /* NODE_EXPERIMENTAL_HTTP */
916+ uint64_t headers_timeout_;
917+ uint64_t header_parsing_start_time_ = 0 ;
887918
888919 // These are helper functions for filling `http_parser_settings`, which turn
889920 // a member function of Parser into a C-style HTTP parser callback.
@@ -957,6 +988,8 @@ void InitializeHttpParser(Local<Object> target,
957988 Integer::NewFromUnsigned (env->isolate (), kOnMessageComplete ));
958989 t->Set (FIXED_ONE_BYTE_STRING (env->isolate (), " kOnExecute" ),
959990 Integer::NewFromUnsigned (env->isolate (), kOnExecute ));
991+ t->Set (FIXED_ONE_BYTE_STRING (env->isolate (), " kOnTimeout" ),
992+ Integer::NewFromUnsigned (env->isolate (), kOnTimeout ));
960993
961994 Local<Array> methods = Array::New (env->isolate ());
962995#define V (num, name, string ) \
0 commit comments