29 #include "http_parser.h" 57 using v8::EscapableHandleScope;
60 using v8::FunctionCallbackInfo;
61 using v8::FunctionTemplate;
62 using v8::HandleScope;
72 const uint32_t kOnHeaders = 0;
73 const uint32_t kOnHeadersComplete = 1;
74 const uint32_t kOnBody = 2;
75 const uint32_t kOnMessageComplete = 3;
76 const uint32_t kOnExecute = 4;
79 #define HTTP_CB(name) \ 80 static int name(http_parser* p_) { \ 81 Parser* self = ContainerOf(&Parser::parser_, p_); \ 82 return self->name##_(); \ 87 #define HTTP_DATA_CB(name) \ 88 static int name(http_parser* p_, const char* at, size_t length) { \ 89 Parser* self = ContainerOf(&Parser::parser_, p_); \ 90 return self->name##_(at, length); \ 92 int name##_(const char* at, size_t length) 113 char*
s =
new char[
size_];
132 void Update(
const char* str,
size_t size) {
133 if (
str_ ==
nullptr) {
138 char*
s =
new char[
size_ + size];
140 memcpy(s +
size_, str, size);
153 Local<String> ToString(Environment* env)
const {
155 return OneByteString(env->isolate(),
str_,
size_);
157 return String::Empty(env->isolate());
167 class Parser :
public AsyncWrap {
169 Parser(Environment* env, Local<Object>
wrap,
enum http_parser_type type)
170 : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTPPARSER),
173 Wrap(
object(),
this);
180 persistent().Reset();
184 size_t self_size()
const override {
185 return sizeof(*this);
198 url_.Update(at, length);
251 enum on_headers_complete_arg_index {
264 Local<Value> argv[A_MAX];
265 Local<Object> obj = object();
266 Local<Value> cb = obj->Get(kOnHeadersComplete);
268 if (!cb->IsFunction())
271 Local<Value> undefined = Undefined(env()->isolate());
272 for (
size_t i = 0; i < arraysize(argv); i++)
280 argv[A_HEADERS] = CreateHeaders();
281 if (
parser_.type == HTTP_REQUEST)
282 argv[A_URL] =
url_.ToString(env());
289 if (
parser_.type == HTTP_REQUEST) {
291 Uint32::NewFromUnsigned(env()->isolate(),
parser_.method);
295 if (
parser_.type == HTTP_RESPONSE) {
296 argv[A_STATUS_CODE] =
305 argv[A_SHOULD_KEEP_ALIVE] =
310 Environment::AsyncCallbackScope callback_scope(env());
312 MaybeLocal<Value> head_response =
315 if (head_response.IsEmpty()) {
320 return head_response.ToLocalChecked()->IntegerValue();
325 EscapableHandleScope scope(env()->isolate());
327 Local<Object> obj = object();
328 Local<Value> cb = obj->Get(kOnBody);
330 if (!cb->IsFunction())
342 Local<Value> argv[3] = {
345 Integer::NewFromUnsigned(env()->isolate(), length)
362 HandleScope scope(env()->isolate());
367 Local<Object> obj = object();
368 Local<Value> cb = obj->Get(kOnMessageComplete);
370 if (!cb->IsFunction())
373 Environment::AsyncCallbackScope callback_scope(env());
375 MaybeLocal<Value> r =
MakeCallback(cb.As<Function>(), 0,
nullptr);
386 static void New(
const FunctionCallbackInfo<Value>& args) {
387 Environment* env = Environment::GetCurrent(args);
388 http_parser_type type =
389 static_cast<http_parser_type
>(args[0]->Int32Value());
390 CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
391 new Parser(env, args.This(), type);
395 static void Close(
const FunctionCallbackInfo<Value>& args) {
397 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
399 if (--parser->refcount_ == 0)
419 static void Execute(
const FunctionCallbackInfo<Value>& args) {
421 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
422 CHECK(parser->current_buffer_.IsEmpty());
423 CHECK_EQ(parser->current_buffer_len_, 0);
424 CHECK_EQ(parser->current_buffer_data_,
nullptr);
427 Local<Object> buffer_obj = args[0].As<Object>();
434 parser->current_buffer_ = buffer_obj;
436 Local<Value> ret = parser->Execute(buffer_data, buffer_len);
439 args.GetReturnValue().Set(ret);
443 static void Finish(
const FunctionCallbackInfo<Value>& args) {
444 Environment* env = Environment::GetCurrent(args);
447 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
449 CHECK(parser->current_buffer_.IsEmpty());
450 parser->got_exception_ =
false;
452 int rv = http_parser_execute(&(parser->parser_), &settings,
nullptr, 0);
454 if (parser->got_exception_)
458 enum http_errno err = HTTP_PARSER_ERRNO(&parser->parser_);
460 Local<Value> e = Exception::Error(env->parse_error_string());
461 Local<Object> obj = e->ToObject(env->isolate());
462 obj->Set(env->bytes_parsed_string(),
Integer::New(env->isolate(), 0));
463 obj->Set(env->code_string(),
464 OneByteString(env->isolate(), http_errno_name(err)));
466 args.GetReturnValue().Set(e);
471 static void Reinitialize(
const FunctionCallbackInfo<Value>& args) {
472 Environment* env = Environment::GetCurrent(args);
474 http_parser_type type =
475 static_cast<http_parser_type
>(args[0]->Int32Value());
477 CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
479 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
481 CHECK_EQ(env, parser->env());
483 parser->AsyncReset();
488 template <
bool should_pause>
489 static void Pause(
const FunctionCallbackInfo<Value>& args) {
490 Environment* env = Environment::GetCurrent(args);
492 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
494 CHECK_EQ(env, parser->env());
495 http_parser_pause(&parser->parser_, should_pause);
499 static void Consume(
const FunctionCallbackInfo<Value>& args) {
501 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
502 CHECK(args[0]->IsExternal());
503 Local<External> stream_obj = args[0].As<External>();
504 StreamBase* stream =
static_cast<StreamBase*
>(stream_obj->Value());
505 CHECK_NE(stream,
nullptr);
509 parser->prev_alloc_cb_ = stream->alloc_cb();
510 parser->prev_read_cb_ = stream->read_cb();
512 stream->set_alloc_cb({ OnAllocImpl, parser });
513 stream->set_read_cb({ OnReadImpl, parser });
517 static void Unconsume(
const FunctionCallbackInfo<Value>& args) {
519 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
522 if (parser->prev_alloc_cb_.is_empty())
526 if (args.Length() == 1 && args[0]->IsExternal()) {
527 Local<External> stream_obj = args[0].As<External>();
528 StreamBase* stream =
static_cast<StreamBase*
>(stream_obj->Value());
529 CHECK_NE(stream,
nullptr);
531 stream->set_alloc_cb(parser->prev_alloc_cb_);
532 stream->set_read_cb(parser->prev_read_cb_);
536 parser->prev_alloc_cb_.clear();
537 parser->prev_read_cb_.clear();
541 static void GetCurrentBuffer(
const FunctionCallbackInfo<Value>& args) {
543 ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
547 parser->current_buffer_data_,
548 parser->current_buffer_len_).ToLocalChecked();
550 args.GetReturnValue().Set(ret);
554 class ScopedRetainParser {
556 explicit ScopedRetainParser(Parser*
p) : p_(p) {
557 CHECK_GT(p_->refcount_, 0);
561 ~ScopedRetainParser() {
562 if (0 == --p_->refcount_)
570 static const size_t kAllocBufferSize = 64 * 1024;
572 static void OnAllocImpl(
size_t suggested_size, uv_buf_t*
buf,
void*
ctx) {
573 Parser* parser =
static_cast<Parser*
>(
ctx);
574 Environment* env = parser->env();
576 if (env->http_parser_buffer() ==
nullptr)
577 env->set_http_parser_buffer(
new char[kAllocBufferSize]);
579 buf->base = env->http_parser_buffer();
580 buf->len = kAllocBufferSize;
584 static void OnReadImpl(ssize_t nread,
586 uv_handle_type pending,
588 Parser* parser =
static_cast<Parser*
>(
ctx);
589 HandleScope scope(parser->env()->isolate());
593 tmp_buf.base =
nullptr;
595 parser->prev_read_cb_.fn(nread,
598 parser->prev_read_cb_.ctx);
606 ScopedRetainParser retain(parser);
608 parser->current_buffer_.Clear();
609 Local<Value> ret = parser->Execute(buf->base, nread);
615 Local<Object> obj = parser->object();
616 Local<Value> cb = obj->Get(kOnExecute);
618 if (!cb->IsFunction())
622 parser->current_buffer_len_ = nread;
623 parser->current_buffer_data_ = buf->base;
625 parser->MakeCallback(cb.As<Function>(), 1, &ret);
627 parser->current_buffer_len_ = 0;
628 parser->current_buffer_data_ =
nullptr;
632 Local<Value> Execute(
char*
data,
size_t len) {
633 EscapableHandleScope scope(env()->isolate());
640 http_parser_execute(&
parser_, &settings, data, len);
651 return scope.Escape(Local<Value>());
653 Local<Integer> nparsed_obj =
Integer::New(env()->isolate(), nparsed);
656 if (!
parser_.upgrade && nparsed != len) {
657 enum http_errno err = HTTP_PARSER_ERRNO(&
parser_);
659 Local<Value> e = Exception::Error(env()->parse_error_string());
660 Local<Object> obj = e->ToObject(env()->isolate());
661 obj->Set(env()->bytes_parsed_string(), nparsed_obj);
662 obj->Set(env()->code_string(),
663 OneByteString(env()->isolate(), http_errno_name(err)));
665 return scope.Escape(e);
667 return scope.Escape(nparsed_obj);
670 Local<Array> CreateHeaders() {
671 Local<Array> headers =
Array::New(env()->isolate());
672 Local<Function> fn = env()->push_values_to_array_function();
673 Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX * 2];
678 while (i <
num_values_ && j < arraysize(argv) / 2) {
679 argv[j * 2] =
fields_[i].ToString(env());
680 argv[j * 2 + 1] =
values_[i].ToString(env());
685 fn->Call(env()->context(), headers, j * 2, argv).ToLocalChecked();
695 HandleScope scope(env()->isolate());
697 Local<Object> obj = object();
698 Local<Value> cb = obj->Get(kOnHeaders);
700 if (!cb->IsFunction())
703 Local<Value> argv[2] = {
720 void Init(
enum http_parser_type type) {
721 http_parser_init(&
parser_, type);
746 static const struct http_parser_settings settings;
748 friend class ScopedRetainParser;
752 const struct http_parser_settings Parser::settings = {
753 Parser::on_message_begin,
756 Parser::on_header_field,
757 Parser::on_header_value,
758 Parser::on_headers_complete,
760 Parser::on_message_complete,
766 void InitHttpParser(Local<Object> target,
768 Local<Context> context,
770 Environment* env = Environment::GetCurrent(context);
771 Local<FunctionTemplate>
t = env->NewFunctionTemplate(
Parser::New);
772 t->InstanceTemplate()->SetInternalFieldCount(1);
773 t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(),
"HTTPParser"));
775 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
"REQUEST"),
777 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
"RESPONSE"),
779 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
"kOnHeaders"),
780 Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
781 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
"kOnHeadersComplete"),
782 Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
783 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
"kOnBody"),
784 Integer::NewFromUnsigned(env->isolate(), kOnBody));
785 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
"kOnMessageComplete"),
786 Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
787 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
"kOnExecute"),
788 Integer::NewFromUnsigned(env->isolate(), kOnExecute));
790 Local<Array> methods =
Array::New(env->isolate());
791 #define V(num, name, string) \ 792 methods->Set(num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)); 795 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
"methods"), methods);
797 AsyncWrap::AddWrapMethods(env, t);
798 env->SetProtoMethod(t,
"close", Parser::Close);
799 env->SetProtoMethod(t,
"execute", Parser::Execute);
800 env->SetProtoMethod(t,
"finish", Parser::Finish);
801 env->SetProtoMethod(t,
"reinitialize", Parser::Reinitialize);
802 env->SetProtoMethod(t,
"pause", Parser::Pause<true>);
803 env->SetProtoMethod(t,
"resume", Parser::Pause<false>);
804 env->SetProtoMethod(t,
"consume", Parser::Consume);
805 env->SetProtoMethod(t,
"unconsume", Parser::Unconsume);
806 env->SetProtoMethod(t,
"getCurrentBuffer", Parser::GetCurrentBuffer);
808 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
"HTTPParser"),
StreamResource::Callback< StreamResource::AllocCb > prev_alloc_cb_
bool HasInstance(Local< Value > val)
#define V(num, name, string)
StringPtr status_message_
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
Local< Object > current_buffer_
union node::cares_wrap::@8::CaresAsyncData::@0 data
char * current_buffer_data_
size_t current_buffer_len_
size_t Length(Local< Value > val)
#define HTTP_DATA_CB(name)
char * Data(Local< Value > val)
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
MaybeLocal< Value > MakeCallback(Isolate *isolate, Local< Object > recv, Local< Function > callback, int argc, Local< Value > *argv, async_id asyncId, async_id triggerAsyncId)
void Init(int *argc, const char **argv, int *exec_argc, const char ***exec_argv)
MaybeLocal< Object > Copy(Isolate *isolate, const char *data, size_t length)
StreamResource::Callback< StreamResource::ReadCb > prev_read_cb_