Skip to content

Commit

Permalink
feat(common): QuotaUserOption for gRPC-based libs
Browse files Browse the repository at this point in the history
  • Loading branch information
coryan committed Apr 6, 2024
1 parent 18f522e commit 404cd19
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 27 deletions.
27 changes: 27 additions & 0 deletions google/cloud/common_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,33 @@ struct UserProjectOption {
using Type = std::string;
};

/**
* Configure the QuotaUser system parameter.
*
* A pseudo user identifier for charging per-user quotas. If not specified, the
* authenticated principal is used. If there is no authenticated principal, the
* client IP address will be used. When specified, a valid API key with service
* restrictions must be used to identify the quota project. Otherwise, this
* parameter is ignored.
*
* @ingroup rest-options
*/
struct QuotaUserOption {
using Type = std::string;
};

/**
* Configure the UserIp query parameter.
*
* This can be used to separate quota usage by source IP address.
*
* @deprecated prefer using `google::cloud::QuotaUser`.
* @ingroup rest-options
*/
struct UserIpOption {
using Type = std::string;
};

/**
* Configure the "authority" attribute.
*
Expand Down
7 changes: 7 additions & 0 deletions google/cloud/grpc_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

#include "google/cloud/grpc_options.h"
#include "google/cloud/common_options.h"
#include "google/cloud/internal/absl_str_cat_quiet.h"
#include "google/cloud/internal/absl_str_join_quiet.h"
#include "google/cloud/internal/background_threads_impl.h"
Expand All @@ -38,6 +39,12 @@ void SetMetadata(grpc::ClientContext& context, Options const& options,
for (auto const& h : options.get<CustomHeadersOption>()) {
context.AddMetadata(h.first, h.second);
}
if (options.has<UserIpOption>() && !options.has<QuotaUserOption>()) {
context.AddMetadata("x-goog-user-ip", options.get<UserIpOption>());
}
if (options.has<QuotaUserOption>()) {
context.AddMetadata("x-goog-quota-user", options.get<QuotaUserOption>());
}
}

void ConfigureContext(grpc::ClientContext& context, Options const& opts) {
Expand Down
40 changes: 40 additions & 0 deletions google/cloud/grpc_options_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ TEST(GrpcSetMetadata, Full) {
context,
Options{}
.set<UserProjectOption>("user-project")
.set<QuotaUserOption>("quota-user")
.set<AuthorityOption>("authority.googleapis.com")
.set<CustomHeadersOption>(
{{"custom-header-1", "v1"}, {"custom-header-2", "v2"}}),
Expand All @@ -338,6 +339,7 @@ TEST(GrpcSetMetadata, Full) {
EXPECT_THAT(metadata,
UnorderedElementsAre(
Pair("x-goog-user-project", "user-project"),
Pair("x-goog-quota-user", "quota-user"),
Pair("fixed-header-1", "v1"), Pair("fixed-header-2", "v2"),
Pair("custom-header-1", "v1"), Pair("custom-header-2", "v2"),
Pair("x-goog-api-client", "api-client-header")));
Expand All @@ -354,6 +356,44 @@ TEST(GrpcSetMetadata, Authority) {
EXPECT_EQ(authority, "authority.googleapis.com");
}

TEST(GrpcSetMetadata, ConfigureUserIp) {
grpc::ClientContext context;
internal::SetMetadata(context, Options{}.set<UserIpOption>("1234"), {},
"api-client-header");

ValidateMetadataFixture fixture;
auto const metadata = fixture.GetMetadata(context);
EXPECT_THAT(metadata, UnorderedElementsAre(
Pair("x-goog-user-ip", "1234"),
Pair("x-goog-api-client", "api-client-header")));
}

TEST(GrpcSetMetadata, ConfigureQuotaUser) {
grpc::ClientContext context;
internal::SetMetadata(context, Options{}.set<QuotaUserOption>("my-user"), {},
"api-client-header");

ValidateMetadataFixture fixture;
auto const metadata = fixture.GetMetadata(context);
EXPECT_THAT(metadata, UnorderedElementsAre(
Pair("x-goog-quota-user", "my-user"),
Pair("x-goog-api-client", "api-client-header")));
}

TEST(GrpcSetMetadata, QuotaUserOverridesUserIp) {
grpc::ClientContext context;
internal::SetMetadata(
context,
Options{}.set<QuotaUserOption>("my-user").set<UserIpOption>("1234"), {},
"api-client-header");

ValidateMetadataFixture fixture;
auto const metadata = fixture.GetMetadata(context);
EXPECT_THAT(metadata, UnorderedElementsAre(
Pair("x-goog-quota-user", "my-user"),
Pair("x-goog-api-client", "api-client-header")));
}

TEST(GrpcClientContext, Configure) {
auto setup = [](grpc::ClientContext& context) {
// This might not be the most useful setting, but it is the most easily
Expand Down
28 changes: 1 addition & 27 deletions google/cloud/rest_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_REST_OPTIONS_H
#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_REST_OPTIONS_H

#include "google/cloud/common_options.h"
#include "google/cloud/options.h"
#include "google/cloud/tracing_options.h"
#include "google/cloud/version.h"
Expand All @@ -25,33 +26,6 @@ namespace google {
namespace cloud {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN

/**
* Configure the QuotaUser system parameter.
*
* A pseudo user identifier for charging per-user quotas. If not specified, the
* authenticated principal is used. If there is no authenticated principal, the
* client IP address will be used. When specified, a valid API key with service
* restrictions must be used to identify the quota project. Otherwise, this
* parameter is ignored.
*
* @ingroup rest-options
*/
struct QuotaUserOption {
using Type = std::string;
};

/**
* Configure the UserIp query parameter.
*
* This can be used to separate quota usage by source IP address.
*
* @deprecated prefer using `google::cloud::QuotaUser`.
* @ingroup rest-options
*/
struct UserIpOption {
using Type = std::string;
};

/**
* Timeout for the server to finish processing the request. This system param
* only applies to REST APIs for which client-side timeout is not applicable.
Expand Down

0 comments on commit 404cd19

Please sign in to comment.