Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
13 changes: 13 additions & 0 deletions google/cloud/internal/curl_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "google/cloud/internal/rest_options.h"
#include "google/cloud/internal/user_agent_prefix.h"
#include "google/cloud/log.h"
#include "google/cloud/rest_options.h"
#include "absl/strings/match.h"
#include "absl/strings/strip.h"
#include <algorithm>
Expand Down Expand Up @@ -196,6 +197,8 @@ CurlImpl::CurlImpl(CurlHandle handle,
proxy_ = CurlOptProxy(options);
proxy_username_ = CurlOptProxyUsername(options);
proxy_password_ = CurlOptProxyPassword(options);

interface_ = CurlOptInterface(options);
}

CurlImpl::~CurlImpl() {
Expand Down Expand Up @@ -319,6 +322,10 @@ Status CurlImpl::MakeRequest(HttpMethod method, RestContext& context,
status = handle_.SetOption(CURLOPT_PROXYPASSWORD, proxy_password_->c_str());
if (!status.ok()) return OnTransferError(context, std::move(status));
}
if (interface_) {
status = handle_.SetOption(CURLOPT_INTERFACE, interface_->c_str());
if (!status.ok()) return OnTransferError(context, std::move(status));
}

if (method == HttpMethod::kGet) {
status = handle_.SetOption(CURLOPT_NOPROGRESS, 1L);
Expand Down Expand Up @@ -786,6 +793,12 @@ absl::optional<std::string> CurlOptProxyPassword(Options const& options) {
return cfg.password();
}

absl::optional<std::string> CurlOptInterface(Options const& options) {
auto const& cfg = options.get<Interface>();
if (cfg.empty()) return absl::nullopt;
return cfg;
}

GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace rest_internal
} // namespace cloud
Expand Down
5 changes: 5 additions & 0 deletions google/cloud/internal/curl_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ class CurlImpl {
absl::optional<std::string> proxy_username_;
absl::optional<std::string> proxy_password_;

absl::optional<std::string> interface_;

CurlReceivedHeaders received_headers_;
std::string url_;
HttpStatusCode http_code_;
Expand Down Expand Up @@ -192,6 +194,9 @@ absl::optional<std::string> CurlOptProxyUsername(Options const& options);
/// Compute the CURLOPT_PROXYPASSWORD setting from @p options.
absl::optional<std::string> CurlOptProxyPassword(Options const& options);

/// Compute the CURLOPT_INTERFACE setting from @p options.
absl::optional<std::string> CurlOptInterface(Options const& options);

GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace rest_internal
} // namespace cloud
Expand Down
7 changes: 7 additions & 0 deletions google/cloud/internal/curl_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "google/cloud/internal/curl_impl.h"
#include "google/cloud/common_options.h"
#include "google/cloud/rest_options.h"
#include "google/cloud/testing_util/status_matchers.h"
#include <gmock/gmock.h>
#include <vector>
Expand Down Expand Up @@ -182,6 +183,12 @@ TEST_F(CurlImplTest, CurlOptProxyPassword) {
absl::make_optional(std::string("password")));
}

TEST_F(CurlImplTest, CurlOptInterface) {
EXPECT_EQ(CurlOptInterface(Options{}), absl::nullopt);
EXPECT_EQ(CurlOptInterface(Options{}.set<Interface>("interface")),
absl::make_optional(std::string("interface")));
}

} // namespace
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace rest_internal
Expand Down
16 changes: 15 additions & 1 deletion google/cloud/rest_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,24 @@ struct RestTracingOptionsOption {
using Type = TracingOptions;
};

/**
* Sets the interface name to use as outgoing network interface. The
* name can be an interface name, IP address, or hostname. To
* utilize one of these use the following special prefixes:
*
* if!<name> for interface name, host!<name for IP address or hostname,
* ifhost!<interface>!<host> for interface name and IP address or hostname.
*
* The default is to use whatever the TCP stack finds suitable.
*/
struct Interface {
using Type = std::string;
};

/// The complete list of options accepted by `CurlRestClient`
using RestOptionList =
::google::cloud::OptionList<QuotaUserOption, RestTracingOptionsOption,
ServerTimeoutOption, UserIpOption>;
ServerTimeoutOption, UserIpOption, Interface>;

GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace cloud
Expand Down
Loading