GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_http_parser.cc Lines: 355 367 96.7 %
Date: 2017-11-19 Branches: 149 198 75.3 %

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

8915
    if (!on_heap_ && size_ > 0) {
109
2910
      char* s = new char[size_];
110
2910
      memcpy(s, str_, size_);
111
2910
      str_ = s;
112
2910
      on_heap_ = true;
113
    }
114
8915
  }
115
116
117
208155
  void Reset() {
118
208155
    if (on_heap_) {
119
836
      delete[] str_;
120
836
      on_heap_ = false;
121
    }
122
123
208155
    str_ = nullptr;
124
208155
    size_ = 0;
125
208155
  }
126
127
128
53662
  void Update(const char* str, size_t size) {
129
53662
    if (str_ == nullptr) {
130
53605
      str_ = str;
131

57
    } else if (on_heap_ || str_ + size_ != str) {
132
      // Non-consecutive input, make a copy on the heap.
133
      // TODO(bnoordhuis) Use slab allocation, O(n) allocs is bad.
134
57
      char* s = new char[size_ + size];
135
57
      memcpy(s, str_, size_);
136
57
      memcpy(s + size_, str, size);
137
138
57
      if (on_heap_)
139
56
        delete[] str_;
140
      else
141
1
        on_heap_ = true;
142
143
57
      str_ = s;
144
    }
145
53662
    size_ += size;
146
53662
  }
147
148
149
53987
  Local<String> ToString(Environment* env) const {
150
53987
    if (str_)
151
53579
      return OneByteString(env->isolate(), str_, size_);
152
    else
153
816
      return String::Empty(env->isolate());
154
  }
155
156
157
  const char* str_;
158
  bool on_heap_;
159
  size_t size_;
160
};
161
162
163
class Parser : public AsyncWrap {
164
 public:
165
1986
  Parser(Environment* env, Local<Object> wrap, enum http_parser_type type)
166
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTPPARSER),
167
        current_buffer_len_(0),
168

3972
        current_buffer_data_(nullptr) {
169
1986
    Wrap(object(), this);
170
1986
    Init(type);
171
1986
  }
172
173
174


15
  ~Parser() override {
175
5
    ClearWrap(object());
176
5
    persistent().Reset();
177
10
  }
178
179
180
  size_t self_size() const override {
181
    return sizeof(*this);
182
  }
183
184
185
28016
  HTTP_CB(on_message_begin) {
186
14008
    num_fields_ = num_values_ = 0;
187
14008
    url_.Reset();
188
14008
    status_message_.Reset();
189
14008
    return 0;
190
  }
191
192
193
24434
  HTTP_DATA_CB(on_url) {
194
12217
    url_.Update(at, length);
195
12217
    return 0;
196
  }
197
198
199
3584
  HTTP_DATA_CB(on_status) {
200
1792
    status_message_.Update(at, length);
201
1792
    return 0;
202
  }
203
204
205
39662
  HTTP_DATA_CB(on_header_field) {
206
19831
    if (num_fields_ == num_values_) {
207
      // start of new field name
208
19802
      num_fields_++;
209
19802
      if (num_fields_ == arraysize(fields_)) {
210
        // ran out of space - flush to javascript land
211
395
        Flush();
212
395
        num_fields_ = 1;
213
395
        num_values_ = 0;
214
      }
215
19802
      fields_[num_fields_ - 1].Reset();
216
    }
217
218
19831
    CHECK_LT(num_fields_, arraysize(fields_));
219
19831
    CHECK_EQ(num_fields_, num_values_ + 1);
220
221
19831
    fields_[num_fields_ - 1].Update(at, length);
222
223
19831
    return 0;
224
  }
225
226
227
39644
  HTTP_DATA_CB(on_header_value) {
228
19822
    if (num_values_ != num_fields_) {
229
      // start of new header value
230
19802
      num_values_++;
231
19802
      values_[num_values_ - 1].Reset();
232
    }
233
234
19822
    CHECK_LT(num_values_, arraysize(values_));
235
19822
    CHECK_EQ(num_values_, num_fields_);
236
237
19822
    values_[num_values_ - 1].Update(at, length);
238
239
19822
    return 0;
240
  }
241
242
243
27998
  HTTP_CB(on_headers_complete) {
244
    // Arguments for the on-headers-complete javascript callback. This
245
    // list needs to be kept in sync with the actual argument list for
246
    // `parserOnHeadersComplete` in lib/_http_common.js.
247
    enum on_headers_complete_arg_index {
248
      A_VERSION_MAJOR = 0,
249
      A_VERSION_MINOR,
250
      A_HEADERS,
251
      A_METHOD,
252
      A_URL,
253
      A_STATUS_CODE,
254
      A_STATUS_MESSAGE,
255
      A_UPGRADE,
256
      A_SHOULD_KEEP_ALIVE,
257
      A_MAX
258
    };
259
260
139990
    Local<Value> argv[A_MAX];
261
13999
    Local<Object> obj = object();
262
13999
    Local<Value> cb = obj->Get(kOnHeadersComplete);
263
264
13999
    if (!cb->IsFunction())
265
      return 0;
266
267
13999
    Local<Value> undefined = Undefined(env()->isolate());
268
139990
    for (size_t i = 0; i < arraysize(argv); i++)
269
125991
      argv[i] = undefined;
270
271
13999
    if (have_flushed_) {
272
      // Slow case, flush remaining headers.
273
10
      Flush();
274
    } else {
275
      // Fast case, pass headers and URL to JS land.
276
27978
      argv[A_HEADERS] = CreateHeaders();
277
13989
      if (parser_.type == HTTP_REQUEST)
278
24400
        argv[A_URL] = url_.ToString(env());
279
    }
280
281
13999
    num_fields_ = 0;
282
13999
    num_values_ = 0;
283
284
    // METHOD
285
13999
    if (parser_.type == HTTP_REQUEST) {
286
      argv[A_METHOD] =
287
24410
          Uint32::NewFromUnsigned(env()->isolate(), parser_.method);
288
    }
289
290
    // STATUS
291
13999
    if (parser_.type == HTTP_RESPONSE) {
292
      argv[A_STATUS_CODE] =
293
3588
          Integer::New(env()->isolate(), parser_.status_code);
294
3588
      argv[A_STATUS_MESSAGE] = status_message_.ToString(env());
295
    }
296
297
    // VERSION
298
27998
    argv[A_VERSION_MAJOR] = Integer::New(env()->isolate(), parser_.http_major);
299
27998
    argv[A_VERSION_MINOR] = Integer::New(env()->isolate(), parser_.http_minor);
300
301
    argv[A_SHOULD_KEEP_ALIVE] =
302
27998
        Boolean::New(env()->isolate(), http_should_keep_alive(&parser_));
303
304
27998
    argv[A_UPGRADE] = Boolean::New(env()->isolate(), parser_.upgrade);
305
306
13999
    Environment::AsyncCallbackScope callback_scope(env());
307
308
    MaybeLocal<Value> head_response =
309
27998
        MakeCallback(cb.As<Function>(), arraysize(argv), argv);
310
311
13995
    if (head_response.IsEmpty()) {
312
7
      got_exception_ = true;
313
7
      return -1;
314
    }
315
316
27976
    return head_response.ToLocalChecked()->IntegerValue();
317
  }
318
319
320
12374
  HTTP_DATA_CB(on_body) {
321
6187
    EscapableHandleScope scope(env()->isolate());
322
323
6187
    Local<Object> obj = object();
324
6187
    Local<Value> cb = obj->Get(kOnBody);
325
326
6187
    if (!cb->IsFunction())
327
      return 0;
328
329
    // We came from consumed stream
330
12374
    if (current_buffer_.IsEmpty()) {
331
      // Make sure Buffer will be in parent HandleScope
332
      current_buffer_ = scope.Escape(Buffer::Copy(
333
          env()->isolate(),
334
          current_buffer_data_,
335
1214
          current_buffer_len_).ToLocalChecked());
336
    }
337
338
    Local<Value> argv[3] = {
339
      current_buffer_,
340
6187
      Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
341
      Integer::NewFromUnsigned(env()->isolate(), length)
342
30935
    };
343
344
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
345
6187
                                       arraysize(argv),
346
12374
                                       argv);
347
348
6187
    if (r.IsEmpty()) {
349
      got_exception_ = true;
350
      return -1;
351
    }
352
353
6187
    return 0;
354
  }
355
356
357
25622
  HTTP_CB(on_message_complete) {
358
12811
    HandleScope scope(env()->isolate());
359
360
12811
    if (num_fields_)
361
4
      Flush();  // Flush trailing HTTP headers.
362
363
12811
    Local<Object> obj = object();
364
12811
    Local<Value> cb = obj->Get(kOnMessageComplete);
365
366
12811
    if (!cb->IsFunction())
367
4
      return 0;
368
369
25614
    Environment::AsyncCallbackScope callback_scope(env());
370
371
12807
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(), 0, nullptr);
372
373
12807
    if (r.IsEmpty()) {
374
      got_exception_ = true;
375
      return -1;
376
    }
377
378
25618
    return 0;
379
  }
380
381
382
1986
  static void New(const FunctionCallbackInfo<Value>& args) {
383
1986
    Environment* env = Environment::GetCurrent(args);
384
    http_parser_type type =
385
3972
        static_cast<http_parser_type>(args[0]->Int32Value());
386

1986
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
387
1986
    new Parser(env, args.This(), type);
388
1986
  }
389
390
391
5
  static void Close(const FunctionCallbackInfo<Value>& args) {
392
    Parser* parser;
393
10
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
394
395
5
    if (--parser->refcount_ == 0)
396
4
      delete parser;
397
  }
398
399
400
2345
  static void Free(const FunctionCallbackInfo<Value>& args) {
401
2345
    Environment* env = Environment::GetCurrent(args);
402
    Parser* parser;
403
4690
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
404
405
    // Since the Parser destructor isn't going to run the destroy() callbacks
406
    // it needs to be triggered manually.
407
2345
    parser->EmitTraceEventDestroy();
408
2345
    parser->EmitDestroy(env, parser->get_async_id());
409
  }
410
411
412
4366
  void Save() {
413
4366
    url_.Save();
414
4366
    status_message_.Save();
415
416
4474
    for (size_t i = 0; i < num_fields_; i++) {
417
108
      fields_[i].Save();
418
    }
419
420
4441
    for (size_t i = 0; i < num_values_; i++) {
421
75
      values_[i].Save();
422
    }
423
4366
  }
424
425
426
  // var bytesParsed = parser->execute(buffer);
427
2095
  static void Execute(const FunctionCallbackInfo<Value>& args) {
428
    Parser* parser;
429
4189
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
430
4190
    CHECK(parser->current_buffer_.IsEmpty());
431
2095
    CHECK_EQ(parser->current_buffer_len_, 0);
432
2095
    CHECK_EQ(parser->current_buffer_data_, nullptr);
433
2095
    CHECK_EQ(Buffer::HasInstance(args[0]), true);
434
435
4190
    Local<Object> buffer_obj = args[0].As<Object>();
436
2095
    char* buffer_data = Buffer::Data(buffer_obj);
437
2095
    size_t buffer_len = Buffer::Length(buffer_obj);
438
439
    // This is a hack to get the current_buffer to the callbacks with the least
440
    // amount of overhead. Nothing else will run while http_parser_execute()
441
    // runs, therefore this pointer can be set and used for the execution.
442
2095
    parser->current_buffer_ = buffer_obj;
443
444
2095
    Local<Value> ret = parser->Execute(buffer_data, buffer_len);
445
446
2094
    if (!ret.IsEmpty())
447
4184
      args.GetReturnValue().Set(ret);
448
  }
449
450
451
268
  static void Finish(const FunctionCallbackInfo<Value>& args) {
452
268
    Environment* env = Environment::GetCurrent(args);
453
454
    Parser* parser;
455
268
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
456
457
536
    CHECK(parser->current_buffer_.IsEmpty());
458
268
    parser->got_exception_ = false;
459
460
268
    int rv = http_parser_execute(&(parser->parser_), &settings, nullptr, 0);
461
462
268
    if (parser->got_exception_)
463
      return;
464
465
268
    if (rv != 0) {
466
15
      enum http_errno err = HTTP_PARSER_ERRNO(&parser->parser_);
467
468
15
      Local<Value> e = Exception::Error(env->parse_error_string());
469
30
      Local<Object> obj = e->ToObject(env->isolate());
470
45
      obj->Set(env->bytes_parsed_string(), Integer::New(env->isolate(), 0));
471
      obj->Set(env->code_string(),
472
45
               OneByteString(env->isolate(), http_errno_name(err)));
473
474
30
      args.GetReturnValue().Set(e);
475
    }
476
  }
477
478
479
2374
  static void Reinitialize(const FunctionCallbackInfo<Value>& args) {
480
2374
    Environment* env = Environment::GetCurrent(args);
481
482
    http_parser_type type =
483
4748
        static_cast<http_parser_type>(args[0]->Int32Value());
484
485

2374
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
486
    Parser* parser;
487
4748
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
488
    // Should always be called from the same context.
489
2374
    CHECK_EQ(env, parser->env());
490
    // The parser is being reused. Reset the async id and call init() callbacks.
491
2374
    parser->AsyncReset();
492
2374
    parser->Init(type);
493
  }
494
495
496
  template <bool should_pause>
497
10
  static void Pause(const FunctionCallbackInfo<Value>& args) {
498
10
    Environment* env = Environment::GetCurrent(args);
499
    Parser* parser;
500

20
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
501
    // Should always be called from the same context.
502

10
    CHECK_EQ(env, parser->env());
503
10
    http_parser_pause(&parser->parser_, should_pause);
504
  }
505
506
507
1506
  static void Consume(const FunctionCallbackInfo<Value>& args) {
508
    Parser* parser;
509
3012
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
510
3012
    CHECK(args[0]->IsExternal());
511
3012
    Local<External> stream_obj = args[0].As<External>();
512
1506
    StreamBase* stream = static_cast<StreamBase*>(stream_obj->Value());
513
1506
    CHECK_NE(stream, nullptr);
514
515
1506
    stream->Consume();
516
517
1506
    parser->prev_alloc_cb_ = stream->alloc_cb();
518
1506
    parser->prev_read_cb_ = stream->read_cb();
519
520
1506
    stream->set_alloc_cb({ OnAllocImpl, parser });
521
1506
    stream->set_read_cb({ OnReadImpl, parser });
522
  }
523
524
525
1494
  static void Unconsume(const FunctionCallbackInfo<Value>& args) {
526
    Parser* parser;
527
1494
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
528
529
    // Already unconsumed
530
1494
    if (parser->prev_alloc_cb_.is_empty())
531
      return;
532
533
    // Restore stream's callbacks
534


5020
    if (args.Length() == 1 && args[0]->IsExternal()) {
535
2032
      Local<External> stream_obj = args[0].As<External>();
536
1016
      StreamBase* stream = static_cast<StreamBase*>(stream_obj->Value());
537
1016
      CHECK_NE(stream, nullptr);
538
539
1016
      stream->set_alloc_cb(parser->prev_alloc_cb_);
540
1016
      stream->set_read_cb(parser->prev_read_cb_);
541
1016
      stream->Unconsume();
542
    }
543
544
1494
    parser->prev_alloc_cb_.clear();
545
1494
    parser->prev_read_cb_.clear();
546
  }
547
548
549
13
  static void GetCurrentBuffer(const FunctionCallbackInfo<Value>& args) {
550
    Parser* parser;
551
26
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
552
553
    Local<Object> ret = Buffer::Copy(
554
        parser->env(),
555
        parser->current_buffer_data_,
556
26
        parser->current_buffer_len_).ToLocalChecked();
557
558
26
    args.GetReturnValue().Set(ret);
559
  }
560
561
 protected:
562
  class ScopedRetainParser {
563
   public:
564
2275
    explicit ScopedRetainParser(Parser* p) : p_(p) {
565
2275
      CHECK_GT(p_->refcount_, 0);
566
2275
      p_->refcount_++;
567
2275
    }
568
569
2271
    ~ScopedRetainParser() {
570
2271
      if (0 == --p_->refcount_)
571
1
        delete p_;
572
2271
    }
573
574
   private:
575
    Parser* const p_;
576
  };
577
578
  static const size_t kAllocBufferSize = 64 * 1024;
579
580
2390
  static void OnAllocImpl(size_t suggested_size, uv_buf_t* buf, void* ctx) {
581
2390
    Parser* parser = static_cast<Parser*>(ctx);
582
2390
    Environment* env = parser->env();
583
584
2390
    if (env->http_parser_buffer() == nullptr)
585
227
      env->set_http_parser_buffer(new char[kAllocBufferSize]);
586
587
2390
    buf->base = env->http_parser_buffer();
588
2390
    buf->len = kAllocBufferSize;
589
2390
  }
590
591
592
2406
  static void OnReadImpl(ssize_t nread,
593
                         const uv_buf_t* buf,
594
                         uv_handle_type pending,
595
                         void* ctx) {
596
2406
    Parser* parser = static_cast<Parser*>(ctx);
597
2406
    HandleScope scope(parser->env()->isolate());
598
599
2406
    if (nread < 0) {
600
      uv_buf_t tmp_buf;
601
131
      tmp_buf.base = nullptr;
602
131
      tmp_buf.len = 0;
603
      parser->prev_read_cb_.fn(nread,
604
                               &tmp_buf,
605
                               pending,
606
131
                               parser->prev_read_cb_.ctx);
607
131
      return;
608
    }
609
610
    // Ignore, empty reads have special meaning in http parser
611
2275
    if (nread == 0)
612
      return;
613
614
3540
    ScopedRetainParser retain(parser);
615
616
2275
    parser->current_buffer_.Clear();
617
2275
    Local<Value> ret = parser->Execute(buf->base, nread);
618
619
    // Exception
620
2272
    if (ret.IsEmpty())
621
5
      return;
622
623
2267
    Local<Object> obj = parser->object();
624
2267
    Local<Value> cb = obj->Get(kOnExecute);
625
626
2267
    if (!cb->IsFunction())
627
1001
      return;
628
629
    // Hooks for GetCurrentBuffer
630
1266
    parser->current_buffer_len_ = nread;
631
1266
    parser->current_buffer_data_ = buf->base;
632
633
1266
    parser->MakeCallback(cb.As<Function>(), 1, &ret);
634
635
1265
    parser->current_buffer_len_ = 0;
636
2530
    parser->current_buffer_data_ = nullptr;
637
  }
638
639
640
4370
  Local<Value> Execute(char* data, size_t len) {
641
4370
    EscapableHandleScope scope(env()->isolate());
642
643
4370
    current_buffer_len_ = len;
644
4370
    current_buffer_data_ = data;
645
4370
    got_exception_ = false;
646
647
    size_t nparsed =
648
4370
      http_parser_execute(&parser_, &settings, data, len);
649
650
4366
    Save();
651
652
    // Unassign the 'buffer_' variable
653
4366
    current_buffer_.Clear();
654
4366
    current_buffer_len_ = 0;
655
4366
    current_buffer_data_ = nullptr;
656
657
    // If there was an exception in one of the callbacks
658
4366
    if (got_exception_)
659
7
      return scope.Escape(Local<Value>());
660
661
4359
    Local<Integer> nparsed_obj = Integer::New(env()->isolate(), nparsed);
662
    // If there was a parse error in one of the callbacks
663
    // TODO(bnoordhuis) What if there is an error on EOF?
664

4359
    if (!parser_.upgrade && nparsed != len) {
665
161
      enum http_errno err = HTTP_PARSER_ERRNO(&parser_);
666
667
161
      Local<Value> e = Exception::Error(env()->parse_error_string());
668
322
      Local<Object> obj = e->ToObject(env()->isolate());
669
322
      obj->Set(env()->bytes_parsed_string(), nparsed_obj);
670
      obj->Set(env()->code_string(),
671
483
               OneByteString(env()->isolate(), http_errno_name(err)));
672
673
      return scope.Escape(e);
674
    }
675
4198
    return scope.Escape(nparsed_obj);
676
  }
677
678
14398
  Local<Array> CreateHeaders() {
679
14398
    Local<Array> headers = Array::New(env()->isolate());
680
14398
    Local<Function> fn = env()->push_values_to_array_function();
681
244766
    Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX * 2];
682
14398
    size_t i = 0;
683
684
15667
    do {
685
15667
      size_t j = 0;
686

51126
      while (i < num_values_ && j < arraysize(argv) / 2) {
687
39584
        argv[j * 2] = fields_[i].ToString(env());
688
39584
        argv[j * 2 + 1] = values_[i].ToString(env());
689
19792
        i++;
690
19792
        j++;
691
      }
692
15667
      if (j > 0) {
693
18360
        fn->Call(env()->context(), headers, j * 2, argv).ToLocalChecked();
694
      }
695
15667
    } while (i < num_values_);
696
697
14398
    return headers;
698
  }
699
700
701
  // spill headers and request path to JS land
702
409
  void Flush() {
703
409
    HandleScope scope(env()->isolate());
704
705
409
    Local<Object> obj = object();
706
409
    Local<Value> cb = obj->Get(kOnHeaders);
707
708
409
    if (!cb->IsFunction())
709
409
      return;
710
711
    Local<Value> argv[2] = {
712
      CreateHeaders(),
713
      url_.ToString(env())
714
1227
    };
715
716
    MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
717
409
                                       arraysize(argv),
718
818
                                       argv);
719
720
409
    if (r.IsEmpty())
721
      got_exception_ = true;
722
723
409
    url_.Reset();
724
409
    have_flushed_ = true;
725
  }
726
727
728
4360
  void Init(enum http_parser_type type) {
729
4360
    http_parser_init(&parser_, type);
730
4360
    url_.Reset();
731
4360
    status_message_.Reset();
732
4360
    num_fields_ = 0;
733
4360
    num_values_ = 0;
734
4360
    have_flushed_ = false;
735
4360
    got_exception_ = false;
736
4360
  }
737
738
739
  http_parser parser_;
740
  StringPtr fields_[32];  // header fields
741
  StringPtr values_[32];  // header values
742
  StringPtr url_;
743
  StringPtr status_message_;
744
  size_t num_fields_;
745
  size_t num_values_;
746
  bool have_flushed_;
747
  bool got_exception_;
748
  Local<Object> current_buffer_;
749
  size_t current_buffer_len_;
750
  char* current_buffer_data_;
751
  StreamResource::Callback<StreamResource::AllocCb> prev_alloc_cb_;
752
  StreamResource::Callback<StreamResource::ReadCb> prev_read_cb_;
753
  int refcount_ = 1;
754
  static const struct http_parser_settings settings;
755
756
  friend class ScopedRetainParser;
757
};
758
759
760
const struct http_parser_settings Parser::settings = {
761
  Parser::on_message_begin,
762
  Parser::on_url,
763
  Parser::on_status,
764
  Parser::on_header_field,
765
  Parser::on_header_value,
766
  Parser::on_headers_complete,
767
  Parser::on_body,
768
  Parser::on_message_complete,
769
  nullptr,  // on_chunk_header
770
  nullptr   // on_chunk_complete
771
};
772
773
774
495
void InitHttpParser(Local<Object> target,
775
                    Local<Value> unused,
776
                    Local<Context> context,
777
                    void* priv) {
778
495
  Environment* env = Environment::GetCurrent(context);
779
495
  Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
780
990
  t->InstanceTemplate()->SetInternalFieldCount(1);
781
990
  t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"));
782
783
495
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"),
784
1485
         Integer::New(env->isolate(), HTTP_REQUEST));
785
495
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"),
786
1485
         Integer::New(env->isolate(), HTTP_RESPONSE));
787
495
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"),
788
1485
         Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
789
495
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"),
790
1485
         Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
791
495
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"),
792
1485
         Integer::NewFromUnsigned(env->isolate(), kOnBody));
793
495
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"),
794
1485
         Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
795
495
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"),
796
1485
         Integer::NewFromUnsigned(env->isolate(), kOnExecute));
797
798
495
  Local<Array> methods = Array::New(env->isolate());
799
#define V(num, name, string)                                                  \
800
    methods->Set(num, FIXED_ONE_BYTE_STRING(env->isolate(), #string));
801
16830
  HTTP_METHOD_MAP(V)
802
#undef V
803
990
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "methods"), methods);
804
805
495
  AsyncWrap::AddWrapMethods(env, t);
806
495
  env->SetProtoMethod(t, "close", Parser::Close);
807
495
  env->SetProtoMethod(t, "free", Parser::Free);
808
495
  env->SetProtoMethod(t, "execute", Parser::Execute);
809
495
  env->SetProtoMethod(t, "finish", Parser::Finish);
810
495
  env->SetProtoMethod(t, "reinitialize", Parser::Reinitialize);
811
495
  env->SetProtoMethod(t, "pause", Parser::Pause<true>);
812
495
  env->SetProtoMethod(t, "resume", Parser::Pause<false>);
813
495
  env->SetProtoMethod(t, "consume", Parser::Consume);
814
495
  env->SetProtoMethod(t, "unconsume", Parser::Unconsume);
815
495
  env->SetProtoMethod(t, "getCurrentBuffer", Parser::GetCurrentBuffer);
816
817
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"),
818
1485
              t->GetFunction());
819
495
}
820
821
}  // anonymous namespace
822
}  // namespace node
823
824
3332
NODE_BUILTIN_MODULE_CONTEXT_AWARE(http_parser, node::InitHttpParser)