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

feat: support HTTP proxy in client SDK #467

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

cwaldren-ld
Copy link
Contributor

@cwaldren-ld cwaldren-ld commented Nov 12, 2024

This supports configuring an HTTP proxy in the client SDK. Although some of the code is shared in common and would be available to the server, I've limited the scope to keep the change manageable.

Users can also set the proxy using the common http_proxy environment variable. The feature is tested via contract test for events, polling, and streaming.

This implementation allows an http proxy to be used for https requests from the SDK. That is, the proxy is a forward proxy. This can be useful if TLS between the SDK and the proxy isn't necessary, but it's not e2e secure.

Future work should implement HTTPS proxy support. In that world, the http proxy mode is only used for HTTP requests (for instance, to Relay) and the https proxy mode is used for https requests (to launchdarkly, or if Relay is in TLS mode.)

@cwaldren-ld cwaldren-ld changed the title feat: support HTTP proxy feat: support HTTP proxy in client SDK Nov 12, 2024
@cwaldren-ld cwaldren-ld added the package: sdk/client Issues affecting the C++ Client SDK label Nov 12, 2024
@@ -33,10 +33,10 @@ HttpResult::HeadersType const& HttpResult::Headers() const {
HttpResult::HttpResult(HttpResult::StatusCode status,
std::optional<std::string> body,
HttpResult::HeadersType headers)
: status_(status),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

reorder to match declaration

@@ -47,7 +47,7 @@ std::optional<std::string> const& HttpResult::ErrorMessage() const {
}

HttpResult::HttpResult(std::optional<std::string> error_message)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

reorder to match declaration

HttpRequest::HttpRequest(std::string const& url,
HttpMethod method,
config::shared::built::HttpProperties properties,
HttpRequest::BodyType body)
: properties_(std::move(properties)),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

reorder to match decl

@@ -108,20 +120,42 @@ HttpRequest::HttpRequest(std::string const& url,
if (uri_components->has_port()) {
port_ = uri_components->port();
}

if (properties_.HttpProxy()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Side note: it would be much better if we could validate these URLs earlier in the config process, but that would be a more major refactoring.

valid_ = true;
}

HttpRequest::HttpRequest(HttpRequest& base_request,
config::shared::built::HttpProperties properties)
: properties_(std::move(properties)),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

reorder to match decl

@@ -68,29 +65,51 @@ static http::verb ConvertMethod(HttpMethod method) {
launchdarkly::detail::unreachable();
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unclear to me how much this matters. This is for setting the Host field on the HTTP request.

std::string tcp_host =
request->HttpProxyHost().value_or(request->Host());

std::string tcp_port = request->HttpProxyPort().value_or(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This could instead be:

request->Https() ? "https" : "http"

since asio accepts "service names". A bit more abstract.

@@ -585,50 +591,93 @@ Builder& Builder::custom_ca_file(std::string path) {
return *this;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some duplication with our internal HTTP request code.

if (!url->has_scheme()) {
return false;
}
return url->scheme_id() == boost::urls::scheme::http ||
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No FTP flag delivery allowed.

tcp_port = http_proxy_components->has_port()
? http_proxy_components->port()
: http_proxy_components->scheme();

Copy link
Contributor Author

Choose a reason for hiding this comment

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

More inconsistencies with our internal http lib stuff. Here we can just pass in ->scheme() as the service, whereas in the previous helper code I was passing 80 or 443, since our internal lib doesn't have a scheme() getter. We could add one though.

@cwaldren-ld cwaldren-ld marked this pull request as ready for review November 19, 2024 22:35
@cwaldren-ld cwaldren-ld requested a review from a team as a code owner November 19, 2024 22:35
@cwaldren-ld cwaldren-ld marked this pull request as draft November 20, 2024 00:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: sdk/client Issues affecting the C++ Client SDK
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant