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: 346 358 96.6 %
Date: 2017-06-14 Branches: 148 196 75.5 %

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

9763
    if (!on_heap_ && size_ > 0) {
112
3512
      char* s = new char[size_];
113
3512
      memcpy(s, str_, size_);
114
3512
      str_ = s;
115
3512
      on_heap_ = true;
116
    }
117
9763
  }
118
119
120
211195
  void Reset() {
121
211195
    if (on_heap_) {
122
1450
      delete[] str_;
123
1450
      on_heap_ = false;
124
    }
125
126
211195
    str_ = nullptr;
127
211195
    size_ = 0;
128
211195
  }
129
130
131
56880
  void Update(const char* str, size_t size) {
132
56880
    if (str_ == nullptr) {
133
56823
      str_ = str;
134

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

3938
        current_buffer_data_(nullptr) {
172
1969
    Wrap(object(), this);
173
1969
    Init(type);
174
1969
  }
175
176
177


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

1969
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
388
1969
    new Parser(env, args.This(), type);
389
1969
  }
390
391
392
3
  static void Close(const FunctionCallbackInfo<Value>& args) {
393
    Parser* parser;
394
6
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
395
396
3
    if (--parser->refcount_ == 0)
397
2
      delete parser;
398
  }
399
400
401
4790
  void Save() {
402
4790
    url_.Save();
403
4790
    status_message_.Save();
404
405
4898
    for (size_t i = 0; i < num_fields_; i++) {
406
108
      fields_[i].Save();
407
    }
408
409
4865
    for (size_t i = 0; i < num_values_; i++) {
410
75
      values_[i].Save();
411
    }
412
4790
  }
413
414
415
  // var bytesParsed = parser->execute(buffer);
416
2179
  static void Execute(const FunctionCallbackInfo<Value>& args) {
417
    Parser* parser;
418
4356
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
419
4358
    CHECK(parser->current_buffer_.IsEmpty());
420
2179
    CHECK_EQ(parser->current_buffer_len_, 0);
421
2179
    CHECK_EQ(parser->current_buffer_data_, nullptr);
422
2179
    CHECK_EQ(Buffer::HasInstance(args[0]), true);
423
424
4358
    Local<Object> buffer_obj = args[0].As<Object>();
425
2179
    char* buffer_data = Buffer::Data(buffer_obj);
426
2179
    size_t buffer_len = Buffer::Length(buffer_obj);
427
428
    // This is a hack to get the current_buffer to the callbacks with the least
429
    // amount of overhead. Nothing else will run while http_parser_execute()
430
    // runs, therefore this pointer can be set and used for the execution.
431
2179
    parser->current_buffer_ = buffer_obj;
432
433
2179
    Local<Value> ret = parser->Execute(buffer_data, buffer_len);
434
435
2177
    if (!ret.IsEmpty())
436
4350
      args.GetReturnValue().Set(ret);
437
  }
438
439
440
234
  static void Finish(const FunctionCallbackInfo<Value>& args) {
441
234
    Environment* env = Environment::GetCurrent(args);
442
443
    Parser* parser;
444
234
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
445
446
468
    CHECK(parser->current_buffer_.IsEmpty());
447
234
    parser->got_exception_ = false;
448
449
234
    int rv = http_parser_execute(&(parser->parser_), &settings, nullptr, 0);
450
451
234
    if (parser->got_exception_)
452
      return;
453
454
234
    if (rv != 0) {
455
15
      enum http_errno err = HTTP_PARSER_ERRNO(&parser->parser_);
456
457
15
      Local<Value> e = Exception::Error(env->parse_error_string());
458
30
      Local<Object> obj = e->ToObject(env->isolate());
459
45
      obj->Set(env->bytes_parsed_string(), Integer::New(env->isolate(), 0));
460
      obj->Set(env->code_string(),
461
45
               OneByteString(env->isolate(), http_errno_name(err)));
462
463
30
      args.GetReturnValue().Set(e);
464
    }
465
  }
466
467
468
2628
  static void Reinitialize(const FunctionCallbackInfo<Value>& args) {
469
2628
    Environment* env = Environment::GetCurrent(args);
470
471
    http_parser_type type =
472
5256
        static_cast<http_parser_type>(args[0]->Int32Value());
473
474

2628
    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
475
    Parser* parser;
476
5256
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
477
    // Should always be called from the same context.
478
2628
    CHECK_EQ(env, parser->env());
479
    // The parser is being reused. Reset the uid and call init() callbacks.
480
2628
    parser->AsyncReset();
481
2628
    parser->Init(type);
482
  }
483
484
485
  template <bool should_pause>
486
10
  static void Pause(const FunctionCallbackInfo<Value>& args) {
487
10
    Environment* env = Environment::GetCurrent(args);
488
    Parser* parser;
489

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

10
    CHECK_EQ(env, parser->env());
492
10
    http_parser_pause(&parser->parser_, should_pause);
493
  }
494
495
496
1500
  static void Consume(const FunctionCallbackInfo<Value>& args) {
497
    Parser* parser;
498
3000
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
499
3000
    CHECK(args[0]->IsExternal());
500
3000
    Local<External> stream_obj = args[0].As<External>();
501
1500
    StreamBase* stream = static_cast<StreamBase*>(stream_obj->Value());
502
1500
    CHECK_NE(stream, nullptr);
503
504
1500
    stream->Consume();
505
506
1500
    parser->prev_alloc_cb_ = stream->alloc_cb();
507
1500
    parser->prev_read_cb_ = stream->read_cb();
508
509
1500
    stream->set_alloc_cb({ OnAllocImpl, parser });
510
1500
    stream->set_read_cb({ OnReadImpl, parser });
511
  }
512
513
514
1483
  static void Unconsume(const FunctionCallbackInfo<Value>& args) {
515
    Parser* parser;
516
1483
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
517
518
    // Already unconsumed
519
1483
    if (parser->prev_alloc_cb_.is_empty())
520
      return;
521
522
    // Restore stream's callbacks
523


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

4783
    if (!parser_.upgrade && nparsed != len) {
653
161
      enum http_errno err = HTTP_PARSER_ERRNO(&parser_);
654
655
161
      Local<Value> e = Exception::Error(env()->parse_error_string());
656
322
      Local<Object> obj = e->ToObject(env()->isolate());
657
322
      obj->Set(env()->bytes_parsed_string(), nparsed_obj);
658
      obj->Set(env()->code_string(),
659
483
               OneByteString(env()->isolate(), http_errno_name(err)));
660
661
      return scope.Escape(e);
662
    }
663
4622
    return scope.Escape(nparsed_obj);
664
  }
665
666
15000
  Local<Array> CreateHeaders() {
667
15000
    Local<Array> headers = Array::New(env()->isolate());
668
15000
    Local<Function> fn = env()->push_values_to_array_function();
669
255000
    Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX * 2];
670
15000
    size_t i = 0;
671
672
16203
    do {
673
16203
      size_t j = 0;
674

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