Skip to content

Commit b63f69f

Browse files
authored
feat: add option to allow setting CURLOPT_INTERFACE (#15044)
* feat: add option to allow setting CURLOPT_INTERFACE * move interface option to rest_options * fix tags in comment
1 parent f080acd commit b63f69f

File tree

4 files changed

+40
-1
lines changed

4 files changed

+40
-1
lines changed

google/cloud/internal/curl_impl.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "google/cloud/internal/rest_options.h"
2424
#include "google/cloud/internal/user_agent_prefix.h"
2525
#include "google/cloud/log.h"
26+
#include "google/cloud/rest_options.h"
2627
#include "absl/strings/match.h"
2728
#include "absl/strings/strip.h"
2829
#include <algorithm>
@@ -196,6 +197,8 @@ CurlImpl::CurlImpl(CurlHandle handle,
196197
proxy_ = CurlOptProxy(options);
197198
proxy_username_ = CurlOptProxyUsername(options);
198199
proxy_password_ = CurlOptProxyPassword(options);
200+
201+
interface_ = CurlOptInterface(options);
199202
}
200203

201204
CurlImpl::~CurlImpl() {
@@ -319,6 +322,10 @@ Status CurlImpl::MakeRequest(HttpMethod method, RestContext& context,
319322
status = handle_.SetOption(CURLOPT_PROXYPASSWORD, proxy_password_->c_str());
320323
if (!status.ok()) return OnTransferError(context, std::move(status));
321324
}
325+
if (interface_) {
326+
status = handle_.SetOption(CURLOPT_INTERFACE, interface_->c_str());
327+
if (!status.ok()) return OnTransferError(context, std::move(status));
328+
}
322329

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

796+
absl::optional<std::string> CurlOptInterface(Options const& options) {
797+
auto const& cfg = options.get<Interface>();
798+
if (cfg.empty()) return absl::nullopt;
799+
return cfg;
800+
}
801+
789802
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
790803
} // namespace rest_internal
791804
} // namespace cloud

google/cloud/internal/curl_impl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ class CurlImpl {
143143
absl::optional<std::string> proxy_username_;
144144
absl::optional<std::string> proxy_password_;
145145

146+
absl::optional<std::string> interface_;
147+
146148
CurlReceivedHeaders received_headers_;
147149
std::string url_;
148150
HttpStatusCode http_code_;
@@ -192,6 +194,9 @@ absl::optional<std::string> CurlOptProxyUsername(Options const& options);
192194
/// Compute the CURLOPT_PROXYPASSWORD setting from @p options.
193195
absl::optional<std::string> CurlOptProxyPassword(Options const& options);
194196

197+
/// Compute the CURLOPT_INTERFACE setting from @p options.
198+
absl::optional<std::string> CurlOptInterface(Options const& options);
199+
195200
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
196201
} // namespace rest_internal
197202
} // namespace cloud

google/cloud/internal/curl_impl_test.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "google/cloud/internal/curl_impl.h"
1616
#include "google/cloud/common_options.h"
17+
#include "google/cloud/rest_options.h"
1718
#include "google/cloud/testing_util/status_matchers.h"
1819
#include <gmock/gmock.h>
1920
#include <vector>
@@ -182,6 +183,12 @@ TEST_F(CurlImplTest, CurlOptProxyPassword) {
182183
absl::make_optional(std::string("password")));
183184
}
184185

186+
TEST_F(CurlImplTest, CurlOptInterface) {
187+
EXPECT_EQ(CurlOptInterface(Options{}), absl::nullopt);
188+
EXPECT_EQ(CurlOptInterface(Options{}.set<Interface>("interface")),
189+
absl::make_optional(std::string("interface")));
190+
}
191+
185192
} // namespace
186193
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
187194
} // namespace rest_internal

google/cloud/rest_options.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,24 @@ struct RestTracingOptionsOption {
4545
using Type = TracingOptions;
4646
};
4747

48+
/**
49+
* Sets the interface name to use as outgoing network interface. The
50+
* name can be an interface name, IP address, or hostname. To
51+
* utilize one of these use the following special prefixes:
52+
*
53+
* if![name] for interface name, host![name] for IP address or hostname,
54+
* ifhost![interface]![host] for interface name and IP address or hostname.
55+
*
56+
* The default is to use whatever the TCP stack finds suitable.
57+
*/
58+
struct Interface {
59+
using Type = std::string;
60+
};
61+
4862
/// The complete list of options accepted by `CurlRestClient`
4963
using RestOptionList =
5064
::google::cloud::OptionList<QuotaUserOption, RestTracingOptionsOption,
51-
ServerTimeoutOption, UserIpOption>;
65+
ServerTimeoutOption, UserIpOption, Interface>;
5266

5367
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
5468
} // namespace cloud

0 commit comments

Comments
 (0)