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_impl.h Lines: 393 416 94.5 %
Date: 2019-05-05 22:32:45 Branches: 179 247 72.5 %

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
// This file is included from 2 files, node_http_parser_traditional.cc
23
// and node_http_parser_llhttp.cc.
24
25
#pragma once
26
27
#include "node.h"
28
#include "node_buffer.h"
29
#include "util.h"
30
31
#include "async_wrap-inl.h"
32
#include "env-inl.h"
33
#include "stream_base-inl.h"
34
#include "v8.h"
35
36
#include "http_parser_adaptor.h"
37
38
#include <cstdlib>  // free()
39
#include <cstring>  // strdup(), strchr()
40
41
42
// This is a binding to http_parser (https://github.com/nodejs/http-parser)
43
// The goal is to decouple sockets from parsing for more javascript-level
44
// agility. A Buffer is read from a socket and passed to parser.execute().
45
// The parser then issues callbacks with slices of the data
46
//     parser.onMessageBegin
47
//     parser.onPath
48
//     parser.onBody
49
//     ...
50
// No copying is performed when slicing the buffer, only small reference
51
// allocations.
52
53
54
namespace node {
55
namespace {  // NOLINT(build/namespaces)
56
57
using v8::Array;
58
using v8::Boolean;
59
using v8::Context;
60
using v8::EscapableHandleScope;
61
using v8::Exception;
62
using v8::Function;
63
using v8::FunctionCallbackInfo;
64
using v8::FunctionTemplate;
65
using v8::HandleScope;
66
using v8::Int32;
67
using v8::Integer;
68
using v8::Local;
69
using v8::MaybeLocal;
70
using v8::Object;
71
using v8::String;
72
using v8::Uint32;
73
using v8::Undefined;
74
using v8::Value;
75
76
const uint32_t kOnHeaders = 0;
77
const uint32_t kOnHeadersComplete = 1;
78
const uint32_t kOnBody = 2;
79
const uint32_t kOnMessageComplete = 3;
80
const uint32_t kOnExecute = 4;
81
// Any more fields than this will be flushed into JS
82
const size_t kMaxHeaderFieldsCount = 32;
83
84
// helper class for the Parser
85
struct StringPtr {
86
191532
  StringPtr() {
87
191532
    on_heap_ = false;
88
191532
    Reset();
89
191532
  }
90
91
92
188694
  ~StringPtr() {
93
188694
    Reset();
94
188694
  }
95
96
97
  // If str_ does not point to a heap string yet, this function makes it do
98
  // so. This is called at the end of each http_parser_execute() so as not
99
  // to leak references. See issue #2438 and test-http-parser-bad-ref.js.
100
154445
  void Save() {
101

154445
    if (!on_heap_ && size_ > 0) {
102
70521
      char* s = new char[size_];
103
70521
      memcpy(s, str_, size_);
104
70521
      str_ = s;
105
70521
      on_heap_ = true;
106
    }
107
154445
  }
108
109
110
859874
  void Reset() {
111
859874
    if (on_heap_) {
112
70476
      delete[] str_;
113
70476
      on_heap_ = false;
114
    }
115
116
859874
    str_ = nullptr;
117
859874
    size_ = 0;
118
859874
  }
119
120
121
335479
  void Update(const char* str, size_t size) {
122
335479
    if (str_ == nullptr) {
123
335306
      str_ = str;
124

173
    } else if (on_heap_ || str_ + size_ != str) {
125
      // Non-consecutive input, make a copy on the heap.
126
      // TODO(bnoordhuis) Use slab allocation, O(n) allocs is bad.
127
173
      char* s = new char[size_ + size];
128
173
      memcpy(s, str_, size_);
129
173
      memcpy(s + size_, str, size);
130
131
173
      if (on_heap_)
132
172
        delete[] str_;
133
      else
134
1
        on_heap_ = true;
135
136
173
      str_ = s;
137
    }
138
335479
    size_ += size;
139
335479
  }
140
141
142
335249
  Local<String> ToString(Environment* env) const {
143
335249
    if (str_)
144
335186
      return OneByteString(env->isolate(), str_, size_);
145
    else
146
126
      return String::Empty(env->isolate());
147
  }
148
149
150
  const char* str_;
151
  bool on_heap_;
152
  size_t size_;
153
};
154
155


5718
class Parser : public AsyncWrap, public StreamListener {
156
 public:
157
2902
  Parser(Environment* env, Local<Object> wrap)
158
      : AsyncWrap(env, wrap),
159
        current_buffer_len_(0),
160

5804
        current_buffer_data_(nullptr) {
161
2902
  }
162
163
164
1
  void MemoryInfo(MemoryTracker* tracker) const override {
165
1
    tracker->TrackField("current_buffer", current_buffer_);
166
1
  }
167
168
1
  SET_MEMORY_INFO_NAME(Parser)
169
1
  SET_SELF_SIZE(Parser)
170
171
81559
  int on_message_begin() {
172
81559
    num_fields_ = num_values_ = 0;
173
81559
    url_.Reset();
174
81559
    status_message_.Reset();
175
81559
    return 0;
176
  }
177
178
179
68737
  int on_url(const char* at, size_t length) {
180
68737
    int rv = TrackHeader(length);
181
68737
    if (rv != 0) {
182
      return rv;
183
    }
184
185
68737
    url_.Update(at, length);
186
68737
    return 0;
187
  }
188
189
190
12814
  int on_status(const char* at, size_t length) {
191
12814
    int rv = TrackHeader(length);
192
12814
    if (rv != 0) {
193
      return rv;
194
    }
195
196
12814
    status_message_.Update(at, length);
197
12814
    return 0;
198
  }
199
200
201
126918
  int on_header_field(const char* at, size_t length) {
202
126918
    int rv = TrackHeader(length);
203
126918
    if (rv != 0) {
204
      return rv;
205
    }
206
207
126918
    if (num_fields_ == num_values_) {
208
      // start of new field name
209
126889
      num_fields_++;
210
126889
      if (num_fields_ == kMaxHeaderFieldsCount) {
211
        // ran out of space - flush to javascript land
212
47
        Flush();
213
47
        num_fields_ = 1;
214
47
        num_values_ = 0;
215
      }
216
126889
      fields_[num_fields_ - 1].Reset();
217
    }
218
219
126918
    CHECK_LT(num_fields_, kMaxHeaderFieldsCount);
220
126918
    CHECK_EQ(num_fields_, num_values_ + 1);
221
222
126918
    fields_[num_fields_ - 1].Update(at, length);
223
224
126918
    return 0;
225
  }
226
227
228
127018
  int on_header_value(const char* at, size_t length) {
229
127018
    int rv = TrackHeader(length);
230
127018
    if (rv != 0) {
231
8
      return rv;
232
    }
233
234
127010
    if (num_values_ != num_fields_) {
235
      // start of new header value
236
126874
      num_values_++;
237
126874
      values_[num_values_ - 1].Reset();
238
    }
239
240
127010
    CHECK_LT(num_values_, arraysize(values_));
241
127010
    CHECK_EQ(num_values_, num_fields_);
242
243
127010
    values_[num_values_ - 1].Update(at, length);
244
245
127010
    return 0;
246
  }
247
248
249
81524
  int on_headers_complete() {
250
#ifdef NODE_EXPERIMENTAL_HTTP
251
81522
    header_nread_ = 0;
252
#endif  /* NODE_EXPERIMENTAL_HTTP */
253
254
    // Arguments for the on-headers-complete javascript callback. This
255
    // list needs to be kept in sync with the actual argument list for
256
    // `parserOnHeadersComplete` in lib/_http_common.js.
257
    enum on_headers_complete_arg_index {
258
      A_VERSION_MAJOR = 0,
259
      A_VERSION_MINOR,
260
      A_HEADERS,
261
      A_METHOD,
262
      A_URL,
263
      A_STATUS_CODE,
264
      A_STATUS_MESSAGE,
265
      A_UPGRADE,
266
      A_SHOULD_KEEP_ALIVE,
267
      A_MAX
268
    };
269
270
815240
    Local<Value> argv[A_MAX];
271
81524
    Local<Object> obj = object();
272
    Local<Value> cb = obj->Get(env()->context(),
273
244572
                               kOnHeadersComplete).ToLocalChecked();
274
275
81524
    if (!cb->IsFunction())
276
      return 0;
277
278
81524
    Local<Value> undefined = Undefined(env()->isolate());
279
815240
    for (size_t i = 0; i < arraysize(argv); i++)
280
733716
      argv[i] = undefined;
281
282
81524
    if (have_flushed_) {
283
      // Slow case, flush remaining headers.
284
16
      Flush();
285
    } else {
286
      // Fast case, pass headers and URL to JS land.
287
163016
      argv[A_HEADERS] = CreateHeaders();
288
81508
      if (parser_.type == HTTP_REQUEST)
289
137410
        argv[A_URL] = url_.ToString(env());
290
    }
291
292
81524
    num_fields_ = 0;
293
81524
    num_values_ = 0;
294
295
    // METHOD
296
81524
    if (parser_.type == HTTP_REQUEST) {
297
      argv[A_METHOD] =
298
137426
          Uint32::NewFromUnsigned(env()->isolate(), parser_.method);
299
    }
300
301
    // STATUS
302
81524
    if (parser_.type == HTTP_RESPONSE) {
303
      argv[A_STATUS_CODE] =
304
25622
          Integer::New(env()->isolate(), parser_.status_code);
305
25622
      argv[A_STATUS_MESSAGE] = status_message_.ToString(env());
306
    }
307
308
    // VERSION
309
163048
    argv[A_VERSION_MAJOR] = Integer::New(env()->isolate(), parser_.http_major);
310
163048
    argv[A_VERSION_MINOR] = Integer::New(env()->isolate(), parser_.http_minor);
311
312
    bool should_keep_alive;
313
#ifdef NODE_EXPERIMENTAL_HTTP
314
81522
    should_keep_alive = llhttp_should_keep_alive(&parser_);
315
#else  /* !NODE_EXPERIMENTAL_HTTP */
316
2
    should_keep_alive = http_should_keep_alive(&parser_);
317
#endif  /* NODE_EXPERIMENTAL_HTTP */
318
319
    argv[A_SHOULD_KEEP_ALIVE] =
320
163048
        Boolean::New(env()->isolate(), should_keep_alive);
321
322
163048
    argv[A_UPGRADE] = Boolean::New(env()->isolate(), parser_.upgrade);
323
324
81524
    AsyncCallbackScope callback_scope(env());
325
326
    MaybeLocal<Value> head_response =
327
163048
        MakeCallback(cb.As<Function>(), arraysize(argv), argv);
328
329
    int64_t val;
330
331

407603
    if (head_response.IsEmpty() || !head_response.ToLocalChecked()
332
407582
                                        ->IntegerValue(env()->context())
333
326067
                                        .To(&val)) {
334
7
      got_exception_ = true;
335
7
      return -1;
336
    }
337
338
81515
    return val;
339
  }
340
341
342
21995
  int on_body(const char* at, size_t length) {
343
21995
    EscapableHandleScope scope(env()->isolate());
344
345
21995
    Local<Object> obj = object();
346
65985
    Local<Value> cb = obj->Get(env()->context(), kOnBody).ToLocalChecked();
347
348
21995
    if (!cb->IsFunction())
349
      return 0;
350
351
    // We came from consumed stream
352
43990
    if (current_buffer_.IsEmpty()) {
353
      // Make sure Buffer will be in parent HandleScope
354
      current_buffer_ = scope.Escape(Buffer::Copy(
355
          env()->isolate(),
356
          current_buffer_data_,
357
5552
          current_buffer_len_).ToLocalChecked());
358
    }
359
360
    Local<Value> argv[3] = {
361
      current_buffer_,
362
21995
      Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
363
      Integer::NewFromUnsigned(env()->isolate(), length)
364
109975
    };
365
366
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
367
21995
                                       arraysize(argv),
368
43990
                                       argv);
369
370
21995
    if (r.IsEmpty()) {
371
      got_exception_ = true;
372
#ifdef NODE_EXPERIMENTAL_HTTP
373
      llhttp_set_error_reason(&parser_, "HPE_JS_EXCEPTION:JS Exception");
374
#endif  /* NODE_EXPERIMENTAL_HTTP */
375
      return HPE_USER;
376
    }
377
378
21995
    return 0;
379
  }
380
381
382
80323
  int on_message_complete() {
383
80323
    HandleScope scope(env()->isolate());
384
385
80323
    if (num_fields_)
386
4
      Flush();  // Flush trailing HTTP headers.
387
388
80323
    Local<Object> obj = object();
389
    Local<Value> cb = obj->Get(env()->context(),
390
240969
                               kOnMessageComplete).ToLocalChecked();
391
392
80323
    if (!cb->IsFunction())
393
2
      return 0;
394
395
160642
    AsyncCallbackScope callback_scope(env());
396
397
80321
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(), 0, nullptr);
398
399
80321
    if (r.IsEmpty()) {
400
      got_exception_ = true;
401
      return -1;
402
    }
403
404
160644
    return 0;
405
  }
406
407
#ifdef NODE_EXPERIMENTAL_HTTP
408
  // Reset nread for the next chunk
409
27408
  int on_chunk_header() {
410
27408
    header_nread_ = 0;
411
27408
    return 0;
412
  }
413
414
415
  // Reset nread for the next chunk
416
27253
  int on_chunk_complete() {
417
27253
    header_nread_ = 0;
418
27253
    return 0;
419
  }
420
#endif  /* NODE_EXPERIMENTAL_HTTP */
421
422
423
2902
  static void New(const FunctionCallbackInfo<Value>& args) {
424
2902
    Environment* env = Environment::GetCurrent(args);
425
2902
    new Parser(env, args.This());
426
2902
  }
427
428
429
3
  static void Close(const FunctionCallbackInfo<Value>& args) {
430
    Parser* parser;
431
6
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
432
433
3
    delete parser;
434
  }
435
436
437
31146
  static void Free(const FunctionCallbackInfo<Value>& args) {
438
    Parser* parser;
439
62292
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
440
441
    // Since the Parser destructor isn't going to run the destroy() callbacks
442
    // it needs to be triggered manually.
443
31146
    parser->EmitTraceEventDestroy();
444
31146
    parser->EmitDestroy();
445
  }
446
447
448
76687
  void Save() {
449
76687
    url_.Save();
450
76687
    status_message_.Save();
451
452
77248
    for (size_t i = 0; i < num_fields_; i++) {
453
561
      fields_[i].Save();
454
    }
455
456
77197
    for (size_t i = 0; i < num_values_; i++) {
457
510
      values_[i].Save();
458
    }
459
76687
  }
460
461
462
  // var bytesParsed = parser->execute(buffer);
463
15693
  static void Execute(const FunctionCallbackInfo<Value>& args) {
464
    Parser* parser;
465
31385
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
466
31386
    CHECK(parser->current_buffer_.IsEmpty());
467
15693
    CHECK_EQ(parser->current_buffer_len_, 0);
468
15693
    CHECK_NULL(parser->current_buffer_data_);
469
15693
    CHECK_EQ(Buffer::HasInstance(args[0]), true);
470
471
31386
    Local<Object> buffer_obj = args[0].As<Object>();
472
15693
    char* buffer_data = Buffer::Data(buffer_obj);
473
15693
    size_t buffer_len = Buffer::Length(buffer_obj);
474
475
    // This is a hack to get the current_buffer to the callbacks with the least
476
    // amount of overhead. Nothing else will run while http_parser_execute()
477
    // runs, therefore this pointer can be set and used for the execution.
478
15693
    parser->current_buffer_ = buffer_obj;
479
480
15693
    Local<Value> ret = parser->Execute(buffer_data, buffer_len);
481
482
15692
    if (!ret.IsEmpty())
483
31380
      args.GetReturnValue().Set(ret);
484
  }
485
486
487
850
  static void Finish(const FunctionCallbackInfo<Value>& args) {
488
    Parser* parser;
489
1700
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
490
491
1700
    CHECK(parser->current_buffer_.IsEmpty());
492
850
    Local<Value> ret = parser->Execute(nullptr, 0);
493
494
850
    if (!ret.IsEmpty())
495
58
      args.GetReturnValue().Set(ret);
496
  }
497
498
499
31350
  static void Initialize(const FunctionCallbackInfo<Value>& args) {
500
31350
    Environment* env = Environment::GetCurrent(args);
501
502
62700
    CHECK(args[0]->IsInt32());
503
62700
    CHECK(args[1]->IsObject());
504
505
    parser_type_t type =
506
94050
        static_cast<parser_type_t>(args[0].As<Int32>()->Value());
507
508

31350
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
509
    Parser* parser;
510
62700
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
511
    // Should always be called from the same context.
512
31350
    CHECK_EQ(env, parser->env());
513
514
    AsyncWrap::ProviderType provider =
515
        (type == HTTP_REQUEST ?
516
            AsyncWrap::PROVIDER_HTTPINCOMINGMESSAGE
517
31350
            : AsyncWrap::PROVIDER_HTTPCLIENTREQUEST);
518
519
31350
    parser->set_provider_type(provider);
520
62700
    parser->AsyncReset(args[1].As<Object>());
521
31350
    parser->Init(type);
522
  }
523
524
  template <bool should_pause>
525
11
  static void Pause(const FunctionCallbackInfo<Value>& args) {
526
11
    Environment* env = Environment::GetCurrent(args);
527
    Parser* parser;
528

15
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
529
    // Should always be called from the same context.
530

11
    CHECK_EQ(env, parser->env());
531
532
#ifdef NODE_EXPERIMENTAL_HTTP
533

11
    if (parser->execute_depth_) {
534
4
      parser->pending_pause_ = should_pause;
535
4
      return;
536
    }
537
538
    if (should_pause) {
539
4
      llhttp_pause(&parser->parser_);
540
    } else {
541
3
      llhttp_resume(&parser->parser_);
542
    }
543
#else  /* !NODE_EXPERIMENTAL_HTTP */
544
    http_parser_pause(&parser->parser_, should_pause);
545
#endif  /* NODE_EXPERIMENTAL_HTTP */
546
  }
547
548
549
18786
  static void Consume(const FunctionCallbackInfo<Value>& args) {
550
    Parser* parser;
551
37572
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
552
37572
    CHECK(args[0]->IsObject());
553
37572
    StreamBase* stream = StreamBase::FromObject(args[0].As<Object>());
554
18786
    CHECK_NOT_NULL(stream);
555
18786
    stream->PushStreamListener(parser);
556
  }
557
558
559
18769
  static void Unconsume(const FunctionCallbackInfo<Value>& args) {
560
    Parser* parser;
561
18769
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
562
563
    // Already unconsumed
564
18769
    if (parser->stream_ == nullptr)
565
      return;
566
567
18769
    parser->stream_->RemoveStreamListener(parser);
568
  }
569
570
571
31
  static void GetCurrentBuffer(const FunctionCallbackInfo<Value>& args) {
572
    Parser* parser;
573
62
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
574
575
    Local<Object> ret = Buffer::Copy(
576
        parser->env(),
577
        parser->current_buffer_data_,
578
62
        parser->current_buffer_len_).ToLocalChecked();
579
580
62
    args.GetReturnValue().Set(ret);
581
  }
582
583
 protected:
584
  static const size_t kAllocBufferSize = 64 * 1024;
585
586
61178
  uv_buf_t OnStreamAlloc(size_t suggested_size) override {
587
    // For most types of streams, OnStreamRead will be immediately after
588
    // OnStreamAlloc, and will consume all data, so using a static buffer for
589
    // reading is more efficient. For other streams, just use Malloc() directly.
590
61178
    if (env()->http_parser_buffer_in_use())
591
      return uv_buf_init(Malloc(suggested_size), suggested_size);
592
61178
    env()->set_http_parser_buffer_in_use(true);
593
594
61178
    if (env()->http_parser_buffer() == nullptr)
595
285
      env()->set_http_parser_buffer(new char[kAllocBufferSize]);
596
597
61178
    return uv_buf_init(env()->http_parser_buffer(), kAllocBufferSize);
598
  }
599
600
601
61195
  void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override {
602
61195
    HandleScope scope(env()->isolate());
603
    // Once we’re done here, either indicate that the HTTP parser buffer
604
    // is free for re-use, or free() the data if it didn’t come from there
605
    // in the first place.
606
61191
    OnScopeLeave on_scope_leave([&]() {
607
61191
      if (buf.base == env()->http_parser_buffer())
608
61174
        env()->set_http_parser_buffer_in_use(false);
609
      else
610
17
        free(buf.base);
611
182371
    });
612
613
61195
    if (nread < 0) {
614
199
      PassReadErrorToPreviousListener(nread);
615
199
      return;
616
    }
617
618
    // Ignore, empty reads have special meaning in http parser
619
60996
    if (nread == 0)
620
      return;
621
622
60996
    current_buffer_.Clear();
623
60996
    Local<Value> ret = Execute(buf.base, nread);
624
625
    // Exception
626
60995
    if (ret.IsEmpty())
627
5
      return;
628
629
    Local<Value> cb =
630
182970
        object()->Get(env()->context(), kOnExecute).ToLocalChecked();
631
632
60990
    if (!cb->IsFunction())
633
1002
      return;
634
635
    // Hooks for GetCurrentBuffer
636
59988
    current_buffer_len_ = nread;
637
59988
    current_buffer_data_ = buf.base;
638
639
59988
    MakeCallback(cb.As<Function>(), 1, &ret);
640
641
59985
    current_buffer_len_ = 0;
642
119970
    current_buffer_data_ = nullptr;
643
  }
644
645
646
77539
  Local<Value> Execute(char* data, size_t len) {
647
77539
    EscapableHandleScope scope(env()->isolate());
648
649
77539
    current_buffer_len_ = len;
650
77539
    current_buffer_data_ = data;
651
77539
    got_exception_ = false;
652
653
    parser_errno_t err;
654
655
#ifdef NODE_EXPERIMENTAL_HTTP
656
    // Do not allow re-entering `http_parser_execute()`
657
77529
    CHECK_EQ(execute_depth_, 0);
658
659
77529
    execute_depth_++;
660
77529
    if (data == nullptr) {
661
847
      err = llhttp_finish(&parser_);
662
    } else {
663
76682
      err = llhttp_execute(&parser_, data, len);
664
76680
      Save();
665
    }
666
77527
    execute_depth_--;
667
668
    // Calculate bytes read and resume after Upgrade/CONNECT pause
669
77527
    size_t nread = len;
670
77527
    if (err != HPE_OK) {
671
307
      nread = llhttp_get_error_pos(&parser_) - data;
672
673
      // This isn't a real pause, just a way to stop parsing early.
674
307
      if (err == HPE_PAUSED_UPGRADE) {
675
49
        err = HPE_OK;
676
49
        llhttp_resume_after_upgrade(&parser_);
677
      }
678
    }
679
680
    // Apply pending pause
681
77527
    if (pending_pause_) {
682
      pending_pause_ = false;
683
      llhttp_pause(&parser_);
684
    }
685
#else  /* !NODE_EXPERIMENTAL_HTTP */
686
10
    size_t nread = http_parser_execute(&parser_, &settings, data, len);
687
10
    err = HTTP_PARSER_ERRNO(&parser_);
688
689
    // Finish()
690
10
    if (data == nullptr) {
691
      // `http_parser_execute()` returns either `0` or `1` when `len` is 0
692
      // (part of the finishing sequence).
693
3
      CHECK_EQ(len, 0);
694
3
      switch (nread) {
695
        case 0:
696
3
          err = HPE_OK;
697
3
          break;
698
        case 1:
699
          nread = 0;
700
          break;
701
        default:
702
          UNREACHABLE();
703
      }
704
705
    // Regular Execute()
706
    } else {
707
7
      Save();
708
    }
709
#endif  /* NODE_EXPERIMENTAL_HTTP */
710
711
    // Unassign the 'buffer_' variable
712
77537
    current_buffer_.Clear();
713
77537
    current_buffer_len_ = 0;
714
77537
    current_buffer_data_ = nullptr;
715
716
    // If there was an exception in one of the callbacks
717
77537
    if (got_exception_)
718
7
      return scope.Escape(Local<Value>());
719
720
77530
    Local<Integer> nread_obj = Integer::New(env()->isolate(), nread);
721
722
    // If there was a parse error in one of the callbacks
723
    // TODO(bnoordhuis) What if there is an error on EOF?
724

77530
    if (!parser_.upgrade && err != HPE_OK) {
725
207
      Local<Value> e = Exception::Error(env()->parse_error_string());
726
414
      Local<Object> obj = e->ToObject(env()->isolate()->GetCurrentContext())
727
414
        .ToLocalChecked();
728
      obj->Set(env()->context(),
729
               env()->bytes_parsed_string(),
730
828
               nread_obj).Check();
731
#ifdef NODE_EXPERIMENTAL_HTTP
732
202
      const char* errno_reason = llhttp_get_error_reason(&parser_);
733
734
      Local<String> code;
735
      Local<String> reason;
736
202
      if (err == HPE_USER) {
737
8
        const char* colon = strchr(errno_reason, ':');
738
8
        CHECK_NOT_NULL(colon);
739
        code = OneByteString(env()->isolate(), errno_reason,
740
8
                             colon - errno_reason);
741
8
        reason = OneByteString(env()->isolate(), colon + 1);
742
      } else {
743
194
        code = OneByteString(env()->isolate(), llhttp_errno_name(err));
744
194
        reason = OneByteString(env()->isolate(), errno_reason);
745
      }
746
747
808
      obj->Set(env()->context(), env()->code_string(), code).Check();
748
808
      obj->Set(env()->context(), env()->reason_string(), reason).Check();
749
#else  /* !NODE_EXPERIMENTAL_HTTP */
750
      obj->Set(env()->context(),
751
               env()->code_string(),
752
               OneByteString(env()->isolate(),
753
25
                             http_errno_name(err))).Check();
754
#endif  /* NODE_EXPERIMENTAL_HTTP */
755
      return scope.Escape(e);
756
    }
757
758
    // No return value is needed for `Finish()`
759
77323
    if (data == nullptr) {
760
821
      return scope.Escape(Local<Value>());
761
    }
762
76502
    return scope.Escape(nread_obj);
763
  }
764
765
81575
  Local<Array> CreateHeaders() {
766
    // There could be extra entries but the max size should be fixed
767
5302375
    Local<Value> headers_v[kMaxHeaderFieldsCount * 2];
768
769
208408
    for (size_t i = 0; i < num_values_; ++i) {
770
253666
      headers_v[i * 2] = fields_[i].ToString(env());
771
253666
      headers_v[i * 2 + 1] = values_[i].ToString(env());
772
    }
773
774
81575
    return Array::New(env()->isolate(), headers_v, num_values_ * 2);
775
  }
776
777
778
  // spill headers and request path to JS land
779
67
  void Flush() {
780
67
    HandleScope scope(env()->isolate());
781
782
67
    Local<Object> obj = object();
783
201
    Local<Value> cb = obj->Get(env()->context(), kOnHeaders).ToLocalChecked();
784
785
67
    if (!cb->IsFunction())
786
67
      return;
787
788
    Local<Value> argv[2] = {
789
      CreateHeaders(),
790
      url_.ToString(env())
791
201
    };
792
793
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
794
67
                                       arraysize(argv),
795
134
                                       argv);
796
797
67
    if (r.IsEmpty())
798
      got_exception_ = true;
799
800
67
    url_.Reset();
801
67
    have_flushed_ = true;
802
  }
803
804
805
31350
  void Init(parser_type_t type) {
806
#ifdef NODE_EXPERIMENTAL_HTTP
807
31342
    llhttp_init(&parser_, type, &settings);
808
31342
    header_nread_ = 0;
809
#else  /* !NODE_EXPERIMENTAL_HTTP */
810
8
    http_parser_init(&parser_, type);
811
#endif  /* NODE_EXPERIMENTAL_HTTP */
812
31350
    url_.Reset();
813
31350
    status_message_.Reset();
814
31350
    num_fields_ = 0;
815
31350
    num_values_ = 0;
816
31350
    have_flushed_ = false;
817
31350
    got_exception_ = false;
818
31350
  }
819
820
821
335487
  int TrackHeader(size_t len) {
822
#ifdef NODE_EXPERIMENTAL_HTTP
823
335447
    header_nread_ += len;
824
335447
    if (header_nread_ >= per_process::cli_options->max_http_header_size) {
825
8
      llhttp_set_error_reason(&parser_, "HPE_HEADER_OVERFLOW:Header overflow");
826
8
      return HPE_USER;
827
    }
828
#endif  /* NODE_EXPERIMENTAL_HTTP */
829
335479
    return 0;
830
  }
831
832
833
655476
  int MaybePause() {
834
#ifdef NODE_EXPERIMENTAL_HTTP
835
655425
    CHECK_NE(execute_depth_, 0);
836
837
655425
    if (!pending_pause_) {
838
655425
      return 0;
839
    }
840
841
    pending_pause_ = false;
842
    llhttp_set_error_reason(&parser_, "Paused in callback");
843
    return HPE_PAUSED;
844
#else  /* !NODE_EXPERIMENTAL_HTTP */
845
51
    return 0;
846
#endif  /* NODE_EXPERIMENTAL_HTTP */
847
  }
848
849
  parser_t parser_;
850
  StringPtr fields_[kMaxHeaderFieldsCount];  // header fields
851
  StringPtr values_[kMaxHeaderFieldsCount];  // header values
852
  StringPtr url_;
853
  StringPtr status_message_;
854
  size_t num_fields_;
855
  size_t num_values_;
856
  bool have_flushed_;
857
  bool got_exception_;
858
  Local<Object> current_buffer_;
859
  size_t current_buffer_len_;
860
  char* current_buffer_data_;
861
#ifdef NODE_EXPERIMENTAL_HTTP
862
  unsigned int execute_depth_ = 0;
863
  bool pending_pause_ = false;
864
  uint64_t header_nread_ = 0;
865
#endif  /* NODE_EXPERIMENTAL_HTTP */
866
867
  // These are helper functions for filling `http_parser_settings`, which turn
868
  // a member function of Parser into a C-style HTTP parser callback.
869
  template <typename Parser, Parser> struct Proxy;
870
  template <typename Parser, typename ...Args, int (Parser::*Member)(Args...)>
871
  struct Proxy<int (Parser::*)(Args...), Member> {
872
655549
    static int Raw(parser_t* p, Args ... args) {
873
655549
      Parser* parser = ContainerOf(&Parser::parser_, p);
874
655549
      int rv = (parser->*Member)(std::forward<Args>(args)...);
875





655547
      if (rv == 0) {
876
655476
        rv = parser->MaybePause();
877
      }
878
655547
      return rv;
879
    }
880
  };
881
882
  typedef int (Parser::*Call)();
883
  typedef int (Parser::*DataCall)(const char* at, size_t length);
884
885
  static const parser_settings_t settings;
886
};
887
888
const parser_settings_t Parser::settings = {
889
  Proxy<Call, &Parser::on_message_begin>::Raw,
890
  Proxy<DataCall, &Parser::on_url>::Raw,
891
  Proxy<DataCall, &Parser::on_status>::Raw,
892
  Proxy<DataCall, &Parser::on_header_field>::Raw,
893
  Proxy<DataCall, &Parser::on_header_value>::Raw,
894
  Proxy<Call, &Parser::on_headers_complete>::Raw,
895
  Proxy<DataCall, &Parser::on_body>::Raw,
896
  Proxy<Call, &Parser::on_message_complete>::Raw,
897
#ifdef NODE_EXPERIMENTAL_HTTP
898
  Proxy<Call, &Parser::on_chunk_header>::Raw,
899
  Proxy<Call, &Parser::on_chunk_complete>::Raw,
900
#else  /* !NODE_EXPERIMENTAL_HTTP */
901
  nullptr,
902
  nullptr,
903
#endif  /* NODE_EXPERIMENTAL_HTTP */
904
};
905
906
907
#ifndef NODE_EXPERIMENTAL_HTTP
908
4
void InitMaxHttpHeaderSizeOnce() {
909
  const uint32_t max_http_header_size =
910
4
      per_process::cli_options->max_http_header_size;
911
4
  http_parser_set_max_header_size(max_http_header_size);
912
4
}
913
#endif  /* NODE_EXPERIMENTAL_HTTP */
914
915
916
672
void InitializeHttpParser(Local<Object> target,
917
                          Local<Value> unused,
918
                          Local<Context> context,
919
                          void* priv) {
920
672
  Environment* env = Environment::GetCurrent(context);
921
672
  Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
922
1344
  t->InstanceTemplate()->SetInternalFieldCount(1);
923
1344
  t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"));
924
925
672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"),
926
2016
         Integer::New(env->isolate(), HTTP_REQUEST));
927
672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"),
928
2016
         Integer::New(env->isolate(), HTTP_RESPONSE));
929
672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"),
930
2016
         Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
931
672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"),
932
2016
         Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
933
672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"),
934
2016
         Integer::NewFromUnsigned(env->isolate(), kOnBody));
935
672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"),
936
2016
         Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
937
672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"),
938
2016
         Integer::NewFromUnsigned(env->isolate(), kOnExecute));
939
940
672
  Local<Array> methods = Array::New(env->isolate());
941
#define V(num, name, string)                                                  \
942
    methods->Set(env->context(),                                              \
943
        num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)).Check();
944
69216
  HTTP_METHOD_MAP(V)
945
#undef V
946
  target->Set(env->context(),
947
              FIXED_ONE_BYTE_STRING(env->isolate(), "methods"),
948
2688
              methods).Check();
949
950
1344
  t->Inherit(AsyncWrap::GetConstructorTemplate(env));
951
672
  env->SetProtoMethod(t, "close", Parser::Close);
952
672
  env->SetProtoMethod(t, "free", Parser::Free);
953
672
  env->SetProtoMethod(t, "execute", Parser::Execute);
954
672
  env->SetProtoMethod(t, "finish", Parser::Finish);
955
672
  env->SetProtoMethod(t, "initialize", Parser::Initialize);
956
672
  env->SetProtoMethod(t, "pause", Parser::Pause<true>);
957
672
  env->SetProtoMethod(t, "resume", Parser::Pause<false>);
958
672
  env->SetProtoMethod(t, "consume", Parser::Consume);
959
672
  env->SetProtoMethod(t, "unconsume", Parser::Unconsume);
960
672
  env->SetProtoMethod(t, "getCurrentBuffer", Parser::GetCurrentBuffer);
961
962
  target->Set(env->context(),
963
              FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"),
964
4032
              t->GetFunction(env->context()).ToLocalChecked()).Check();
965
966
#ifndef NODE_EXPERIMENTAL_HTTP
967
  static uv_once_t init_once = UV_ONCE_INIT;
968
4
  uv_once(&init_once, InitMaxHttpHeaderSizeOnce);
969
#endif  /* NODE_EXPERIMENTAL_HTTP */
970
672
}
971
972
}  // anonymous namespace
973
}  // namespace node