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

[WIP] new listener filter for terminating HTTP/1 CONNECT(#19077) #19346

Closed
wants to merge 9 commits into from

Conversation

liverbirdkte
Copy link
Contributor

Add a new listener filter to handle CONNECT request, only HTTP/1.x is supported.

  1. inspect if incoming request is HTTP CONNECT

  2. drain CONNECT request data out of queue

  3. terminate HTTP CONNECT by writing a response to the client

  4. set server names using request url in CONNECT request

It seems the behavior of draining CONNECT data and writing response may have an impact on other listener filters in the loop. Is there any way to exit the listener filter iteration? Or I should put this listener filter as the last one in the config.

Commit Message:
Additional Description:
Risk Level:
Testing:
Docs Changes:
Release Notes:
Platform Specific Features:
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Fixes commit #PR or SHA]
[Optional Deprecated:]
[Optional API Considerations:]

@repokitteh-read-only
Copy link

Hi @liverbirdkte, welcome and thank you for your contribution.

We will try to review your Pull Request as quickly as possible.

In the meantime, please take a look at the contribution guidelines if you have not done so already.

🐱

Caused by: #19346 was opened by liverbirdkte.

see: more, trace.

@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy/|docs/root/api-docs/).
envoyproxy/api-shepherds assignee is @adisuissa
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #19346 was opened by liverbirdkte.

see: more, trace.

Copy link
Member

@rojkov rojkov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I added a few comments.

Also this PR needs docs and tests.

};

thread_local uint8_t Filter::buf_[Config::MAX_INSPECT_SIZE];
static absl::string_view response_body = " 200 Connection Established\r\n\r\n";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables

Suggested change
static absl::string_view response_body = " 200 Connection Established\r\n\r\n";
static constexpr absl::string_view response_body = " 200 Connection Established\r\n\r\n";

And instead of static we prefer anonymous namespaces.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it, will use anonymous namespace instead.

Event::PlatformDefaultTriggerType, Event::FileReadyType::Read);
return Network::FilterStatus::StopIteration;
}
NOT_REACHED_GCOVR_EXCL_LINE;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The switch above is meant to be fully exhaustive. We'd better detect a missing case in it if we extend ParseState. Better replace NOT_REACHED_GCOVR_EXCL_LINE with ENVOY_BUG().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean adding a default for switch to handle missing cases or to extend ParseState by adding a new status?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to add default as some compilers can generate a warning at compile time about non-exhaustive switch'es.

If ParseState is ever extended with a new value then this switch will become non-exhaustive. So, it'll be possible to reach NOT_REACHED_GCOVR_EXCL_LINE. And that would be a bug most probably. Unfortunately reaching NOT_REACHED_GCOVR_EXCL_LINE doesn't trigger a bug nor prints a warning. Thus it's better to replace it with ENVOY_BUG().

if (result.return_value_ == 0) {
return ParseState::Error;
}
return parseConnect(absl::string_view(reinterpret_cast<const char*>(buf_)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no need to instantiate a string_view here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it

@rojkov rojkov self-assigned this Dec 23, 2021
@rojkov
Copy link
Member

rojkov commented Dec 27, 2021

/wait

Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this, left an API comment.

Comment on lines 18 to 19
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.filter.listener.http_inspector.v2.ConnectHandler";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think such a type exists.
If there is no v2 predecessor, you should remove the annotation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, will remove this.

@liverbirdkte
Copy link
Contributor Author

Sorry for the late response, thanks for the comments, I'll submit a new version soon. The patch is for issue #19077.

@liverbirdkte
Copy link
Contributor Author

start working on tests and docs, will update when code is ready

@rojkov
Copy link
Member

rojkov commented Jan 5, 2022

/wait

@liverbirdkte
Copy link
Contributor Author

Add unittest, looking at how to write fuzz tests..

Add a new listener filter to handle CONNECT request, only HTTP/1.x is supported.

1. inspect if incoming request is HTTP CONNECT

2. drain CONNECT request queue

3. terminate HTTP CONNECT by writing a response to the client

4. set server names using request url in CONNECT request

Signed-off-by: leizhang <[email protected]>
Signed-off-by: leizhang <[email protected]>
Signed-off-by: leizhang <[email protected]>
Signed-off-by: leizhang <[email protected]>
@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy[\w/]*/(v1alpha\d?|v1|v2alpha\d?|v2))|(api/envoy/type/(matcher/)?\w+.proto).

🐱

Caused by: #19346 was synchronize by liverbirdkte.

see: more, trace.

@rojkov
Copy link
Member

rojkov commented Jan 20, 2022

Please never use git force-push. If the PR is not ready for review you can turn it into a Draft.

@liverbirdkte
Copy link
Contributor Author

OK, I was fixing some CI failures, saw the DOC issue, so I added sign-off and force push as the instruction on the page told me to.

Also didn't mean to modify unrelated jwt_authn proto, but git hook format checker won't get passed unless I apply these changes.

@liverbirdkte liverbirdkte marked this pull request as draft January 20, 2022 09:28
@liverbirdkte
Copy link
Contributor Author

Thanks, I will convert it back when it's ready.

@liverbirdkte liverbirdkte marked this pull request as ready for review January 26, 2022 01:57
Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm api
left a minor comment.

CODEOWNERS Outdated
Comment on lines 220 to 221
# connect handler
/*/extensions/filters/listener/connect_handler @rojkov @alyssawilk
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move up to the extensions part.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

@rojkov rojkov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Looks good. I added a few questions.

static constexpr absl::string_view HTTP1_CONNECT_PREFACE = "CONNECT";
Buffer::OwnedImpl resp_buf_{};
absl::string_view protocol_;
absl::string_view request_url_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

return ParseState::Error;
}
// terminate CONNECT request
resp_buf_.add(protocol_);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems there's no need to make protocol_ a member of the class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines 28 to 30
http_parser_settings Filter::settings_{
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it be just a compilation unit-wide constexpr?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

thread_local uint8_t Filter::buf_[Config::MAX_INSPECT_SIZE];

namespace {
constexpr absl::string_view response_body = " 200 Connection Established\r\n\r\n";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to STYLE.md this should be

Suggested change
constexpr absl::string_view response_body = " 200 Connection Established\r\n\r\n";
constexpr absl::string_view ResponseBody = " 200 Connection Established\r\n\r\n";

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if (result.return_value_ == 0) {
return ParseState::Error;
}
return parseConnect(absl::string_view(reinterpret_cast<const char*>(buf_), result.return_value_));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to instantiate a temp string_view here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return ParseState::Done;
}

std::vector<absl::string_view> fields = absl::StrSplit(data, absl::ByAnyChar(" :"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be more efficient to use StringUtil::cropLeft() and StringUtil::cropRight() for server name extraction?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -756,6 +756,7 @@ interpretable
intra
ints
invariance
iov
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably not needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this because my local checker could not get passed, removing this to see if CI job works well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed the check fails. This is weird as I used iov in my PRs and everything was ok. And it's all over the code base. Looks like the code is treated as a comment by the spellchecker. @phlax could you please have a look?

@rojkov
Copy link
Member

rojkov commented Jan 31, 2022

/wait

@liverbirdkte liverbirdkte marked this pull request as draft February 8, 2022 11:01
@liverbirdkte liverbirdkte marked this pull request as ready for review February 8, 2022 14:57
constexpr http_parser_settings Settings{
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
};
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
}
} // namespace

Comment on lines +19 to +20
#TODO(davinci26): The test passes on Windows *but* http inspector
# *used* to rely on Event::FileTriggerType::Edge and we got away with it
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment relevant to connect_handler?

Comment on lines +49 to +57
envoy_cc_fuzz_test(
name = "connect_handler_fuzz_test",
srcs = ["connect_handler_fuzz_test.cc"],
corpus = "connect_handler_corpus",
deps = [
"//source/extensions/filters/listener/connect_handler:connect_handler_lib",
"//test/extensions/filters/listener/common/fuzz:listener_filter_fuzzer_lib",
],
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This target seems to be missing in the PR.

Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
Left a small comment on the doc.
/lgtm api
I suggest adding an integration test.

Connect Handler
===============

Connect Handler listener filter allows detecting whether the incoming request appears to be HTTP/1.x CONNECT, and if it is CONNECT, it removes the CONNECT by reading data from socket and responding with a 200 status code to indicate a connection to remote server is established. It also extracts remote server url from the CONNECT. This can be used to select a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Connect Handler listener filter allows detecting whether the incoming request appears to be HTTP/1.x CONNECT, and if it is CONNECT, it removes the CONNECT by reading data from socket and responding with a 200 status code to indicate a connection to remote server is established. It also extracts remote server url from the CONNECT. This can be used to select a
Connect Handler listener filter allows detecting whether the incoming request appears to be HTTP/1.x CONNECT, and if it is CONNECT, it removes the CONNECT by reading data from the socket and responding with a 200 status code to indicate a connection to the remote server is established. It also extracts the remote server url from the CONNECT. This can be used to select a

@rojkov
Copy link
Member

rojkov commented Feb 11, 2022

/wait

@github-actions
Copy link

This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@github-actions github-actions bot added the stale stalebot believes this issue/PR has not been touched recently label Mar 13, 2022
@github-actions
Copy link

This pull request has been automatically closed because it has not had activity in the last 37 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale stalebot believes this issue/PR has not been touched recently v2-freeze waiting
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants