GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_http_parser.cc Lines: 425 450 94.4 %
Date: 2020-09-03 22:13:26 Branches: 198 268 73.9 %

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::Local;
64
using v8::MaybeLocal;
65
using v8::Number;
66
using v8::Object;
67
using v8::String;
68
using v8::Uint32;
69
using v8::Undefined;
70
using v8::Value;
71
72
const uint32_t kOnHeaders = 0;
73
const uint32_t kOnHeadersComplete = 1;
74
const uint32_t kOnBody = 2;
75
const uint32_t kOnMessageComplete = 3;
76
const uint32_t kOnExecute = 4;
77
const uint32_t kOnTimeout = 5;
78
// Any more fields than this will be flushed into JS
79
const size_t kMaxHeaderFieldsCount = 32;
80
81
16075
inline bool IsOWS(char c) {
82

16075
  return c == ' ' || c == '\t';
83
}
84
85
1382
class BindingData : public BaseObject {
86
 public:
87
718
  BindingData(Environment* env, Local<Object> obj)
88
718
      : BaseObject(env, obj) {}
89
90
  static constexpr FastStringKey binding_data_name { "http_parser" };
91
92
  std::vector<char> parser_buffer;
93
  bool parser_buffer_in_use = false;
94
95
3
  void MemoryInfo(MemoryTracker* tracker) const override {
96
3
    tracker->TrackField("parser_buffer", parser_buffer);
97
3
  }
98
3
  SET_SELF_SIZE(BindingData)
99
3
  SET_MEMORY_INFO_NAME(BindingData)
100
};
101
102
// TODO(addaleax): Remove once we're on C++17.
103
constexpr FastStringKey BindingData::binding_data_name;
104
105
// helper class for the Parser
106
struct StringPtr {
107
201366
  StringPtr() {
108
201366
    on_heap_ = false;
109
201366
    Reset();
110
201366
  }
111
112
113
399432
  ~StringPtr() {
114
199716
    Reset();
115
199716
  }
116
117
118
  // If str_ does not point to a heap string yet, this function makes it do
119
  // so. This is called at the end of each http_parser_execute() so as not
120
  // to leak references. See issue #2438 and test-http-parser-bad-ref.js.
121
13094
  void Save() {
122

13094
    if (!on_heap_ && size_ > 0) {
123
5278
      char* s = new char[size_];
124
5278
      memcpy(s, str_, size_);
125
5278
      str_ = s;
126
5278
      on_heap_ = true;
127
    }
128
13094
  }
129
130
131
477544
  void Reset() {
132
477544
    if (on_heap_) {
133
5251
      delete[] str_;
134
5251
      on_heap_ = false;
135
    }
136
137
477544
    str_ = nullptr;
138
477544
    size_ = 0;
139
477544
  }
140
141
142
48994
  void Update(const char* str, size_t size) {
143
48994
    if (str_ == nullptr) {
144
48929
      str_ = str;
145

65
    } else if (on_heap_ || str_ + size_ != str) {
146
      // Non-consecutive input, make a copy on the heap.
147
      // TODO(bnoordhuis) Use slab allocation, O(n) allocs is bad.
148
65
      char* s = new char[size_ + size];
149
65
      memcpy(s, str_, size_);
150
65
      memcpy(s + size_, str, size);
151
152
65
      if (on_heap_)
153
64
        delete[] str_;
154
      else
155
1
        on_heap_ = true;
156
157
65
      str_ = s;
158
    }
159
48994
    size_ += size;
160
48994
  }
161
162
163
48851
  Local<String> ToString(Environment* env) const {
164
48851
    if (size_ != 0)
165
48787
      return OneByteString(env->isolate(), str_, size_);
166
    else
167
128
      return String::Empty(env->isolate());
168
  }
169
170
171
  // Strip trailing OWS (SPC or HTAB) from string.
172
16077
  Local<String> ToTrimmedString(Environment* env) {
173

16088
    while (size_ > 0 && IsOWS(str_[size_ - 1])) {
174
11
      size_--;
175
    }
176
16066
    return ToString(env);
177
  }
178
179
180
  const char* str_;
181
  bool on_heap_;
182
  size_t size_;
183
};
184
185


6052
class Parser : public AsyncWrap, public StreamListener {
186
 public:
187
3051
  Parser(BindingData* binding_data, Local<Object> wrap)
188
3051
      : AsyncWrap(binding_data->env(), wrap),
189
        current_buffer_len_(0),
190
        current_buffer_data_(nullptr),
191

6102
        binding_data_(binding_data) {
192
3051
  }
193
194
195
  void MemoryInfo(MemoryTracker* tracker) const override {
196
    tracker->TrackField("current_buffer", current_buffer_);
197
  }
198
199
  SET_MEMORY_INFO_NAME(Parser)
200
  SET_SELF_SIZE(Parser)
201
202
16704
  int on_message_begin() {
203
16704
    num_fields_ = num_values_ = 0;
204
16704
    url_.Reset();
205
16704
    status_message_.Reset();
206
16704
    header_parsing_start_time_ = uv_hrtime();
207
16704
    return 0;
208
  }
209
210
211
13961
  int on_url(const char* at, size_t length) {
212
13961
    int rv = TrackHeader(length);
213
13961
    if (rv != 0) {
214
      return rv;
215
    }
216
217
13961
    url_.Update(at, length);
218
13961
    return 0;
219
  }
220
221
222
2733
  int on_status(const char* at, size_t length) {
223
2733
    int rv = TrackHeader(length);
224
2733
    if (rv != 0) {
225
      return rv;
226
    }
227
228
2733
    status_message_.Update(at, length);
229
2733
    return 0;
230
  }
231
232
233
16161
  int on_header_field(const char* at, size_t length) {
234
16161
    int rv = TrackHeader(length);
235
16161
    if (rv != 0) {
236
      return rv;
237
    }
238
239
16161
    if (num_fields_ == num_values_) {
240
      // start of new field name
241
16132
      num_fields_++;
242
16132
      if (num_fields_ == kMaxHeaderFieldsCount) {
243
        // ran out of space - flush to javascript land
244
47
        Flush();
245
47
        num_fields_ = 1;
246
47
        num_values_ = 0;
247
      }
248
16132
      fields_[num_fields_ - 1].Reset();
249
    }
250
251
16161
    CHECK_LT(num_fields_, kMaxHeaderFieldsCount);
252
16161
    CHECK_EQ(num_fields_, num_values_ + 1);
253
254
16161
    fields_[num_fields_ - 1].Update(at, length);
255
256
16161
    return 0;
257
  }
258
259
260
16154
  int on_header_value(const char* at, size_t length) {
261
16154
    int rv = TrackHeader(length);
262
16154
    if (rv != 0) {
263
15
      return rv;
264
    }
265
266
16139
    if (num_values_ != num_fields_) {
267
      // start of new header value
268
16111
      num_values_++;
269
16111
      values_[num_values_ - 1].Reset();
270
    }
271
272
16139
    CHECK_LT(num_values_, arraysize(values_));
273
16139
    CHECK_EQ(num_values_, num_fields_);
274
275
16139
    values_[num_values_ - 1].Update(at, length);
276
277
16139
    return 0;
278
  }
279
280
281
16660
  int on_headers_complete() {
282
16660
    header_nread_ = 0;
283
16660
    header_parsing_start_time_ = 0;
284
285
    // Arguments for the on-headers-complete javascript callback. This
286
    // list needs to be kept in sync with the actual argument list for
287
    // `parserOnHeadersComplete` in lib/_http_common.js.
288
    enum on_headers_complete_arg_index {
289
      A_VERSION_MAJOR = 0,
290
      A_VERSION_MINOR,
291
      A_HEADERS,
292
      A_METHOD,
293
      A_URL,
294
      A_STATUS_CODE,
295
      A_STATUS_MESSAGE,
296
      A_UPGRADE,
297
      A_SHOULD_KEEP_ALIVE,
298
      A_MAX
299
    };
300
301
166600
    Local<Value> argv[A_MAX];
302
16660
    Local<Object> obj = object();
303
33320
    Local<Value> cb = obj->Get(env()->context(),
304
49980
                               kOnHeadersComplete).ToLocalChecked();
305
306
16660
    if (!cb->IsFunction())
307
      return 0;
308
309
16660
    Local<Value> undefined = Undefined(env()->isolate());
310
166600
    for (size_t i = 0; i < arraysize(argv); i++)
311
149940
      argv[i] = undefined;
312
313
16660
    if (have_flushed_) {
314
      // Slow case, flush remaining headers.
315
16
      Flush();
316
    } else {
317
      // Fast case, pass headers and URL to JS land.
318
33288
      argv[A_HEADERS] = CreateHeaders();
319
16644
      if (parser_.type == HTTP_REQUEST)
320
27852
        argv[A_URL] = url_.ToString(env());
321
    }
322
323
16660
    num_fields_ = 0;
324
16660
    num_values_ = 0;
325
326
    // METHOD
327
16660
    if (parser_.type == HTTP_REQUEST) {
328
13934
      argv[A_METHOD] =
329
27868
          Uint32::NewFromUnsigned(env()->isolate(), parser_.method);
330
    }
331
332
    // STATUS
333
16660
    if (parser_.type == HTTP_RESPONSE) {
334
2726
      argv[A_STATUS_CODE] =
335
5452
          Integer::New(env()->isolate(), parser_.status_code);
336
5452
      argv[A_STATUS_MESSAGE] = status_message_.ToString(env());
337
    }
338
339
    // VERSION
340
33320
    argv[A_VERSION_MAJOR] = Integer::New(env()->isolate(), parser_.http_major);
341
33320
    argv[A_VERSION_MINOR] = Integer::New(env()->isolate(), parser_.http_minor);
342
343
    bool should_keep_alive;
344
16660
    should_keep_alive = llhttp_should_keep_alive(&parser_);
345
346
16660
    argv[A_SHOULD_KEEP_ALIVE] =
347
33320
        Boolean::New(env()->isolate(), should_keep_alive);
348
349
33320
    argv[A_UPGRADE] = Boolean::New(env()->isolate(), parser_.upgrade);
350
351
    MaybeLocal<Value> head_response;
352
    {
353
      InternalCallbackScope callback_scope(
354
33318
          this, InternalCallbackScope::kSkipTaskQueues);
355
33318
      head_response = cb.As<Function>()->Call(
356
66638
          env()->context(), object(), arraysize(argv), argv);
357
16658
      if (head_response.IsEmpty()) callback_scope.MarkAsFailed();
358
    }
359
360
    int64_t val;
361
362

66616
    if (head_response.IsEmpty() || !head_response.ToLocalChecked()
363
49958
                                        ->IntegerValue(env()->context())
364
16650
                                        .To(&val)) {
365
8
      got_exception_ = true;
366
8
      return -1;
367
    }
368
369
16650
    return val;
370
  }
371
372
373
10707
  int on_body(const char* at, size_t length) {
374
10707
    EscapableHandleScope scope(env()->isolate());
375
376
10707
    Local<Object> obj = object();
377
32121
    Local<Value> cb = obj->Get(env()->context(), kOnBody).ToLocalChecked();
378
379
10707
    if (!cb->IsFunction())
380
      return 0;
381
382
    // We came from consumed stream
383
21414
    if (current_buffer_.IsEmpty()) {
384
      // Make sure Buffer will be in parent HandleScope
385
988
      current_buffer_ = scope.Escape(Buffer::Copy(
386
          env()->isolate(),
387
          current_buffer_data_,
388
988
          current_buffer_len_).ToLocalChecked());
389
    }
390
391
    Local<Value> argv[3] = {
392
      current_buffer_,
393
10707
      Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
394
      Integer::NewFromUnsigned(env()->isolate(), length)
395
53535
    };
396
397
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
398
10707
                                       arraysize(argv),
399
21414
                                       argv);
400
401
10707
    if (r.IsEmpty()) {
402
      got_exception_ = true;
403
      llhttp_set_error_reason(&parser_, "HPE_JS_EXCEPTION:JS Exception");
404
      return HPE_USER;
405
    }
406
407
10707
    return 0;
408
  }
409
410
411
15458
  int on_message_complete() {
412
30916
    HandleScope scope(env()->isolate());
413
414
15458
    if (num_fields_)
415
4
      Flush();  // Flush trailing HTTP headers.
416
417
15458
    Local<Object> obj = object();
418
30916
    Local<Value> cb = obj->Get(env()->context(),
419
46374
                               kOnMessageComplete).ToLocalChecked();
420
421
15458
    if (!cb->IsFunction())
422
2
      return 0;
423
424
    MaybeLocal<Value> r;
425
    {
426
      InternalCallbackScope callback_scope(
427
30912
          this, InternalCallbackScope::kSkipTaskQueues);
428
61824
      r = cb.As<Function>()->Call(env()->context(), object(), 0, nullptr);
429
15456
      if (r.IsEmpty()) callback_scope.MarkAsFailed();
430
    }
431
432
15456
    if (r.IsEmpty()) {
433
      got_exception_ = true;
434
      return -1;
435
    }
436
437
15456
    return 0;
438
  }
439
440
  // Reset nread for the next chunk
441
10277
  int on_chunk_header() {
442
10277
    header_nread_ = 0;
443
10277
    return 0;
444
  }
445
446
447
  // Reset nread for the next chunk
448
10123
  int on_chunk_complete() {
449
10123
    header_nread_ = 0;
450
10123
    return 0;
451
  }
452
453
3051
  static void New(const FunctionCallbackInfo<Value>& args) {
454
3051
    BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
455
3051
    new Parser(binding_data, args.This());
456
3051
  }
457
458
459
3
  static void Close(const FunctionCallbackInfo<Value>& args) {
460
    Parser* parser;
461
3
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
462
463
3
    delete parser;
464
  }
465
466
467
5176
  static void Free(const FunctionCallbackInfo<Value>& args) {
468
    Parser* parser;
469
5176
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
470
471
    // Since the Parser destructor isn't going to run the destroy() callbacks
472
    // it needs to be triggered manually.
473
5176
    parser->EmitTraceEventDestroy();
474
5176
    parser->EmitDestroy();
475
  }
476
477
478
6376
  void Save() {
479
6376
    url_.Save();
480
6376
    status_message_.Save();
481
482
6575
    for (size_t i = 0; i < num_fields_; i++) {
483
199
      fields_[i].Save();
484
    }
485
486
6519
    for (size_t i = 0; i < num_values_; i++) {
487
143
      values_[i].Save();
488
    }
489
6376
  }
490
491
492
  // var bytesParsed = parser->execute(buffer);
493
2798
  static void Execute(const FunctionCallbackInfo<Value>& args) {
494
    Parser* parser;
495
2798
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
496
5596
    CHECK(parser->current_buffer_.IsEmpty());
497
2798
    CHECK_EQ(parser->current_buffer_len_, 0);
498
2798
    CHECK_NULL(parser->current_buffer_data_);
499
500
2798
    ArrayBufferViewContents<char> buffer(args[0]);
501
502
    // This is a hack to get the current_buffer to the callbacks with the least
503
    // amount of overhead. Nothing else will run while http_parser_execute()
504
    // runs, therefore this pointer can be set and used for the execution.
505
8394
    parser->current_buffer_ = args[0].As<Object>();
506
507
2798
    Local<Value> ret = parser->Execute(buffer.data(), buffer.length());
508
509
2797
    if (!ret.IsEmpty())
510
5588
      args.GetReturnValue().Set(ret);
511
  }
512
513
514
916
  static void Finish(const FunctionCallbackInfo<Value>& args) {
515
    Parser* parser;
516
916
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
517
518
1832
    CHECK(parser->current_buffer_.IsEmpty());
519
916
    Local<Value> ret = parser->Execute(nullptr, 0);
520
521
916
    if (!ret.IsEmpty())
522
58
      args.GetReturnValue().Set(ret);
523
  }
524
525
526
5372
  static void Initialize(const FunctionCallbackInfo<Value>& args) {
527
5372
    Environment* env = Environment::GetCurrent(args);
528
10744
    bool lenient = args[3]->IsTrue();
529
530
5372
    uint64_t max_http_header_size = 0;
531
5372
    uint64_t headers_timeout = 0;
532
533
10744
    CHECK(args[0]->IsInt32());
534
10744
    CHECK(args[1]->IsObject());
535
536
5372
    if (args.Length() > 2) {
537
8404
      CHECK(args[2]->IsNumber());
538
12606
      max_http_header_size = args[2].As<Number>()->Value();
539
    }
540
5372
    if (max_http_header_size == 0) {
541
5370
      max_http_header_size = env->options()->max_http_header_size;
542
    }
543
544
5372
    if (args.Length() > 4) {
545
8404
      CHECK(args[4]->IsInt32());
546
12606
      headers_timeout = args[4].As<Number>()->Value();
547
    }
548
549
    llhttp_type_t type =
550
16116
        static_cast<llhttp_type_t>(args[0].As<Int32>()->Value());
551
552

5372
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
553
    Parser* parser;
554
5372
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
555
    // Should always be called from the same context.
556
5372
    CHECK_EQ(env, parser->env());
557
558
    AsyncWrap::ProviderType provider =
559
5372
        (type == HTTP_REQUEST ?
560
            AsyncWrap::PROVIDER_HTTPINCOMINGMESSAGE
561
5372
            : AsyncWrap::PROVIDER_HTTPCLIENTREQUEST);
562
563
5372
    parser->set_provider_type(provider);
564
10744
    parser->AsyncReset(args[1].As<Object>());
565
5372
    parser->Init(type, max_http_header_size, lenient, headers_timeout);
566
  }
567
568
  template <bool should_pause>
569
13
  static void Pause(const FunctionCallbackInfo<Value>& args) {
570
13
    Environment* env = Environment::GetCurrent(args);
571
    Parser* parser;
572

17
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
573
    // Should always be called from the same context.
574

13
    CHECK_EQ(env, parser->env());
575
576

13
    if (parser->execute_depth_) {
577
4
      parser->pending_pause_ = should_pause;
578
4
      return;
579
    }
580
581
    if (should_pause) {
582
5
      llhttp_pause(&parser->parser_);
583
    } else {
584
4
      llhttp_resume(&parser->parser_);
585
    }
586
  }
587
588
589
2884
  static void Consume(const FunctionCallbackInfo<Value>& args) {
590
    Parser* parser;
591
2884
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
592
5768
    CHECK(args[0]->IsObject());
593
5768
    StreamBase* stream = StreamBase::FromObject(args[0].As<Object>());
594
2884
    CHECK_NOT_NULL(stream);
595
2884
    stream->PushStreamListener(parser);
596
  }
597
598
599
2874
  static void Unconsume(const FunctionCallbackInfo<Value>& args) {
600
    Parser* parser;
601
2874
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
602
603
    // Already unconsumed
604
2874
    if (parser->stream_ == nullptr)
605
      return;
606
607
2874
    parser->stream_->RemoveStreamListener(parser);
608
  }
609
610
611
49
  static void GetCurrentBuffer(const FunctionCallbackInfo<Value>& args) {
612
    Parser* parser;
613
49
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
614
615
98
    Local<Object> ret = Buffer::Copy(
616
        parser->env(),
617
        parser->current_buffer_data_,
618
98
        parser->current_buffer_len_).ToLocalChecked();
619
620
98
    args.GetReturnValue().Set(ret);
621
  }
622
623
 protected:
624
  static const size_t kAllocBufferSize = 64 * 1024;
625
626
3805
  uv_buf_t OnStreamAlloc(size_t suggested_size) override {
627
    // For most types of streams, OnStreamRead will be immediately after
628
    // OnStreamAlloc, and will consume all data, so using a static buffer for
629
    // reading is more efficient. For other streams, just use Malloc() directly.
630
3805
    if (binding_data_->parser_buffer_in_use)
631
      return uv_buf_init(Malloc(suggested_size), suggested_size);
632
3805
    binding_data_->parser_buffer_in_use = true;
633
634
3805
    if (binding_data_->parser_buffer.empty())
635
314
      binding_data_->parser_buffer.resize(kAllocBufferSize);
636
637
3805
    return uv_buf_init(binding_data_->parser_buffer.data(), kAllocBufferSize);
638
  }
639
640
641
3825
  void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override {
642
6388
    HandleScope scope(env()->isolate());
643
    // Once we’re done here, either indicate that the HTTP parser buffer
644
    // is free for re-use, or free() the data if it didn’t come from there
645
    // in the first place.
646
3821
    auto on_scope_leave = OnScopeLeave([&]() {
647
3839
      if (buf.base == binding_data_->parser_buffer.data())
648
3803
        binding_data_->parser_buffer_in_use = false;
649
      else
650
18
        free(buf.base);
651
10209
    });
652
653
3825
    if (nread < 0) {
654
245
      PassReadErrorToPreviousListener(nread);
655
245
      return;
656
    }
657
658
    // Ignore, empty reads have special meaning in http parser
659
3580
    if (nread == 0)
660
      return;
661
662
3580
    current_buffer_.Clear();
663
3580
    Local<Value> ret = Execute(buf.base, nread);
664
665
    // Exception
666
3579
    if (ret.IsEmpty())
667
5
      return;
668
669
    // check header parsing time
670

3574
    if (header_parsing_start_time_ != 0 && headers_timeout_ != 0) {
671
39
      uint64_t now = uv_hrtime();
672
39
      uint64_t parsing_time = (now - header_parsing_start_time_) / 1e6;
673
674
39
      if (parsing_time > headers_timeout_) {
675
        Local<Value> cb =
676
18
            object()->Get(env()->context(), kOnTimeout).ToLocalChecked();
677
678
6
        if (!cb->IsFunction())
679
          return;
680
681
6
        MakeCallback(cb.As<Function>(), 0, nullptr);
682
683
6
        return;
684
      }
685
    }
686
687
    Local<Value> cb =
688
10704
        object()->Get(env()->context(), kOnExecute).ToLocalChecked();
689
690
3568
    if (!cb->IsFunction())
691
1002
      return;
692
693
    // Hooks for GetCurrentBuffer
694
2566
    current_buffer_len_ = nread;
695
2566
    current_buffer_data_ = buf.base;
696
697
2566
    MakeCallback(cb.As<Function>(), 1, &ret);
698
699
2563
    current_buffer_len_ = 0;
700
2563
    current_buffer_data_ = nullptr;
701
  }
702
703
704
7294
  Local<Value> Execute(const char* data, size_t len) {
705
7294
    EscapableHandleScope scope(env()->isolate());
706
707
7294
    current_buffer_len_ = len;
708
7294
    current_buffer_data_ = data;
709
7294
    got_exception_ = false;
710
711
    llhttp_errno_t err;
712
713
    // Do not allow re-entering `http_parser_execute()`
714
7294
    CHECK_EQ(execute_depth_, 0);
715
716
7294
    execute_depth_++;
717
7294
    if (data == nullptr) {
718
916
      err = llhttp_finish(&parser_);
719
    } else {
720
6378
      err = llhttp_execute(&parser_, data, len);
721
6376
      Save();
722
    }
723
7292
    execute_depth_--;
724
725
    // Calculate bytes read and resume after Upgrade/CONNECT pause
726
7292
    size_t nread = len;
727
7292
    if (err != HPE_OK) {
728
328
      nread = llhttp_get_error_pos(&parser_) - data;
729
730
      // This isn't a real pause, just a way to stop parsing early.
731
328
      if (err == HPE_PAUSED_UPGRADE) {
732
52
        err = HPE_OK;
733
52
        llhttp_resume_after_upgrade(&parser_);
734
      }
735
    }
736
737
    // Apply pending pause
738
7292
    if (pending_pause_) {
739
      pending_pause_ = false;
740
      llhttp_pause(&parser_);
741
    }
742
743
    // Unassign the 'buffer_' variable
744
7292
    current_buffer_.Clear();
745
7292
    current_buffer_len_ = 0;
746
7292
    current_buffer_data_ = nullptr;
747
748
    // If there was an exception in one of the callbacks
749
7292
    if (got_exception_)
750
8
      return scope.Escape(Local<Value>());
751
752
7284
    Local<Integer> nread_obj = Integer::New(env()->isolate(), nread);
753
754
    // If there was a parse error in one of the callbacks
755
    // TODO(bnoordhuis) What if there is an error on EOF?
756

7284
    if (!parser_.upgrade && err != HPE_OK) {
757
216
      Local<Value> e = Exception::Error(env()->parse_error_string());
758
648
      Local<Object> obj = e->ToObject(env()->isolate()->GetCurrentContext())
759
216
        .ToLocalChecked();
760
432
      obj->Set(env()->context(),
761
               env()->bytes_parsed_string(),
762
864
               nread_obj).Check();
763
216
      const char* errno_reason = llhttp_get_error_reason(&parser_);
764
765
      Local<String> code;
766
      Local<String> reason;
767
216
      if (err == HPE_USER) {
768
15
        const char* colon = strchr(errno_reason, ':');
769
15
        CHECK_NOT_NULL(colon);
770
        code = OneByteString(env()->isolate(), errno_reason,
771
15
                             colon - errno_reason);
772
15
        reason = OneByteString(env()->isolate(), colon + 1);
773
      } else {
774
201
        code = OneByteString(env()->isolate(), llhttp_errno_name(err));
775
201
        reason = OneByteString(env()->isolate(), errno_reason);
776
      }
777
778
864
      obj->Set(env()->context(), env()->code_string(), code).Check();
779
864
      obj->Set(env()->context(), env()->reason_string(), reason).Check();
780
      return scope.Escape(e);
781
    }
782
783
    // No return value is needed for `Finish()`
784
7068
    if (data == nullptr) {
785
887
      return scope.Escape(Local<Value>());
786
    }
787
6181
    return scope.Escape(nread_obj);
788
  }
789
790
16711
  Local<Array> CreateHeaders() {
791
    // There could be extra entries but the max size should be fixed
792
1086215
    Local<Value> headers_v[kMaxHeaderFieldsCount * 2];
793
794
32777
    for (size_t i = 0; i < num_values_; ++i) {
795
32132
      headers_v[i * 2] = fields_[i].ToString(env());
796
32132
      headers_v[i * 2 + 1] = values_[i].ToTrimmedString(env());
797
    }
798
799
16711
    return Array::New(env()->isolate(), headers_v, num_values_ * 2);
800
  }
801
802
803
  // spill headers and request path to JS land
804
67
  void Flush() {
805
134
    HandleScope scope(env()->isolate());
806
807
67
    Local<Object> obj = object();
808
201
    Local<Value> cb = obj->Get(env()->context(), kOnHeaders).ToLocalChecked();
809
810
67
    if (!cb->IsFunction())
811
      return;
812
813
    Local<Value> argv[2] = {
814
      CreateHeaders(),
815
      url_.ToString(env())
816
201
    };
817
818
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
819
67
                                       arraysize(argv),
820
134
                                       argv);
821
822
67
    if (r.IsEmpty())
823
      got_exception_ = true;
824
825
67
    url_.Reset();
826
67
    have_flushed_ = true;
827
  }
828
829
830
5372
  void Init(llhttp_type_t type, uint64_t max_http_header_size,
831
            bool lenient, uint64_t headers_timeout) {
832
5372
    llhttp_init(&parser_, type, &settings);
833
5372
    llhttp_set_lenient(&parser_, lenient);
834
5372
    header_nread_ = 0;
835
5372
    url_.Reset();
836
5372
    status_message_.Reset();
837
5372
    num_fields_ = 0;
838
5372
    num_values_ = 0;
839
5372
    have_flushed_ = false;
840
5372
    got_exception_ = false;
841
5372
    max_http_header_size_ = max_http_header_size;
842
5372
    header_parsing_start_time_ = 0;
843
5372
    headers_timeout_ = headers_timeout;
844
5372
  }
845
846
847
49009
  int TrackHeader(size_t len) {
848
49009
    header_nread_ += len;
849
49009
    if (header_nread_ >= max_http_header_size_) {
850
15
      llhttp_set_error_reason(&parser_, "HPE_HEADER_OVERFLOW:Header overflow");
851
15
      return HPE_USER;
852
    }
853
48994
    return 0;
854
  }
855
856
857
128852
  int MaybePause() {
858
128852
    CHECK_NE(execute_depth_, 0);
859
860
128852
    if (!pending_pause_) {
861
128852
      return 0;
862
    }
863
864
    pending_pause_ = false;
865
    llhttp_set_error_reason(&parser_, "Paused in callback");
866
    return HPE_PAUSED;
867
  }
868
869
  llhttp_t parser_;
870
  StringPtr fields_[kMaxHeaderFieldsCount];  // header fields
871
  StringPtr values_[kMaxHeaderFieldsCount];  // header values
872
  StringPtr url_;
873
  StringPtr status_message_;
874
  size_t num_fields_;
875
  size_t num_values_;
876
  bool have_flushed_;
877
  bool got_exception_;
878
  Local<Object> current_buffer_;
879
  size_t current_buffer_len_;
880
  const char* current_buffer_data_;
881
  unsigned int execute_depth_ = 0;
882
  bool pending_pause_ = false;
883
  uint64_t header_nread_ = 0;
884
  uint64_t max_http_header_size_;
885
  uint64_t headers_timeout_;
886
  uint64_t header_parsing_start_time_ = 0;
887
888
  BaseObjectPtr<BindingData> binding_data_;
889
890
  // These are helper functions for filling `http_parser_settings`, which turn
891
  // a member function of Parser into a C-style HTTP parser callback.
892
  template <typename Parser, Parser> struct Proxy;
893
  template <typename Parser, typename ...Args, int (Parser::*Member)(Args...)>
894
  struct Proxy<int (Parser::*)(Args...), Member> {
895
128938
    static int Raw(llhttp_t* p, Args ... args) {
896
128938
      Parser* parser = ContainerOf(&Parser::parser_, p);
897
128938
      int rv = (parser->*Member)(std::forward<Args>(args)...);
898





128936
      if (rv == 0) {
899
128852
        rv = parser->MaybePause();
900
      }
901
128936
      return rv;
902
    }
903
  };
904
905
  typedef int (Parser::*Call)();
906
  typedef int (Parser::*DataCall)(const char* at, size_t length);
907
908
  static const llhttp_settings_t settings;
909
};
910
911
const llhttp_settings_t Parser::settings = {
912
  Proxy<Call, &Parser::on_message_begin>::Raw,
913
  Proxy<DataCall, &Parser::on_url>::Raw,
914
  Proxy<DataCall, &Parser::on_status>::Raw,
915
  Proxy<DataCall, &Parser::on_header_field>::Raw,
916
  Proxy<DataCall, &Parser::on_header_value>::Raw,
917
  Proxy<Call, &Parser::on_headers_complete>::Raw,
918
  Proxy<DataCall, &Parser::on_body>::Raw,
919
  Proxy<Call, &Parser::on_message_complete>::Raw,
920
  Proxy<Call, &Parser::on_chunk_header>::Raw,
921
  Proxy<Call, &Parser::on_chunk_complete>::Raw,
922
};
923
924
925
718
void InitializeHttpParser(Local<Object> target,
926
                          Local<Value> unused,
927
                          Local<Context> context,
928
                          void* priv) {
929
718
  Environment* env = Environment::GetCurrent(context);
930
  BindingData* const binding_data =
931
718
      env->AddBindingData<BindingData>(context, target);
932
718
  if (binding_data == nullptr) return;
933
934
718
  Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
935
1436
  t->InstanceTemplate()->SetInternalFieldCount(Parser::kInternalFieldCount);
936
1436
  t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"));
937
938
2872
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"),
939
718
         Integer::New(env->isolate(), HTTP_REQUEST));
940
2872
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"),
941
718
         Integer::New(env->isolate(), HTTP_RESPONSE));
942
2872
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"),
943
718
         Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
944
2872
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"),
945
718
         Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
946
2872
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"),
947
718
         Integer::NewFromUnsigned(env->isolate(), kOnBody));
948
2872
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"),
949
718
         Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
950
2872
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"),
951
718
         Integer::NewFromUnsigned(env->isolate(), kOnExecute));
952
2872
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnTimeout"),
953
718
         Integer::NewFromUnsigned(env->isolate(), kOnTimeout));
954
955
718
  Local<Array> methods = Array::New(env->isolate());
956
#define V(num, name, string)                                                  \
957
    methods->Set(env->context(),                                              \
958
        num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)).Check();
959
73954
  HTTP_METHOD_MAP(V)
960
#undef V
961
1436
  target->Set(env->context(),
962
              FIXED_ONE_BYTE_STRING(env->isolate(), "methods"),
963
2872
              methods).Check();
964
965
1436
  t->Inherit(AsyncWrap::GetConstructorTemplate(env));
966
718
  env->SetProtoMethod(t, "close", Parser::Close);
967
718
  env->SetProtoMethod(t, "free", Parser::Free);
968
718
  env->SetProtoMethod(t, "execute", Parser::Execute);
969
718
  env->SetProtoMethod(t, "finish", Parser::Finish);
970
718
  env->SetProtoMethod(t, "initialize", Parser::Initialize);
971
718
  env->SetProtoMethod(t, "pause", Parser::Pause<true>);
972
718
  env->SetProtoMethod(t, "resume", Parser::Pause<false>);
973
718
  env->SetProtoMethod(t, "consume", Parser::Consume);
974
718
  env->SetProtoMethod(t, "unconsume", Parser::Unconsume);
975
718
  env->SetProtoMethod(t, "getCurrentBuffer", Parser::GetCurrentBuffer);
976
977
1436
  target->Set(env->context(),
978
              FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"),
979
4308
              t->GetFunction(env->context()).ToLocalChecked()).Check();
980
}
981
982
}  // anonymous namespace
983
}  // namespace node
984
985

17887
NODE_MODULE_CONTEXT_AWARE_INTERNAL(http_parser, node::InitializeHttpParser)