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-09-17 22:33:17 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
199320
  StringPtr() {
87
199320
    on_heap_ = false;
88
199320
    Reset();
89
199320
  }
90
91
92
195426
  ~StringPtr() {
93
195426
    Reset();
94
195426
  }
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
249014
  void Save() {
101

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

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


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

6040
        current_buffer_data_(nullptr) {
161
3020
  }
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
127705
  int on_message_begin() {
172
127705
    num_fields_ = num_values_ = 0;
173
127705
    url_.Reset();
174
127705
    status_message_.Reset();
175
127705
    return 0;
176
  }
177
178
179
114816
  int on_url(const char* at, size_t length) {
180
114816
    int rv = TrackHeader(length);
181
114816
    if (rv != 0) {
182
      return rv;
183
    }
184
185
114816
    url_.Update(at, length);
186
114816
    return 0;
187
  }
188
189
190
12879
  int on_status(const char* at, size_t length) {
191
12879
    int rv = TrackHeader(length);
192
12879
    if (rv != 0) {
193
      return rv;
194
    }
195
196
12879
    status_message_.Update(at, length);
197
12879
    return 0;
198
  }
199
200
201
187666
  int on_header_field(const char* at, size_t length) {
202
187666
    int rv = TrackHeader(length);
203
187666
    if (rv != 0) {
204
      return rv;
205
    }
206
207
187666
    if (num_fields_ == num_values_) {
208
      // start of new field name
209
187637
      num_fields_++;
210
187637
      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
187637
      fields_[num_fields_ - 1].Reset();
217
    }
218
219
187666
    CHECK_LT(num_fields_, kMaxHeaderFieldsCount);
220
187666
    CHECK_EQ(num_fields_, num_values_ + 1);
221
222
187666
    fields_[num_fields_ - 1].Update(at, length);
223
224
187666
    return 0;
225
  }
226
227
228
187844
  int on_header_value(const char* at, size_t length) {
229
187844
    int rv = TrackHeader(length);
230
187844
    if (rv != 0) {
231
13
      return rv;
232
    }
233
234
187831
    if (num_values_ != num_fields_) {
235
      // start of new header value
236
187614
      num_values_++;
237
187614
      values_[num_values_ - 1].Reset();
238
    }
239
240
187831
    CHECK_LT(num_values_, arraysize(values_));
241
187831
    CHECK_EQ(num_values_, num_fields_);
242
243
187831
    values_[num_values_ - 1].Update(at, length);
244
245
187831
    return 0;
246
  }
247
248
249
127657
  int on_headers_complete() {
250
#ifdef NODE_EXPERIMENTAL_HTTP
251
127654
    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
1276570
    Local<Value> argv[A_MAX];
271
127657
    Local<Object> obj = object();
272
    Local<Value> cb = obj->Get(env()->context(),
273
382971
                               kOnHeadersComplete).ToLocalChecked();
274
275
127657
    if (!cb->IsFunction())
276
      return 0;
277
278
127657
    Local<Value> undefined = Undefined(env()->isolate());
279
1276570
    for (size_t i = 0; i < arraysize(argv); i++)
280
1148913
      argv[i] = undefined;
281
282
127657
    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
255282
      argv[A_HEADERS] = CreateHeaders();
288
127641
      if (parser_.type == HTTP_REQUEST)
289
229556
        argv[A_URL] = url_.ToString(env());
290
    }
291
292
127657
    num_fields_ = 0;
293
127657
    num_values_ = 0;
294
295
    // METHOD
296
127657
    if (parser_.type == HTTP_REQUEST) {
297
      argv[A_METHOD] =
298
229572
          Uint32::NewFromUnsigned(env()->isolate(), parser_.method);
299
    }
300
301
    // STATUS
302
127657
    if (parser_.type == HTTP_RESPONSE) {
303
      argv[A_STATUS_CODE] =
304
25742
          Integer::New(env()->isolate(), parser_.status_code);
305
25742
      argv[A_STATUS_MESSAGE] = status_message_.ToString(env());
306
    }
307
308
    // VERSION
309
255314
    argv[A_VERSION_MAJOR] = Integer::New(env()->isolate(), parser_.http_major);
310
255314
    argv[A_VERSION_MINOR] = Integer::New(env()->isolate(), parser_.http_minor);
311
312
    bool should_keep_alive;
313
#ifdef NODE_EXPERIMENTAL_HTTP
314
127654
    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
255314
        Boolean::New(env()->isolate(), should_keep_alive);
321
322
255314
    argv[A_UPGRADE] = Boolean::New(env()->isolate(), parser_.upgrade);
323
324
127657
    AsyncCallbackScope callback_scope(env());
325
326
    MaybeLocal<Value> head_response =
327
255314
        MakeCallback(cb.As<Function>(), arraysize(argv), argv);
328
329
    int64_t val;
330
331

638268
    if (head_response.IsEmpty() || !head_response.ToLocalChecked()
332
638247
                                        ->IntegerValue(env()->context())
333
510599
                                        .To(&val)) {
334
7
      got_exception_ = true;
335
7
      return -1;
336
    }
337
338
127648
    return val;
339
  }
340
341
342
23274
  int on_body(const char* at, size_t length) {
343
23274
    EscapableHandleScope scope(env()->isolate());
344
345
23274
    Local<Object> obj = object();
346
69822
    Local<Value> cb = obj->Get(env()->context(), kOnBody).ToLocalChecked();
347
348
23274
    if (!cb->IsFunction())
349
      return 0;
350
351
    // We came from consumed stream
352
46548
    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
5296
          current_buffer_len_).ToLocalChecked());
358
    }
359
360
    Local<Value> argv[3] = {
361
      current_buffer_,
362
23274
      Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
363
      Integer::NewFromUnsigned(env()->isolate(), length)
364
116370
    };
365
366
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
367
23274
                                       arraysize(argv),
368
46548
                                       argv);
369
370
23274
    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
23274
    return 0;
379
  }
380
381
382
126461
  int on_message_complete() {
383
126461
    HandleScope scope(env()->isolate());
384
385
126461
    if (num_fields_)
386
4
      Flush();  // Flush trailing HTTP headers.
387
388
126461
    Local<Object> obj = object();
389
    Local<Value> cb = obj->Get(env()->context(),
390
379383
                               kOnMessageComplete).ToLocalChecked();
391
392
126461
    if (!cb->IsFunction())
393
2
      return 0;
394
395
252918
    AsyncCallbackScope callback_scope(env());
396
397
126459
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(), 0, nullptr);
398
399
126459
    if (r.IsEmpty()) {
400
      got_exception_ = true;
401
      return -1;
402
    }
403
404
252920
    return 0;
405
  }
406
407
#ifdef NODE_EXPERIMENTAL_HTTP
408
  // Reset nread for the next chunk
409
27213
  int on_chunk_header() {
410
27213
    header_nread_ = 0;
411
27213
    return 0;
412
  }
413
414
415
  // Reset nread for the next chunk
416
27058
  int on_chunk_complete() {
417
27058
    header_nread_ = 0;
418
27058
    return 0;
419
  }
420
#endif  /* NODE_EXPERIMENTAL_HTTP */
421
422
423
3020
  static void New(const FunctionCallbackInfo<Value>& args) {
424
3020
    Environment* env = Environment::GetCurrent(args);
425
3020
    new Parser(env, args.This());
426
3020
  }
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
43602
  static void Free(const FunctionCallbackInfo<Value>& args) {
438
    Parser* parser;
439
87204
    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
43602
    parser->EmitTraceEventDestroy();
444
43602
    parser->EmitDestroy();
445
  }
446
447
448
123666
  void Save() {
449
123666
    url_.Save();
450
123666
    status_message_.Save();
451
452
124536
    for (size_t i = 0; i < num_fields_; i++) {
453
870
      fields_[i].Save();
454
    }
455
456
124478
    for (size_t i = 0; i < num_values_; i++) {
457
812
      values_[i].Save();
458
    }
459
123666
  }
460
461
462
  // var bytesParsed = parser->execute(buffer);
463
16560
  static void Execute(const FunctionCallbackInfo<Value>& args) {
464
    Parser* parser;
465
33119
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
466
33120
    CHECK(parser->current_buffer_.IsEmpty());
467
16560
    CHECK_EQ(parser->current_buffer_len_, 0);
468
16560
    CHECK_NULL(parser->current_buffer_data_);
469
470
16560
    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
49680
    parser->current_buffer_ = args[0].As<Object>();
476
477
16560
    Local<Value> ret = parser->Execute(buffer.data(), buffer.length());
478
479
16559
    if (!ret.IsEmpty())
480
33114
      args.GetReturnValue().Set(ret);
481
  }
482
483
484
29137
  static void Finish(const FunctionCallbackInfo<Value>& args) {
485
    Parser* parser;
486
58274
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
487
488
58274
    CHECK(parser->current_buffer_.IsEmpty());
489
29137
    Local<Value> ret = parser->Execute(nullptr, 0);
490
491
29137
    if (!ret.IsEmpty())
492
48
      args.GetReturnValue().Set(ret);
493
  }
494
495
496
43808
  static void Initialize(const FunctionCallbackInfo<Value>& args) {
497
43808
    Environment* env = Environment::GetCurrent(args);
498
499
87616
    CHECK(args[0]->IsInt32());
500
87616
    CHECK(args[1]->IsObject());
501
502
    parser_type_t type =
503
131424
        static_cast<parser_type_t>(args[0].As<Int32>()->Value());
504
505

43808
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
506
    Parser* parser;
507
87616
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
508
    // Should always be called from the same context.
509
43808
    CHECK_EQ(env, parser->env());
510
511
    AsyncWrap::ProviderType provider =
512
        (type == HTTP_REQUEST ?
513
            AsyncWrap::PROVIDER_HTTPINCOMINGMESSAGE
514
43808
            : AsyncWrap::PROVIDER_HTTPCLIENTREQUEST);
515
516
43808
    parser->set_provider_type(provider);
517
87616
    parser->AsyncReset(args[1].As<Object>());
518
43808
    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
31180
  static void Consume(const FunctionCallbackInfo<Value>& args) {
547
    Parser* parser;
548
62360
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
549
62360
    CHECK(args[0]->IsObject());
550
62360
    StreamBase* stream = StreamBase::FromObject(args[0].As<Object>());
551
31180
    CHECK_NOT_NULL(stream);
552
31180
    stream->PushStreamListener(parser);
553
  }
554
555
556
31161
  static void Unconsume(const FunctionCallbackInfo<Value>& args) {
557
    Parser* parser;
558
31161
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
559
560
    // Already unconsumed
561
31161
    if (parser->stream_ == nullptr)
562
      return;
563
564
31161
    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
135578
  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
135578
    if (env()->http_parser_buffer_in_use())
588
      return uv_buf_init(Malloc(suggested_size), suggested_size);
589
135578
    env()->set_http_parser_buffer_in_use(true);
590
591
135578
    if (env()->http_parser_buffer() == nullptr)
592
298
      env()->set_http_parser_buffer(new char[kAllocBufferSize]);
593
594
135578
    return uv_buf_init(env()->http_parser_buffer(), kAllocBufferSize);
595
  }
596
597
598
135595
  void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override {
599
135595
    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
135589
    OnScopeLeave on_scope_leave([&]() {
604
135589
      if (buf.base == env()->http_parser_buffer())
605
135572
        env()->set_http_parser_buffer_in_use(false);
606
      else
607
17
        free(buf.base);
608
377279
    });
609
610
135595
    if (nread < 0) {
611
28487
      PassReadErrorToPreviousListener(nread);
612
28487
      return;
613
    }
614
615
    // Ignore, empty reads have special meaning in http parser
616
107108
    if (nread == 0)
617
      return;
618
619
107108
    current_buffer_.Clear();
620
107108
    Local<Value> ret = Execute(buf.base, nread);
621
622
    // Exception
623
107107
    if (ret.IsEmpty())
624
5
      return;
625
626
    Local<Value> cb =
627
321306
        object()->Get(env()->context(), kOnExecute).ToLocalChecked();
628
629
107102
    if (!cb->IsFunction())
630
1002
      return;
631
632
    // Hooks for GetCurrentBuffer
633
106100
    current_buffer_len_ = nread;
634
106100
    current_buffer_data_ = buf.base;
635
636
106100
    MakeCallback(cb.As<Function>(), 1, &ret);
637
638
106095
    current_buffer_len_ = 0;
639
212190
    current_buffer_data_ = nullptr;
640
  }
641
642
643
152805
  Local<Value> Execute(const char* data, size_t len) {
644
152805
    EscapableHandleScope scope(env()->isolate());
645
646
152805
    current_buffer_len_ = len;
647
152805
    current_buffer_data_ = data;
648
152805
    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
152786
    CHECK_EQ(execute_depth_, 0);
655
656
152786
    execute_depth_++;
657
152786
    if (data == nullptr) {
658
29131
      err = llhttp_finish(&parser_);
659
    } else {
660
123655
      err = llhttp_execute(&parser_, data, len);
661
123653
      Save();
662
    }
663
152784
    execute_depth_--;
664
665
    // Calculate bytes read and resume after Upgrade/CONNECT pause
666
152784
    size_t nread = len;
667
152784
    if (err != HPE_OK) {
668
314
      nread = llhttp_get_error_pos(&parser_) - data;
669
670
      // This isn't a real pause, just a way to stop parsing early.
671
314
      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
152784
    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
152803
    current_buffer_.Clear();
710
152803
    current_buffer_len_ = 0;
711
152803
    current_buffer_data_ = nullptr;
712
713
    // If there was an exception in one of the callbacks
714
152803
    if (got_exception_)
715
7
      return scope.Escape(Local<Value>());
716
717
152796
    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

152796
    if (!parser_.upgrade && err != HPE_OK) {
722
215
      Local<Value> e = Exception::Error(env()->parse_error_string());
723
430
      Local<Object> obj = e->ToObject(env()->isolate()->GetCurrentContext())
724
430
        .ToLocalChecked();
725
      obj->Set(env()->context(),
726
               env()->bytes_parsed_string(),
727
860
               nread_obj).Check();
728
#ifdef NODE_EXPERIMENTAL_HTTP
729
205
      const char* errno_reason = llhttp_get_error_reason(&parser_);
730
731
      Local<String> code;
732
      Local<String> reason;
733
205
      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
192
        code = OneByteString(env()->isolate(), llhttp_errno_name(err));
741
192
        reason = OneByteString(env()->isolate(), errno_reason);
742
      }
743
744
820
      obj->Set(env()->context(), env()->code_string(), code).Check();
745
820
      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
152581
    if (data == nullptr) {
757
29113
      return scope.Escape(Local<Value>());
758
    }
759
123468
    return scope.Escape(nread_obj);
760
  }
761
762
127708
  Local<Array> CreateHeaders() {
763
    // There could be extra entries but the max size should be fixed
764
8301020
    Local<Value> headers_v[kMaxHeaderFieldsCount * 2];
765
766
315261
    for (size_t i = 0; i < num_values_; ++i) {
767
375106
      headers_v[i * 2] = fields_[i].ToString(env());
768
375106
      headers_v[i * 2 + 1] = values_[i].ToString(env());
769
    }
770
771
127708
    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
43808
  void Init(parser_type_t type) {
803
#ifdef NODE_EXPERIMENTAL_HTTP
804
43794
    llhttp_init(&parser_, type, &settings);
805
43794
    header_nread_ = 0;
806
#else  /* !NODE_EXPERIMENTAL_HTTP */
807
14
    http_parser_init(&parser_, type);
808
#endif  /* NODE_EXPERIMENTAL_HTTP */
809
43808
    url_.Reset();
810
43808
    status_message_.Reset();
811
43808
    num_fields_ = 0;
812
43808
    num_values_ = 0;
813
43808
    have_flushed_ = false;
814
43808
    got_exception_ = false;
815
43808
  }
816
817
818
503205
  int TrackHeader(size_t len) {
819
#ifdef NODE_EXPERIMENTAL_HTTP
820
503130
    header_nread_ += len;
821
503130
    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
503192
    return 0;
827
  }
828
829
830
962492
  int MaybePause() {
831
#ifdef NODE_EXPERIMENTAL_HTTP
832
962398
    CHECK_NE(execute_depth_, 0);
833
834
962398
    if (!pending_pause_) {
835
962398
      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
962573
    static int Raw(parser_t* p, Args ... args) {
870
962573
      Parser* parser = ContainerOf(&Parser::parser_, p);
871
962573
      int rv = (parser->*Member)(std::forward<Args>(args)...);
872





962571
      if (rv == 0) {
873
962492
        rv = parser->MaybePause();
874
      }
875
962571
      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
756
void InitializeHttpParser(Local<Object> target,
914
                          Local<Value> unused,
915
                          Local<Context> context,
916
                          void* priv) {
917
756
  Environment* env = Environment::GetCurrent(context);
918
756
  Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
919
1512
  t->InstanceTemplate()->SetInternalFieldCount(1);
920
1512
  t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"));
921
922
756
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"),
923
2268
         Integer::New(env->isolate(), HTTP_REQUEST));
924
756
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"),
925
2268
         Integer::New(env->isolate(), HTTP_RESPONSE));
926
756
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"),
927
2268
         Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
928
756
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"),
929
2268
         Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
930
756
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"),
931
2268
         Integer::NewFromUnsigned(env->isolate(), kOnBody));
932
756
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"),
933
2268
         Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
934
756
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"),
935
2268
         Integer::NewFromUnsigned(env->isolate(), kOnExecute));
936
937
756
  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
77868
  HTTP_METHOD_MAP(V)
942
#undef V
943
  target->Set(env->context(),
944
              FIXED_ONE_BYTE_STRING(env->isolate(), "methods"),
945
3024
              methods).Check();
946
947
1512
  t->Inherit(AsyncWrap::GetConstructorTemplate(env));
948
756
  env->SetProtoMethod(t, "close", Parser::Close);
949
756
  env->SetProtoMethod(t, "free", Parser::Free);
950
756
  env->SetProtoMethod(t, "execute", Parser::Execute);
951
756
  env->SetProtoMethod(t, "finish", Parser::Finish);
952
756
  env->SetProtoMethod(t, "initialize", Parser::Initialize);
953
756
  env->SetProtoMethod(t, "pause", Parser::Pause<true>);
954
756
  env->SetProtoMethod(t, "resume", Parser::Pause<false>);
955
756
  env->SetProtoMethod(t, "consume", Parser::Consume);
956
756
  env->SetProtoMethod(t, "unconsume", Parser::Unconsume);
957
756
  env->SetProtoMethod(t, "getCurrentBuffer", Parser::GetCurrentBuffer);
958
959
  target->Set(env->context(),
960
              FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"),
961
4536
              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
756
}
968
969
}  // anonymous namespace
970
}  // namespace node