@@ -78,6 +78,7 @@ const uint32_t kOnHeadersComplete = 1;
78
78
const uint32_t kOnBody = 2 ;
79
79
const uint32_t kOnMessageComplete = 3 ;
80
80
const uint32_t kOnExecute = 4 ;
81
+ const uint32_t kOnTimeout = 5 ;
81
82
// Any more fields than this will be flushed into JS
82
83
const size_t kMaxHeaderFieldsCount = 32 ;
83
84
@@ -185,6 +186,7 @@ class Parser : public AsyncWrap, public StreamListener {
185
186
num_fields_ = num_values_ = 0 ;
186
187
url_.Reset ();
187
188
status_message_.Reset ();
189
+ header_parsing_start_time_ = uv_hrtime ();
188
190
return 0 ;
189
191
}
190
192
@@ -518,9 +520,16 @@ class Parser : public AsyncWrap, public StreamListener {
518
520
Environment* env = Environment::GetCurrent (args);
519
521
bool lenient = args[2 ]->IsTrue ();
520
522
523
+ uint64_t headers_timeout = 0 ;
524
+
521
525
CHECK (args[0 ]->IsInt32 ());
522
526
CHECK (args[1 ]->IsObject ());
523
527
528
+ if (args.Length () > 3 ) {
529
+ CHECK (args[3 ]->IsInt32 ());
530
+ headers_timeout = args[3 ].As <Int32>()->Value ();
531
+ }
532
+
524
533
parser_type_t type =
525
534
static_cast <parser_type_t >(args[0 ].As <Int32>()->Value ());
526
535
@@ -537,7 +546,7 @@ class Parser : public AsyncWrap, public StreamListener {
537
546
538
547
parser->set_provider_type (provider);
539
548
parser->AsyncReset (args[1 ].As <Object>());
540
- parser->Init (type, lenient);
549
+ parser->Init (type, lenient, headers_timeout );
541
550
}
542
551
543
552
template <bool should_pause>
@@ -645,6 +654,24 @@ class Parser : public AsyncWrap, public StreamListener {
645
654
if (ret.IsEmpty ())
646
655
return ;
647
656
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
+
648
675
Local<Value> cb =
649
676
object ()->Get (env ()->context (), kOnExecute ).ToLocalChecked ();
650
677
@@ -821,7 +848,7 @@ class Parser : public AsyncWrap, public StreamListener {
821
848
}
822
849
823
850
824
- void Init (parser_type_t type, bool lenient) {
851
+ void Init (parser_type_t type, bool lenient, uint64_t headers_timeout ) {
825
852
#ifdef NODE_EXPERIMENTAL_HTTP
826
853
llhttp_init (&parser_, type, &settings);
827
854
llhttp_set_lenient (&parser_, lenient);
@@ -836,6 +863,8 @@ class Parser : public AsyncWrap, public StreamListener {
836
863
num_values_ = 0 ;
837
864
have_flushed_ = false ;
838
865
got_exception_ = false ;
866
+ header_parsing_start_time_ = 0 ;
867
+ headers_timeout_ = headers_timeout;
839
868
}
840
869
841
870
@@ -884,6 +913,8 @@ class Parser : public AsyncWrap, public StreamListener {
884
913
bool pending_pause_ = false ;
885
914
uint64_t header_nread_ = 0 ;
886
915
#endif /* NODE_EXPERIMENTAL_HTTP */
916
+ uint64_t headers_timeout_;
917
+ uint64_t header_parsing_start_time_ = 0 ;
887
918
888
919
// These are helper functions for filling `http_parser_settings`, which turn
889
920
// a member function of Parser into a C-style HTTP parser callback.
@@ -957,6 +988,8 @@ void InitializeHttpParser(Local<Object> target,
957
988
Integer::NewFromUnsigned (env->isolate (), kOnMessageComplete ));
958
989
t->Set (FIXED_ONE_BYTE_STRING (env->isolate (), " kOnExecute" ),
959
990
Integer::NewFromUnsigned (env->isolate (), kOnExecute ));
991
+ t->Set (FIXED_ONE_BYTE_STRING (env->isolate (), " kOnTimeout" ),
992
+ Integer::NewFromUnsigned (env->isolate (), kOnTimeout ));
960
993
961
994
Local<Array> methods = Array::New (env->isolate ());
962
995
#define V (num, name, string ) \
0 commit comments