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-08-17 22:35:23 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
201168
  StringPtr() {
87
201168
    on_heap_ = false;
88
201168
    Reset();
89
201168
  }
90
91
92
198198
  ~StringPtr() {
93
198198
    Reset();
94
198198
  }
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
273863
  void Save() {
101

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

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


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

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

702788
    if (head_response.IsEmpty() || !head_response.ToLocalChecked()
332
702767
                                        ->IntegerValue(env()->context())
333
562215
                                        .To(&val)) {
334
7
      got_exception_ = true;
335
7
      return -1;
336
    }
337
338
140552
    return val;
339
  }
340
341
342
22823
  int on_body(const char* at, size_t length) {
343
22823
    EscapableHandleScope scope(env()->isolate());
344
345
22823
    Local<Object> obj = object();
346
68469
    Local<Value> cb = obj->Get(env()->context(), kOnBody).ToLocalChecked();
347
348
22823
    if (!cb->IsFunction())
349
      return 0;
350
351
    // We came from consumed stream
352
45646
    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
5520
          current_buffer_len_).ToLocalChecked());
358
    }
359
360
    Local<Value> argv[3] = {
361
      current_buffer_,
362
22823
      Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
363
      Integer::NewFromUnsigned(env()->isolate(), length)
364
114115
    };
365
366
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
367
22823
                                       arraysize(argv),
368
45646
                                       argv);
369
370
22823
    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
22823
    return 0;
379
  }
380
381
382
139368
  int on_message_complete() {
383
139368
    HandleScope scope(env()->isolate());
384
385
139368
    if (num_fields_)
386
4
      Flush();  // Flush trailing HTTP headers.
387
388
139368
    Local<Object> obj = object();
389
    Local<Value> cb = obj->Get(env()->context(),
390
418104
                               kOnMessageComplete).ToLocalChecked();
391
392
139368
    if (!cb->IsFunction())
393
2
      return 0;
394
395
278732
    AsyncCallbackScope callback_scope(env());
396
397
139366
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(), 0, nullptr);
398
399
139366
    if (r.IsEmpty()) {
400
      got_exception_ = true;
401
      return -1;
402
    }
403
404
278734
    return 0;
405
  }
406
407
#ifdef NODE_EXPERIMENTAL_HTTP
408
  // Reset nread for the next chunk
409
27464
  int on_chunk_header() {
410
27464
    header_nread_ = 0;
411
27464
    return 0;
412
  }
413
414
415
  // Reset nread for the next chunk
416
27309
  int on_chunk_complete() {
417
27309
    header_nread_ = 0;
418
27309
    return 0;
419
  }
420
#endif  /* NODE_EXPERIMENTAL_HTTP */
421
422
423
3048
  static void New(const FunctionCallbackInfo<Value>& args) {
424
3048
    Environment* env = Environment::GetCurrent(args);
425
3048
    new Parser(env, args.This());
426
3048
  }
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
44097
  static void Free(const FunctionCallbackInfo<Value>& args) {
438
    Parser* parser;
439
88194
    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
44097
    parser->EmitTraceEventDestroy();
444
44097
    parser->EmitDestroy();
445
  }
446
447
448
136100
  void Save() {
449
136100
    url_.Save();
450
136100
    status_message_.Save();
451
452
136961
    for (size_t i = 0; i < num_fields_; i++) {
453
861
      fields_[i].Save();
454
    }
455
456
136902
    for (size_t i = 0; i < num_values_; i++) {
457
802
      values_[i].Save();
458
    }
459
136100
  }
460
461
462
  // var bytesParsed = parser->execute(buffer);
463
16109
  static void Execute(const FunctionCallbackInfo<Value>& args) {
464
    Parser* parser;
465
32217
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
466
32218
    CHECK(parser->current_buffer_.IsEmpty());
467
16109
    CHECK_EQ(parser->current_buffer_len_, 0);
468
16109
    CHECK_NULL(parser->current_buffer_data_);
469
470
16109
    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
48327
    parser->current_buffer_ = args[0].As<Object>();
476
477
16109
    Local<Value> ret = parser->Execute(buffer.data(), buffer.length());
478
479
16108
    if (!ret.IsEmpty())
480
32212
      args.GetReturnValue().Set(ret);
481
  }
482
483
484
29130
  static void Finish(const FunctionCallbackInfo<Value>& args) {
485
    Parser* parser;
486
58260
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
487
488
58260
    CHECK(parser->current_buffer_.IsEmpty());
489
29130
    Local<Value> ret = parser->Execute(nullptr, 0);
490
491
29130
    if (!ret.IsEmpty())
492
42
      args.GetReturnValue().Set(ret);
493
  }
494
495
496
44303
  static void Initialize(const FunctionCallbackInfo<Value>& args) {
497
44303
    Environment* env = Environment::GetCurrent(args);
498
499
88606
    CHECK(args[0]->IsInt32());
500
88606
    CHECK(args[1]->IsObject());
501
502
    parser_type_t type =
503
132909
        static_cast<parser_type_t>(args[0].As<Int32>()->Value());
504
505

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

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





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