Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor http parser implementation in http_inspector #36430

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion source/extensions/filters/listener/http_inspector/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ envoy_cc_library(
srcs = ["http_inspector.cc"],
hdrs = ["http_inspector.h"],
deps = [
"//bazel/external/http_parser",
"//envoy/event:dispatcher_interface",
"//envoy/event:timer_interface",
"//envoy/network:filter_interface",
Expand All @@ -25,6 +24,8 @@ envoy_cc_library(
"//source/common/common:minimal_logger_lib",
"//source/common/http:headers_lib",
"//source/common/http:utility_lib",
"//source/common/http/http1:legacy_parser_lib",
"//source/common/http/http1:parser_interface",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ Config::Config(Stats::Scope& scope)
const absl::string_view Filter::HTTP2_CONNECTION_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";

Filter::Filter(const ConfigSharedPtr config) : config_(config) {
http_parser_init(&parser_, HTTP_REQUEST);
// Filter for only Request Message types with NoOp callbacks
no_op_callbacks_ = std::make_unique<NoOpParserCallbacks>();
parser_ = std::make_unique<Http::Http1::LegacyHttpParserImpl>(Http::Http1::MessageType::Request,
no_op_callbacks_.get());
}

http_parser_settings Filter::settings_{
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
};

Network::FilterStatus Filter::onData(Network::ListenerFilterBuffer& buffer) {
auto raw_slice = buffer.rawSlice();
const char* buf = static_cast<const char*>(raw_slice.mem_);
Expand Down Expand Up @@ -81,35 +80,40 @@ ParseState Filter::parseHttpHeader(absl::string_view data) {
return ParseState::Error;
}

absl::string_view new_data = data.substr(parser_.nread);
absl::string_view new_data = data.substr(nread_);
const size_t pos = new_data.find_first_of("\r\n");

if (pos != absl::string_view::npos) {
// Include \r or \n
new_data = new_data.substr(0, pos + 1);
ssize_t rc = http_parser_execute(&parser_, &settings_, new_data.data(), new_data.length());
ssize_t rc = parser_->execute(new_data.data(), new_data.length());
nread_ += rc;
ENVOY_LOG(trace, "http inspector: http_parser parsed {} chars, error code: {}", rc,
static_cast<int>(HTTP_PARSER_ERRNO(&parser_)));
parser_->errorMessage());

// Errors in parsing HTTP.
if (HTTP_PARSER_ERRNO(&parser_) != HPE_OK && HTTP_PARSER_ERRNO(&parser_) != HPE_PAUSED) {
if (parser_->getStatus() != Http::Http1::ParserStatus::Ok &&
parser_->getStatus() != Http::Http1::ParserStatus::Paused) {
return ParseState::Error;
}

if (parser_.http_major == 1 && parser_.http_minor == 1) {
if (parser_->isHttp11()) {
protocol_ = Http::Headers::get().ProtocolStrings.Http11String;
} else {
// Set other HTTP protocols to HTTP/1.0
protocol_ = Http::Headers::get().ProtocolStrings.Http10String;
}

return ParseState::Done;
} else {
ssize_t rc = http_parser_execute(&parser_, &settings_, new_data.data(), new_data.length());
ssize_t rc = parser_->execute(new_data.data(), new_data.length());
nread_ += rc;
ENVOY_LOG(trace, "http inspector: http_parser parsed {} chars, error code: {}", rc,
static_cast<int>(HTTP_PARSER_ERRNO(&parser_)));
parser_->errorMessage());

// Errors in parsing HTTP.
if (HTTP_PARSER_ERRNO(&parser_) != HPE_OK && HTTP_PARSER_ERRNO(&parser_) != HPE_PAUSED) {
if (parser_->getStatus() != Http::Http1::ParserStatus::Ok &&
parser_->getStatus() != Http::Http1::ParserStatus::Paused) {
return ParseState::Error;
} else {
return ParseState::Continue;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#pragma once

#include <http_parser.h>

#include "envoy/event/file_event.h"
#include "envoy/event/timer.h"
#include "envoy/network/filter.h"
#include "envoy/stats/scope.h"
#include "envoy/stats/stats_macros.h"

#include "source/common/common/logger.h"
#include "source/common/http/http1/legacy_parser_impl.h"
#include "source/common/http/http1/parser.h"

#include "absl/container/flat_hash_set.h"

Expand Down Expand Up @@ -58,6 +58,41 @@ class Config {
HttpInspectorStats stats_;
};

class NoOpParserCallbacks : public Http::Http1::ParserCallbacks {
public:
Http::Http1::CallbackResult onMessageBegin() override {
return Http::Http1::CallbackResult::Success;
}

Http::Http1::CallbackResult onUrl(const char* /*data*/, size_t /*length*/) override {
return Http::Http1::CallbackResult::Success;
}

Http::Http1::CallbackResult onStatus(const char* /*data*/, size_t /*length*/) override {
return Http::Http1::CallbackResult::Success;
}

Http::Http1::CallbackResult onHeaderField(const char* /*data*/, size_t /*length*/) override {
return Http::Http1::CallbackResult::Success;
}

Http::Http1::CallbackResult onHeaderValue(const char* /*data*/, size_t /*length*/) override {
return Http::Http1::CallbackResult::Success;
}

Http::Http1::CallbackResult onHeadersComplete() override {
return Http::Http1::CallbackResult::Success;
}

void bufferBody(const char* /*data*/, size_t /*length*/) override {}

Http::Http1::CallbackResult onMessageComplete() override {
return Http::Http1::CallbackResult::Success;
}

void onChunkHeader(bool /*is_final_chunk*/) override {}
};

using ConfigSharedPtr = std::shared_ptr<Config>;

/**
Expand Down Expand Up @@ -85,8 +120,10 @@ class Filter : public Network::ListenerFilter, Logger::Loggable<Logger::Id::filt
ConfigSharedPtr config_;
Network::ListenerFilterCallbacks* cb_{nullptr};
absl::string_view protocol_;
http_parser parser_;
static http_parser_settings settings_;

std::unique_ptr<Http::Http1::Parser> parser_;
std::unique_ptr<NoOpParserCallbacks> no_op_callbacks_;
ssize_t nread_ = 0;
};

} // namespace HttpInspector
Expand Down