GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_http_parser.cc Lines: 506 583 86.8 %
Date: 2022-04-26 04:15:06 Branches: 226 320 70.6 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "node.h"
23
#include "node_buffer.h"
24
#include "util.h"
25
26
#include "async_wrap-inl.h"
27
#include "env-inl.h"
28
#include "memory_tracker-inl.h"
29
#include "stream_base-inl.h"
30
#include "v8.h"
31
#include "llhttp.h"
32
33
#include <cstdlib>  // free()
34
#include <cstring>  // strdup(), strchr()
35
36
37
// This is a binding to llhttp (https://github.com/nodejs/llhttp)
38
// The goal is to decouple sockets from parsing for more javascript-level
39
// agility. A Buffer is read from a socket and passed to parser.execute().
40
// The parser then issues callbacks with slices of the data
41
//     parser.onMessageBegin
42
//     parser.onPath
43
//     parser.onBody
44
//     ...
45
// No copying is performed when slicing the buffer, only small reference
46
// allocations.
47
48
49
namespace node {
50
namespace {  // NOLINT(build/namespaces)
51
52
using v8::Array;
53
using v8::Boolean;
54
using v8::Context;
55
using v8::EscapableHandleScope;
56
using v8::Exception;
57
using v8::Function;
58
using v8::FunctionCallbackInfo;
59
using v8::FunctionTemplate;
60
using v8::HandleScope;
61
using v8::Int32;
62
using v8::Integer;
63
using v8::Isolate;
64
using v8::Local;
65
using v8::MaybeLocal;
66
using v8::Number;
67
using v8::Object;
68
using v8::String;
69
using v8::Uint32;
70
using v8::Undefined;
71
using v8::Value;
72
73
const uint32_t kOnMessageBegin = 0;
74
const uint32_t kOnHeaders = 1;
75
const uint32_t kOnHeadersComplete = 2;
76
const uint32_t kOnBody = 3;
77
const uint32_t kOnMessageComplete = 4;
78
const uint32_t kOnExecute = 5;
79
const uint32_t kOnTimeout = 6;
80
// Any more fields than this will be flushed into JS
81
const size_t kMaxHeaderFieldsCount = 32;
82
83
const uint32_t kLenientNone = 0;
84
const uint32_t kLenientHeaders = 1 << 0;
85
const uint32_t kLenientChunkedLength = 1 << 1;
86
const uint32_t kLenientKeepAlive = 1 << 2;
87
const uint32_t kLenientAll = kLenientHeaders | kLenientChunkedLength |
88
  kLenientKeepAlive;
89
90
17917
inline bool IsOWS(char c) {
91

17917
  return c == ' ' || c == '\t';
92
}
93
94
class BindingData : public BaseObject {
95
 public:
96
824
  BindingData(Environment* env, Local<Object> obj)
97
824
      : BaseObject(env, obj) {}
98
99
  static constexpr FastStringKey type_name { "http_parser" };
100
101
  std::vector<char> parser_buffer;
102
  bool parser_buffer_in_use = false;
103
104
3
  void MemoryInfo(MemoryTracker* tracker) const override {
105
3
    tracker->TrackField("parser_buffer", parser_buffer);
106
3
  }
107
3
  SET_SELF_SIZE(BindingData)
108
3
  SET_MEMORY_INFO_NAME(BindingData)
109
};
110
111
// helper class for the Parser
112
struct StringPtr {
113
273768
  StringPtr() {
114
273768
    on_heap_ = false;
115
273768
    Reset();
116
273768
  }
117
118
119
541200
  ~StringPtr() {
120
270600
    Reset();
121
270600
  }
122
123
124
  // If str_ does not point to a heap string yet, this function makes it do
125
  // so. This is called at the end of each http_parser_execute() so as not
126
  // to leak references. See issue #2438 and test-http-parser-bad-ref.js.
127
15170
  void Save() {
128

15170
    if (!on_heap_ && size_ > 0) {
129
6325
      char* s = new char[size_];
130
6325
      memcpy(s, str_, size_);
131
6325
      str_ = s;
132
6325
      on_heap_ = true;
133
    }
134
15170
  }
135
136
137
627816
  void Reset() {
138
627816
    if (on_heap_) {
139
6276
      delete[] str_;
140
6276
      on_heap_ = false;
141
    }
142
143
627816
    str_ = nullptr;
144
627816
    size_ = 0;
145
627816
  }
146
147
148
53327
  void Update(const char* str, size_t size) {
149
53327
    if (str_ == nullptr) {
150
53267
      str_ = str;
151

60
    } else if (on_heap_ || str_ + size_ != str) {
152
      // Non-consecutive input, make a copy on the heap.
153
      // TODO(bnoordhuis) Use slab allocation, O(n) allocs is bad.
154
60
      char* s = new char[size_ + size];
155
60
      memcpy(s, str_, size_);
156
60
      memcpy(s + size_, str, size);
157
158
60
      if (on_heap_)
159
59
        delete[] str_;
160
      else
161
1
        on_heap_ = true;
162
163
60
      str_ = s;
164
    }
165
53327
    size_ += size;
166
53327
  }
167
168
169
53180
  Local<String> ToString(Environment* env) const {
170
53180
    if (size_ != 0)
171
53116
      return OneByteString(env->isolate(), str_, size_);
172
    else
173
128
      return String::Empty(env->isolate());
174
  }
175
176
177
  // Strip trailing OWS (SPC or HTAB) from string.
178
17919
  Local<String> ToTrimmedString(Environment* env) {
179

17919
    while (size_ > 0 && IsOWS(str_[size_ - 1])) {
180
11
      size_--;
181
    }
182
17908
    return ToString(env);
183
  }
184
185
186
  const char* str_;
187
  bool on_heap_;
188
  size_t size_;
189
};
190
191
class Parser;
192
193
struct ParserComparator {
194
  bool operator()(const Parser* lhs, const Parser* rhs) const;
195
};
196
197
class ConnectionsList : public BaseObject {
198
 public:
199
    static void New(const FunctionCallbackInfo<Value>& args);
200
201
    static void All(const FunctionCallbackInfo<Value>& args);
202
203
    static void Idle(const FunctionCallbackInfo<Value>& args);
204
205
    static void Active(const FunctionCallbackInfo<Value>& args);
206
207
    static void Expired(const FunctionCallbackInfo<Value>& args);
208
209
2369
    void Push(Parser* parser) {
210
2369
      all_connections_.insert(parser);
211
2369
    }
212
213
2354
    void Pop(Parser* parser) {
214
2354
      all_connections_.erase(parser);
215
2354
    }
216
217
16308
    void PushActive(Parser* parser) {
218
16308
      active_connections_.insert(parser);
219
16308
    }
220
221
30181
    void PopActive(Parser* parser) {
222
30181
      active_connections_.erase(parser);
223
30181
    }
224
225
    SET_NO_MEMORY_INFO()
226
    SET_MEMORY_INFO_NAME(ConnectionsList)
227
    SET_SELF_SIZE(ConnectionsList)
228
229
 private:
230
556
    ConnectionsList(Environment* env, Local<Object> object)
231
556
      : BaseObject(env, object) {
232
556
        MakeWeak();
233
556
      }
234
235
    std::set<Parser*, ParserComparator> all_connections_;
236
    std::set<Parser*, ParserComparator> active_connections_;
237
};
238
239
class Parser : public AsyncWrap, public StreamListener {
240
  friend class ConnectionsList;
241
  friend struct ParserComparator;
242
243
 public:
244
4148
  Parser(BindingData* binding_data, Local<Object> wrap)
245
4148
      : AsyncWrap(binding_data->env(), wrap),
246
        current_buffer_len_(0),
247
        current_buffer_data_(nullptr),
248

269620
        binding_data_(binding_data) {
249
4148
  }
250
251
252
  void MemoryInfo(MemoryTracker* tracker) const override {
253
    tracker->TrackField("current_buffer", current_buffer_);
254
  }
255
256
  SET_MEMORY_INFO_NAME(Parser)
257
  SET_SELF_SIZE(Parser)
258
259
17356
  int on_message_begin() {
260
    // Important: Pop from the list BEFORE resetting the last_message_start_
261
    // otherwise std::set.erase will fail.
262
17356
    if (connectionsList_ != nullptr) {
263
13939
      connectionsList_->PopActive(this);
264
    }
265
266
17356
    num_fields_ = num_values_ = 0;
267
17356
    headers_completed_ = false;
268
17356
    last_message_start_ = uv_hrtime();
269
17356
    url_.Reset();
270
17356
    status_message_.Reset();
271
272
17356
    if (connectionsList_ != nullptr) {
273
13939
      connectionsList_->PushActive(this);
274
    }
275
276
34712
    Local<Value> cb = object()->Get(env()->context(), kOnMessageBegin)
277
17356
                              .ToLocalChecked();
278
17356
    if (cb->IsFunction()) {
279
      InternalCallbackScope callback_scope(
280
        this, InternalCallbackScope::kSkipTaskQueues);
281
282
      MaybeLocal<Value> r = cb.As<Function>()->Call(
283
        env()->context(), object(), 0, nullptr);
284
285
      if (r.IsEmpty()) callback_scope.MarkAsFailed();
286
    }
287
288
17356
    return 0;
289
  }
290
291
292
14105
  int on_url(const char* at, size_t length) {
293
14105
    int rv = TrackHeader(length);
294
14105
    if (rv != 0) {
295
      return rv;
296
    }
297
298
14105
    url_.Update(at, length);
299
14105
    return 0;
300
  }
301
302
303
3243
  int on_status(const char* at, size_t length) {
304
3243
    int rv = TrackHeader(length);
305
3243
    if (rv != 0) {
306
      return rv;
307
    }
308
309
3243
    status_message_.Update(at, length);
310
3243
    return 0;
311
  }
312
313
314
18008
  int on_header_field(const char* at, size_t length) {
315
18008
    int rv = TrackHeader(length);
316
18008
    if (rv != 0) {
317
      return rv;
318
    }
319
320
18008
    if (num_fields_ == num_values_) {
321
      // start of new field name
322
17979
      num_fields_++;
323
17979
      if (num_fields_ == kMaxHeaderFieldsCount) {
324
        // ran out of space - flush to javascript land
325
47
        Flush();
326
47
        num_fields_ = 1;
327
47
        num_values_ = 0;
328
      }
329
17979
      fields_[num_fields_ - 1].Reset();
330
    }
331
332
18008
    CHECK_LT(num_fields_, kMaxHeaderFieldsCount);
333
18008
    CHECK_EQ(num_fields_, num_values_ + 1);
334
335
18008
    fields_[num_fields_ - 1].Update(at, length);
336
337
18008
    return 0;
338
  }
339
340
341
17988
  int on_header_value(const char* at, size_t length) {
342
17988
    int rv = TrackHeader(length);
343
17988
    if (rv != 0) {
344
17
      return rv;
345
    }
346
347
17971
    if (num_values_ != num_fields_) {
348
      // start of new header value
349
17948
      num_values_++;
350
17948
      values_[num_values_ - 1].Reset();
351
    }
352
353
17971
    CHECK_LT(num_values_, arraysize(values_));
354
17971
    CHECK_EQ(num_values_, num_fields_);
355
356
17971
    values_[num_values_ - 1].Update(at, length);
357
358
17971
    return 0;
359
  }
360
361
362
17305
  int on_headers_complete() {
363
17305
    headers_completed_ = true;
364
17305
    header_nread_ = 0;
365
366
    // Arguments for the on-headers-complete javascript callback. This
367
    // list needs to be kept in sync with the actual argument list for
368
    // `parserOnHeadersComplete` in lib/_http_common.js.
369
    enum on_headers_complete_arg_index {
370
      A_VERSION_MAJOR = 0,
371
      A_VERSION_MINOR,
372
      A_HEADERS,
373
      A_METHOD,
374
      A_URL,
375
      A_STATUS_CODE,
376
      A_STATUS_MESSAGE,
377
      A_UPGRADE,
378
      A_SHOULD_KEEP_ALIVE,
379
      A_MAX
380
    };
381
382
173050
    Local<Value> argv[A_MAX];
383
17305
    Local<Object> obj = object();
384
17305
    Local<Value> cb = obj->Get(env()->context(),
385
34610
                               kOnHeadersComplete).ToLocalChecked();
386
387
17305
    if (!cb->IsFunction())
388
      return 0;
389
390
17305
    Local<Value> undefined = Undefined(env()->isolate());
391
173050
    for (size_t i = 0; i < arraysize(argv); i++)
392
155745
      argv[i] = undefined;
393
394
17305
    if (have_flushed_) {
395
      // Slow case, flush remaining headers.
396
16
      Flush();
397
    } else {
398
      // Fast case, pass headers and URL to JS land.
399
17289
      argv[A_HEADERS] = CreateHeaders();
400
17289
      if (parser_.type == HTTP_REQUEST)
401
28126
        argv[A_URL] = url_.ToString(env());
402
    }
403
404
17305
    num_fields_ = 0;
405
17305
    num_values_ = 0;
406
407
    // METHOD
408
17305
    if (parser_.type == HTTP_REQUEST) {
409
28142
      argv[A_METHOD] =
410
14071
          Uint32::NewFromUnsigned(env()->isolate(), parser_.method);
411
    }
412
413
    // STATUS
414
17305
    if (parser_.type == HTTP_RESPONSE) {
415
3234
      argv[A_STATUS_CODE] =
416
3234
          Integer::New(env()->isolate(), parser_.status_code);
417
6468
      argv[A_STATUS_MESSAGE] = status_message_.ToString(env());
418
    }
419
420
    // VERSION
421
17305
    argv[A_VERSION_MAJOR] = Integer::New(env()->isolate(), parser_.http_major);
422
17305
    argv[A_VERSION_MINOR] = Integer::New(env()->isolate(), parser_.http_minor);
423
424
    bool should_keep_alive;
425
17305
    should_keep_alive = llhttp_should_keep_alive(&parser_);
426
427
17305
    argv[A_SHOULD_KEEP_ALIVE] =
428
        Boolean::New(env()->isolate(), should_keep_alive);
429
430
34610
    argv[A_UPGRADE] = Boolean::New(env()->isolate(), parser_.upgrade);
431
432
    MaybeLocal<Value> head_response;
433
    {
434
      InternalCallbackScope callback_scope(
435
34608
          this, InternalCallbackScope::kSkipTaskQueues);
436
17305
      head_response = cb.As<Function>()->Call(
437
34610
          env()->context(), object(), arraysize(argv), argv);
438
17303
      if (head_response.IsEmpty()) callback_scope.MarkAsFailed();
439
    }
440
441
    int64_t val;
442
443
51893
    if (head_response.IsEmpty() || !head_response.ToLocalChecked()
444
34598
                                        ->IntegerValue(env()->context())
445
17295
                                        .To(&val)) {
446
8
      got_exception_ = true;
447
8
      return -1;
448
    }
449
450
17295
    return static_cast<int>(val);
451
  }
452
453
454
11222
  int on_body(const char* at, size_t length) {
455
11222
    EscapableHandleScope scope(env()->isolate());
456
457
11222
    Local<Object> obj = object();
458
22444
    Local<Value> cb = obj->Get(env()->context(), kOnBody).ToLocalChecked();
459
460
11222
    if (!cb->IsFunction())
461
      return 0;
462
463
    // We came from consumed stream
464
11222
    if (current_buffer_.IsEmpty()) {
465
      // Make sure Buffer will be in parent HandleScope
466
514
      current_buffer_ = scope.Escape(Buffer::Copy(
467
          env()->isolate(),
468
          current_buffer_data_,
469
1028
          current_buffer_len_).ToLocalChecked());
470
    }
471
472
    Local<Value> argv[3] = {
473
        current_buffer_,
474
        Integer::NewFromUnsigned(
475
11222
            env()->isolate(), static_cast<uint32_t>(at - current_buffer_data_)),
476
22444
        Integer::NewFromUnsigned(env()->isolate(), length)};
477
478
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
479
11222
                                       arraysize(argv),
480
22444
                                       argv);
481
482
11222
    if (r.IsEmpty()) {
483
      got_exception_ = true;
484
      llhttp_set_error_reason(&parser_, "HPE_JS_EXCEPTION:JS Exception");
485
      return HPE_USER;
486
    }
487
488
11222
    return 0;
489
  }
490
491
492
16097
  int on_message_complete() {
493
32194
    HandleScope scope(env()->isolate());
494
495
    // Important: Pop from the list BEFORE resetting the last_message_start_
496
    // otherwise std::set.erase will fail.
497
16097
    if (connectionsList_ != nullptr) {
498
13888
      connectionsList_->PopActive(this);
499
    }
500
501
16097
    last_message_start_ = 0;
502
503
16097
    if (num_fields_)
504
4
      Flush();  // Flush trailing HTTP headers.
505
506
16097
    Local<Object> obj = object();
507
16097
    Local<Value> cb = obj->Get(env()->context(),
508
32194
                               kOnMessageComplete).ToLocalChecked();
509
510
16097
    if (!cb->IsFunction())
511
2
      return 0;
512
513
    MaybeLocal<Value> r;
514
    {
515
      InternalCallbackScope callback_scope(
516
32190
          this, InternalCallbackScope::kSkipTaskQueues);
517
32190
      r = cb.As<Function>()->Call(env()->context(), object(), 0, nullptr);
518
16095
      if (r.IsEmpty()) callback_scope.MarkAsFailed();
519
    }
520
521
16095
    if (r.IsEmpty()) {
522
      got_exception_ = true;
523
      return -1;
524
    }
525
526
16095
    return 0;
527
  }
528
529
  // Reset nread for the next chunk
530
11179
  int on_chunk_header() {
531
11179
    header_nread_ = 0;
532
11179
    return 0;
533
  }
534
535
536
  // Reset nread for the next chunk
537
11025
  int on_chunk_complete() {
538
11025
    header_nread_ = 0;
539
11025
    return 0;
540
  }
541
542
4148
  static void New(const FunctionCallbackInfo<Value>& args) {
543
4148
    BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
544
4148
    new Parser(binding_data, args.This());
545
4148
  }
546
547
548
3
  static void Close(const FunctionCallbackInfo<Value>& args) {
549
    Parser* parser;
550
3
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
551
552
3
    delete parser;
553
  }
554
555
556
6174
  static void Free(const FunctionCallbackInfo<Value>& args) {
557
    Parser* parser;
558
6174
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
559
560
6174
    if (parser->connectionsList_ != nullptr) {
561
2354
      parser->connectionsList_->Pop(parser);
562
2354
      parser->connectionsList_->PopActive(parser);
563
    }
564
565
    // Since the Parser destructor isn't going to run the destroy() callbacks
566
    // it needs to be triggered manually.
567
6174
    parser->EmitTraceEventDestroy();
568
6174
    parser->EmitDestroy();
569
  }
570
571
572
7441
  void Save() {
573
7441
    url_.Save();
574
7441
    status_message_.Save();
575
576
7618
    for (size_t i = 0; i < num_fields_; i++) {
577
177
      fields_[i].Save();
578
    }
579
580
7552
    for (size_t i = 0; i < num_values_; i++) {
581
111
      values_[i].Save();
582
    }
583
7441
  }
584
585
  // var bytesParsed = parser->execute(buffer);
586
3314
  static void Execute(const FunctionCallbackInfo<Value>& args) {
587
    Parser* parser;
588
3314
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
589
3314
    CHECK(parser->current_buffer_.IsEmpty());
590
3314
    CHECK_EQ(parser->current_buffer_len_, 0);
591
3314
    CHECK_NULL(parser->current_buffer_data_);
592
593
3314
    ArrayBufferViewContents<char> buffer(args[0]);
594
595
    // This is a hack to get the current_buffer to the callbacks with the least
596
    // amount of overhead. Nothing else will run while http_parser_execute()
597
    // runs, therefore this pointer can be set and used for the execution.
598
3314
    parser->current_buffer_ = args[0].As<Object>();
599
600
3314
    Local<Value> ret = parser->Execute(buffer.data(), buffer.length());
601
602
3313
    if (!ret.IsEmpty())
603
6620
      args.GetReturnValue().Set(ret);
604
  }
605
606
607
1033
  static void Finish(const FunctionCallbackInfo<Value>& args) {
608
    Parser* parser;
609
1033
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
610
611
1033
    CHECK(parser->current_buffer_.IsEmpty());
612
1033
    Local<Value> ret = parser->Execute(nullptr, 0);
613
614
1033
    if (!ret.IsEmpty())
615
66
      args.GetReturnValue().Set(ret);
616
  }
617
618
619
6371
  static void Initialize(const FunctionCallbackInfo<Value>& args) {
620
6371
    Environment* env = Environment::GetCurrent(args);
621
622
6371
    uint64_t max_http_header_size = 0;
623
6371
    uint32_t lenient_flags = kLenientNone;
624
6371
    ConnectionsList* connectionsList = nullptr;
625
626
6371
    CHECK(args[0]->IsInt32());
627
6371
    CHECK(args[1]->IsObject());
628
629
6371
    if (args.Length() > 2) {
630
5201
      CHECK(args[2]->IsNumber());
631
5201
      max_http_header_size =
632
10402
          static_cast<uint64_t>(args[2].As<Number>()->Value());
633
    }
634
6371
    if (max_http_header_size == 0) {
635
6367
      max_http_header_size = env->options()->max_http_header_size;
636
    }
637
638
6371
    if (args.Length() > 3) {
639
5201
      CHECK(args[3]->IsInt32());
640
10402
      lenient_flags = args[3].As<Int32>()->Value();
641
    }
642
643

11113
    if (args.Length() > 4 && !args[4]->IsNullOrUndefined()) {
644
2369
      CHECK(args[4]->IsObject());
645
2369
      ASSIGN_OR_RETURN_UNWRAP(&connectionsList, args[4]);
646
    }
647
648
    llhttp_type_t type =
649
12742
        static_cast<llhttp_type_t>(args[0].As<Int32>()->Value());
650
651

6371
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
652
    Parser* parser;
653
6371
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
654
    // Should always be called from the same context.
655
6371
    CHECK_EQ(env, parser->env());
656
657
6371
    AsyncWrap::ProviderType provider =
658
6371
        (type == HTTP_REQUEST ?
659
            AsyncWrap::PROVIDER_HTTPINCOMINGMESSAGE
660
            : AsyncWrap::PROVIDER_HTTPCLIENTREQUEST);
661
662
6371
    parser->set_provider_type(provider);
663
19113
    parser->AsyncReset(args[1].As<Object>());
664
6371
    parser->Init(type, max_http_header_size, lenient_flags);
665
666
6371
    if (connectionsList != nullptr) {
667
2369
      parser->connectionsList_ = connectionsList;
668
669
2369
      parser->connectionsList_->Push(parser);
670
671
      // This protects from a DoS attack where an attacker establishes
672
      // the connection without sending any data on applications where
673
      // server.timeout is left to the default value of zero.
674
2369
      parser->last_message_start_ = uv_hrtime();
675
2369
      parser->connectionsList_->PushActive(parser);
676
    } else {
677
4002
      parser->connectionsList_ = nullptr;
678
    }
679
  }
680
681
  template <bool should_pause>
682
22
  static void Pause(const FunctionCallbackInfo<Value>& args) {
683
22
    Environment* env = Environment::GetCurrent(args);
684
    Parser* parser;
685
30
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
686
    // Should always be called from the same context.
687
22
    CHECK_EQ(env, parser->env());
688
689
22
    if (parser->execute_depth_) {
690
8
      parser->pending_pause_ = should_pause;
691
8
      return;
692
    }
693
694
    if (should_pause) {
695
8
      llhttp_pause(&parser->parser_);
696
    } else {
697
6
      llhttp_resume(&parser->parser_);
698
    }
699
  }
700
701
702
3362
  static void Consume(const FunctionCallbackInfo<Value>& args) {
703
    Parser* parser;
704
3362
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
705
3362
    CHECK(args[0]->IsObject());
706
6724
    StreamBase* stream = StreamBase::FromObject(args[0].As<Object>());
707
3362
    CHECK_NOT_NULL(stream);
708
3362
    stream->PushStreamListener(parser);
709
  }
710
711
712
3352
  static void Unconsume(const FunctionCallbackInfo<Value>& args) {
713
    Parser* parser;
714
3352
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
715
716
    // Already unconsumed
717
3352
    if (parser->stream_ == nullptr)
718
      return;
719
720
3352
    parser->stream_->RemoveStreamListener(parser);
721
  }
722
723
724
38
  static void GetCurrentBuffer(const FunctionCallbackInfo<Value>& args) {
725
    Parser* parser;
726
38
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
727
728
38
    Local<Object> ret = Buffer::Copy(
729
        parser->env(),
730
        parser->current_buffer_data_,
731
76
        parser->current_buffer_len_).ToLocalChecked();
732
733
76
    args.GetReturnValue().Set(ret);
734
  }
735
736
  static void Duration(const FunctionCallbackInfo<Value>& args) {
737
    Parser* parser;
738
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
739
740
    if (parser->last_message_start_ == 0) {
741
      args.GetReturnValue().Set(0);
742
      return;
743
    }
744
745
    double duration = (uv_hrtime() - parser->last_message_start_) / 1e6;
746
    args.GetReturnValue().Set(duration);
747
  }
748
749
  static void HeadersCompleted(const FunctionCallbackInfo<Value>& args) {
750
    Parser* parser;
751
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
752
753
    args.GetReturnValue().Set(parser->headers_completed_);
754
  }
755
756
 protected:
757
  static const size_t kAllocBufferSize = 64 * 1024;
758
759
4395
  uv_buf_t OnStreamAlloc(size_t suggested_size) override {
760
    // For most types of streams, OnStreamRead will be immediately after
761
    // OnStreamAlloc, and will consume all data, so using a static buffer for
762
    // reading is more efficient. For other streams, just use Malloc() directly.
763
4395
    if (binding_data_->parser_buffer_in_use)
764
      return uv_buf_init(Malloc(suggested_size), suggested_size);
765
4395
    binding_data_->parser_buffer_in_use = true;
766
767
4395
    if (binding_data_->parser_buffer.empty())
768
350
      binding_data_->parser_buffer.resize(kAllocBufferSize);
769
770
4395
    return uv_buf_init(binding_data_->parser_buffer.data(), kAllocBufferSize);
771
  }
772
773
774
4435
  void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override {
775
4435
    HandleScope scope(env()->isolate());
776
    // Once we’re done here, either indicate that the HTTP parser buffer
777
    // is free for re-use, or free() the data if it didn’t come from there
778
    // in the first place.
779
4431
    auto on_scope_leave = OnScopeLeave([&]() {
780
4431
      if (buf.base == binding_data_->parser_buffer.data())
781
4393
        binding_data_->parser_buffer_in_use = false;
782
      else
783
38
        free(buf.base);
784
4435
    });
785
786
4435
    if (nread < 0) {
787
306
      PassReadErrorToPreviousListener(nread);
788
306
      return;
789
    }
790
791
    // Ignore, empty reads have special meaning in http parser
792
4129
    if (nread == 0)
793
      return;
794
795
4129
    current_buffer_.Clear();
796
4129
    Local<Value> ret = Execute(buf.base, nread);
797
798
    // Exception
799
4128
    if (ret.IsEmpty())
800
5
      return;
801
802
    Local<Value> cb =
803
12369
        object()->Get(env()->context(), kOnExecute).ToLocalChecked();
804
805
4123
    if (!cb->IsFunction())
806
1003
      return;
807
808
    // Hooks for GetCurrentBuffer
809
3120
    current_buffer_len_ = nread;
810
3120
    current_buffer_data_ = buf.base;
811
812
6240
    MakeCallback(cb.As<Function>(), 1, &ret);
813
814
3117
    current_buffer_len_ = 0;
815
3117
    current_buffer_data_ = nullptr;
816
  }
817
818
819
8476
  Local<Value> Execute(const char* data, size_t len) {
820
8476
    EscapableHandleScope scope(env()->isolate());
821
822
8476
    current_buffer_len_ = len;
823
8476
    current_buffer_data_ = data;
824
8476
    got_exception_ = false;
825
826
    llhttp_errno_t err;
827
828
    // Do not allow re-entering `http_parser_execute()`
829
8476
    CHECK_EQ(execute_depth_, 0);
830
831
8476
    execute_depth_++;
832
8476
    if (data == nullptr) {
833
1033
      err = llhttp_finish(&parser_);
834
    } else {
835
7443
      err = llhttp_execute(&parser_, data, len);
836
7441
      Save();
837
    }
838
8474
    execute_depth_--;
839
840
    // Calculate bytes read and resume after Upgrade/CONNECT pause
841
8474
    size_t nread = len;
842
8474
    if (err != HPE_OK) {
843
430
      nread = llhttp_get_error_pos(&parser_) - data;
844
845
      // This isn't a real pause, just a way to stop parsing early.
846
430
      if (err == HPE_PAUSED_UPGRADE) {
847
97
        err = HPE_OK;
848
97
        llhttp_resume_after_upgrade(&parser_);
849
      }
850
    }
851
852
    // Apply pending pause
853
8474
    if (pending_pause_) {
854
      pending_pause_ = false;
855
      llhttp_pause(&parser_);
856
    }
857
858
    // Unassign the 'buffer_' variable
859
8474
    current_buffer_.Clear();
860
8474
    current_buffer_len_ = 0;
861
8474
    current_buffer_data_ = nullptr;
862
863
    // If there was an exception in one of the callbacks
864
8474
    if (got_exception_)
865
8
      return scope.Escape(Local<Value>());
866
867
8466
    Local<Integer> nread_obj = Integer::New(env()->isolate(), nread);
868
869
    // If there was a parse error in one of the callbacks
870
    // TODO(bnoordhuis) What if there is an error on EOF?
871

8466
    if (!parser_.upgrade && err != HPE_OK) {
872
228
      Local<Value> e = Exception::Error(env()->parse_error_string());
873
228
      Local<Object> obj = e->ToObject(env()->isolate()->GetCurrentContext())
874
228
        .ToLocalChecked();
875
228
      obj->Set(env()->context(),
876
               env()->bytes_parsed_string(),
877
456
               nread_obj).Check();
878
228
      const char* errno_reason = llhttp_get_error_reason(&parser_);
879
880
      Local<String> code;
881
      Local<String> reason;
882
228
      if (err == HPE_USER) {
883
19
        const char* colon = strchr(errno_reason, ':');
884
19
        CHECK_NOT_NULL(colon);
885
        code = OneByteString(env()->isolate(),
886
                             errno_reason,
887
19
                             static_cast<int>(colon - errno_reason));
888
19
        reason = OneByteString(env()->isolate(), colon + 1);
889
      } else {
890
209
        code = OneByteString(env()->isolate(), llhttp_errno_name(err));
891
209
        reason = OneByteString(env()->isolate(), errno_reason);
892
      }
893
894
684
      obj->Set(env()->context(), env()->code_string(), code).Check();
895
684
      obj->Set(env()->context(), env()->reason_string(), reason).Check();
896
228
      return scope.Escape(e);
897
    }
898
899
    // No return value is needed for `Finish()`
900
8238
    if (data == nullptr) {
901
1000
      return scope.Escape(Local<Value>());
902
    }
903
7238
    return scope.Escape(nread_obj);
904
  }
905
906
17356
  Local<Array> CreateHeaders() {
907
    // There could be extra entries but the max size should be fixed
908
1128140
    Local<Value> headers_v[kMaxHeaderFieldsCount * 2];
909
910
35264
    for (size_t i = 0; i < num_values_; ++i) {
911
17908
      headers_v[i * 2] = fields_[i].ToString(env());
912
35816
      headers_v[i * 2 + 1] = values_[i].ToTrimmedString(env());
913
    }
914
915
17356
    return Array::New(env()->isolate(), headers_v, num_values_ * 2);
916
  }
917
918
919
  // spill headers and request path to JS land
920
67
  void Flush() {
921
67
    HandleScope scope(env()->isolate());
922
923
67
    Local<Object> obj = object();
924
134
    Local<Value> cb = obj->Get(env()->context(), kOnHeaders).ToLocalChecked();
925
926
67
    if (!cb->IsFunction())
927
      return;
928
929
    Local<Value> argv[2] = {
930
      CreateHeaders(),
931
      url_.ToString(env())
932
134
    };
933
934
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
935
67
                                       arraysize(argv),
936
134
                                       argv);
937
938
67
    if (r.IsEmpty())
939
      got_exception_ = true;
940
941
67
    url_.Reset();
942
67
    have_flushed_ = true;
943
  }
944
945
946
6371
  void Init(llhttp_type_t type, uint64_t max_http_header_size,
947
            uint32_t lenient_flags) {
948
6371
    llhttp_init(&parser_, type, &settings);
949
950
6371
    if (lenient_flags & kLenientHeaders) {
951
5
      llhttp_set_lenient_headers(&parser_, 1);
952
    }
953
6371
    if (lenient_flags & kLenientChunkedLength) {
954
5
      llhttp_set_lenient_chunked_length(&parser_, 1);
955
    }
956
6371
    if (lenient_flags & kLenientKeepAlive) {
957
5
      llhttp_set_lenient_keep_alive(&parser_, 1);
958
    }
959
960
6371
    header_nread_ = 0;
961
6371
    url_.Reset();
962
6371
    status_message_.Reset();
963
6371
    num_fields_ = 0;
964
6371
    num_values_ = 0;
965
6371
    have_flushed_ = false;
966
6371
    got_exception_ = false;
967
6371
    headers_completed_ = false;
968
6371
    max_http_header_size_ = max_http_header_size;
969
6371
  }
970
971
972
53344
  int TrackHeader(size_t len) {
973
53344
    header_nread_ += len;
974
53344
    if (header_nread_ >= max_http_header_size_) {
975
17
      llhttp_set_error_reason(&parser_, "HPE_HEADER_OVERFLOW:Header overflow");
976
17
      return HPE_USER;
977
    }
978
53327
    return 0;
979
  }
980
981
982
137395
  int MaybePause() {
983
137395
    CHECK_NE(execute_depth_, 0);
984
985
137395
    if (!pending_pause_) {
986
137395
      return 0;
987
    }
988
989
    pending_pause_ = false;
990
    llhttp_set_error_reason(&parser_, "Paused in callback");
991
    return HPE_PAUSED;
992
  }
993
994
995
  bool IsNotIndicativeOfMemoryLeakAtExit() const override {
996
    // HTTP parsers are able to emit events without any GC root referring
997
    // to them, because they receive events directly from the underlying
998
    // libuv resource.
999
    return true;
1000
  }
1001
1002
1003
  llhttp_t parser_;
1004
  StringPtr fields_[kMaxHeaderFieldsCount];  // header fields
1005
  StringPtr values_[kMaxHeaderFieldsCount];  // header values
1006
  StringPtr url_;
1007
  StringPtr status_message_;
1008
  size_t num_fields_;
1009
  size_t num_values_;
1010
  bool have_flushed_;
1011
  bool got_exception_;
1012
  Local<Object> current_buffer_;
1013
  size_t current_buffer_len_;
1014
  const char* current_buffer_data_;
1015
  unsigned int execute_depth_ = 0;
1016
  bool headers_completed_ = false;
1017
  bool pending_pause_ = false;
1018
  uint64_t header_nread_ = 0;
1019
  uint64_t max_http_header_size_;
1020
  uint64_t last_message_start_;
1021
  ConnectionsList* connectionsList_;
1022
1023
  BaseObjectPtr<BindingData> binding_data_;
1024
1025
  // These are helper functions for filling `http_parser_settings`, which turn
1026
  // a member function of Parser into a C-style HTTP parser callback.
1027
  template <typename Parser, Parser> struct Proxy;
1028
  template <typename Parser, typename ...Args, int (Parser::*Member)(Args...)>
1029
  struct Proxy<int (Parser::*)(Args...), Member> {
1030
275056
    static int Raw(llhttp_t* p, Args ... args) {
1031
275056
      Parser* parser = ContainerOf(&Parser::parser_, p);
1032
275056
      int rv = (parser->*Member)(std::forward<Args>(args)...);
1033
275052
      if (rv == 0) {
1034
274790
        rv = parser->MaybePause();
1035
      }
1036
275052
      return rv;
1037
    }
1038
  };
1039
1040
  typedef int (Parser::*Call)();
1041
  typedef int (Parser::*DataCall)(const char* at, size_t length);
1042
1043
  static const llhttp_settings_t settings;
1044
};
1045
1046
105710
bool ParserComparator::operator()(const Parser* lhs, const Parser* rhs) const {
1047
105710
  if (lhs->last_message_start_ == 0) {
1048
10956
    return false;
1049
94754
  } else if (rhs->last_message_start_ == 0) {
1050
10073
    return true;
1051
  }
1052
1053
84681
  return lhs->last_message_start_ < rhs->last_message_start_;
1054
}
1055
1056
556
void ConnectionsList::New(const FunctionCallbackInfo<Value>& args) {
1057
556
  Local<Context> context = args.GetIsolate()->GetCurrentContext();
1058
556
  Environment* env = Environment::GetCurrent(context);
1059
1060
556
  new ConnectionsList(env, args.This());
1061
556
}
1062
1063
void ConnectionsList::All(const FunctionCallbackInfo<Value>& args) {
1064
  Isolate* isolate = args.GetIsolate();
1065
  Local<Context> context = isolate->GetCurrentContext();
1066
1067
  Local<Array> all = Array::New(isolate);
1068
  ConnectionsList* list;
1069
1070
  ASSIGN_OR_RETURN_UNWRAP(&list, args.Holder());
1071
1072
  uint32_t i = 0;
1073
  for (auto parser : list->all_connections_) {
1074
    if (all->Set(context, i++, parser->object()).IsNothing()) {
1075
      return;
1076
    }
1077
  }
1078
1079
  return args.GetReturnValue().Set(all);
1080
}
1081
1082
void ConnectionsList::Idle(const FunctionCallbackInfo<Value>& args) {
1083
  Isolate* isolate = args.GetIsolate();
1084
  Local<Context> context = isolate->GetCurrentContext();
1085
1086
  Local<Array> idle = Array::New(isolate);
1087
  ConnectionsList* list;
1088
1089
  ASSIGN_OR_RETURN_UNWRAP(&list, args.Holder());
1090
1091
  uint32_t i = 0;
1092
  for (auto parser : list->all_connections_) {
1093
    if (parser->last_message_start_ == 0) {
1094
      if (idle->Set(context, i++, parser->object()).IsNothing()) {
1095
        return;
1096
      }
1097
    }
1098
  }
1099
1100
  return args.GetReturnValue().Set(idle);
1101
}
1102
1103
void ConnectionsList::Active(const FunctionCallbackInfo<Value>& args) {
1104
  Isolate* isolate = args.GetIsolate();
1105
  Local<Context> context = isolate->GetCurrentContext();
1106
1107
  Local<Array> active = Array::New(isolate);
1108
  ConnectionsList* list;
1109
1110
  ASSIGN_OR_RETURN_UNWRAP(&list, args.Holder());
1111
1112
  uint32_t i = 0;
1113
  for (auto parser : list->active_connections_) {
1114
    if (active->Set(context, i++, parser->object()).IsNothing()) {
1115
      return;
1116
    }
1117
  }
1118
1119
  return args.GetReturnValue().Set(active);
1120
}
1121
1122
72
void ConnectionsList::Expired(const FunctionCallbackInfo<Value>& args) {
1123
72
  Isolate* isolate = args.GetIsolate();
1124
72
  Local<Context> context = isolate->GetCurrentContext();
1125
1126
72
  Local<Array> expired = Array::New(isolate);
1127
  ConnectionsList* list;
1128
1129
72
  ASSIGN_OR_RETURN_UNWRAP(&list, args.Holder());
1130
72
  CHECK(args[0]->IsNumber());
1131
72
  CHECK(args[1]->IsNumber());
1132
  uint64_t headers_timeout =
1133
144
    static_cast<uint64_t>(args[0].As<Uint32>()->Value()) * 1000000;
1134
  uint64_t request_timeout =
1135
144
    static_cast<uint64_t>(args[1].As<Uint32>()->Value()) * 1000000;
1136
1137

72
  if (headers_timeout == 0 && request_timeout == 0) {
1138
    return args.GetReturnValue().Set(expired);
1139

72
  } else if (request_timeout > 0 && headers_timeout > request_timeout) {
1140
    std::swap(headers_timeout, request_timeout);
1141
  }
1142
1143
72
  const uint64_t now = uv_hrtime();
1144
72
  const uint64_t headers_deadline =
1145
72
    headers_timeout > 0 ? now - headers_timeout : 0;
1146
72
  const uint64_t request_deadline =
1147
72
    request_timeout > 0 ? now - request_timeout : 0;
1148
1149
72
  uint32_t i = 0;
1150
72
  auto iter = list->active_connections_.begin();
1151
72
  auto end = list->active_connections_.end();
1152
124
  while (iter != end) {
1153
52
    Parser* parser = *iter;
1154
52
    iter++;
1155
1156
    // Check for expiration.
1157
52
    if (
1158

52
      (!parser->headers_completed_ && headers_deadline > 0 &&
1159

52
        parser->last_message_start_ < headers_deadline) ||
1160
      (
1161
31
        request_deadline > 0 &&
1162
31
        parser->last_message_start_ < request_deadline)
1163
    ) {
1164
30
      if (expired->Set(context, i++, parser->object()).IsNothing()) {
1165
        return;
1166
      }
1167
1168
10
      list->active_connections_.erase(parser);
1169
    }
1170
  }
1171
1172
144
  return args.GetReturnValue().Set(expired);
1173
}
1174
1175
const llhttp_settings_t Parser::settings = {
1176
  Proxy<Call, &Parser::on_message_begin>::Raw,
1177
  Proxy<DataCall, &Parser::on_url>::Raw,
1178
  Proxy<DataCall, &Parser::on_status>::Raw,
1179
  Proxy<DataCall, &Parser::on_header_field>::Raw,
1180
  Proxy<DataCall, &Parser::on_header_value>::Raw,
1181
  Proxy<Call, &Parser::on_headers_complete>::Raw,
1182
  Proxy<DataCall, &Parser::on_body>::Raw,
1183
  Proxy<Call, &Parser::on_message_complete>::Raw,
1184
  Proxy<Call, &Parser::on_chunk_header>::Raw,
1185
  Proxy<Call, &Parser::on_chunk_complete>::Raw,
1186
1187
  // on_url_complete
1188
  nullptr,
1189
  // on_status_complete
1190
  nullptr,
1191
  // on_header_field_complete
1192
  nullptr,
1193
  // on_header_value_complete
1194
  nullptr,
1195
};
1196
1197
1198
824
void InitializeHttpParser(Local<Object> target,
1199
                          Local<Value> unused,
1200
                          Local<Context> context,
1201
                          void* priv) {
1202
824
  Environment* env = Environment::GetCurrent(context);
1203
  BindingData* const binding_data =
1204
824
      env->AddBindingData<BindingData>(context, target);
1205
824
  if (binding_data == nullptr) return;
1206
1207
824
  Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
1208
1648
  t->InstanceTemplate()->SetInternalFieldCount(Parser::kInternalFieldCount);
1209
1210
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"),
1211
         Integer::New(env->isolate(), HTTP_REQUEST));
1212
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"),
1213
         Integer::New(env->isolate(), HTTP_RESPONSE));
1214
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageBegin"),
1215
         Integer::NewFromUnsigned(env->isolate(), kOnMessageBegin));
1216
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"),
1217
         Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
1218
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"),
1219
         Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
1220
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"),
1221
         Integer::NewFromUnsigned(env->isolate(), kOnBody));
1222
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"),
1223
         Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
1224
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"),
1225
         Integer::NewFromUnsigned(env->isolate(), kOnExecute));
1226
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnTimeout"),
1227
         Integer::NewFromUnsigned(env->isolate(), kOnTimeout));
1228
1229
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientNone"),
1230
         Integer::NewFromUnsigned(env->isolate(), kLenientNone));
1231
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientHeaders"),
1232
         Integer::NewFromUnsigned(env->isolate(), kLenientHeaders));
1233
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientChunkedLength"),
1234
         Integer::NewFromUnsigned(env->isolate(), kLenientChunkedLength));
1235
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientKeepAlive"),
1236
         Integer::NewFromUnsigned(env->isolate(), kLenientKeepAlive));
1237
2472
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientAll"),
1238
         Integer::NewFromUnsigned(env->isolate(), kLenientAll));
1239
1240
824
  Local<Array> methods = Array::New(env->isolate());
1241
#define V(num, name, string)                                                  \
1242
    methods->Set(env->context(),                                              \
1243
        num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)).Check();
1244
56856
  HTTP_METHOD_MAP(V)
1245
#undef V
1246
824
  target->Set(env->context(),
1247
              FIXED_ONE_BYTE_STRING(env->isolate(), "methods"),
1248
2472
              methods).Check();
1249
1250
824
  t->Inherit(AsyncWrap::GetConstructorTemplate(env));
1251
824
  env->SetProtoMethod(t, "close", Parser::Close);
1252
824
  env->SetProtoMethod(t, "free", Parser::Free);
1253
824
  env->SetProtoMethod(t, "execute", Parser::Execute);
1254
824
  env->SetProtoMethod(t, "finish", Parser::Finish);
1255
824
  env->SetProtoMethod(t, "initialize", Parser::Initialize);
1256
824
  env->SetProtoMethod(t, "pause", Parser::Pause<true>);
1257
824
  env->SetProtoMethod(t, "resume", Parser::Pause<false>);
1258
824
  env->SetProtoMethod(t, "consume", Parser::Consume);
1259
824
  env->SetProtoMethod(t, "unconsume", Parser::Unconsume);
1260
824
  env->SetProtoMethod(t, "getCurrentBuffer", Parser::GetCurrentBuffer);
1261
824
  env->SetProtoMethod(t, "duration", Parser::Duration);
1262
824
  env->SetProtoMethod(t, "headersCompleted", Parser::HeadersCompleted);
1263
1264
824
  env->SetConstructorFunction(target, "HTTPParser", t);
1265
1266
824
  Local<FunctionTemplate> c = env->NewFunctionTemplate(ConnectionsList::New);
1267
824
  c->InstanceTemplate()
1268
824
    ->SetInternalFieldCount(ConnectionsList::kInternalFieldCount);
1269
824
  env->SetProtoMethod(c, "all", ConnectionsList::All);
1270
824
  env->SetProtoMethod(c, "idle", ConnectionsList::Idle);
1271
824
  env->SetProtoMethod(c, "active", ConnectionsList::Active);
1272
824
  env->SetProtoMethod(c, "expired", ConnectionsList::Expired);
1273
824
  env->SetConstructorFunction(target, "ConnectionsList", c);
1274
}
1275
1276
}  // anonymous namespace
1277
}  // namespace node
1278
1279
5082
NODE_MODULE_CONTEXT_AWARE_INTERNAL(http_parser, node::InitializeHttpParser)