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.cc Lines: 398 422 94.3 %
Date: 2020-02-19 22:14:06 Branches: 186 250 74.4 %

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
#include "node.h"
23
#include "node_buffer.h"
24
#include "util.h"
25
26
#include "async_wrap-inl.h"
27
#include "env-inl.h"
28
#include "memory_tracker-inl.h"
29
#include "stream_base-inl.h"
30
#include "v8.h"
31
#include "llhttp.h"
32
33
#include <cstdlib>  // free()
34
#include <cstring>  // strdup(), strchr()
35
36
37
// This is a binding to llhttp (https://github.com/nodejs/llhttp)
38
// The goal is to decouple sockets from parsing for more javascript-level
39
// agility. A Buffer is read from a socket and passed to parser.execute().
40
// The parser then issues callbacks with slices of the data
41
//     parser.onMessageBegin
42
//     parser.onPath
43
//     parser.onBody
44
//     ...
45
// No copying is performed when slicing the buffer, only small reference
46
// allocations.
47
48
49
namespace node {
50
namespace {  // NOLINT(build/namespaces)
51
52
using v8::Array;
53
using v8::Boolean;
54
using v8::Context;
55
using v8::EscapableHandleScope;
56
using v8::Exception;
57
using v8::Function;
58
using v8::FunctionCallbackInfo;
59
using v8::FunctionTemplate;
60
using v8::HandleScope;
61
using v8::Int32;
62
using v8::Integer;
63
using v8::Local;
64
using v8::MaybeLocal;
65
using v8::Number;
66
using v8::Object;
67
using v8::String;
68
using v8::Uint32;
69
using v8::Undefined;
70
using v8::Value;
71
72
const uint32_t kOnHeaders = 0;
73
const uint32_t kOnHeadersComplete = 1;
74
const uint32_t kOnBody = 2;
75
const uint32_t kOnMessageComplete = 3;
76
const uint32_t kOnExecute = 4;
77
// Any more fields than this will be flushed into JS
78
const size_t kMaxHeaderFieldsCount = 32;
79
80
14293
inline bool IsOWS(char c) {
81

14293
  return c == ' ' || c == '\t';
82
}
83
84
// helper class for the Parser
85
struct StringPtr {
86
191796
  StringPtr() {
87
191796
    on_heap_ = false;
88
191796
    Reset();
89
191796
  }
90
91
92
379896
  ~StringPtr() {
93
189948
    Reset();
94
189948
  }
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
17028
  void Save() {
101

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

178
    } 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
178
      char* s = new char[size_ + size];
128
178
      memcpy(s, str_, size_);
129
178
      memcpy(s + size_, str, size);
130
131
178
      if (on_heap_)
132
177
        delete[] str_;
133
      else
134
1
        on_heap_ = true;
135
136
178
      str_ = s;
137
    }
138
44920
    size_ += size;
139
44920
  }
140
141
142
44662
  Local<String> ToString(Environment* env) const {
143
44662
    if (size_ != 0)
144
44598
      return OneByteString(env->isolate(), str_, size_);
145
    else
146
128
      return String::Empty(env->isolate());
147
  }
148
149
150
  // Strip trailing OWS (SPC or HTAB) from string.
151
14295
  Local<String> ToTrimmedString(Environment* env) {
152

14306
    while (size_ > 0 && IsOWS(str_[size_ - 1])) {
153
11
      size_--;
154
    }
155
14284
    return ToString(env);
156
  }
157
158
159
  const char* str_;
160
  bool on_heap_;
161
  size_t size_;
162
};
163
164


5756
class Parser : public AsyncWrap, public StreamListener {
165
 public:
166
2906
  Parser(Environment* env, Local<Object> wrap)
167
2906
      : AsyncWrap(env, wrap),
168
        current_buffer_len_(0),
169

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

64116
    if (head_response.IsEmpty() || !head_response.ToLocalChecked()
339
48083
                                        ->IntegerValue(env()->context())
340
16025
                                        .To(&val)) {
341
8
      got_exception_ = true;
342
8
      return -1;
343
    }
344
345
16025
    return val;
346
  }
347
348
349
12277
  int on_body(const char* at, size_t length) {
350
12277
    EscapableHandleScope scope(env()->isolate());
351
352
12277
    Local<Object> obj = object();
353
36831
    Local<Value> cb = obj->Get(env()->context(), kOnBody).ToLocalChecked();
354
355
12277
    if (!cb->IsFunction())
356
      return 0;
357
358
    // We came from consumed stream
359
24554
    if (current_buffer_.IsEmpty()) {
360
      // Make sure Buffer will be in parent HandleScope
361
1058
      current_buffer_ = scope.Escape(Buffer::Copy(
362
          env()->isolate(),
363
          current_buffer_data_,
364
1058
          current_buffer_len_).ToLocalChecked());
365
    }
366
367
    Local<Value> argv[3] = {
368
      current_buffer_,
369
12277
      Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
370
      Integer::NewFromUnsigned(env()->isolate(), length)
371
61385
    };
372
373
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
374
12277
                                       arraysize(argv),
375
24554
                                       argv);
376
377
12277
    if (r.IsEmpty()) {
378
      got_exception_ = true;
379
      llhttp_set_error_reason(&parser_, "HPE_JS_EXCEPTION:JS Exception");
380
      return HPE_USER;
381
    }
382
383
12277
    return 0;
384
  }
385
386
387
14837
  int on_message_complete() {
388
29674
    HandleScope scope(env()->isolate());
389
390
14837
    if (num_fields_)
391
4
      Flush();  // Flush trailing HTTP headers.
392
393
14837
    Local<Object> obj = object();
394
29674
    Local<Value> cb = obj->Get(env()->context(),
395
44511
                               kOnMessageComplete).ToLocalChecked();
396
397
14837
    if (!cb->IsFunction())
398
2
      return 0;
399
400
    MaybeLocal<Value> r;
401
    {
402
      InternalCallbackScope callback_scope(
403
29670
          this, InternalCallbackScope::kSkipTaskQueues);
404
59340
      r = cb.As<Function>()->Call(env()->context(), object(), 0, nullptr);
405
14835
      if (r.IsEmpty()) callback_scope.MarkAsFailed();
406
    }
407
408
14835
    if (r.IsEmpty()) {
409
      got_exception_ = true;
410
      return -1;
411
    }
412
413
14835
    return 0;
414
  }
415
416
  // Reset nread for the next chunk
417
10253
  int on_chunk_header() {
418
10253
    header_nread_ = 0;
419
10253
    return 0;
420
  }
421
422
423
  // Reset nread for the next chunk
424
10099
  int on_chunk_complete() {
425
10099
    header_nread_ = 0;
426
10099
    return 0;
427
  }
428
429
2906
  static void New(const FunctionCallbackInfo<Value>& args) {
430
2906
    Environment* env = Environment::GetCurrent(args);
431
2906
    new Parser(env, args.This());
432
2906
  }
433
434
435
3
  static void Close(const FunctionCallbackInfo<Value>& args) {
436
    Parser* parser;
437
3
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
438
439
3
    delete parser;
440
  }
441
442
443
4994
  static void Free(const FunctionCallbackInfo<Value>& args) {
444
    Parser* parser;
445
4994
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
446
447
    // Since the Parser destructor isn't going to run the destroy() callbacks
448
    // it needs to be triggered manually.
449
4994
    parser->EmitTraceEventDestroy();
450
4994
    parser->EmitDestroy();
451
  }
452
453
454
7975
  void Save() {
455
7975
    url_.Save();
456
7975
    status_message_.Save();
457
458
8541
    for (size_t i = 0; i < num_fields_; i++) {
459
566
      fields_[i].Save();
460
    }
461
462
8487
    for (size_t i = 0; i < num_values_; i++) {
463
512
      values_[i].Save();
464
    }
465
7975
  }
466
467
468
  // var bytesParsed = parser->execute(buffer);
469
4358
  static void Execute(const FunctionCallbackInfo<Value>& args) {
470
    Parser* parser;
471
4358
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
472
8716
    CHECK(parser->current_buffer_.IsEmpty());
473
4358
    CHECK_EQ(parser->current_buffer_len_, 0);
474
4358
    CHECK_NULL(parser->current_buffer_data_);
475
476
4358
    ArrayBufferViewContents<char> buffer(args[0]);
477
478
    // This is a hack to get the current_buffer to the callbacks with the least
479
    // amount of overhead. Nothing else will run while http_parser_execute()
480
    // runs, therefore this pointer can be set and used for the execution.
481
13074
    parser->current_buffer_ = args[0].As<Object>();
482
483
4358
    Local<Value> ret = parser->Execute(buffer.data(), buffer.length());
484
485
4357
    if (!ret.IsEmpty())
486
8708
      args.GetReturnValue().Set(ret);
487
  }
488
489
490
864
  static void Finish(const FunctionCallbackInfo<Value>& args) {
491
    Parser* parser;
492
864
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
493
494
1728
    CHECK(parser->current_buffer_.IsEmpty());
495
864
    Local<Value> ret = parser->Execute(nullptr, 0);
496
497
864
    if (!ret.IsEmpty())
498
50
      args.GetReturnValue().Set(ret);
499
  }
500
501
502
5190
  static void Initialize(const FunctionCallbackInfo<Value>& args) {
503
5190
    Environment* env = Environment::GetCurrent(args);
504
10380
    bool lenient = args[3]->IsTrue();
505
506
5190
    uint64_t max_http_header_size = 0;
507
508
10380
    CHECK(args[0]->IsInt32());
509
10380
    CHECK(args[1]->IsObject());
510
511
5190
    if (args.Length() > 2) {
512
8040
      CHECK(args[2]->IsNumber());
513
12060
      max_http_header_size = args[2].As<Number>()->Value();
514
    }
515
5190
    if (max_http_header_size == 0) {
516
5188
      max_http_header_size = env->options()->max_http_header_size;
517
    }
518
519
    llhttp_type_t type =
520
15570
        static_cast<llhttp_type_t>(args[0].As<Int32>()->Value());
521
522

5190
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
523
    Parser* parser;
524
5190
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
525
    // Should always be called from the same context.
526
5190
    CHECK_EQ(env, parser->env());
527
528
    AsyncWrap::ProviderType provider =
529
5190
        (type == HTTP_REQUEST ?
530
            AsyncWrap::PROVIDER_HTTPINCOMINGMESSAGE
531
5190
            : AsyncWrap::PROVIDER_HTTPCLIENTREQUEST);
532
533
5190
    parser->set_provider_type(provider);
534
10380
    parser->AsyncReset(args[1].As<Object>());
535
5190
    parser->Init(type, max_http_header_size, lenient);
536
  }
537
538
  template <bool should_pause>
539
11
  static void Pause(const FunctionCallbackInfo<Value>& args) {
540
11
    Environment* env = Environment::GetCurrent(args);
541
    Parser* parser;
542

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

11
    CHECK_EQ(env, parser->env());
545
546

11
    if (parser->execute_depth_) {
547
4
      parser->pending_pause_ = should_pause;
548
4
      return;
549
    }
550
551
    if (should_pause) {
552
4
      llhttp_pause(&parser->parser_);
553
    } else {
554
3
      llhttp_resume(&parser->parser_);
555
    }
556
  }
557
558
559
2814
  static void Consume(const FunctionCallbackInfo<Value>& args) {
560
    Parser* parser;
561
2814
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
562
5628
    CHECK(args[0]->IsObject());
563
5628
    StreamBase* stream = StreamBase::FromObject(args[0].As<Object>());
564
2814
    CHECK_NOT_NULL(stream);
565
2814
    stream->PushStreamListener(parser);
566
  }
567
568
569
2805
  static void Unconsume(const FunctionCallbackInfo<Value>& args) {
570
    Parser* parser;
571
2805
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
572
573
    // Already unconsumed
574
2805
    if (parser->stream_ == nullptr)
575
      return;
576
577
2805
    parser->stream_->RemoveStreamListener(parser);
578
  }
579
580
581
49
  static void GetCurrentBuffer(const FunctionCallbackInfo<Value>& args) {
582
    Parser* parser;
583
49
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
584
585
98
    Local<Object> ret = Buffer::Copy(
586
        parser->env(),
587
        parser->current_buffer_data_,
588
98
        parser->current_buffer_len_).ToLocalChecked();
589
590
98
    args.GetReturnValue().Set(ret);
591
  }
592
593
 protected:
594
  static const size_t kAllocBufferSize = 64 * 1024;
595
596
3802
  uv_buf_t OnStreamAlloc(size_t suggested_size) override {
597
    // For most types of streams, OnStreamRead will be immediately after
598
    // OnStreamAlloc, and will consume all data, so using a static buffer for
599
    // reading is more efficient. For other streams, just use Malloc() directly.
600
3802
    if (env()->http_parser_buffer_in_use())
601
      return uv_buf_init(Malloc(suggested_size), suggested_size);
602
3802
    env()->set_http_parser_buffer_in_use(true);
603
604
3802
    if (env()->http_parser_buffer() == nullptr)
605
293
      env()->set_http_parser_buffer(new char[kAllocBufferSize]);
606
607
3802
    return uv_buf_init(env()->http_parser_buffer(), kAllocBufferSize);
608
  }
609
610
611
3820
  void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override {
612
6428
    HandleScope scope(env()->isolate());
613
    // Once we’re done here, either indicate that the HTTP parser buffer
614
    // is free for re-use, or free() the data if it didn’t come from there
615
    // in the first place.
616
3816
    auto on_scope_leave = OnScopeLeave([&]() {
617
3834
      if (buf.base == env()->http_parser_buffer())
618
3798
        env()->set_http_parser_buffer_in_use(false);
619
      else
620
18
        free(buf.base);
621
10244
    });
622
623
3820
    if (nread < 0) {
624
201
      PassReadErrorToPreviousListener(nread);
625
201
      return;
626
    }
627
628
    // Ignore, empty reads have special meaning in http parser
629
3619
    if (nread == 0)
630
      return;
631
632
3619
    current_buffer_.Clear();
633
3619
    Local<Value> ret = Execute(buf.base, nread);
634
635
    // Exception
636
3618
    if (ret.IsEmpty())
637
5
      return;
638
639
    Local<Value> cb =
640
10839
        object()->Get(env()->context(), kOnExecute).ToLocalChecked();
641
642
3613
    if (!cb->IsFunction())
643
1002
      return;
644
645
    // Hooks for GetCurrentBuffer
646
2611
    current_buffer_len_ = nread;
647
2611
    current_buffer_data_ = buf.base;
648
649
2611
    MakeCallback(cb.As<Function>(), 1, &ret);
650
651
2608
    current_buffer_len_ = 0;
652
2608
    current_buffer_data_ = nullptr;
653
  }
654
655
656
8841
  Local<Value> Execute(const char* data, size_t len) {
657
8841
    EscapableHandleScope scope(env()->isolate());
658
659
8841
    current_buffer_len_ = len;
660
8841
    current_buffer_data_ = data;
661
8841
    got_exception_ = false;
662
663
    llhttp_errno_t err;
664
665
    // Do not allow re-entering `http_parser_execute()`
666
8841
    CHECK_EQ(execute_depth_, 0);
667
668
8841
    execute_depth_++;
669
8841
    if (data == nullptr) {
670
864
      err = llhttp_finish(&parser_);
671
    } else {
672
7977
      err = llhttp_execute(&parser_, data, len);
673
7975
      Save();
674
    }
675
8839
    execute_depth_--;
676
677
    // Calculate bytes read and resume after Upgrade/CONNECT pause
678
8839
    size_t nread = len;
679
8839
    if (err != HPE_OK) {
680
320
      nread = llhttp_get_error_pos(&parser_) - data;
681
682
      // This isn't a real pause, just a way to stop parsing early.
683
320
      if (err == HPE_PAUSED_UPGRADE) {
684
50
        err = HPE_OK;
685
50
        llhttp_resume_after_upgrade(&parser_);
686
      }
687
    }
688
689
    // Apply pending pause
690
8839
    if (pending_pause_) {
691
      pending_pause_ = false;
692
      llhttp_pause(&parser_);
693
    }
694
695
    // Unassign the 'buffer_' variable
696
8839
    current_buffer_.Clear();
697
8839
    current_buffer_len_ = 0;
698
8839
    current_buffer_data_ = nullptr;
699
700
    // If there was an exception in one of the callbacks
701
8839
    if (got_exception_)
702
8
      return scope.Escape(Local<Value>());
703
704
8831
    Local<Integer> nread_obj = Integer::New(env()->isolate(), nread);
705
706
    // If there was a parse error in one of the callbacks
707
    // TODO(bnoordhuis) What if there is an error on EOF?
708

8831
    if (!parser_.upgrade && err != HPE_OK) {
709
212
      Local<Value> e = Exception::Error(env()->parse_error_string());
710
636
      Local<Object> obj = e->ToObject(env()->isolate()->GetCurrentContext())
711
212
        .ToLocalChecked();
712
424
      obj->Set(env()->context(),
713
               env()->bytes_parsed_string(),
714
848
               nread_obj).Check();
715
212
      const char* errno_reason = llhttp_get_error_reason(&parser_);
716
717
      Local<String> code;
718
      Local<String> reason;
719
212
      if (err == HPE_USER) {
720
15
        const char* colon = strchr(errno_reason, ':');
721
15
        CHECK_NOT_NULL(colon);
722
        code = OneByteString(env()->isolate(), errno_reason,
723
15
                             colon - errno_reason);
724
15
        reason = OneByteString(env()->isolate(), colon + 1);
725
      } else {
726
197
        code = OneByteString(env()->isolate(), llhttp_errno_name(err));
727
197
        reason = OneByteString(env()->isolate(), errno_reason);
728
      }
729
730
848
      obj->Set(env()->context(), env()->code_string(), code).Check();
731
848
      obj->Set(env()->context(), env()->reason_string(), reason).Check();
732
      return scope.Escape(e);
733
    }
734
735
    // No return value is needed for `Finish()`
736
8619
    if (data == nullptr) {
737
839
      return scope.Escape(Local<Value>());
738
    }
739
7780
    return scope.Escape(nread_obj);
740
  }
741
742
16086
  Local<Array> CreateHeaders() {
743
    // There could be extra entries but the max size should be fixed
744
1045590
    Local<Value> headers_v[kMaxHeaderFieldsCount * 2];
745
746
30370
    for (size_t i = 0; i < num_values_; ++i) {
747
28568
      headers_v[i * 2] = fields_[i].ToString(env());
748
28568
      headers_v[i * 2 + 1] = values_[i].ToTrimmedString(env());
749
    }
750
751
16086
    return Array::New(env()->isolate(), headers_v, num_values_ * 2);
752
  }
753
754
755
  // spill headers and request path to JS land
756
67
  void Flush() {
757
134
    HandleScope scope(env()->isolate());
758
759
67
    Local<Object> obj = object();
760
201
    Local<Value> cb = obj->Get(env()->context(), kOnHeaders).ToLocalChecked();
761
762
67
    if (!cb->IsFunction())
763
      return;
764
765
    Local<Value> argv[2] = {
766
      CreateHeaders(),
767
      url_.ToString(env())
768
201
    };
769
770
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
771
67
                                       arraysize(argv),
772
134
                                       argv);
773
774
67
    if (r.IsEmpty())
775
      got_exception_ = true;
776
777
67
    url_.Reset();
778
67
    have_flushed_ = true;
779
  }
780
781
782
5190
  void Init(llhttp_type_t type, uint64_t max_http_header_size, bool lenient) {
783
5190
    llhttp_init(&parser_, type, &settings);
784
5190
    llhttp_set_lenient(&parser_, lenient);
785
5190
    header_nread_ = 0;
786
5190
    url_.Reset();
787
5190
    status_message_.Reset();
788
5190
    num_fields_ = 0;
789
5190
    num_values_ = 0;
790
5190
    have_flushed_ = false;
791
5190
    got_exception_ = false;
792
5190
    max_http_header_size_ = max_http_header_size;
793
5190
  }
794
795
796
44935
  int TrackHeader(size_t len) {
797
44935
    header_nread_ += len;
798
44935
    if (header_nread_ >= max_http_header_size_) {
799
15
      llhttp_set_error_reason(&parser_, "HPE_HEADER_OVERFLOW:Header overflow");
800
15
      return HPE_USER;
801
    }
802
44920
    return 0;
803
  }
804
805
806
124432
  int MaybePause() {
807
124432
    CHECK_NE(execute_depth_, 0);
808
809
124432
    if (!pending_pause_) {
810
124432
      return 0;
811
    }
812
813
    pending_pause_ = false;
814
    llhttp_set_error_reason(&parser_, "Paused in callback");
815
    return HPE_PAUSED;
816
  }
817
818
  llhttp_t parser_;
819
  StringPtr fields_[kMaxHeaderFieldsCount];  // header fields
820
  StringPtr values_[kMaxHeaderFieldsCount];  // header values
821
  StringPtr url_;
822
  StringPtr status_message_;
823
  size_t num_fields_;
824
  size_t num_values_;
825
  bool have_flushed_;
826
  bool got_exception_;
827
  Local<Object> current_buffer_;
828
  size_t current_buffer_len_;
829
  const char* current_buffer_data_;
830
  unsigned int execute_depth_ = 0;
831
  bool pending_pause_ = false;
832
  uint64_t header_nread_ = 0;
833
  uint64_t max_http_header_size_;
834
835
  // These are helper functions for filling `http_parser_settings`, which turn
836
  // a member function of Parser into a C-style HTTP parser callback.
837
  template <typename Parser, Parser> struct Proxy;
838
  template <typename Parser, typename ...Args, int (Parser::*Member)(Args...)>
839
  struct Proxy<int (Parser::*)(Args...), Member> {
840
124515
    static int Raw(llhttp_t* p, Args ... args) {
841
124515
      Parser* parser = ContainerOf(&Parser::parser_, p);
842
124515
      int rv = (parser->*Member)(std::forward<Args>(args)...);
843





124513
      if (rv == 0) {
844
124432
        rv = parser->MaybePause();
845
      }
846
124513
      return rv;
847
    }
848
  };
849
850
  typedef int (Parser::*Call)();
851
  typedef int (Parser::*DataCall)(const char* at, size_t length);
852
853
  static const llhttp_settings_t settings;
854
};
855
856
const llhttp_settings_t Parser::settings = {
857
  Proxy<Call, &Parser::on_message_begin>::Raw,
858
  Proxy<DataCall, &Parser::on_url>::Raw,
859
  Proxy<DataCall, &Parser::on_status>::Raw,
860
  Proxy<DataCall, &Parser::on_header_field>::Raw,
861
  Proxy<DataCall, &Parser::on_header_value>::Raw,
862
  Proxy<Call, &Parser::on_headers_complete>::Raw,
863
  Proxy<DataCall, &Parser::on_body>::Raw,
864
  Proxy<Call, &Parser::on_message_complete>::Raw,
865
  Proxy<Call, &Parser::on_chunk_header>::Raw,
866
  Proxy<Call, &Parser::on_chunk_complete>::Raw,
867
};
868
869
870
668
void InitializeHttpParser(Local<Object> target,
871
                          Local<Value> unused,
872
                          Local<Context> context,
873
                          void* priv) {
874
668
  Environment* env = Environment::GetCurrent(context);
875
668
  Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
876
1336
  t->InstanceTemplate()->SetInternalFieldCount(1);
877
1336
  t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"));
878
879
2672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"),
880
668
         Integer::New(env->isolate(), HTTP_REQUEST));
881
2672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"),
882
668
         Integer::New(env->isolate(), HTTP_RESPONSE));
883
2672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"),
884
668
         Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
885
2672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"),
886
668
         Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
887
2672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"),
888
668
         Integer::NewFromUnsigned(env->isolate(), kOnBody));
889
2672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"),
890
668
         Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
891
2672
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"),
892
668
         Integer::NewFromUnsigned(env->isolate(), kOnExecute));
893
894
668
  Local<Array> methods = Array::New(env->isolate());
895
#define V(num, name, string)                                                  \
896
    methods->Set(env->context(),                                              \
897
        num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)).Check();
898
68804
  HTTP_METHOD_MAP(V)
899
#undef V
900
1336
  target->Set(env->context(),
901
              FIXED_ONE_BYTE_STRING(env->isolate(), "methods"),
902
2672
              methods).Check();
903
904
1336
  t->Inherit(AsyncWrap::GetConstructorTemplate(env));
905
668
  env->SetProtoMethod(t, "close", Parser::Close);
906
668
  env->SetProtoMethod(t, "free", Parser::Free);
907
668
  env->SetProtoMethod(t, "execute", Parser::Execute);
908
668
  env->SetProtoMethod(t, "finish", Parser::Finish);
909
668
  env->SetProtoMethod(t, "initialize", Parser::Initialize);
910
668
  env->SetProtoMethod(t, "pause", Parser::Pause<true>);
911
668
  env->SetProtoMethod(t, "resume", Parser::Pause<false>);
912
668
  env->SetProtoMethod(t, "consume", Parser::Consume);
913
668
  env->SetProtoMethod(t, "unconsume", Parser::Unconsume);
914
668
  env->SetProtoMethod(t, "getCurrentBuffer", Parser::GetCurrentBuffer);
915
916
1336
  target->Set(env->context(),
917
              FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"),
918
4008
              t->GetFunction(env->context()).ToLocalChecked()).Check();
919
668
}
920
921
}  // anonymous namespace
922
}  // namespace node
923
924
4185
NODE_MODULE_CONTEXT_AWARE_INTERNAL(http_parser, node::InitializeHttpParser)