1 // Copyright 2024 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/core/client_channel/lb_metadata.h"
16
17 #include "absl/log/log.h"
18
19 namespace grpc_core {
20
21 //
22 // LbMetadata
23 //
24
25 namespace {
26
27 class Encoder {
28 public:
Encode(const Slice & key,const Slice & value)29 void Encode(const Slice& key, const Slice& value) {
30 out_.emplace_back(std::string(key.as_string_view()),
31 std::string(value.as_string_view()));
32 }
33
34 template <class Which>
Encode(Which,const typename Which::ValueType & value)35 void Encode(Which, const typename Which::ValueType& value) {
36 auto value_slice = Which::Encode(value);
37 out_.emplace_back(std::string(Which::key()),
38 std::string(value_slice.as_string_view()));
39 }
40
Encode(GrpcTimeoutMetadata,const typename GrpcTimeoutMetadata::ValueType &)41 void Encode(GrpcTimeoutMetadata,
42 const typename GrpcTimeoutMetadata::ValueType&) {}
Encode(HttpPathMetadata,const Slice &)43 void Encode(HttpPathMetadata, const Slice&) {}
Encode(HttpMethodMetadata,const typename HttpMethodMetadata::ValueType &)44 void Encode(HttpMethodMetadata,
45 const typename HttpMethodMetadata::ValueType&) {}
46
Take()47 std::vector<std::pair<std::string, std::string>> Take() {
48 return std::move(out_);
49 }
50
51 private:
52 std::vector<std::pair<std::string, std::string>> out_;
53 };
54
55 } // namespace
56
Lookup(absl::string_view key,std::string * buffer) const57 absl::optional<absl::string_view> LbMetadata::Lookup(
58 absl::string_view key, std::string* buffer) const {
59 if (batch_ == nullptr) return absl::nullopt;
60 return batch_->GetStringValue(key, buffer);
61 }
62
63 std::vector<std::pair<std::string, std::string>>
TestOnlyCopyToVector() const64 LbMetadata::TestOnlyCopyToVector() const {
65 if (batch_ == nullptr) return {};
66 Encoder encoder;
67 batch_->Encode(&encoder);
68 return encoder.Take();
69 }
70
71 //
72 // MetadataMutationHandler
73 //
74
Apply(LoadBalancingPolicy::MetadataMutations & metadata_mutations,grpc_metadata_batch * metadata)75 void MetadataMutationHandler::Apply(
76 LoadBalancingPolicy::MetadataMutations& metadata_mutations,
77 grpc_metadata_batch* metadata) {
78 for (auto& p : metadata_mutations.metadata_) {
79 absl::string_view key = p.first;
80 Slice& value =
81 grpc_event_engine::experimental::internal::SliceCast<Slice>(p.second);
82 // TODO(roth): Should we prevent this from setting special keys like
83 // :authority, :path, content-type, etc?
84 metadata->Remove(key);
85 // Gross, egregious hack to support legacy grpclb behavior.
86 // TODO(ctiller): Use a promise context for this once that plumbing is done.
87 if (key == GrpcLbClientStatsMetadata::key()) {
88 metadata->Set(
89 GrpcLbClientStatsMetadata(),
90 const_cast<GrpcLbClientStats*>(
91 reinterpret_cast<const GrpcLbClientStats*>(value.data())));
92 continue;
93 }
94 metadata->Append(key, std::move(value),
95 [key](absl::string_view error, const Slice& value) {
96 LOG(ERROR) << error << " key:" << key
97 << " value:" << value.as_string_view();
98 });
99 }
100 }
101
102 //
103 // MaybeOverrideAuthority()
104 //
105
MaybeOverrideAuthority(grpc_event_engine::experimental::Slice authority_override,grpc_metadata_batch * metadata)106 void MaybeOverrideAuthority(
107 grpc_event_engine::experimental::Slice authority_override,
108 grpc_metadata_batch* metadata) {
109 // Skip if no override requested.
110 if (authority_override.empty()) return;
111 // Skip if authority already set by the application on this RPC.
112 if (metadata->get_pointer(HttpAuthorityMetadata()) != nullptr) return;
113 // Otherwise, apply override.
114 Slice& authority =
115 grpc_event_engine::experimental::internal::SliceCast<Slice>(
116 authority_override);
117 metadata->Set(HttpAuthorityMetadata(), std::move(authority));
118 }
119
120 } // namespace grpc_core
121