2017-01-03 13:16:48 -08:00
|
|
|
|
// Copyright Joyent, Inc. and other Node contributors.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
|
// copy of this software and associated documentation files (the
|
|
|
|
|
|
// "Software"), to deal in the Software without restriction, including
|
|
|
|
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
|
|
|
|
// persons to whom the Software is furnished to do so, subject to the
|
|
|
|
|
|
// following conditions:
|
|
|
|
|
|
//
|
|
|
|
|
|
// The above copyright notice and this permission notice shall be included
|
|
|
|
|
|
// in all copies or substantial portions of the Software.
|
|
|
|
|
|
//
|
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
|
|
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
|
|
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
|
|
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
2018-11-30 07:39:02 +01:00
|
|
|
|
// This file is included from 2 files, node_http_parser_traditional.cc
|
|
|
|
|
|
// and node_http_parser_llhttp.cc.
|
|
|
|
|
|
|
2019-02-25 17:27:19 -05:00
|
|
|
|
#pragma once
|
2018-11-30 07:39:02 +01:00
|
|
|
|
|
2012-03-10 00:11:11 +01:00
|
|
|
|
#include "node.h"
|
|
|
|
|
|
#include "node_buffer.h"
|
2019-01-13 17:17:26 +08:00
|
|
|
|
#include "util.h"
|
2013-08-11 00:26:11 +02:00
|
|
|
|
|
2017-11-14 13:34:52 +01:00
|
|
|
|
#include "async_wrap-inl.h"
|
2013-08-11 00:26:11 +02:00
|
|
|
|
#include "env-inl.h"
|
2015-08-11 20:02:22 -07:00
|
|
|
|
#include "stream_base-inl.h"
|
2013-07-31 23:16:08 +02:00
|
|
|
|
#include "v8.h"
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2019-02-25 17:27:19 -05:00
|
|
|
|
#include "http_parser_adaptor.h"
|
|
|
|
|
|
|
2019-02-17 10:53:47 +08:00
|
|
|
|
#include <cstdlib> // free()
|
|
|
|
|
|
#include <cstring> // strdup(), strchr()
|
2013-07-31 23:16:08 +02:00
|
|
|
|
|
2018-10-29 22:06:09 -04:00
|
|
|
|
|
2017-02-21 12:59:36 +01:00
|
|
|
|
// This is a binding to http_parser (https://github.com/nodejs/http-parser)
|
2010-01-24 11:21:45 -08:00
|
|
|
|
// The goal is to decouple sockets from parsing for more javascript-level
|
|
|
|
|
|
// agility. A Buffer is read from a socket and passed to parser.execute().
|
|
|
|
|
|
// The parser then issues callbacks with slices of the data
|
|
|
|
|
|
// parser.onMessageBegin
|
|
|
|
|
|
// parser.onPath
|
|
|
|
|
|
// parser.onBody
|
|
|
|
|
|
// ...
|
|
|
|
|
|
// No copying is performed when slicing the buffer, only small reference
|
|
|
|
|
|
// allocations.
|
|
|
|
|
|
|
2010-06-29 23:12:46 -07:00
|
|
|
|
|
2011-12-07 13:31:55 -08:00
|
|
|
|
namespace node {
|
2018-11-30 07:39:02 +01:00
|
|
|
|
namespace { // NOLINT(build/namespaces)
|
2010-09-06 12:10:33 -07:00
|
|
|
|
|
2013-07-03 04:23:44 +02:00
|
|
|
|
using v8::Array;
|
2015-01-13 02:32:09 +01:00
|
|
|
|
using v8::Boolean;
|
2013-08-11 00:26:11 +02:00
|
|
|
|
using v8::Context;
|
2015-08-11 20:02:22 -07:00
|
|
|
|
using v8::EscapableHandleScope;
|
2013-07-03 04:23:44 +02:00
|
|
|
|
using v8::Exception;
|
|
|
|
|
|
using v8::Function;
|
|
|
|
|
|
using v8::FunctionCallbackInfo;
|
|
|
|
|
|
using v8::FunctionTemplate;
|
|
|
|
|
|
using v8::HandleScope;
|
2018-09-02 17:49:11 +02:00
|
|
|
|
using v8::Int32;
|
2013-07-03 04:23:44 +02:00
|
|
|
|
using v8::Integer;
|
|
|
|
|
|
using v8::Local;
|
2017-07-31 02:05:20 +02:00
|
|
|
|
using v8::MaybeLocal;
|
2013-07-03 04:23:44 +02:00
|
|
|
|
using v8::Object;
|
|
|
|
|
|
using v8::String;
|
2013-10-28 13:44:41 +01:00
|
|
|
|
using v8::Uint32;
|
2015-01-13 02:32:09 +01:00
|
|
|
|
using v8::Undefined;
|
2013-07-03 04:23:44 +02:00
|
|
|
|
using v8::Value;
|
|
|
|
|
|
|
2013-08-13 23:47:17 +02:00
|
|
|
|
const uint32_t kOnHeaders = 0;
|
|
|
|
|
|
const uint32_t kOnHeadersComplete = 1;
|
|
|
|
|
|
const uint32_t kOnBody = 2;
|
|
|
|
|
|
const uint32_t kOnMessageComplete = 3;
|
2015-08-11 20:02:22 -07:00
|
|
|
|
const uint32_t kOnExecute = 4;
|
2018-11-09 11:33:12 +08:00
|
|
|
|
// Any more fields than this will be flushed into JS
|
|
|
|
|
|
const size_t kMaxHeaderFieldsCount = 32;
|
2010-09-06 12:10:33 -07:00
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
// helper class for the Parser
|
|
|
|
|
|
struct StringPtr {
|
|
|
|
|
|
StringPtr() {
|
|
|
|
|
|
on_heap_ = false;
|
|
|
|
|
|
Reset();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
~StringPtr() {
|
|
|
|
|
|
Reset();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-12-29 16:06:14 -08:00
|
|
|
|
// If str_ does not point to a heap string yet, this function makes it do
|
|
|
|
|
|
// so. This is called at the end of each http_parser_execute() so as not
|
|
|
|
|
|
// to leak references. See issue #2438 and test-http-parser-bad-ref.js.
|
|
|
|
|
|
void Save() {
|
|
|
|
|
|
if (!on_heap_ && size_ > 0) {
|
|
|
|
|
|
char* s = new char[size_];
|
|
|
|
|
|
memcpy(s, str_, size_);
|
|
|
|
|
|
str_ = s;
|
|
|
|
|
|
on_heap_ = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
void Reset() {
|
|
|
|
|
|
if (on_heap_) {
|
|
|
|
|
|
delete[] str_;
|
|
|
|
|
|
on_heap_ = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-10-22 03:29:32 +02:00
|
|
|
|
str_ = nullptr;
|
2011-09-27 17:07:56 +02:00
|
|
|
|
size_ = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Update(const char* str, size_t size) {
|
2016-06-28 21:21:21 +02:00
|
|
|
|
if (str_ == nullptr) {
|
2011-09-27 17:07:56 +02:00
|
|
|
|
str_ = str;
|
2016-06-28 21:21:21 +02:00
|
|
|
|
} else if (on_heap_ || str_ + size_ != str) {
|
2011-09-27 17:07:56 +02:00
|
|
|
|
// Non-consecutive input, make a copy on the heap.
|
2013-07-31 22:07:29 +04:00
|
|
|
|
// TODO(bnoordhuis) Use slab allocation, O(n) allocs is bad.
|
2011-09-27 17:07:56 +02:00
|
|
|
|
char* s = new char[size_ + size];
|
|
|
|
|
|
memcpy(s, str_, size_);
|
|
|
|
|
|
memcpy(s + size_, str, size);
|
|
|
|
|
|
|
|
|
|
|
|
if (on_heap_)
|
|
|
|
|
|
delete[] str_;
|
|
|
|
|
|
else
|
|
|
|
|
|
on_heap_ = true;
|
|
|
|
|
|
|
|
|
|
|
|
str_ = s;
|
|
|
|
|
|
}
|
|
|
|
|
|
size_ += size;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-02-21 17:02:42 +04:00
|
|
|
|
Local<String> ToString(Environment* env) const {
|
2011-12-28 14:08:19 -08:00
|
|
|
|
if (str_)
|
2014-02-21 17:02:42 +04:00
|
|
|
|
return OneByteString(env->isolate(), str_, size_);
|
2011-12-28 14:08:19 -08:00
|
|
|
|
else
|
2014-02-21 17:02:42 +04:00
|
|
|
|
return String::Empty(env->isolate());
|
2011-09-27 17:07:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char* str_;
|
|
|
|
|
|
bool on_heap_;
|
|
|
|
|
|
size_t size_;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-08 01:14:06 +01:00
|
|
|
|
class Parser : public AsyncWrap, public StreamListener {
|
2013-07-31 22:07:29 +04:00
|
|
|
|
public:
|
2018-10-29 22:06:09 -04:00
|
|
|
|
Parser(Environment* env, Local<Object> wrap, parser_type_t type)
|
2016-02-19 13:13:04 -07:00
|
|
|
|
: AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTPPARSER),
|
2013-10-16 20:34:39 +04:00
|
|
|
|
current_buffer_len_(0),
|
2014-10-22 03:29:32 +02:00
|
|
|
|
current_buffer_data_(nullptr) {
|
2010-01-26 18:37:16 -08:00
|
|
|
|
Init(type);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2018-06-10 16:40:13 +02:00
|
|
|
|
void MemoryInfo(MemoryTracker* tracker) const override {
|
|
|
|
|
|
tracker->TrackField("current_buffer", current_buffer_);
|
2016-02-19 13:13:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-23 17:52:09 -04:00
|
|
|
|
SET_MEMORY_INFO_NAME(Parser)
|
|
|
|
|
|
SET_SELF_SIZE(Parser)
|
2016-02-19 13:13:04 -07:00
|
|
|
|
|
2018-01-13 14:41:16 +01:00
|
|
|
|
int on_message_begin() {
|
2011-12-29 16:06:14 -08:00
|
|
|
|
num_fields_ = num_values_ = 0;
|
2011-09-27 17:07:56 +02:00
|
|
|
|
url_.Reset();
|
2013-09-23 00:06:58 +10:00
|
|
|
|
status_message_.Reset();
|
2011-09-27 17:07:56 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-13 14:41:16 +01:00
|
|
|
|
int on_url(const char* at, size_t length) {
|
2018-10-29 22:06:09 -04:00
|
|
|
|
int rv = TrackHeader(length);
|
|
|
|
|
|
if (rv != 0) {
|
|
|
|
|
|
return rv;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
url_.Update(at, length);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2018-01-13 14:41:16 +01:00
|
|
|
|
int on_status(const char* at, size_t length) {
|
2018-10-29 22:06:09 -04:00
|
|
|
|
int rv = TrackHeader(length);
|
|
|
|
|
|
if (rv != 0) {
|
|
|
|
|
|
return rv;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-09-23 00:06:58 +10:00
|
|
|
|
status_message_.Update(at, length);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-13 14:41:16 +01:00
|
|
|
|
int on_header_field(const char* at, size_t length) {
|
2018-10-29 22:06:09 -04:00
|
|
|
|
int rv = TrackHeader(length);
|
|
|
|
|
|
if (rv != 0) {
|
|
|
|
|
|
return rv;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
if (num_fields_ == num_values_) {
|
|
|
|
|
|
// start of new field name
|
2011-12-29 16:06:14 -08:00
|
|
|
|
num_fields_++;
|
2018-11-09 11:33:12 +08:00
|
|
|
|
if (num_fields_ == kMaxHeaderFieldsCount) {
|
2011-12-29 16:06:14 -08:00
|
|
|
|
// ran out of space - flush to javascript land
|
2011-09-27 17:07:56 +02:00
|
|
|
|
Flush();
|
2011-12-29 16:06:14 -08:00
|
|
|
|
num_fields_ = 1;
|
|
|
|
|
|
num_values_ = 0;
|
2011-09-27 17:07:56 +02:00
|
|
|
|
}
|
2011-12-29 16:06:14 -08:00
|
|
|
|
fields_[num_fields_ - 1].Reset();
|
2011-09-27 17:07:56 +02:00
|
|
|
|
}
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2018-11-09 11:33:12 +08:00
|
|
|
|
CHECK_LT(num_fields_, kMaxHeaderFieldsCount);
|
2014-10-11 16:52:07 +02:00
|
|
|
|
CHECK_EQ(num_fields_, num_values_ + 1);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2011-12-29 16:06:14 -08:00
|
|
|
|
fields_[num_fields_ - 1].Update(at, length);
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-13 14:41:16 +01:00
|
|
|
|
int on_header_value(const char* at, size_t length) {
|
2018-10-29 22:06:09 -04:00
|
|
|
|
int rv = TrackHeader(length);
|
|
|
|
|
|
if (rv != 0) {
|
|
|
|
|
|
return rv;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
if (num_values_ != num_fields_) {
|
|
|
|
|
|
// start of new header value
|
2011-12-29 16:06:14 -08:00
|
|
|
|
num_values_++;
|
|
|
|
|
|
values_[num_values_ - 1].Reset();
|
2011-09-27 17:07:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-03-31 12:54:09 +02:00
|
|
|
|
CHECK_LT(num_values_, arraysize(values_));
|
2014-10-11 16:52:07 +02:00
|
|
|
|
CHECK_EQ(num_values_, num_fields_);
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2011-12-29 16:06:14 -08:00
|
|
|
|
values_[num_values_ - 1].Update(at, length);
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-13 14:41:16 +01:00
|
|
|
|
int on_headers_complete() {
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
header_nread_ = 0;
|
|
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
|
2015-01-13 02:32:09 +01:00
|
|
|
|
// Arguments for the on-headers-complete javascript callback. This
|
|
|
|
|
|
// list needs to be kept in sync with the actual argument list for
|
|
|
|
|
|
// `parserOnHeadersComplete` in lib/_http_common.js.
|
|
|
|
|
|
enum on_headers_complete_arg_index {
|
|
|
|
|
|
A_VERSION_MAJOR = 0,
|
|
|
|
|
|
A_VERSION_MINOR,
|
|
|
|
|
|
A_HEADERS,
|
|
|
|
|
|
A_METHOD,
|
|
|
|
|
|
A_URL,
|
|
|
|
|
|
A_STATUS_CODE,
|
|
|
|
|
|
A_STATUS_MESSAGE,
|
|
|
|
|
|
A_UPGRADE,
|
|
|
|
|
|
A_SHOULD_KEEP_ALIVE,
|
|
|
|
|
|
A_MAX
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Local<Value> argv[A_MAX];
|
2013-09-27 10:30:02 -07:00
|
|
|
|
Local<Object> obj = object();
|
2018-11-08 07:22:13 +01:00
|
|
|
|
Local<Value> cb = obj->Get(env()->context(),
|
|
|
|
|
|
kOnHeadersComplete).ToLocalChecked();
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
|
|
|
|
|
if (!cb->IsFunction())
|
|
|
|
|
|
return 0;
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2015-01-13 02:32:09 +01:00
|
|
|
|
Local<Value> undefined = Undefined(env()->isolate());
|
2016-03-31 12:47:06 +02:00
|
|
|
|
for (size_t i = 0; i < arraysize(argv); i++)
|
2015-01-13 02:32:09 +01:00
|
|
|
|
argv[i] = undefined;
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
if (have_flushed_) {
|
|
|
|
|
|
// Slow case, flush remaining headers.
|
|
|
|
|
|
Flush();
|
2013-07-31 22:07:29 +04:00
|
|
|
|
} else {
|
2011-09-27 17:07:56 +02:00
|
|
|
|
// Fast case, pass headers and URL to JS land.
|
2015-01-13 02:32:09 +01:00
|
|
|
|
argv[A_HEADERS] = CreateHeaders();
|
2011-09-27 17:07:56 +02:00
|
|
|
|
if (parser_.type == HTTP_REQUEST)
|
2015-01-13 02:32:09 +01:00
|
|
|
|
argv[A_URL] = url_.ToString(env());
|
2011-09-27 17:07:56 +02:00
|
|
|
|
}
|
2015-01-13 02:32:09 +01:00
|
|
|
|
|
|
|
|
|
|
num_fields_ = 0;
|
|
|
|
|
|
num_values_ = 0;
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2010-01-24 11:21:45 -08:00
|
|
|
|
// METHOD
|
2011-09-27 17:07:56 +02:00
|
|
|
|
if (parser_.type == HTTP_REQUEST) {
|
2015-01-13 02:32:09 +01:00
|
|
|
|
argv[A_METHOD] =
|
|
|
|
|
|
Uint32::NewFromUnsigned(env()->isolate(), parser_.method);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// STATUS
|
2011-09-27 17:07:56 +02:00
|
|
|
|
if (parser_.type == HTTP_RESPONSE) {
|
2015-01-13 02:32:09 +01:00
|
|
|
|
argv[A_STATUS_CODE] =
|
|
|
|
|
|
Integer::New(env()->isolate(), parser_.status_code);
|
|
|
|
|
|
argv[A_STATUS_MESSAGE] = status_message_.ToString(env());
|
2010-01-24 11:21:45 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// VERSION
|
2015-01-13 02:32:09 +01:00
|
|
|
|
argv[A_VERSION_MAJOR] = Integer::New(env()->isolate(), parser_.http_major);
|
|
|
|
|
|
argv[A_VERSION_MINOR] = Integer::New(env()->isolate(), parser_.http_minor);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2018-10-29 22:06:09 -04:00
|
|
|
|
bool should_keep_alive;
|
|
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
should_keep_alive = llhttp_should_keep_alive(&parser_);
|
|
|
|
|
|
#else /* !NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
should_keep_alive = http_should_keep_alive(&parser_);
|
|
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
|
2015-01-13 02:32:09 +01:00
|
|
|
|
argv[A_SHOULD_KEEP_ALIVE] =
|
2018-10-29 22:06:09 -04:00
|
|
|
|
Boolean::New(env()->isolate(), should_keep_alive);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2015-01-13 02:32:09 +01:00
|
|
|
|
argv[A_UPGRADE] = Boolean::New(env()->isolate(), parser_.upgrade);
|
2010-04-14 03:52:15 -07:00
|
|
|
|
|
2019-03-20 19:19:02 +08:00
|
|
|
|
AsyncCallbackScope callback_scope(env());
|
2016-02-19 13:13:04 -07:00
|
|
|
|
|
2017-07-31 02:05:20 +02:00
|
|
|
|
MaybeLocal<Value> head_response =
|
2016-03-31 12:47:06 +02:00
|
|
|
|
MakeCallback(cb.As<Function>(), arraysize(argv), argv);
|
2010-01-26 18:37:16 -08:00
|
|
|
|
|
2018-08-29 16:12:36 +02:00
|
|
|
|
int64_t val;
|
|
|
|
|
|
|
|
|
|
|
|
if (head_response.IsEmpty() || !head_response.ToLocalChecked()
|
|
|
|
|
|
->IntegerValue(env()->context())
|
|
|
|
|
|
.To(&val)) {
|
2011-09-27 17:07:56 +02:00
|
|
|
|
got_exception_ = true;
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-29 16:12:36 +02:00
|
|
|
|
return val;
|
2011-09-27 17:07:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-13 14:41:16 +01:00
|
|
|
|
int on_body(const char* at, size_t length) {
|
2015-08-11 20:02:22 -07:00
|
|
|
|
EscapableHandleScope scope(env()->isolate());
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2013-09-27 10:30:02 -07:00
|
|
|
|
Local<Object> obj = object();
|
2018-11-08 07:22:13 +01:00
|
|
|
|
Local<Value> cb = obj->Get(env()->context(), kOnBody).ToLocalChecked();
|
2013-07-03 04:23:44 +02:00
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
if (!cb->IsFunction())
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
2015-08-11 20:02:22 -07:00
|
|
|
|
// We came from consumed stream
|
|
|
|
|
|
if (current_buffer_.IsEmpty()) {
|
|
|
|
|
|
// Make sure Buffer will be in parent HandleScope
|
|
|
|
|
|
current_buffer_ = scope.Escape(Buffer::Copy(
|
|
|
|
|
|
env()->isolate(),
|
|
|
|
|
|
current_buffer_data_,
|
|
|
|
|
|
current_buffer_len_).ToLocalChecked());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-03-26 06:57:28 -07:00
|
|
|
|
Local<Value> argv[3] = {
|
2013-08-11 00:26:11 +02:00
|
|
|
|
current_buffer_,
|
2014-03-13 20:38:14 +04:00
|
|
|
|
Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
|
|
|
|
|
|
Integer::NewFromUnsigned(env()->isolate(), length)
|
2011-09-27 17:07:56 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
2017-07-31 02:05:20 +02:00
|
|
|
|
MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
|
|
|
|
|
|
arraysize(argv),
|
|
|
|
|
|
argv);
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
|
|
|
|
|
if (r.IsEmpty()) {
|
|
|
|
|
|
got_exception_ = true;
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
2018-11-20 23:33:49 -05:00
|
|
|
|
llhttp_set_error_reason(&parser_, "HPE_JS_EXCEPTION:JS Exception");
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
return HPE_USER;
|
2010-05-20 15:21:40 -07:00
|
|
|
|
}
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
|
|
|
|
|
return 0;
|
2010-01-24 11:21:45 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2018-01-13 14:41:16 +01:00
|
|
|
|
int on_message_complete() {
|
2014-02-21 17:02:42 +04:00
|
|
|
|
HandleScope scope(env()->isolate());
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2011-12-29 16:06:14 -08:00
|
|
|
|
if (num_fields_)
|
2013-07-31 22:07:29 +04:00
|
|
|
|
Flush(); // Flush trailing HTTP headers.
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2013-09-27 10:30:02 -07:00
|
|
|
|
Local<Object> obj = object();
|
2018-11-08 07:22:13 +01:00
|
|
|
|
Local<Value> cb = obj->Get(env()->context(),
|
|
|
|
|
|
kOnMessageComplete).ToLocalChecked();
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
if (!cb->IsFunction())
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
2019-03-20 19:19:02 +08:00
|
|
|
|
AsyncCallbackScope callback_scope(env());
|
2016-02-19 13:13:04 -07:00
|
|
|
|
|
2017-07-31 02:05:20 +02:00
|
|
|
|
MaybeLocal<Value> r = MakeCallback(cb.As<Function>(), 0, nullptr);
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
|
|
|
|
|
if (r.IsEmpty()) {
|
|
|
|
|
|
got_exception_ = true;
|
2018-11-20 23:33:49 -05:00
|
|
|
|
return -1;
|
2011-09-27 17:07:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
// Reset nread for the next chunk
|
|
|
|
|
|
int on_chunk_header() {
|
|
|
|
|
|
header_nread_ = 0;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Reset nread for the next chunk
|
|
|
|
|
|
int on_chunk_complete() {
|
|
|
|
|
|
header_nread_ = 0;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2013-07-03 04:23:44 +02:00
|
|
|
|
static void New(const FunctionCallbackInfo<Value>& args) {
|
2014-10-13 15:19:55 +02:00
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
2018-09-02 17:49:11 +02:00
|
|
|
|
CHECK(args[0]->IsInt32());
|
2018-10-29 22:06:09 -04:00
|
|
|
|
parser_type_t type =
|
|
|
|
|
|
static_cast<parser_type_t>(args[0].As<Int32>()->Value());
|
2014-10-11 16:52:07 +02:00
|
|
|
|
CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
|
2013-09-25 12:57:03 +02:00
|
|
|
|
new Parser(env, args.This(), type);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2014-08-23 00:31:44 +02:00
|
|
|
|
static void Close(const FunctionCallbackInfo<Value>& args) {
|
2016-04-13 13:16:42 -06:00
|
|
|
|
Parser* parser;
|
|
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
|
2015-09-18 12:15:39 -07:00
|
|
|
|
|
2018-01-13 17:48:07 +01:00
|
|
|
|
delete parser;
|
2014-08-23 00:31:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-07-17 16:47:12 -07:00
|
|
|
|
static void Free(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
|
|
Parser* parser;
|
|
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
|
|
|
|
|
|
|
|
|
|
|
|
// Since the Parser destructor isn't going to run the destroy() callbacks
|
|
|
|
|
|
// it needs to be triggered manually.
|
|
|
|
|
|
parser->EmitTraceEventDestroy();
|
|
|
|
|
|
parser->EmitDestroy(env, parser->get_async_id());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-12-29 16:06:14 -08:00
|
|
|
|
void Save() {
|
|
|
|
|
|
url_.Save();
|
2013-09-23 00:06:58 +10:00
|
|
|
|
status_message_.Save();
|
2011-12-29 16:06:14 -08:00
|
|
|
|
|
2016-03-31 12:54:09 +02:00
|
|
|
|
for (size_t i = 0; i < num_fields_; i++) {
|
2011-12-29 16:06:14 -08:00
|
|
|
|
fields_[i].Save();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-03-31 12:54:09 +02:00
|
|
|
|
for (size_t i = 0; i < num_values_; i++) {
|
2011-12-29 16:06:14 -08:00
|
|
|
|
values_[i].Save();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-06-21 11:35:29 -07:00
|
|
|
|
// var bytesParsed = parser->execute(buffer);
|
2013-07-03 04:23:44 +02:00
|
|
|
|
static void Execute(const FunctionCallbackInfo<Value>& args) {
|
2016-04-13 13:16:42 -06:00
|
|
|
|
Parser* parser;
|
|
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
|
2014-10-11 16:52:07 +02:00
|
|
|
|
CHECK(parser->current_buffer_.IsEmpty());
|
|
|
|
|
|
CHECK_EQ(parser->current_buffer_len_, 0);
|
2018-05-20 17:44:06 +02:00
|
|
|
|
CHECK_NULL(parser->current_buffer_data_);
|
2014-10-11 16:52:07 +02:00
|
|
|
|
CHECK_EQ(Buffer::HasInstance(args[0]), true);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2013-08-11 00:26:11 +02:00
|
|
|
|
Local<Object> buffer_obj = args[0].As<Object>();
|
|
|
|
|
|
char* buffer_data = Buffer::Data(buffer_obj);
|
2010-09-06 12:10:33 -07:00
|
|
|
|
size_t buffer_len = Buffer::Length(buffer_obj);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2013-08-11 00:26:11 +02:00
|
|
|
|
// This is a hack to get the current_buffer to the callbacks with the least
|
|
|
|
|
|
// amount of overhead. Nothing else will run while http_parser_execute()
|
|
|
|
|
|
// runs, therefore this pointer can be set and used for the execution.
|
|
|
|
|
|
parser->current_buffer_ = buffer_obj;
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2015-08-11 20:02:22 -07:00
|
|
|
|
Local<Value> ret = parser->Execute(buffer_data, buffer_len);
|
2013-08-11 00:26:11 +02:00
|
|
|
|
|
2015-08-11 20:02:22 -07:00
|
|
|
|
if (!ret.IsEmpty())
|
|
|
|
|
|
args.GetReturnValue().Set(ret);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2013-07-03 04:23:44 +02:00
|
|
|
|
static void Finish(const FunctionCallbackInfo<Value>& args) {
|
2016-04-13 13:16:42 -06:00
|
|
|
|
Parser* parser;
|
|
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
|
2010-01-25 17:55:02 -08:00
|
|
|
|
|
2014-10-11 16:52:07 +02:00
|
|
|
|
CHECK(parser->current_buffer_.IsEmpty());
|
2018-11-29 22:01:33 -05:00
|
|
|
|
Local<Value> ret = parser->Execute(nullptr, 0);
|
|
|
|
|
|
|
|
|
|
|
|
if (!ret.IsEmpty())
|
|
|
|
|
|
args.GetReturnValue().Set(ret);
|
2010-01-26 18:37:16 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2013-07-03 04:23:44 +02:00
|
|
|
|
static void Reinitialize(const FunctionCallbackInfo<Value>& args) {
|
2014-10-13 15:19:55 +02:00
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
2010-01-26 18:37:16 -08:00
|
|
|
|
|
2018-09-02 17:49:11 +02:00
|
|
|
|
CHECK(args[0]->IsInt32());
|
2018-10-01 17:11:25 +02:00
|
|
|
|
CHECK(args[1]->IsBoolean());
|
|
|
|
|
|
bool isReused = args[1]->IsTrue();
|
2018-10-29 22:06:09 -04:00
|
|
|
|
parser_type_t type =
|
|
|
|
|
|
static_cast<parser_type_t>(args[0].As<Int32>()->Value());
|
2010-01-26 18:37:16 -08:00
|
|
|
|
|
2014-10-11 16:52:07 +02:00
|
|
|
|
CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
|
2016-04-13 13:16:42 -06:00
|
|
|
|
Parser* parser;
|
|
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
|
2013-08-11 00:26:11 +02:00
|
|
|
|
// Should always be called from the same context.
|
2014-10-11 16:52:07 +02:00
|
|
|
|
CHECK_EQ(env, parser->env());
|
2018-10-01 17:11:25 +02:00
|
|
|
|
// This parser has either just been created or it is being reused.
|
|
|
|
|
|
// We must only call AsyncReset for the latter case, because AsyncReset has
|
|
|
|
|
|
// already been called via the constructor for the former case.
|
|
|
|
|
|
if (isReused) {
|
|
|
|
|
|
parser->AsyncReset();
|
|
|
|
|
|
}
|
2011-09-27 17:07:56 +02:00
|
|
|
|
parser->Init(type);
|
2010-01-25 17:55:02 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2013-10-12 17:47:35 -07:00
|
|
|
|
template <bool should_pause>
|
|
|
|
|
|
static void Pause(const FunctionCallbackInfo<Value>& args) {
|
2014-10-13 15:19:55 +02:00
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
2016-04-13 13:16:42 -06:00
|
|
|
|
Parser* parser;
|
|
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
|
2013-10-12 17:47:35 -07:00
|
|
|
|
// Should always be called from the same context.
|
2014-10-11 16:52:07 +02:00
|
|
|
|
CHECK_EQ(env, parser->env());
|
2018-10-29 22:06:09 -04:00
|
|
|
|
|
|
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
if (parser->execute_depth_) {
|
|
|
|
|
|
parser->pending_pause_ = should_pause;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (should_pause) {
|
|
|
|
|
|
llhttp_pause(&parser->parser_);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
llhttp_resume(&parser->parser_);
|
|
|
|
|
|
}
|
|
|
|
|
|
#else /* !NODE_EXPERIMENTAL_HTTP */
|
2013-10-12 17:47:35 -07:00
|
|
|
|
http_parser_pause(&parser->parser_, should_pause);
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
2013-10-12 17:47:35 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-08-11 20:02:22 -07:00
|
|
|
|
static void Consume(const FunctionCallbackInfo<Value>& args) {
|
2016-04-13 13:16:42 -06:00
|
|
|
|
Parser* parser;
|
|
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
|
2019-03-08 09:47:45 +01:00
|
|
|
|
CHECK(args[0]->IsObject());
|
|
|
|
|
|
StreamBase* stream = StreamBase::FromObject(args[0].As<Object>());
|
2018-05-20 17:44:06 +02:00
|
|
|
|
CHECK_NOT_NULL(stream);
|
2018-01-08 01:14:06 +01:00
|
|
|
|
stream->PushStreamListener(parser);
|
2015-08-11 20:02:22 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void Unconsume(const FunctionCallbackInfo<Value>& args) {
|
2016-04-13 13:16:42 -06:00
|
|
|
|
Parser* parser;
|
|
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
|
2015-08-11 20:02:22 -07:00
|
|
|
|
|
|
|
|
|
|
// Already unconsumed
|
2018-01-08 01:14:06 +01:00
|
|
|
|
if (parser->stream_ == nullptr)
|
2015-08-11 20:02:22 -07:00
|
|
|
|
return;
|
|
|
|
|
|
|
2018-01-08 01:14:06 +01:00
|
|
|
|
parser->stream_->RemoveStreamListener(parser);
|
2015-08-11 20:02:22 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void GetCurrentBuffer(const FunctionCallbackInfo<Value>& args) {
|
2016-04-13 13:16:42 -06:00
|
|
|
|
Parser* parser;
|
|
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
|
2015-08-11 20:02:22 -07:00
|
|
|
|
|
|
|
|
|
|
Local<Object> ret = Buffer::Copy(
|
|
|
|
|
|
parser->env(),
|
|
|
|
|
|
parser->current_buffer_data_,
|
|
|
|
|
|
parser->current_buffer_len_).ToLocalChecked();
|
|
|
|
|
|
|
|
|
|
|
|
args.GetReturnValue().Set(ret);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
static const size_t kAllocBufferSize = 64 * 1024;
|
|
|
|
|
|
|
2018-01-08 01:14:06 +01:00
|
|
|
|
uv_buf_t OnStreamAlloc(size_t suggested_size) override {
|
2018-03-07 14:16:34 +01:00
|
|
|
|
// For most types of streams, OnStreamRead will be immediately after
|
|
|
|
|
|
// OnStreamAlloc, and will consume all data, so using a static buffer for
|
2019-02-18 22:58:27 +01:00
|
|
|
|
// reading is more efficient. For other streams, just use Malloc() directly.
|
2018-03-07 14:16:34 +01:00
|
|
|
|
if (env()->http_parser_buffer_in_use())
|
2019-02-18 22:58:27 +01:00
|
|
|
|
return uv_buf_init(Malloc(suggested_size), suggested_size);
|
2018-03-07 14:16:34 +01:00
|
|
|
|
env()->set_http_parser_buffer_in_use(true);
|
|
|
|
|
|
|
2018-01-08 01:14:06 +01:00
|
|
|
|
if (env()->http_parser_buffer() == nullptr)
|
|
|
|
|
|
env()->set_http_parser_buffer(new char[kAllocBufferSize]);
|
2015-08-11 20:02:22 -07:00
|
|
|
|
|
2018-01-08 01:14:06 +01:00
|
|
|
|
return uv_buf_init(env()->http_parser_buffer(), kAllocBufferSize);
|
2015-08-11 20:02:22 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-08 01:14:06 +01:00
|
|
|
|
void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override {
|
|
|
|
|
|
HandleScope scope(env()->isolate());
|
2018-03-07 14:16:34 +01:00
|
|
|
|
// Once we’re done here, either indicate that the HTTP parser buffer
|
|
|
|
|
|
// is free for re-use, or free() the data if it didn’t come from there
|
|
|
|
|
|
// in the first place.
|
|
|
|
|
|
OnScopeLeave on_scope_leave([&]() {
|
|
|
|
|
|
if (buf.base == env()->http_parser_buffer())
|
|
|
|
|
|
env()->set_http_parser_buffer_in_use(false);
|
|
|
|
|
|
else
|
|
|
|
|
|
free(buf.base);
|
|
|
|
|
|
});
|
2015-08-11 20:02:22 -07:00
|
|
|
|
|
|
|
|
|
|
if (nread < 0) {
|
2018-01-08 01:14:06 +01:00
|
|
|
|
PassReadErrorToPreviousListener(nread);
|
2015-08-11 20:02:22 -07:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Ignore, empty reads have special meaning in http parser
|
|
|
|
|
|
if (nread == 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2018-01-08 01:14:06 +01:00
|
|
|
|
current_buffer_.Clear();
|
|
|
|
|
|
Local<Value> ret = Execute(buf.base, nread);
|
2015-08-11 20:02:22 -07:00
|
|
|
|
|
|
|
|
|
|
// Exception
|
|
|
|
|
|
if (ret.IsEmpty())
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2018-01-08 01:14:06 +01:00
|
|
|
|
Local<Value> cb =
|
|
|
|
|
|
object()->Get(env()->context(), kOnExecute).ToLocalChecked();
|
2015-08-11 20:02:22 -07:00
|
|
|
|
|
|
|
|
|
|
if (!cb->IsFunction())
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
// Hooks for GetCurrentBuffer
|
2018-01-08 01:14:06 +01:00
|
|
|
|
current_buffer_len_ = nread;
|
|
|
|
|
|
current_buffer_data_ = buf.base;
|
2015-08-11 20:02:22 -07:00
|
|
|
|
|
2018-01-08 01:14:06 +01:00
|
|
|
|
MakeCallback(cb.As<Function>(), 1, &ret);
|
2015-08-11 20:02:22 -07:00
|
|
|
|
|
2018-01-08 01:14:06 +01:00
|
|
|
|
current_buffer_len_ = 0;
|
|
|
|
|
|
current_buffer_data_ = nullptr;
|
2015-08-11 20:02:22 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Local<Value> Execute(char* data, size_t len) {
|
|
|
|
|
|
EscapableHandleScope scope(env()->isolate());
|
|
|
|
|
|
|
|
|
|
|
|
current_buffer_len_ = len;
|
|
|
|
|
|
current_buffer_data_ = data;
|
|
|
|
|
|
got_exception_ = false;
|
|
|
|
|
|
|
2018-10-29 22:06:09 -04:00
|
|
|
|
parser_errno_t err;
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
// Do not allow re-entering `http_parser_execute()`
|
|
|
|
|
|
CHECK_EQ(execute_depth_, 0);
|
|
|
|
|
|
|
|
|
|
|
|
execute_depth_++;
|
|
|
|
|
|
if (data == nullptr) {
|
|
|
|
|
|
err = llhttp_finish(&parser_);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
err = llhttp_execute(&parser_, data, len);
|
|
|
|
|
|
Save();
|
|
|
|
|
|
}
|
|
|
|
|
|
execute_depth_--;
|
|
|
|
|
|
|
|
|
|
|
|
// Calculate bytes read and resume after Upgrade/CONNECT pause
|
|
|
|
|
|
size_t nread = len;
|
|
|
|
|
|
if (err != HPE_OK) {
|
|
|
|
|
|
nread = llhttp_get_error_pos(&parser_) - data;
|
|
|
|
|
|
|
|
|
|
|
|
// This isn't a real pause, just a way to stop parsing early.
|
|
|
|
|
|
if (err == HPE_PAUSED_UPGRADE) {
|
|
|
|
|
|
err = HPE_OK;
|
|
|
|
|
|
llhttp_resume_after_upgrade(&parser_);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Apply pending pause
|
|
|
|
|
|
if (pending_pause_) {
|
|
|
|
|
|
pending_pause_ = false;
|
|
|
|
|
|
llhttp_pause(&parser_);
|
|
|
|
|
|
}
|
|
|
|
|
|
#else /* !NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
size_t nread = http_parser_execute(&parser_, &settings, data, len);
|
2018-11-29 22:01:33 -05:00
|
|
|
|
err = HTTP_PARSER_ERRNO(&parser_);
|
|
|
|
|
|
|
|
|
|
|
|
// Finish()
|
|
|
|
|
|
if (data == nullptr) {
|
|
|
|
|
|
// `http_parser_execute()` returns either `0` or `1` when `len` is 0
|
|
|
|
|
|
// (part of the finishing sequence).
|
|
|
|
|
|
CHECK_EQ(len, 0);
|
|
|
|
|
|
switch (nread) {
|
|
|
|
|
|
case 0:
|
|
|
|
|
|
err = HPE_OK;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
nread = 0;
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
UNREACHABLE();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Regular Execute()
|
|
|
|
|
|
} else {
|
2018-10-29 22:06:09 -04:00
|
|
|
|
Save();
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
2015-08-11 20:02:22 -07:00
|
|
|
|
|
|
|
|
|
|
// Unassign the 'buffer_' variable
|
|
|
|
|
|
current_buffer_.Clear();
|
|
|
|
|
|
current_buffer_len_ = 0;
|
|
|
|
|
|
current_buffer_data_ = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
// If there was an exception in one of the callbacks
|
|
|
|
|
|
if (got_exception_)
|
|
|
|
|
|
return scope.Escape(Local<Value>());
|
|
|
|
|
|
|
2018-10-29 22:06:09 -04:00
|
|
|
|
Local<Integer> nread_obj = Integer::New(env()->isolate(), nread);
|
|
|
|
|
|
|
2015-08-11 20:02:22 -07:00
|
|
|
|
// If there was a parse error in one of the callbacks
|
|
|
|
|
|
// TODO(bnoordhuis) What if there is an error on EOF?
|
2018-10-29 22:06:09 -04:00
|
|
|
|
if (!parser_.upgrade && err != HPE_OK) {
|
2015-08-11 20:02:22 -07:00
|
|
|
|
Local<Value> e = Exception::Error(env()->parse_error_string());
|
2018-10-07 10:07:25 -04:00
|
|
|
|
Local<Object> obj = e->ToObject(env()->isolate()->GetCurrentContext())
|
|
|
|
|
|
.ToLocalChecked();
|
2018-11-08 07:22:13 +01:00
|
|
|
|
obj->Set(env()->context(),
|
|
|
|
|
|
env()->bytes_parsed_string(),
|
2019-04-09 15:21:36 -07:00
|
|
|
|
nread_obj).Check();
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
2018-11-20 23:33:49 -05:00
|
|
|
|
const char* errno_reason = llhttp_get_error_reason(&parser_);
|
|
|
|
|
|
|
|
|
|
|
|
Local<String> code;
|
|
|
|
|
|
Local<String> reason;
|
|
|
|
|
|
if (err == HPE_USER) {
|
|
|
|
|
|
const char* colon = strchr(errno_reason, ':');
|
2019-02-04 15:38:51 +08:00
|
|
|
|
CHECK_NOT_NULL(colon);
|
2018-11-20 23:33:49 -05:00
|
|
|
|
code = OneByteString(env()->isolate(), errno_reason,
|
|
|
|
|
|
colon - errno_reason);
|
|
|
|
|
|
reason = OneByteString(env()->isolate(), colon + 1);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
code = OneByteString(env()->isolate(), llhttp_errno_name(err));
|
|
|
|
|
|
reason = OneByteString(env()->isolate(), errno_reason);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-04-09 15:21:36 -07:00
|
|
|
|
obj->Set(env()->context(), env()->code_string(), code).Check();
|
|
|
|
|
|
obj->Set(env()->context(), env()->reason_string(), reason).Check();
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#else /* !NODE_EXPERIMENTAL_HTTP */
|
2018-11-08 07:22:13 +01:00
|
|
|
|
obj->Set(env()->context(),
|
|
|
|
|
|
env()->code_string(),
|
|
|
|
|
|
OneByteString(env()->isolate(),
|
2019-04-09 15:21:36 -07:00
|
|
|
|
http_errno_name(err))).Check();
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
2015-08-11 20:02:22 -07:00
|
|
|
|
return scope.Escape(e);
|
|
|
|
|
|
}
|
2018-10-29 22:06:09 -04:00
|
|
|
|
|
2018-11-29 22:01:33 -05:00
|
|
|
|
// No return value is needed for `Finish()`
|
|
|
|
|
|
if (data == nullptr) {
|
|
|
|
|
|
return scope.Escape(Local<Value>());
|
|
|
|
|
|
}
|
2018-10-29 22:06:09 -04:00
|
|
|
|
return scope.Escape(nread_obj);
|
2015-08-11 20:02:22 -07:00
|
|
|
|
}
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
Local<Array> CreateHeaders() {
|
2018-11-09 11:33:12 +08:00
|
|
|
|
// There could be extra entries but the max size should be fixed
|
|
|
|
|
|
Local<Value> headers_v[kMaxHeaderFieldsCount * 2];
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < num_values_; ++i) {
|
|
|
|
|
|
headers_v[i * 2] = fields_[i].ToString(env());
|
|
|
|
|
|
headers_v[i * 2 + 1] = values_[i].ToString(env());
|
|
|
|
|
|
}
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2018-11-09 11:33:12 +08:00
|
|
|
|
return Array::New(env()->isolate(), headers_v, num_values_ * 2);
|
2011-09-27 17:07:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// spill headers and request path to JS land
|
|
|
|
|
|
void Flush() {
|
2014-02-21 17:02:42 +04:00
|
|
|
|
HandleScope scope(env()->isolate());
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2013-09-27 10:30:02 -07:00
|
|
|
|
Local<Object> obj = object();
|
2018-11-08 07:22:13 +01:00
|
|
|
|
Local<Value> cb = obj->Get(env()->context(), kOnHeaders).ToLocalChecked();
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
|
|
|
|
|
if (!cb->IsFunction())
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2012-03-26 06:57:28 -07:00
|
|
|
|
Local<Value> argv[2] = {
|
2011-09-27 17:07:56 +02:00
|
|
|
|
CreateHeaders(),
|
2014-02-21 17:02:42 +04:00
|
|
|
|
url_.ToString(env())
|
2011-09-27 17:07:56 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
2017-07-31 02:05:20 +02:00
|
|
|
|
MaybeLocal<Value> r = MakeCallback(cb.As<Function>(),
|
|
|
|
|
|
arraysize(argv),
|
|
|
|
|
|
argv);
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
|
|
|
|
|
if (r.IsEmpty())
|
|
|
|
|
|
got_exception_ = true;
|
|
|
|
|
|
|
|
|
|
|
|
url_.Reset();
|
|
|
|
|
|
have_flushed_ = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-10-29 22:06:09 -04:00
|
|
|
|
void Init(parser_type_t type) {
|
|
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
llhttp_init(&parser_, type, &settings);
|
2018-11-27 11:04:09 +11:00
|
|
|
|
header_nread_ = 0;
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#else /* !NODE_EXPERIMENTAL_HTTP */
|
2010-01-26 18:37:16 -08:00
|
|
|
|
http_parser_init(&parser_, type);
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
2011-09-27 17:07:56 +02:00
|
|
|
|
url_.Reset();
|
2013-09-23 00:06:58 +10:00
|
|
|
|
status_message_.Reset();
|
2011-12-29 16:06:14 -08:00
|
|
|
|
num_fields_ = 0;
|
|
|
|
|
|
num_values_ = 0;
|
2011-09-27 17:07:56 +02:00
|
|
|
|
have_flushed_ = false;
|
|
|
|
|
|
got_exception_ = false;
|
2010-01-26 18:37:16 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2018-10-29 22:06:09 -04:00
|
|
|
|
int TrackHeader(size_t len) {
|
|
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
header_nread_ += len;
|
2019-01-01 13:56:53 +08:00
|
|
|
|
if (header_nread_ >= per_process::cli_options->max_http_header_size) {
|
2018-11-20 23:33:49 -05:00
|
|
|
|
llhttp_set_error_reason(&parser_, "HPE_HEADER_OVERFLOW:Header overflow");
|
2018-10-29 22:06:09 -04:00
|
|
|
|
return HPE_USER;
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int MaybePause() {
|
|
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
CHECK_NE(execute_depth_, 0);
|
|
|
|
|
|
|
|
|
|
|
|
if (!pending_pause_) {
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pending_pause_ = false;
|
|
|
|
|
|
llhttp_set_error_reason(&parser_, "Paused in callback");
|
|
|
|
|
|
return HPE_PAUSED;
|
|
|
|
|
|
#else /* !NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
parser_t parser_;
|
2018-11-09 11:33:12 +08:00
|
|
|
|
StringPtr fields_[kMaxHeaderFieldsCount]; // header fields
|
|
|
|
|
|
StringPtr values_[kMaxHeaderFieldsCount]; // header values
|
2011-09-27 17:07:56 +02:00
|
|
|
|
StringPtr url_;
|
2013-09-23 00:06:58 +10:00
|
|
|
|
StringPtr status_message_;
|
2016-03-31 12:54:09 +02:00
|
|
|
|
size_t num_fields_;
|
|
|
|
|
|
size_t num_values_;
|
2011-09-27 17:07:56 +02:00
|
|
|
|
bool have_flushed_;
|
|
|
|
|
|
bool got_exception_;
|
2013-08-11 00:26:11 +02:00
|
|
|
|
Local<Object> current_buffer_;
|
|
|
|
|
|
size_t current_buffer_len_;
|
|
|
|
|
|
char* current_buffer_data_;
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
unsigned int execute_depth_ = 0;
|
|
|
|
|
|
bool pending_pause_ = false;
|
|
|
|
|
|
uint64_t header_nread_ = 0;
|
|
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
2018-01-13 14:41:16 +01:00
|
|
|
|
|
|
|
|
|
|
// These are helper functions for filling `http_parser_settings`, which turn
|
|
|
|
|
|
// a member function of Parser into a C-style HTTP parser callback.
|
|
|
|
|
|
template <typename Parser, Parser> struct Proxy;
|
|
|
|
|
|
template <typename Parser, typename ...Args, int (Parser::*Member)(Args...)>
|
|
|
|
|
|
struct Proxy<int (Parser::*)(Args...), Member> {
|
2018-10-29 22:06:09 -04:00
|
|
|
|
static int Raw(parser_t* p, Args ... args) {
|
2018-01-13 14:41:16 +01:00
|
|
|
|
Parser* parser = ContainerOf(&Parser::parser_, p);
|
2018-10-29 22:06:09 -04:00
|
|
|
|
int rv = (parser->*Member)(std::forward<Args>(args)...);
|
|
|
|
|
|
if (rv == 0) {
|
|
|
|
|
|
rv = parser->MaybePause();
|
|
|
|
|
|
}
|
|
|
|
|
|
return rv;
|
2018-01-13 14:41:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
typedef int (Parser::*Call)();
|
|
|
|
|
|
typedef int (Parser::*DataCall)(const char* at, size_t length);
|
|
|
|
|
|
|
2018-10-29 22:06:09 -04:00
|
|
|
|
static const parser_settings_t settings;
|
2010-01-24 11:21:45 -08:00
|
|
|
|
};
|
|
|
|
|
|
|
2018-10-29 22:06:09 -04:00
|
|
|
|
const parser_settings_t Parser::settings = {
|
2018-01-13 14:41:16 +01:00
|
|
|
|
Proxy<Call, &Parser::on_message_begin>::Raw,
|
|
|
|
|
|
Proxy<DataCall, &Parser::on_url>::Raw,
|
|
|
|
|
|
Proxy<DataCall, &Parser::on_status>::Raw,
|
|
|
|
|
|
Proxy<DataCall, &Parser::on_header_field>::Raw,
|
|
|
|
|
|
Proxy<DataCall, &Parser::on_header_value>::Raw,
|
|
|
|
|
|
Proxy<Call, &Parser::on_headers_complete>::Raw,
|
|
|
|
|
|
Proxy<DataCall, &Parser::on_body>::Raw,
|
|
|
|
|
|
Proxy<Call, &Parser::on_message_complete>::Raw,
|
2018-10-29 22:06:09 -04:00
|
|
|
|
#ifdef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
Proxy<Call, &Parser::on_chunk_header>::Raw,
|
|
|
|
|
|
Proxy<Call, &Parser::on_chunk_complete>::Raw,
|
|
|
|
|
|
#else /* !NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
nullptr,
|
|
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
2013-08-11 00:26:11 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2018-12-03 12:27:46 -05:00
|
|
|
|
#ifndef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
void InitMaxHttpHeaderSizeOnce() {
|
2019-01-01 13:56:53 +08:00
|
|
|
|
const uint32_t max_http_header_size =
|
|
|
|
|
|
per_process::cli_options->max_http_header_size;
|
2018-12-03 12:27:46 -05:00
|
|
|
|
http_parser_set_max_header_size(max_http_header_size);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-30 07:39:02 +01:00
|
|
|
|
void InitializeHttpParser(Local<Object> target,
|
|
|
|
|
|
Local<Value> unused,
|
|
|
|
|
|
Local<Context> context,
|
|
|
|
|
|
void* priv) {
|
2014-02-21 17:02:42 +04:00
|
|
|
|
Environment* env = Environment::GetCurrent(context);
|
2014-10-13 15:19:55 +02:00
|
|
|
|
Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
t->InstanceTemplate()->SetInternalFieldCount(1);
|
2014-02-21 17:02:42 +04:00
|
|
|
|
t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"));
|
|
|
|
|
|
|
|
|
|
|
|
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"),
|
2014-03-13 20:38:14 +04:00
|
|
|
|
Integer::New(env->isolate(), HTTP_REQUEST));
|
2014-02-21 17:02:42 +04:00
|
|
|
|
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"),
|
2014-03-13 20:38:14 +04:00
|
|
|
|
Integer::New(env->isolate(), HTTP_RESPONSE));
|
2014-02-21 17:02:42 +04:00
|
|
|
|
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"),
|
2014-03-13 20:38:14 +04:00
|
|
|
|
Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
|
2014-02-21 17:02:42 +04:00
|
|
|
|
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"),
|
2014-03-13 20:38:14 +04:00
|
|
|
|
Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
|
2014-02-21 17:02:42 +04:00
|
|
|
|
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"),
|
2014-03-13 20:38:14 +04:00
|
|
|
|
Integer::NewFromUnsigned(env->isolate(), kOnBody));
|
2014-02-21 17:02:42 +04:00
|
|
|
|
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"),
|
2014-03-13 20:38:14 +04:00
|
|
|
|
Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
|
2015-08-11 20:02:22 -07:00
|
|
|
|
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"),
|
|
|
|
|
|
Integer::NewFromUnsigned(env->isolate(), kOnExecute));
|
2011-09-27 17:07:56 +02:00
|
|
|
|
|
2014-03-13 20:38:14 +04:00
|
|
|
|
Local<Array> methods = Array::New(env->isolate());
|
2013-10-28 13:35:33 +01:00
|
|
|
|
#define V(num, name, string) \
|
2018-11-08 07:22:13 +01:00
|
|
|
|
methods->Set(env->context(), \
|
2019-04-09 15:21:36 -07:00
|
|
|
|
num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)).Check();
|
2013-10-28 13:35:33 +01:00
|
|
|
|
HTTP_METHOD_MAP(V)
|
|
|
|
|
|
#undef V
|
2018-11-08 07:22:13 +01:00
|
|
|
|
target->Set(env->context(),
|
|
|
|
|
|
FIXED_ONE_BYTE_STRING(env->isolate(), "methods"),
|
2019-04-09 15:21:36 -07:00
|
|
|
|
methods).Check();
|
2013-10-28 13:35:33 +01:00
|
|
|
|
|
2018-09-23 19:24:33 +02:00
|
|
|
|
t->Inherit(AsyncWrap::GetConstructorTemplate(env));
|
2014-10-13 15:19:55 +02:00
|
|
|
|
env->SetProtoMethod(t, "close", Parser::Close);
|
2017-07-17 16:47:12 -07:00
|
|
|
|
env->SetProtoMethod(t, "free", Parser::Free);
|
2014-10-13 15:19:55 +02:00
|
|
|
|
env->SetProtoMethod(t, "execute", Parser::Execute);
|
|
|
|
|
|
env->SetProtoMethod(t, "finish", Parser::Finish);
|
|
|
|
|
|
env->SetProtoMethod(t, "reinitialize", Parser::Reinitialize);
|
|
|
|
|
|
env->SetProtoMethod(t, "pause", Parser::Pause<true>);
|
|
|
|
|
|
env->SetProtoMethod(t, "resume", Parser::Pause<false>);
|
2015-08-11 20:02:22 -07:00
|
|
|
|
env->SetProtoMethod(t, "consume", Parser::Consume);
|
|
|
|
|
|
env->SetProtoMethod(t, "unconsume", Parser::Unconsume);
|
|
|
|
|
|
env->SetProtoMethod(t, "getCurrentBuffer", Parser::GetCurrentBuffer);
|
2010-01-24 11:21:45 -08:00
|
|
|
|
|
2018-11-08 07:22:13 +01:00
|
|
|
|
target->Set(env->context(),
|
|
|
|
|
|
FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"),
|
2019-04-09 15:21:36 -07:00
|
|
|
|
t->GetFunction(env->context()).ToLocalChecked()).Check();
|
2018-12-03 12:27:46 -05:00
|
|
|
|
|
|
|
|
|
|
#ifndef NODE_EXPERIMENTAL_HTTP
|
|
|
|
|
|
static uv_once_t init_once = UV_ONCE_INIT;
|
|
|
|
|
|
uv_once(&init_once, InitMaxHttpHeaderSizeOnce);
|
|
|
|
|
|
#endif /* NODE_EXPERIMENTAL_HTTP */
|
2010-01-24 11:21:45 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-12 19:17:24 +02:00
|
|
|
|
} // anonymous namespace
|
2010-01-24 11:21:45 -08:00
|
|
|
|
} // namespace node
|