• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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