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: 385 412 93.4 %
Date: 2019-07-28 22:34:34 Branches: 178 245 72.7 %

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
194700
  StringPtr() {
87
194700
    on_heap_ = false;
88
194700
    Reset();
89
194700
  }
90
91
92
191730
  ~StringPtr() {
93
191730
    Reset();
94
191730
  }
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
156944
  void Save() {
101

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

154
    } 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
154
      char* s = new char[size_ + size];
128
154
      memcpy(s, str_, size_);
129
154
      memcpy(s + size_, str, size);
130
131
154
      if (on_heap_)
132
153
        delete[] str_;
133
      else
134
1
        on_heap_ = true;
135
136
154
      str_ = s;
137
    }
138
339182
    size_ += size;
139
339182
  }
140
141
142
338912
  Local<String> ToString(Environment* env) const {
143
338912
    if (str_)
144
338849
      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


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

5900
        current_buffer_data_(nullptr) {
161
2950
  }
162
163
164
  void MemoryInfo(MemoryTracker* tracker) const override {
165
    tracker->TrackField("current_buffer", current_buffer_);
166
  }
167
168
  SET_MEMORY_INFO_NAME(Parser)
169
  SET_SELF_SIZE(Parser)
170
171
82569
  int on_message_begin() {
172
82569
    num_fields_ = num_values_ = 0;
173
82569
    url_.Reset();
174
82569
    status_message_.Reset();
175
82569
    return 0;
176
  }
177
178
179
69684
  int on_url(const char* at, size_t length) {
180
69684
    int rv = TrackHeader(length);
181
69684
    if (rv != 0) {
182
      return rv;
183
    }
184
185
69684
    url_.Update(at, length);
186
69684
    return 0;
187
  }
188
189
190
12875
  int on_status(const char* at, size_t length) {
191
12875
    int rv = TrackHeader(length);
192
12875
    if (rv != 0) {
193
      return rv;
194
    }
195
196
12875
    status_message_.Update(at, length);
197
12875
    return 0;
198
  }
199
200
201
128279
  int on_header_field(const char* at, size_t length) {
202
128279
    int rv = TrackHeader(length);
203
128279
    if (rv != 0) {
204
      return rv;
205
    }
206
207
128279
    if (num_fields_ == num_values_) {
208
      // start of new field name
209
128250
      num_fields_++;
210
128250
      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
128250
      fields_[num_fields_ - 1].Reset();
217
    }
218
219
128279
    CHECK_LT(num_fields_, kMaxHeaderFieldsCount);
220
128279
    CHECK_EQ(num_fields_, num_values_ + 1);
221
222
128279
    fields_[num_fields_ - 1].Update(at, length);
223
224
128279
    return 0;
225
  }
226
227
228
128357
  int on_header_value(const char* at, size_t length) {
229
128357
    int rv = TrackHeader(length);
230
128357
    if (rv != 0) {
231
13
      return rv;
232
    }
233
234
128344
    if (num_values_ != num_fields_) {
235
      // start of new header value
236
128227
      num_values_++;
237
128227
      values_[num_values_ - 1].Reset();
238
    }
239
240
128344
    CHECK_LT(num_values_, arraysize(values_));
241
128344
    CHECK_EQ(num_values_, num_fields_);
242
243
128344
    values_[num_values_ - 1].Update(at, length);
244
245
128344
    return 0;
246
  }
247
248
249
82521
  int on_headers_complete() {
250
#ifdef NODE_EXPERIMENTAL_HTTP
251
82518
    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
825210
    Local<Value> argv[A_MAX];
271
82521
    Local<Object> obj = object();
272
    Local<Value> cb = obj->Get(env()->context(),
273
247563
                               kOnHeadersComplete).ToLocalChecked();
274
275
82521
    if (!cb->IsFunction())
276
      return 0;
277
278
82521
    Local<Value> undefined = Undefined(env()->isolate());
279
825210
    for (size_t i = 0; i < arraysize(argv); i++)
280
742689
      argv[i] = undefined;
281
282
82521
    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
165010
      argv[A_HEADERS] = CreateHeaders();
288
82505
      if (parser_.type == HTTP_REQUEST)
289
139292
        argv[A_URL] = url_.ToString(env());
290
    }
291
292
82521
    num_fields_ = 0;
293
82521
    num_values_ = 0;
294
295
    // METHOD
296
82521
    if (parser_.type == HTTP_REQUEST) {
297
      argv[A_METHOD] =
298
139308
          Uint32::NewFromUnsigned(env()->isolate(), parser_.method);
299
    }
300
301
    // STATUS
302
82521
    if (parser_.type == HTTP_RESPONSE) {
303
      argv[A_STATUS_CODE] =
304
25734
          Integer::New(env()->isolate(), parser_.status_code);
305
25734
      argv[A_STATUS_MESSAGE] = status_message_.ToString(env());
306
    }
307
308
    // VERSION
309
165042
    argv[A_VERSION_MAJOR] = Integer::New(env()->isolate(), parser_.http_major);
310
165042
    argv[A_VERSION_MINOR] = Integer::New(env()->isolate(), parser_.http_minor);
311
312
    bool should_keep_alive;
313
#ifdef NODE_EXPERIMENTAL_HTTP
314
82518
    should_keep_alive = llhttp_should_keep_alive(&parser_);
315
#else  /* !NODE_EXPERIMENTAL_HTTP */
316
3
    should_keep_alive = http_should_keep_alive(&parser_);
317
#endif  /* NODE_EXPERIMENTAL_HTTP */
318
319
    argv[A_SHOULD_KEEP_ALIVE] =
320
165042
        Boolean::New(env()->isolate(), should_keep_alive);
321
322
165042
    argv[A_UPGRADE] = Boolean::New(env()->isolate(), parser_.upgrade);
323
324
82521
    AsyncCallbackScope callback_scope(env());
325
326
    MaybeLocal<Value> head_response =
327
165042
        MakeCallback(cb.As<Function>(), arraysize(argv), argv);
328
329
    int64_t val;
330
331

412588
    if (head_response.IsEmpty() || !head_response.ToLocalChecked()
332
412567
                                        ->IntegerValue(env()->context())
333
330055
                                        .To(&val)) {
334
7
      got_exception_ = true;
335
7
      return -1;
336
    }
337
338
82512
    return val;
339
  }
340
341
342
22801
  int on_body(const char* at, size_t length) {
343
22801
    EscapableHandleScope scope(env()->isolate());
344
345
22801
    Local<Object> obj = object();
346
68403
    Local<Value> cb = obj->Get(env()->context(), kOnBody).ToLocalChecked();
347
348
22801
    if (!cb->IsFunction())
349
      return 0;
350
351
    // We came from consumed stream
352
45602
    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
5554
          current_buffer_len_).ToLocalChecked());
358
    }
359
360
    Local<Value> argv[3] = {
361
      current_buffer_,
362
22801
      Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
363
      Integer::NewFromUnsigned(env()->isolate(), length)
364
114005
    };
365
366
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
367
22801
                                       arraysize(argv),
368
45602
                                       argv);
369
370
22801
    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
22801
    return 0;
379
  }
380
381
382
81327
  int on_message_complete() {
383
81327
    HandleScope scope(env()->isolate());
384
385
81327
    if (num_fields_)
386
4
      Flush();  // Flush trailing HTTP headers.
387
388
81327
    Local<Object> obj = object();
389
    Local<Value> cb = obj->Get(env()->context(),
390
243981
                               kOnMessageComplete).ToLocalChecked();
391
392
81327
    if (!cb->IsFunction())
393
2
      return 0;
394
395
162650
    AsyncCallbackScope callback_scope(env());
396
397
81325
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(), 0, nullptr);
398
399
81325
    if (r.IsEmpty()) {
400
      got_exception_ = true;
401
      return -1;
402
    }
403
404
162652
    return 0;
405
  }
406
407
#ifdef NODE_EXPERIMENTAL_HTTP
408
  // Reset nread for the next chunk
409
27428
  int on_chunk_header() {
410
27428
    header_nread_ = 0;
411
27428
    return 0;
412
  }
413
414
415
  // Reset nread for the next chunk
416
27273
  int on_chunk_complete() {
417
27273
    header_nread_ = 0;
418
27273
    return 0;
419
  }
420
#endif  /* NODE_EXPERIMENTAL_HTTP */
421
422
423
2950
  static void New(const FunctionCallbackInfo<Value>& args) {
424
2950
    Environment* env = Environment::GetCurrent(args);
425
2950
    new Parser(env, args.This());
426
2950
  }
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
30369
  static void Free(const FunctionCallbackInfo<Value>& args) {
438
    Parser* parser;
439
60738
    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
30369
    parser->EmitTraceEventDestroy();
444
30369
    parser->EmitDestroy();
445
  }
446
447
448
77978
  void Save() {
449
77978
    url_.Save();
450
77978
    status_message_.Save();
451
452
78501
    for (size_t i = 0; i < num_fields_; i++) {
453
523
      fields_[i].Save();
454
    }
455
456
78443
    for (size_t i = 0; i < num_values_; i++) {
457
465
      values_[i].Save();
458
    }
459
77978
  }
460
461
462
  // var bytesParsed = parser->execute(buffer);
463
16079
  static void Execute(const FunctionCallbackInfo<Value>& args) {
464
    Parser* parser;
465
32157
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
466
32158
    CHECK(parser->current_buffer_.IsEmpty());
467
16079
    CHECK_EQ(parser->current_buffer_len_, 0);
468
16079
    CHECK_NULL(parser->current_buffer_data_);
469
470
16079
    ArrayBufferViewContents<char> buffer(args[0]);
471
472
    // This is a hack to get the current_buffer to the callbacks with the least
473
    // amount of overhead. Nothing else will run while http_parser_execute()
474
    // runs, therefore this pointer can be set and used for the execution.
475
48237
    parser->current_buffer_ = args[0].As<Object>();
476
477
16079
    Local<Value> ret = parser->Execute(buffer.data(), buffer.length());
478
479
16078
    if (!ret.IsEmpty())
480
32152
      args.GetReturnValue().Set(ret);
481
  }
482
483
484
15934
  static void Finish(const FunctionCallbackInfo<Value>& args) {
485
    Parser* parser;
486
31868
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
487
488
31868
    CHECK(parser->current_buffer_.IsEmpty());
489
15934
    Local<Value> ret = parser->Execute(nullptr, 0);
490
491
15934
    if (!ret.IsEmpty())
492
44
      args.GetReturnValue().Set(ret);
493
  }
494
495
496
30575
  static void Initialize(const FunctionCallbackInfo<Value>& args) {
497
30575
    Environment* env = Environment::GetCurrent(args);
498
499
61150
    CHECK(args[0]->IsInt32());
500
61150
    CHECK(args[1]->IsObject());
501
502
    parser_type_t type =
503
91725
        static_cast<parser_type_t>(args[0].As<Int32>()->Value());
504
505

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

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

11
    CHECK_EQ(env, parser->env());
528
529
#ifdef NODE_EXPERIMENTAL_HTTP
530

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

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





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