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 kOnMessageBegin = 0;
73 const uint32_t kOnHeaders = 1;
74 const uint32_t kOnHeadersComplete = 2;
75 const uint32_t kOnBody = 3;
76 const uint32_t kOnMessageComplete = 4;
77 const uint32_t kOnExecute = 5;
78 const uint32_t kOnTimeout = 6;
79 // Any more fields than this will be flushed into JS
80 const size_t kMaxHeaderFieldsCount = 32;
81
IsOWS(char c)82 inline bool IsOWS(char c) {
83 return c == ' ' || c == '\t';
84 }
85
86 class BindingData : public BaseObject {
87 public:
BindingData(Environment * env,Local<Object> obj)88 BindingData(Environment* env, Local<Object> obj)
89 : BaseObject(env, obj) {}
90
91 static constexpr FastStringKey type_name { "http_parser" };
92
93 std::vector<char> parser_buffer;
94 bool parser_buffer_in_use = false;
95
MemoryInfo(MemoryTracker * tracker) const96 void MemoryInfo(MemoryTracker* tracker) const override {
97 tracker->TrackField("parser_buffer", parser_buffer);
98 }
99 SET_SELF_SIZE(BindingData)
100 SET_MEMORY_INFO_NAME(BindingData)
101 };
102
103 // TODO(addaleax): Remove once we're on C++17.
104 constexpr FastStringKey BindingData::type_name;
105
106 // helper class for the Parser
107 struct StringPtr {
StringPtrnode::__anon439301180111::StringPtr108 StringPtr() {
109 on_heap_ = false;
110 Reset();
111 }
112
113
~StringPtrnode::__anon439301180111::StringPtr114 ~StringPtr() {
115 Reset();
116 }
117
118
119 // If str_ does not point to a heap string yet, this function makes it do
120 // so. This is called at the end of each http_parser_execute() so as not
121 // to leak references. See issue #2438 and test-http-parser-bad-ref.js.
Savenode::__anon439301180111::StringPtr122 void Save() {
123 if (!on_heap_ && size_ > 0) {
124 char* s = new char[size_];
125 memcpy(s, str_, size_);
126 str_ = s;
127 on_heap_ = true;
128 }
129 }
130
131
Resetnode::__anon439301180111::StringPtr132 void Reset() {
133 if (on_heap_) {
134 delete[] str_;
135 on_heap_ = false;
136 }
137
138 str_ = nullptr;
139 size_ = 0;
140 }
141
142
Updatenode::__anon439301180111::StringPtr143 void Update(const char* str, size_t size) {
144 if (str_ == nullptr) {
145 str_ = str;
146 } else if (on_heap_ || str_ + size_ != str) {
147 // Non-consecutive input, make a copy on the heap.
148 // TODO(bnoordhuis) Use slab allocation, O(n) allocs is bad.
149 char* s = new char[size_ + size];
150 memcpy(s, str_, size_);
151 memcpy(s + size_, str, size);
152
153 if (on_heap_)
154 delete[] str_;
155 else
156 on_heap_ = true;
157
158 str_ = s;
159 }
160 size_ += size;
161 }
162
163
ToStringnode::__anon439301180111::StringPtr164 Local<String> ToString(Environment* env) const {
165 if (size_ != 0)
166 return OneByteString(env->isolate(), str_, size_);
167 else
168 return String::Empty(env->isolate());
169 }
170
171
172 // Strip trailing OWS (SPC or HTAB) from string.
ToTrimmedStringnode::__anon439301180111::StringPtr173 Local<String> ToTrimmedString(Environment* env) {
174 while (size_ > 0 && IsOWS(str_[size_ - 1])) {
175 size_--;
176 }
177 return ToString(env);
178 }
179
180
181 const char* str_;
182 bool on_heap_;
183 size_t size_;
184 };
185
186 class Parser : public AsyncWrap, public StreamListener {
187 public:
Parser(BindingData * binding_data,Local<Object> wrap)188 Parser(BindingData* binding_data, Local<Object> wrap)
189 : AsyncWrap(binding_data->env(), wrap),
190 current_buffer_len_(0),
191 current_buffer_data_(nullptr),
192 binding_data_(binding_data) {
193 }
194
195
MemoryInfo(MemoryTracker * tracker) const196 void MemoryInfo(MemoryTracker* tracker) const override {
197 tracker->TrackField("current_buffer", current_buffer_);
198 }
199
200 SET_MEMORY_INFO_NAME(Parser)
SET_SELF_SIZE(Parser)201 SET_SELF_SIZE(Parser)
202
203 int on_message_begin() {
204 num_fields_ = num_values_ = 0;
205 url_.Reset();
206 status_message_.Reset();
207 header_parsing_start_time_ = uv_hrtime();
208
209 Local<Value> cb = object()->Get(env()->context(), kOnMessageBegin)
210 .ToLocalChecked();
211 if (cb->IsFunction()) {
212 InternalCallbackScope callback_scope(
213 this, InternalCallbackScope::kSkipTaskQueues);
214
215 MaybeLocal<Value> r = cb.As<Function>()->Call(
216 env()->context(), object(), 0, nullptr);
217
218 if (r.IsEmpty()) callback_scope.MarkAsFailed();
219 }
220
221 return 0;
222 }
223
224
on_url(const char * at,size_t length)225 int on_url(const char* at, size_t length) {
226 int rv = TrackHeader(length);
227 if (rv != 0) {
228 return rv;
229 }
230
231 url_.Update(at, length);
232 return 0;
233 }
234
235
on_status(const char * at,size_t length)236 int on_status(const char* at, size_t length) {
237 int rv = TrackHeader(length);
238 if (rv != 0) {
239 return rv;
240 }
241
242 status_message_.Update(at, length);
243 return 0;
244 }
245
246
on_header_field(const char * at,size_t length)247 int on_header_field(const char* at, size_t length) {
248 int rv = TrackHeader(length);
249 if (rv != 0) {
250 return rv;
251 }
252
253 if (num_fields_ == num_values_) {
254 // start of new field name
255 num_fields_++;
256 if (num_fields_ == kMaxHeaderFieldsCount) {
257 // ran out of space - flush to javascript land
258 Flush();
259 num_fields_ = 1;
260 num_values_ = 0;
261 }
262 fields_[num_fields_ - 1].Reset();
263 }
264
265 CHECK_LT(num_fields_, kMaxHeaderFieldsCount);
266 CHECK_EQ(num_fields_, num_values_ + 1);
267
268 fields_[num_fields_ - 1].Update(at, length);
269
270 return 0;
271 }
272
273
on_header_value(const char * at,size_t length)274 int on_header_value(const char* at, size_t length) {
275 int rv = TrackHeader(length);
276 if (rv != 0) {
277 return rv;
278 }
279
280 if (num_values_ != num_fields_) {
281 // start of new header value
282 num_values_++;
283 values_[num_values_ - 1].Reset();
284 }
285
286 CHECK_LT(num_values_, arraysize(values_));
287 CHECK_EQ(num_values_, num_fields_);
288
289 values_[num_values_ - 1].Update(at, length);
290
291 return 0;
292 }
293
294
on_headers_complete()295 int on_headers_complete() {
296 header_nread_ = 0;
297 header_parsing_start_time_ = 0;
298
299 // Arguments for the on-headers-complete javascript callback. This
300 // list needs to be kept in sync with the actual argument list for
301 // `parserOnHeadersComplete` in lib/_http_common.js.
302 enum on_headers_complete_arg_index {
303 A_VERSION_MAJOR = 0,
304 A_VERSION_MINOR,
305 A_HEADERS,
306 A_METHOD,
307 A_URL,
308 A_STATUS_CODE,
309 A_STATUS_MESSAGE,
310 A_UPGRADE,
311 A_SHOULD_KEEP_ALIVE,
312 A_MAX
313 };
314
315 Local<Value> argv[A_MAX];
316 Local<Object> obj = object();
317 Local<Value> cb = obj->Get(env()->context(),
318 kOnHeadersComplete).ToLocalChecked();
319
320 if (!cb->IsFunction())
321 return 0;
322
323 Local<Value> undefined = Undefined(env()->isolate());
324 for (size_t i = 0; i < arraysize(argv); i++)
325 argv[i] = undefined;
326
327 if (have_flushed_) {
328 // Slow case, flush remaining headers.
329 Flush();
330 } else {
331 // Fast case, pass headers and URL to JS land.
332 argv[A_HEADERS] = CreateHeaders();
333 if (parser_.type == HTTP_REQUEST)
334 argv[A_URL] = url_.ToString(env());
335 }
336
337 num_fields_ = 0;
338 num_values_ = 0;
339
340 // METHOD
341 if (parser_.type == HTTP_REQUEST) {
342 argv[A_METHOD] =
343 Uint32::NewFromUnsigned(env()->isolate(), parser_.method);
344 }
345
346 // STATUS
347 if (parser_.type == HTTP_RESPONSE) {
348 argv[A_STATUS_CODE] =
349 Integer::New(env()->isolate(), parser_.status_code);
350 argv[A_STATUS_MESSAGE] = status_message_.ToString(env());
351 }
352
353 // VERSION
354 argv[A_VERSION_MAJOR] = Integer::New(env()->isolate(), parser_.http_major);
355 argv[A_VERSION_MINOR] = Integer::New(env()->isolate(), parser_.http_minor);
356
357 bool should_keep_alive;
358 should_keep_alive = llhttp_should_keep_alive(&parser_);
359
360 argv[A_SHOULD_KEEP_ALIVE] =
361 Boolean::New(env()->isolate(), should_keep_alive);
362
363 argv[A_UPGRADE] = Boolean::New(env()->isolate(), parser_.upgrade);
364
365 MaybeLocal<Value> head_response;
366 {
367 InternalCallbackScope callback_scope(
368 this, InternalCallbackScope::kSkipTaskQueues);
369 head_response = cb.As<Function>()->Call(
370 env()->context(), object(), arraysize(argv), argv);
371 if (head_response.IsEmpty()) callback_scope.MarkAsFailed();
372 }
373
374 int64_t val;
375
376 if (head_response.IsEmpty() || !head_response.ToLocalChecked()
377 ->IntegerValue(env()->context())
378 .To(&val)) {
379 got_exception_ = true;
380 return -1;
381 }
382
383 return val;
384 }
385
386
on_body(const char * at,size_t length)387 int on_body(const char* at, size_t length) {
388 EscapableHandleScope scope(env()->isolate());
389
390 Local<Object> obj = object();
391 Local<Value> cb = obj->Get(env()->context(), kOnBody).ToLocalChecked();
392
393 if (!cb->IsFunction())
394 return 0;
395
396 // We came from consumed stream
397 if (current_buffer_.IsEmpty()) {
398 // Make sure Buffer will be in parent HandleScope
399 current_buffer_ = scope.Escape(Buffer::Copy(
400 env()->isolate(),
401 current_buffer_data_,
402 current_buffer_len_).ToLocalChecked());
403 }
404
405 Local<Value> argv[3] = {
406 current_buffer_,
407 Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
408 Integer::NewFromUnsigned(env()->isolate(), length)
409 };
410
411 MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
412 arraysize(argv),
413 argv);
414
415 if (r.IsEmpty()) {
416 got_exception_ = true;
417 llhttp_set_error_reason(&parser_, "HPE_JS_EXCEPTION:JS Exception");
418 return HPE_USER;
419 }
420
421 return 0;
422 }
423
424
on_message_complete()425 int on_message_complete() {
426 HandleScope scope(env()->isolate());
427
428 if (num_fields_)
429 Flush(); // Flush trailing HTTP headers.
430
431 Local<Object> obj = object();
432 Local<Value> cb = obj->Get(env()->context(),
433 kOnMessageComplete).ToLocalChecked();
434
435 if (!cb->IsFunction())
436 return 0;
437
438 MaybeLocal<Value> r;
439 {
440 InternalCallbackScope callback_scope(
441 this, InternalCallbackScope::kSkipTaskQueues);
442 r = cb.As<Function>()->Call(env()->context(), object(), 0, nullptr);
443 if (r.IsEmpty()) callback_scope.MarkAsFailed();
444 }
445
446 if (r.IsEmpty()) {
447 got_exception_ = true;
448 return -1;
449 }
450
451 return 0;
452 }
453
454 // Reset nread for the next chunk
on_chunk_header()455 int on_chunk_header() {
456 header_nread_ = 0;
457 return 0;
458 }
459
460
461 // Reset nread for the next chunk
on_chunk_complete()462 int on_chunk_complete() {
463 header_nread_ = 0;
464 return 0;
465 }
466
New(const FunctionCallbackInfo<Value> & args)467 static void New(const FunctionCallbackInfo<Value>& args) {
468 BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
469 new Parser(binding_data, args.This());
470 }
471
472
Close(const FunctionCallbackInfo<Value> & args)473 static void Close(const FunctionCallbackInfo<Value>& args) {
474 Parser* parser;
475 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
476
477 delete parser;
478 }
479
480
Free(const FunctionCallbackInfo<Value> & args)481 static void Free(const FunctionCallbackInfo<Value>& args) {
482 Parser* parser;
483 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
484
485 // Since the Parser destructor isn't going to run the destroy() callbacks
486 // it needs to be triggered manually.
487 parser->EmitTraceEventDestroy();
488 parser->EmitDestroy();
489 }
490
491
Save()492 void Save() {
493 url_.Save();
494 status_message_.Save();
495
496 for (size_t i = 0; i < num_fields_; i++) {
497 fields_[i].Save();
498 }
499
500 for (size_t i = 0; i < num_values_; i++) {
501 values_[i].Save();
502 }
503 }
504
505
506 // var bytesParsed = parser->execute(buffer);
Execute(const FunctionCallbackInfo<Value> & args)507 static void Execute(const FunctionCallbackInfo<Value>& args) {
508 Parser* parser;
509 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
510 CHECK(parser->current_buffer_.IsEmpty());
511 CHECK_EQ(parser->current_buffer_len_, 0);
512 CHECK_NULL(parser->current_buffer_data_);
513
514 ArrayBufferViewContents<char> buffer(args[0]);
515
516 // This is a hack to get the current_buffer to the callbacks with the least
517 // amount of overhead. Nothing else will run while http_parser_execute()
518 // runs, therefore this pointer can be set and used for the execution.
519 parser->current_buffer_ = args[0].As<Object>();
520
521 Local<Value> ret = parser->Execute(buffer.data(), buffer.length());
522
523 if (!ret.IsEmpty())
524 args.GetReturnValue().Set(ret);
525 }
526
527
Finish(const FunctionCallbackInfo<Value> & args)528 static void Finish(const FunctionCallbackInfo<Value>& args) {
529 Parser* parser;
530 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
531
532 CHECK(parser->current_buffer_.IsEmpty());
533 Local<Value> ret = parser->Execute(nullptr, 0);
534
535 if (!ret.IsEmpty())
536 args.GetReturnValue().Set(ret);
537 }
538
539
Initialize(const FunctionCallbackInfo<Value> & args)540 static void Initialize(const FunctionCallbackInfo<Value>& args) {
541 Environment* env = Environment::GetCurrent(args);
542 bool lenient = args[3]->IsTrue();
543
544 uint64_t max_http_header_size = 0;
545 uint64_t headers_timeout = 0;
546
547 CHECK(args[0]->IsInt32());
548 CHECK(args[1]->IsObject());
549
550 if (args.Length() > 2) {
551 CHECK(args[2]->IsNumber());
552 max_http_header_size = args[2].As<Number>()->Value();
553 }
554 if (max_http_header_size == 0) {
555 max_http_header_size = env->options()->max_http_header_size;
556 }
557
558 if (args.Length() > 4) {
559 CHECK(args[4]->IsInt32());
560 headers_timeout = args[4].As<Number>()->Value();
561 }
562
563 llhttp_type_t type =
564 static_cast<llhttp_type_t>(args[0].As<Int32>()->Value());
565
566 CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
567 Parser* parser;
568 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
569 // Should always be called from the same context.
570 CHECK_EQ(env, parser->env());
571
572 AsyncWrap::ProviderType provider =
573 (type == HTTP_REQUEST ?
574 AsyncWrap::PROVIDER_HTTPINCOMINGMESSAGE
575 : AsyncWrap::PROVIDER_HTTPCLIENTREQUEST);
576
577 parser->set_provider_type(provider);
578 parser->AsyncReset(args[1].As<Object>());
579 parser->Init(type, max_http_header_size, lenient, headers_timeout);
580 }
581
582 template <bool should_pause>
Pause(const FunctionCallbackInfo<Value> & args)583 static void Pause(const FunctionCallbackInfo<Value>& args) {
584 Environment* env = Environment::GetCurrent(args);
585 Parser* parser;
586 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
587 // Should always be called from the same context.
588 CHECK_EQ(env, parser->env());
589
590 if (parser->execute_depth_) {
591 parser->pending_pause_ = should_pause;
592 return;
593 }
594
595 if (should_pause) {
596 llhttp_pause(&parser->parser_);
597 } else {
598 llhttp_resume(&parser->parser_);
599 }
600 }
601
602
Consume(const FunctionCallbackInfo<Value> & args)603 static void Consume(const FunctionCallbackInfo<Value>& args) {
604 Parser* parser;
605 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
606 CHECK(args[0]->IsObject());
607 StreamBase* stream = StreamBase::FromObject(args[0].As<Object>());
608 CHECK_NOT_NULL(stream);
609 stream->PushStreamListener(parser);
610 }
611
612
Unconsume(const FunctionCallbackInfo<Value> & args)613 static void Unconsume(const FunctionCallbackInfo<Value>& args) {
614 Parser* parser;
615 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
616
617 // Already unconsumed
618 if (parser->stream_ == nullptr)
619 return;
620
621 parser->stream_->RemoveStreamListener(parser);
622 }
623
624
GetCurrentBuffer(const FunctionCallbackInfo<Value> & args)625 static void GetCurrentBuffer(const FunctionCallbackInfo<Value>& args) {
626 Parser* parser;
627 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
628
629 Local<Object> ret = Buffer::Copy(
630 parser->env(),
631 parser->current_buffer_data_,
632 parser->current_buffer_len_).ToLocalChecked();
633
634 args.GetReturnValue().Set(ret);
635 }
636
637 protected:
638 static const size_t kAllocBufferSize = 64 * 1024;
639
OnStreamAlloc(size_t suggested_size)640 uv_buf_t OnStreamAlloc(size_t suggested_size) override {
641 // For most types of streams, OnStreamRead will be immediately after
642 // OnStreamAlloc, and will consume all data, so using a static buffer for
643 // reading is more efficient. For other streams, just use Malloc() directly.
644 if (binding_data_->parser_buffer_in_use)
645 return uv_buf_init(Malloc(suggested_size), suggested_size);
646 binding_data_->parser_buffer_in_use = true;
647
648 if (binding_data_->parser_buffer.empty())
649 binding_data_->parser_buffer.resize(kAllocBufferSize);
650
651 return uv_buf_init(binding_data_->parser_buffer.data(), kAllocBufferSize);
652 }
653
654
OnStreamRead(ssize_t nread,const uv_buf_t & buf)655 void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override {
656 HandleScope scope(env()->isolate());
657 // Once we’re done here, either indicate that the HTTP parser buffer
658 // is free for re-use, or free() the data if it didn’t come from there
659 // in the first place.
660 auto on_scope_leave = OnScopeLeave([&]() {
661 if (buf.base == binding_data_->parser_buffer.data())
662 binding_data_->parser_buffer_in_use = false;
663 else
664 free(buf.base);
665 });
666
667 if (nread < 0) {
668 PassReadErrorToPreviousListener(nread);
669 return;
670 }
671
672 // Ignore, empty reads have special meaning in http parser
673 if (nread == 0)
674 return;
675
676 current_buffer_.Clear();
677 Local<Value> ret = Execute(buf.base, nread);
678
679 // Exception
680 if (ret.IsEmpty())
681 return;
682
683 // check header parsing time
684 if (header_parsing_start_time_ != 0 && headers_timeout_ != 0) {
685 uint64_t now = uv_hrtime();
686 uint64_t parsing_time = (now - header_parsing_start_time_) / 1e6;
687
688 if (parsing_time > headers_timeout_) {
689 Local<Value> cb =
690 object()->Get(env()->context(), kOnTimeout).ToLocalChecked();
691
692 if (!cb->IsFunction())
693 return;
694
695 MakeCallback(cb.As<Function>(), 0, nullptr);
696
697 return;
698 }
699 }
700
701 Local<Value> cb =
702 object()->Get(env()->context(), kOnExecute).ToLocalChecked();
703
704 if (!cb->IsFunction())
705 return;
706
707 // Hooks for GetCurrentBuffer
708 current_buffer_len_ = nread;
709 current_buffer_data_ = buf.base;
710
711 MakeCallback(cb.As<Function>(), 1, &ret);
712
713 current_buffer_len_ = 0;
714 current_buffer_data_ = nullptr;
715 }
716
717
Execute(const char * data,size_t len)718 Local<Value> Execute(const char* data, size_t len) {
719 EscapableHandleScope scope(env()->isolate());
720
721 current_buffer_len_ = len;
722 current_buffer_data_ = data;
723 got_exception_ = false;
724
725 llhttp_errno_t err;
726
727 // Do not allow re-entering `http_parser_execute()`
728 CHECK_EQ(execute_depth_, 0);
729
730 execute_depth_++;
731 if (data == nullptr) {
732 err = llhttp_finish(&parser_);
733 } else {
734 err = llhttp_execute(&parser_, data, len);
735 Save();
736 }
737 execute_depth_--;
738
739 // Calculate bytes read and resume after Upgrade/CONNECT pause
740 size_t nread = len;
741 if (err != HPE_OK) {
742 nread = llhttp_get_error_pos(&parser_) - data;
743
744 // This isn't a real pause, just a way to stop parsing early.
745 if (err == HPE_PAUSED_UPGRADE) {
746 err = HPE_OK;
747 llhttp_resume_after_upgrade(&parser_);
748 }
749 }
750
751 // Apply pending pause
752 if (pending_pause_) {
753 pending_pause_ = false;
754 llhttp_pause(&parser_);
755 }
756
757 // Unassign the 'buffer_' variable
758 current_buffer_.Clear();
759 current_buffer_len_ = 0;
760 current_buffer_data_ = nullptr;
761
762 // If there was an exception in one of the callbacks
763 if (got_exception_)
764 return scope.Escape(Local<Value>());
765
766 Local<Integer> nread_obj = Integer::New(env()->isolate(), nread);
767
768 // If there was a parse error in one of the callbacks
769 // TODO(bnoordhuis) What if there is an error on EOF?
770 if (!parser_.upgrade && err != HPE_OK) {
771 Local<Value> e = Exception::Error(env()->parse_error_string());
772 Local<Object> obj = e->ToObject(env()->isolate()->GetCurrentContext())
773 .ToLocalChecked();
774 obj->Set(env()->context(),
775 env()->bytes_parsed_string(),
776 nread_obj).Check();
777 const char* errno_reason = llhttp_get_error_reason(&parser_);
778
779 Local<String> code;
780 Local<String> reason;
781 if (err == HPE_USER) {
782 const char* colon = strchr(errno_reason, ':');
783 CHECK_NOT_NULL(colon);
784 code = OneByteString(env()->isolate(), errno_reason,
785 colon - errno_reason);
786 reason = OneByteString(env()->isolate(), colon + 1);
787 } else {
788 code = OneByteString(env()->isolate(), llhttp_errno_name(err));
789 reason = OneByteString(env()->isolate(), errno_reason);
790 }
791
792 obj->Set(env()->context(), env()->code_string(), code).Check();
793 obj->Set(env()->context(), env()->reason_string(), reason).Check();
794 return scope.Escape(e);
795 }
796
797 // No return value is needed for `Finish()`
798 if (data == nullptr) {
799 return scope.Escape(Local<Value>());
800 }
801 return scope.Escape(nread_obj);
802 }
803
CreateHeaders()804 Local<Array> CreateHeaders() {
805 // There could be extra entries but the max size should be fixed
806 Local<Value> headers_v[kMaxHeaderFieldsCount * 2];
807
808 for (size_t i = 0; i < num_values_; ++i) {
809 headers_v[i * 2] = fields_[i].ToString(env());
810 headers_v[i * 2 + 1] = values_[i].ToTrimmedString(env());
811 }
812
813 return Array::New(env()->isolate(), headers_v, num_values_ * 2);
814 }
815
816
817 // spill headers and request path to JS land
Flush()818 void Flush() {
819 HandleScope scope(env()->isolate());
820
821 Local<Object> obj = object();
822 Local<Value> cb = obj->Get(env()->context(), kOnHeaders).ToLocalChecked();
823
824 if (!cb->IsFunction())
825 return;
826
827 Local<Value> argv[2] = {
828 CreateHeaders(),
829 url_.ToString(env())
830 };
831
832 MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
833 arraysize(argv),
834 argv);
835
836 if (r.IsEmpty())
837 got_exception_ = true;
838
839 url_.Reset();
840 have_flushed_ = true;
841 }
842
843
Init(llhttp_type_t type,uint64_t max_http_header_size,bool lenient,uint64_t headers_timeout)844 void Init(llhttp_type_t type, uint64_t max_http_header_size,
845 bool lenient, uint64_t headers_timeout) {
846 llhttp_init(&parser_, type, &settings);
847 llhttp_set_lenient(&parser_, lenient);
848 header_nread_ = 0;
849 url_.Reset();
850 status_message_.Reset();
851 num_fields_ = 0;
852 num_values_ = 0;
853 have_flushed_ = false;
854 got_exception_ = false;
855 max_http_header_size_ = max_http_header_size;
856 header_parsing_start_time_ = 0;
857 headers_timeout_ = headers_timeout;
858 }
859
860
TrackHeader(size_t len)861 int TrackHeader(size_t len) {
862 header_nread_ += len;
863 if (header_nread_ >= max_http_header_size_) {
864 llhttp_set_error_reason(&parser_, "HPE_HEADER_OVERFLOW:Header overflow");
865 return HPE_USER;
866 }
867 return 0;
868 }
869
870
MaybePause()871 int MaybePause() {
872 CHECK_NE(execute_depth_, 0);
873
874 if (!pending_pause_) {
875 return 0;
876 }
877
878 pending_pause_ = false;
879 llhttp_set_error_reason(&parser_, "Paused in callback");
880 return HPE_PAUSED;
881 }
882
883
IsNotIndicativeOfMemoryLeakAtExit() const884 bool IsNotIndicativeOfMemoryLeakAtExit() const override {
885 // HTTP parsers are able to emit events without any GC root referring
886 // to them, because they receive events directly from the underlying
887 // libuv resource.
888 return true;
889 }
890
891
892 llhttp_t parser_;
893 StringPtr fields_[kMaxHeaderFieldsCount]; // header fields
894 StringPtr values_[kMaxHeaderFieldsCount]; // header values
895 StringPtr url_;
896 StringPtr status_message_;
897 size_t num_fields_;
898 size_t num_values_;
899 bool have_flushed_;
900 bool got_exception_;
901 Local<Object> current_buffer_;
902 size_t current_buffer_len_;
903 const char* current_buffer_data_;
904 unsigned int execute_depth_ = 0;
905 bool pending_pause_ = false;
906 uint64_t header_nread_ = 0;
907 uint64_t max_http_header_size_;
908 uint64_t headers_timeout_;
909 uint64_t header_parsing_start_time_ = 0;
910
911 BaseObjectPtr<BindingData> binding_data_;
912
913 // These are helper functions for filling `http_parser_settings`, which turn
914 // a member function of Parser into a C-style HTTP parser callback.
915 template <typename Parser, Parser> struct Proxy;
916 template <typename Parser, typename ...Args, int (Parser::*Member)(Args...)>
917 struct Proxy<int (Parser::*)(Args...), Member> {
Rawnode::__anon439301180111::Parser::Proxy918 static int Raw(llhttp_t* p, Args ... args) {
919 Parser* parser = ContainerOf(&Parser::parser_, p);
920 int rv = (parser->*Member)(std::forward<Args>(args)...);
921 if (rv == 0) {
922 rv = parser->MaybePause();
923 }
924 return rv;
925 }
926 };
927
928 typedef int (Parser::*Call)();
929 typedef int (Parser::*DataCall)(const char* at, size_t length);
930
931 static const llhttp_settings_t settings;
932 };
933
934 const llhttp_settings_t Parser::settings = {
935 Proxy<Call, &Parser::on_message_begin>::Raw,
936 Proxy<DataCall, &Parser::on_url>::Raw,
937 Proxy<DataCall, &Parser::on_status>::Raw,
938 Proxy<DataCall, &Parser::on_header_field>::Raw,
939 Proxy<DataCall, &Parser::on_header_value>::Raw,
940 Proxy<Call, &Parser::on_headers_complete>::Raw,
941 Proxy<DataCall, &Parser::on_body>::Raw,
942 Proxy<Call, &Parser::on_message_complete>::Raw,
943 Proxy<Call, &Parser::on_chunk_header>::Raw,
944 Proxy<Call, &Parser::on_chunk_complete>::Raw,
945 };
946
947
InitializeHttpParser(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)948 void InitializeHttpParser(Local<Object> target,
949 Local<Value> unused,
950 Local<Context> context,
951 void* priv) {
952 Environment* env = Environment::GetCurrent(context);
953 BindingData* const binding_data =
954 env->AddBindingData<BindingData>(context, target);
955 if (binding_data == nullptr) return;
956
957 Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
958 t->InstanceTemplate()->SetInternalFieldCount(Parser::kInternalFieldCount);
959
960 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"),
961 Integer::New(env->isolate(), HTTP_REQUEST));
962 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"),
963 Integer::New(env->isolate(), HTTP_RESPONSE));
964 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageBegin"),
965 Integer::NewFromUnsigned(env->isolate(), kOnMessageBegin));
966 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"),
967 Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
968 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"),
969 Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
970 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"),
971 Integer::NewFromUnsigned(env->isolate(), kOnBody));
972 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"),
973 Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
974 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"),
975 Integer::NewFromUnsigned(env->isolate(), kOnExecute));
976 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnTimeout"),
977 Integer::NewFromUnsigned(env->isolate(), kOnTimeout));
978
979 Local<Array> methods = Array::New(env->isolate());
980 #define V(num, name, string) \
981 methods->Set(env->context(), \
982 num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)).Check();
983 HTTP_METHOD_MAP(V)
984 #undef V
985 target->Set(env->context(),
986 FIXED_ONE_BYTE_STRING(env->isolate(), "methods"),
987 methods).Check();
988
989 t->Inherit(AsyncWrap::GetConstructorTemplate(env));
990 env->SetProtoMethod(t, "close", Parser::Close);
991 env->SetProtoMethod(t, "free", Parser::Free);
992 env->SetProtoMethod(t, "execute", Parser::Execute);
993 env->SetProtoMethod(t, "finish", Parser::Finish);
994 env->SetProtoMethod(t, "initialize", Parser::Initialize);
995 env->SetProtoMethod(t, "pause", Parser::Pause<true>);
996 env->SetProtoMethod(t, "resume", Parser::Pause<false>);
997 env->SetProtoMethod(t, "consume", Parser::Consume);
998 env->SetProtoMethod(t, "unconsume", Parser::Unconsume);
999 env->SetProtoMethod(t, "getCurrentBuffer", Parser::GetCurrentBuffer);
1000
1001 env->SetConstructorFunction(target, "HTTPParser", t);
1002 }
1003
1004 } // anonymous namespace
1005 } // namespace node
1006
1007 NODE_MODULE_CONTEXT_AWARE_INTERNAL(http_parser, node::InitializeHttpParser)
1008