Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.

Commit 778bb81

Browse files
authored
Add grpc-tags-bin propagation helpers. (#414)
1 parent 2abf364 commit 778bb81

File tree

9 files changed

+511
-0
lines changed

9 files changed

+511
-0
lines changed

opencensus/tags/BUILD

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# limitations under the License.
1616

1717
load("//opencensus:copts.bzl", "DEFAULT_COPTS", "TEST_COPTS")
18+
load("//bazel:cc_fuzz_target.bzl", "cc_fuzz_target")
1819

1920
licenses(["notice"]) # Apache License 2.0
2021

@@ -54,6 +55,18 @@ cc_library(
5455
],
5556
)
5657

58+
cc_library(
59+
name = "grpc_tags_bin",
60+
srcs = ["internal/grpc_tags_bin.cc"],
61+
hdrs = ["propagation/grpc_tags_bin.h"],
62+
copts = DEFAULT_COPTS,
63+
visibility = ["//visibility:public"],
64+
deps = [
65+
":tags",
66+
"@com_google_absl//absl/strings",
67+
],
68+
)
69+
5770
cc_library(
5871
name = "with_tag_map",
5972
srcs = ["internal/with_tag_map.cc"],
@@ -82,6 +95,18 @@ cc_test(
8295
],
8396
)
8497

98+
cc_test(
99+
name = "grpc_tags_bin_test",
100+
srcs = ["internal/grpc_tags_bin_test.cc"],
101+
copts = TEST_COPTS,
102+
deps = [
103+
":grpc_tags_bin",
104+
":tags",
105+
"@com_google_absl//absl/strings",
106+
"@com_google_googletest//:gtest_main",
107+
],
108+
)
109+
85110
cc_test(
86111
name = "tag_key_test",
87112
srcs = ["internal/tag_key_test.cc"],
@@ -119,6 +144,20 @@ cc_test(
119144
# Benchmarks
120145
# ========================================================================= #
121146

147+
cc_binary(
148+
name = "grpc_tags_bin_benchmark",
149+
testonly = 1,
150+
srcs = ["internal/grpc_tags_bin_benchmark.cc"],
151+
copts = TEST_COPTS,
152+
linkstatic = 1,
153+
deps = [
154+
":grpc_tags_bin",
155+
":tags",
156+
"@com_github_google_benchmark//:benchmark",
157+
"@com_google_absl//absl/strings",
158+
],
159+
)
160+
122161
cc_binary(
123162
name = "tag_map_benchmark",
124163
testonly = 1,
@@ -144,3 +183,16 @@ cc_binary(
144183
"@com_github_google_benchmark//:benchmark",
145184
],
146185
)
186+
187+
# Fuzzers
188+
# ========================================================================= #
189+
190+
cc_fuzz_target(
191+
name = "grpc_tags_bin_fuzzer",
192+
srcs = ["internal/grpc_tags_bin_fuzzer.cc"],
193+
corpus = glob(["internal/grpc_tags_bin_corpus/*"]),
194+
deps = [
195+
":grpc_tags_bin",
196+
"@com_google_absl//absl/strings",
197+
],
198+
)

opencensus/tags/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ opencensus_lib(
3333
tags
3434
context)
3535

36+
opencensus_lib(
37+
tags_grpc_tags_bin
38+
PUBLIC
39+
SRCS
40+
internal/grpc_tags_bin.cc
41+
DEPS
42+
tags
43+
absl::strings)
44+
3645
opencensus_lib(
3746
tags_with_tag_map
3847
PUBLIC
@@ -46,12 +55,22 @@ opencensus_lib(
4655
opencensus_test(tags_context_util_test internal/context_util_test.cc tags
4756
tags_context_util tags_with_tag_map context)
4857

58+
opencensus_test(tags_grpc_tags_bin_test internal/grpc_tags_bin_test.cc tags
59+
tags_grpc_tags_bin)
60+
4961
opencensus_test(tags_tag_key_test internal/tag_key_test.cc tags)
5062

5163
opencensus_test(tags_tag_map_test internal/tag_map_test.cc tags)
5264

5365
opencensus_test(tags_with_tag_map_test internal/with_tag_map_test.cc tags
5466
tags_with_tag_map context)
5567

68+
opencensus_benchmark(
69+
tags_grpc_tags_bin_benchmark internal/grpc_tags_bin_benchmark.cc tags
70+
tags_grpc_tags_bin absl::strings)
71+
5672
opencensus_benchmark(tags_tag_map_benchmark internal/tag_map_benchmark.cc tags
5773
absl::strings)
74+
75+
opencensus_fuzzer(tags_grpc_tags_bin_fuzzer internal/grpc_tags_bin_fuzzer.cc
76+
tags_grpc_tags_bin absl::strings)
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// Copyright 2019, OpenCensus 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 "opencensus/tags/propagation/grpc_tags_bin.h"
16+
17+
#include <cstdint>
18+
#include <string>
19+
#include <unordered_map>
20+
#include <vector>
21+
22+
#include "absl/strings/string_view.h"
23+
#include "opencensus/tags/tag_key.h"
24+
#include "opencensus/tags/tag_map.h"
25+
26+
namespace opencensus {
27+
namespace tags {
28+
namespace propagation {
29+
30+
namespace {
31+
32+
constexpr char kVersionId = '\0';
33+
constexpr char kTagFieldId = '\0';
34+
constexpr int kMaxLen = 8192;
35+
36+
// Appends a variable-length encoded integer to the destination string.
37+
void AppendVarint(unsigned int i, std::string* out) {
38+
do {
39+
// Encode 7 bits.
40+
uint8_t c = i & 0x7F;
41+
i = i >> 7;
42+
if (i != 0) {
43+
c |= 0x80;
44+
}
45+
out->push_back(c);
46+
} while (i != 0);
47+
}
48+
49+
// Parses a variable-length encoded integer from the input. Returns false on
50+
// failure. Returns true and consumes the bytes from the input, on success.
51+
bool ParseVarint(absl::string_view* input, int* out) {
52+
absl::string_view s = *input;
53+
int i = 0;
54+
uint8_t c;
55+
do {
56+
if (s.empty()) {
57+
return false; // Too short.
58+
}
59+
c = s[0];
60+
s = s.substr(1);
61+
i = (i << 7) | (c & 0x7F);
62+
} while (c & 0x80);
63+
*input = s;
64+
*out = i;
65+
return true;
66+
}
67+
68+
} // namespace
69+
70+
bool FromGrpcTagsBinHeader(absl::string_view header, TagMap* out) {
71+
std::unordered_map<std::string, absl::string_view> keys_vals;
72+
if (header.length() < 1) {
73+
return false; // Too short.
74+
}
75+
if (header.length() > kMaxLen) {
76+
return false; // Too long.
77+
}
78+
if (header[0] != kVersionId) {
79+
return false; // Wrong version.
80+
}
81+
header = header.substr(1);
82+
while (header.length() > 0) {
83+
// Parse tag field id.
84+
if (header[0] != kTagFieldId) {
85+
return false; // Wrong field id.
86+
}
87+
header = header.substr(1);
88+
89+
// Parse key.
90+
absl::string_view key;
91+
{
92+
int key_len;
93+
if (!ParseVarint(&header, &key_len)) {
94+
return false; // Invalid key_len.
95+
}
96+
if (key_len > header.length()) {
97+
return false; // Key len longer than remaining buffer.
98+
}
99+
key = header.substr(0, key_len);
100+
header = header.substr(key_len);
101+
}
102+
103+
// Parse val.
104+
absl::string_view val;
105+
{
106+
int val_len;
107+
if (!ParseVarint(&header, &val_len)) {
108+
return false; // Invalid val_len.
109+
}
110+
if (val_len > header.length()) {
111+
return false; // Val len longer than remaining buffer.
112+
}
113+
val = header.substr(0, val_len);
114+
header = header.substr(val_len);
115+
}
116+
117+
// Drop empty keys.
118+
if (!key.empty()) {
119+
// For duplicate keys, last wins.
120+
keys_vals[std::string(key)] = val;
121+
}
122+
}
123+
124+
// Convert to tagmap.
125+
std::vector<std::pair<opencensus::tags::TagKey, std::string>> tags;
126+
tags.reserve(keys_vals.size());
127+
for (const auto& kv : keys_vals) {
128+
tags.emplace_back(TagKey::Register(kv.first), std::string(kv.second));
129+
}
130+
*out = TagMap(std::move(tags));
131+
return true;
132+
}
133+
134+
std::string ToGrpcTagsBinHeader(const TagMap& tags) {
135+
std::string out;
136+
out.push_back(kVersionId);
137+
for (const auto& key_val : tags.tags()) {
138+
const auto& key = key_val.first;
139+
const auto& val = key_val.second;
140+
out.push_back(kTagFieldId);
141+
AppendVarint(key.name().length(), &out);
142+
out.append(key.name());
143+
AppendVarint(val.length(), &out);
144+
// Encoded value must be UTF-8.
145+
out.append(val);
146+
if (out.size() > kMaxLen) {
147+
break;
148+
}
149+
}
150+
if (out.size() > kMaxLen) {
151+
return "";
152+
}
153+
return out;
154+
}
155+
156+
} // namespace propagation
157+
} // namespace tags
158+
} // namespace opencensus
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2019, OpenCensus 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 "absl/strings/string_view.h"
16+
#include "benchmark/benchmark.h"
17+
#include "opencensus/tags/propagation/grpc_tags_bin.h"
18+
#include "opencensus/tags/tag_key.h"
19+
#include "opencensus/tags/tag_map.h"
20+
21+
namespace opencensus {
22+
namespace tags {
23+
namespace propagation {
24+
namespace {
25+
26+
void BM_FromGrpcTagsBinHeader(benchmark::State& state) {
27+
constexpr char tagsbin[] = {
28+
0, // Version
29+
0, // Tag field
30+
3, 'k', 'e', 'y', // k1
31+
3, 'v', 'a', 'l', // v1
32+
};
33+
const absl::string_view hdr(tagsbin, sizeof(tagsbin));
34+
TagMap m({});
35+
for (auto _ : state) {
36+
FromGrpcTagsBinHeader(hdr, &m);
37+
}
38+
}
39+
BENCHMARK(BM_FromGrpcTagsBinHeader);
40+
41+
void BM_ToGrpcTagsBinHeader(benchmark::State& state) {
42+
TagMap m({{TagKey::Register("key"), "val"}});
43+
for (auto _ : state) {
44+
ToGrpcTagsBinHeader(m);
45+
}
46+
}
47+
BENCHMARK(BM_ToGrpcTagsBinHeader);
48+
49+
} // namespace
50+
} // namespace propagation
51+
} // namespace tags
52+
} // namespace opencensus
53+
54+
BENCHMARK_MAIN();
9 Bytes
Binary file not shown.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2019, OpenCensus 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 "absl/strings/string_view.h"
16+
#include "opencensus/tags/propagation/grpc_tags_bin.h"
17+
18+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
19+
absl::string_view input(reinterpret_cast<const char *>(Data), Size);
20+
TagMap m({});
21+
opencensus::tags::propagation::FromGrpcTagsBinHeader(input, &m);
22+
return 0;
23+
}

0 commit comments

Comments
 (0)