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: 394 421 93.6 %
Date: 2019-03-02 22:23:06 Branches: 184 255 72.2 %

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

159081
    if (!on_heap_ && size_ > 0) {
103
73167
      char* s = new char[size_];
104
73167
      memcpy(s, str_, size_);
105
73167
      str_ = s;
106
73167
      on_heap_ = true;
107
    }
108
159081
  }
109
110
111
872188
  void Reset() {
112
872188
    if (on_heap_) {
113
73128
      delete[] str_;
114
73128
      on_heap_ = false;
115
    }
116
117
872188
    str_ = nullptr;
118
872188
    size_ = 0;
119
872188
  }
120
121
122
343034
  void Update(const char* str, size_t size) {
123
343034
    if (str_ == nullptr) {
124
342916
      str_ = str;
125

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


5646
class Parser : public AsyncWrap, public StreamListener {
158
 public:
159
2860
  Parser(Environment* env, Local<Object> wrap, parser_type_t type)
160
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTPPARSER),
161
        current_buffer_len_(0),
162

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

420843
    if (head_response.IsEmpty() || !head_response.ToLocalChecked()
335
420822
                                        ->IntegerValue(env()->context())
336
336659
                                        .To(&val)) {
337
7
      got_exception_ = true;
338
7
      return -1;
339
    }
340
341
84163
    return val;
342
  }
343
344
345
21956
  int on_body(const char* at, size_t length) {
346
21956
    EscapableHandleScope scope(env()->isolate());
347
348
21956
    Local<Object> obj = object();
349
65868
    Local<Value> cb = obj->Get(env()->context(), kOnBody).ToLocalChecked();
350
351
21956
    if (!cb->IsFunction())
352
      return 0;
353
354
    // We came from consumed stream
355
43912
    if (current_buffer_.IsEmpty()) {
356
      // Make sure Buffer will be in parent HandleScope
357
      current_buffer_ = scope.Escape(Buffer::Copy(
358
          env()->isolate(),
359
          current_buffer_data_,
360
5478
          current_buffer_len_).ToLocalChecked());
361
    }
362
363
    Local<Value> argv[3] = {
364
      current_buffer_,
365
21956
      Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
366
      Integer::NewFromUnsigned(env()->isolate(), length)
367
109780
    };
368
369
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
370
21956
                                       arraysize(argv),
371
43912
                                       argv);
372
373
21956
    if (r.IsEmpty()) {
374
      got_exception_ = true;
375
#ifdef NODE_EXPERIMENTAL_HTTP
376
      llhttp_set_error_reason(&parser_, "HPE_JS_EXCEPTION:JS Exception");
377
#endif  /* NODE_EXPERIMENTAL_HTTP */
378
      return HPE_USER;
379
    }
380
381
21956
    return 0;
382
  }
383
384
385
82971
  int on_message_complete() {
386
82971
    HandleScope scope(env()->isolate());
387
388
82971
    if (num_fields_)
389
4
      Flush();  // Flush trailing HTTP headers.
390
391
82971
    Local<Object> obj = object();
392
    Local<Value> cb = obj->Get(env()->context(),
393
248913
                               kOnMessageComplete).ToLocalChecked();
394
395
82971
    if (!cb->IsFunction())
396
2
      return 0;
397
398
165938
    Environment::AsyncCallbackScope callback_scope(env());
399
400
82969
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(), 0, nullptr);
401
402
82969
    if (r.IsEmpty()) {
403
      got_exception_ = true;
404
      return -1;
405
    }
406
407
165940
    return 0;
408
  }
409
410
#ifdef NODE_EXPERIMENTAL_HTTP
411
  // Reset nread for the next chunk
412
27420
  int on_chunk_header() {
413
27420
    header_nread_ = 0;
414
27420
    return 0;
415
  }
416
417
418
  // Reset nread for the next chunk
419
27265
  int on_chunk_complete() {
420
27265
    header_nread_ = 0;
421
27265
    return 0;
422
  }
423
#endif  /* NODE_EXPERIMENTAL_HTTP */
424
425
426
2860
  static void New(const FunctionCallbackInfo<Value>& args) {
427
2860
    Environment* env = Environment::GetCurrent(args);
428
5720
    CHECK(args[0]->IsInt32());
429
    parser_type_t type =
430
8580
        static_cast<parser_type_t>(args[0].As<Int32>()->Value());
431

2860
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
432
2860
    new Parser(env, args.This(), type);
433
2860
  }
434
435
436
3
  static void Close(const FunctionCallbackInfo<Value>& args) {
437
    Parser* parser;
438
6
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
439
440
3
    delete parser;
441
  }
442
443
444
32057
  static void Free(const FunctionCallbackInfo<Value>& args) {
445
32057
    Environment* env = Environment::GetCurrent(args);
446
    Parser* parser;
447
64114
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
448
449
    // Since the Parser destructor isn't going to run the destroy() callbacks
450
    // it needs to be triggered manually.
451
32057
    parser->EmitTraceEventDestroy();
452
32057
    parser->EmitDestroy(env, parser->get_async_id());
453
  }
454
455
456
79219
  void Save() {
457
79219
    url_.Save();
458
79219
    status_message_.Save();
459
460
79566
    for (size_t i = 0; i < num_fields_; i++) {
461
347
      fields_[i].Save();
462
    }
463
464
79515
    for (size_t i = 0; i < num_values_; i++) {
465
296
      values_[i].Save();
466
    }
467
79219
  }
468
469
470
  // var bytesParsed = parser->execute(buffer);
471
15572
  static void Execute(const FunctionCallbackInfo<Value>& args) {
472
    Parser* parser;
473
31143
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
474
31144
    CHECK(parser->current_buffer_.IsEmpty());
475
15572
    CHECK_EQ(parser->current_buffer_len_, 0);
476
15572
    CHECK_NULL(parser->current_buffer_data_);
477
15572
    CHECK_EQ(Buffer::HasInstance(args[0]), true);
478
479
31144
    Local<Object> buffer_obj = args[0].As<Object>();
480
15572
    char* buffer_data = Buffer::Data(buffer_obj);
481
15572
    size_t buffer_len = Buffer::Length(buffer_obj);
482
483
    // This is a hack to get the current_buffer to the callbacks with the least
484
    // amount of overhead. Nothing else will run while http_parser_execute()
485
    // runs, therefore this pointer can be set and used for the execution.
486
15572
    parser->current_buffer_ = buffer_obj;
487
488
15572
    Local<Value> ret = parser->Execute(buffer_data, buffer_len);
489
490
15571
    if (!ret.IsEmpty())
491
31138
      args.GetReturnValue().Set(ret);
492
  }
493
494
495
831
  static void Finish(const FunctionCallbackInfo<Value>& args) {
496
    Parser* parser;
497
1662
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
498
499
1662
    CHECK(parser->current_buffer_.IsEmpty());
500
831
    Local<Value> ret = parser->Execute(nullptr, 0);
501
502
831
    if (!ret.IsEmpty())
503
58
      args.GetReturnValue().Set(ret);
504
  }
505
506
507
32092
  static void Reinitialize(const FunctionCallbackInfo<Value>& args) {
508
32092
    Environment* env = Environment::GetCurrent(args);
509
510
64184
    CHECK(args[0]->IsInt32());
511
64184
    CHECK(args[1]->IsBoolean());
512
64184
    bool isReused = args[1]->IsTrue();
513
    parser_type_t type =
514
96276
        static_cast<parser_type_t>(args[0].As<Int32>()->Value());
515
516

32092
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
517
    Parser* parser;
518
64184
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
519
    // Should always be called from the same context.
520
32092
    CHECK_EQ(env, parser->env());
521
    // This parser has either just been created or it is being reused.
522
    // We must only call AsyncReset for the latter case, because AsyncReset has
523
    // already been called via the constructor for the former case.
524
32092
    if (isReused) {
525
29397
      parser->AsyncReset();
526
    }
527
32092
    parser->Init(type);
528
  }
529
530
531
  template <bool should_pause>
532
11
  static void Pause(const FunctionCallbackInfo<Value>& args) {
533
11
    Environment* env = Environment::GetCurrent(args);
534
    Parser* parser;
535

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

11
    CHECK_EQ(env, parser->env());
538
539
#ifdef NODE_EXPERIMENTAL_HTTP
540

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

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





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