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-13 22:28:55 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
197010
  StringPtr() {
87
197010
    on_heap_ = false;
88
197010
    Reset();
89
197010
  }
90
91
92
194106
  ~StringPtr() {
93
194106
    Reset();
94
194106
  }
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
250416
  void Save() {
101

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

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


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

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

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

44196
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
506
    Parser* parser;
507
88392
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
508
    // Should always be called from the same context.
509
44196
    CHECK_EQ(env, parser->env());
510
511
    AsyncWrap::ProviderType provider =
512
        (type == HTTP_REQUEST ?
513
            AsyncWrap::PROVIDER_HTTPINCOMINGMESSAGE
514
44196
            : AsyncWrap::PROVIDER_HTTPCLIENTREQUEST);
515
516
44196
    parser->set_provider_type(provider);
517
88392
    parser->AsyncReset(args[1].As<Object>());
518
44196
    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
31658
  static void Consume(const FunctionCallbackInfo<Value>& args) {
547
    Parser* parser;
548
63316
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
549
63316
    CHECK(args[0]->IsObject());
550
63316
    StreamBase* stream = StreamBase::FromObject(args[0].As<Object>());
551
31658
    CHECK_NOT_NULL(stream);
552
31658
    stream->PushStreamListener(parser);
553
  }
554
555
556
31639
  static void Unconsume(const FunctionCallbackInfo<Value>& args) {
557
    Parser* parser;
558
31639
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
559
560
    // Already unconsumed
561
31639
    if (parser->stream_ == nullptr)
562
      return;
563
564
31639
    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
136795
  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
136795
    if (env()->http_parser_buffer_in_use())
588
      return uv_buf_init(Malloc(suggested_size), suggested_size);
589
136795
    env()->set_http_parser_buffer_in_use(true);
590
591
136795
    if (env()->http_parser_buffer() == nullptr)
592
298
      env()->set_http_parser_buffer(new char[kAllocBufferSize]);
593
594
136795
    return uv_buf_init(env()->http_parser_buffer(), kAllocBufferSize);
595
  }
596
597
598
136812
  void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override {
599
136812
    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
136806
    OnScopeLeave on_scope_leave([&]() {
604
136806
      if (buf.base == env()->http_parser_buffer())
605
136789
        env()->set_http_parser_buffer_in_use(false);
606
      else
607
17
        free(buf.base);
608
380943
    });
609
610
136812
    if (nread < 0) {
611
28474
      PassReadErrorToPreviousListener(nread);
612
28474
      return;
613
    }
614
615
    // Ignore, empty reads have special meaning in http parser
616
108338
    if (nread == 0)
617
      return;
618
619
108338
    current_buffer_.Clear();
620
108338
    Local<Value> ret = Execute(buf.base, nread);
621
622
    // Exception
623
108337
    if (ret.IsEmpty())
624
5
      return;
625
626
    Local<Value> cb =
627
324996
        object()->Get(env()->context(), kOnExecute).ToLocalChecked();
628
629
108332
    if (!cb->IsFunction())
630
1002
      return;
631
632
    // Hooks for GetCurrentBuffer
633
107330
    current_buffer_len_ = nread;
634
107330
    current_buffer_data_ = buf.base;
635
636
107330
    MakeCallback(cb.As<Function>(), 1, &ret);
637
638
107325
    current_buffer_len_ = 0;
639
214650
    current_buffer_data_ = nullptr;
640
  }
641
642
643
153465
  Local<Value> Execute(const char* data, size_t len) {
644
153465
    EscapableHandleScope scope(env()->isolate());
645
646
153465
    current_buffer_len_ = len;
647
153465
    current_buffer_data_ = data;
648
153465
    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
153446
    CHECK_EQ(execute_depth_, 0);
655
656
153446
    execute_depth_++;
657
153446
    if (data == nullptr) {
658
29119
      err = llhttp_finish(&parser_);
659
    } else {
660
124327
      err = llhttp_execute(&parser_, data, len);
661
124325
      Save();
662
    }
663
153444
    execute_depth_--;
664
665
    // Calculate bytes read and resume after Upgrade/CONNECT pause
666
153444
    size_t nread = len;
667
153444
    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
153444
    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
153463
    current_buffer_.Clear();
710
153463
    current_buffer_len_ = 0;
711
153463
    current_buffer_data_ = nullptr;
712
713
    // If there was an exception in one of the callbacks
714
153463
    if (got_exception_)
715
7
      return scope.Escape(Local<Value>());
716
717
153456
    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

153456
    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
153241
    if (data == nullptr) {
757
29101
      return scope.Escape(Local<Value>());
758
    }
759
124140
    return scope.Escape(nread_obj);
760
  }
761
762
128819
  Local<Array> CreateHeaders() {
763
    // There could be extra entries but the max size should be fixed
764
8373235
    Local<Value> headers_v[kMaxHeaderFieldsCount * 2];
765
766
316592
    for (size_t i = 0; i < num_values_; ++i) {
767
375546
      headers_v[i * 2] = fields_[i].ToString(env());
768
375546
      headers_v[i * 2 + 1] = values_[i].ToString(env());
769
    }
770
771
128819
    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
44196
  void Init(parser_type_t type) {
803
#ifdef NODE_EXPERIMENTAL_HTTP
804
44182
    llhttp_init(&parser_, type, &settings);
805
44182
    header_nread_ = 0;
806
#else  /* !NODE_EXPERIMENTAL_HTTP */
807
14
    http_parser_init(&parser_, type);
808
#endif  /* NODE_EXPERIMENTAL_HTTP */
809
44196
    url_.Reset();
810
44196
    status_message_.Reset();
811
44196
    num_fields_ = 0;
812
44196
    num_values_ = 0;
813
44196
    have_flushed_ = false;
814
44196
    got_exception_ = false;
815
44196
  }
816
817
818
504775
  int TrackHeader(size_t len) {
819
#ifdef NODE_EXPERIMENTAL_HTTP
820
504700
    header_nread_ += len;
821
504700
    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
504762
    return 0;
827
  }
828
829
830
966889
  int MaybePause() {
831
#ifdef NODE_EXPERIMENTAL_HTTP
832
966795
    CHECK_NE(execute_depth_, 0);
833
834
966795
    if (!pending_pause_) {
835
966795
      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
966970
    static int Raw(parser_t* p, Args ... args) {
870
966970
      Parser* parser = ContainerOf(&Parser::parser_, p);
871
966970
      int rv = (parser->*Member)(std::forward<Args>(args)...);
872





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