1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <stdio.h>
20
21 #include <string>
22
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25
26 #include <grpc/impl/channel_arg_names.h>
27 #include <grpc/status.h>
28
29 #include "src/core/lib/channel/channel_args.h"
30 #include "src/core/lib/gprpp/time.h"
31 #include "test/core/end2end/end2end_tests.h"
32
33 namespace grpc_core {
34 namespace {
35
36 class LargeMetadataTest {
37 public:
LargeMetadataTest(Http2SingleHopTest & test,const ChannelArgs & args)38 LargeMetadataTest(Http2SingleHopTest& test, const ChannelArgs& args)
39 : test_(test) {
40 test_.InitClient(args);
41 test_.InitServer(args);
42 }
43
PerformRequests(size_t metadata_size,int count)44 int PerformRequests(size_t metadata_size, int count) {
45 int num_requests_accepted = 0;
46 for (int i = 0; i < count; ++i) {
47 auto status = PerformOneRequest(metadata_size);
48 if (status.status() == GRPC_STATUS_RESOURCE_EXHAUSTED) {
49 EXPECT_THAT(status.message(),
50 ::testing::StartsWith("received metadata size exceeds"));
51 } else {
52 num_requests_accepted++;
53 EXPECT_EQ(status.status(), GRPC_STATUS_OK);
54 EXPECT_EQ(status.message(), "xyz");
55 }
56 }
57 return num_requests_accepted;
58 }
59
60 private:
PerformOneRequest(const size_t metadata_size)61 CoreEnd2endTest::IncomingStatusOnClient PerformOneRequest(
62 const size_t metadata_size) {
63 auto c = test_.NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create();
64 CoreEnd2endTest::IncomingMetadata server_initial_metadata;
65 CoreEnd2endTest::IncomingStatusOnClient server_status;
66 c.NewBatch(1)
67 .SendInitialMetadata({})
68 .SendCloseFromClient()
69 .RecvInitialMetadata(server_initial_metadata)
70 .RecvStatusOnClient(server_status);
71 auto s = test_.RequestCall(101);
72 test_.Expect(101, true);
73 test_.Step();
74 // Server: send metadata of size `metadata_size`.
75 CoreEnd2endTest::IncomingCloseOnServer client_close;
76 s.NewBatch(102)
77 .SendInitialMetadata({{"key", std::string(metadata_size, 'a')}})
78 .RecvCloseOnServer(client_close)
79 .SendStatusFromServer(GRPC_STATUS_OK, "xyz", {});
80 test_.Expect(102, true);
81 test_.Expect(1, true);
82 test_.Step();
83 return server_status;
84 }
85
86 Http2SingleHopTest& test_;
87 };
88
89 // Server responds with metadata under soft limit of what client accepts. No
90 // requests should be rejected.
CORE_END2END_TEST(Http2SingleHopTest,RequestWithLargeMetadataUnderSoftLimit)91 CORE_END2END_TEST(Http2SingleHopTest, RequestWithLargeMetadataUnderSoftLimit) {
92 const size_t soft_limit = 32 * 1024;
93 const size_t hard_limit = 45 * 1024;
94 const size_t metadata_size = soft_limit;
95 LargeMetadataTest test(
96 *this, ChannelArgs()
97 .Set(GRPC_ARG_MAX_METADATA_SIZE, soft_limit + 1024)
98 .Set(GRPC_ARG_ABSOLUTE_MAX_METADATA_SIZE, hard_limit + 1024));
99 EXPECT_EQ(test.PerformRequests(metadata_size, 100), 100);
100 }
101
102 // Server responds with metadata between soft and hard limits of what client
103 // accepts. Some requests should be rejected.
CORE_END2END_TEST(Http2SingleHopTest,RequestWithLargeMetadataBetweenSoftAndHardLimits)104 CORE_END2END_TEST(Http2SingleHopTest,
105 RequestWithLargeMetadataBetweenSoftAndHardLimits) {
106 const size_t soft_limit = 32 * 1024;
107 const size_t hard_limit = 45 * 1024;
108 const size_t metadata_size = (soft_limit + hard_limit) / 2;
109 LargeMetadataTest test(
110 *this, ChannelArgs()
111 .Set(GRPC_ARG_MAX_METADATA_SIZE, soft_limit + 1024)
112 .Set(GRPC_ARG_ABSOLUTE_MAX_METADATA_SIZE, hard_limit + 1024));
113 EXPECT_THAT(test.PerformRequests(metadata_size, 100),
114 ::testing::AllOf(::testing::Ge(5), ::testing::Le(95)));
115 }
116
117 // Server responds with metadata above hard limit of what the client accepts.
118 // All requests should be rejected.
CORE_END2END_TEST(Http2SingleHopTest,RequestWithLargeMetadataAboveHardLimit)119 CORE_END2END_TEST(Http2SingleHopTest, RequestWithLargeMetadataAboveHardLimit) {
120 const size_t soft_limit = 32 * 1024;
121 const size_t hard_limit = 45 * 1024;
122 const size_t metadata_size = hard_limit * 3 / 2;
123 LargeMetadataTest test(
124 *this, ChannelArgs()
125 .Set(GRPC_ARG_MAX_METADATA_SIZE, soft_limit + 1024)
126 .Set(GRPC_ARG_ABSOLUTE_MAX_METADATA_SIZE, hard_limit + 1024));
127 EXPECT_EQ(test.PerformRequests(metadata_size, 100), 0);
128 }
129
130 // Set soft limit higher than hard limit. All requests above hard limit should
131 // be rejected, all requests below hard limit should be accepted (soft limit
132 // should not be respected).
CORE_END2END_TEST(Http2SingleHopTest,RequestWithLargeMetadataSoftLimitAboveHardLimit)133 CORE_END2END_TEST(Http2SingleHopTest,
134 RequestWithLargeMetadataSoftLimitAboveHardLimit) {
135 const size_t soft_limit = 64 * 1024;
136 const size_t hard_limit = 32 * 1024;
137 const size_t metadata_size_below_hard_limit = hard_limit;
138 const size_t metadata_size_above_hard_limit = hard_limit * 2;
139 LargeMetadataTest test(
140 *this, ChannelArgs()
141 .Set(GRPC_ARG_MAX_METADATA_SIZE, soft_limit + 1024)
142 .Set(GRPC_ARG_ABSOLUTE_MAX_METADATA_SIZE, hard_limit + 1024));
143 // Send 50 requests below hard limit. Should be accepted.
144 EXPECT_EQ(test.PerformRequests(metadata_size_below_hard_limit, 50), 50);
145 // Send 50 requests above hard limit. Should be rejected.
146 EXPECT_EQ(test.PerformRequests(metadata_size_above_hard_limit, 50), 0);
147 }
148
149 // Set soft limit * 1.25 higher than default hard limit and do not set hard
150 // limit. Soft limit * 1.25 should be used as hard limit.
CORE_END2END_TEST(Http2SingleHopTest,RequestWithLargeMetadataSoftLimitOverridesDefaultHard)151 CORE_END2END_TEST(Http2SingleHopTest,
152 RequestWithLargeMetadataSoftLimitOverridesDefaultHard) {
153 const size_t soft_limit = 64 * 1024;
154 const size_t metadata_size_below_soft_limit = soft_limit;
155 const size_t metadata_size_above_hard_limit = soft_limit * 1.5;
156 const size_t metadata_size_between_limits =
157 (soft_limit + soft_limit * 1.25) / 2;
158 LargeMetadataTest test(
159 *this, ChannelArgs().Set(GRPC_ARG_MAX_METADATA_SIZE, soft_limit + 1024));
160 // Send 50 requests below soft limit. Should be accepted.
161 EXPECT_EQ(test.PerformRequests(metadata_size_below_soft_limit, 50), 50);
162 // Send 100 requests between soft and hard limits. Some should be rejected.
163 EXPECT_THAT(test.PerformRequests(metadata_size_between_limits, 100),
164 ::testing::AllOf(::testing::Ge(5), ::testing::Le(95)));
165 // Send 50 requests above hard limit. Should be rejected.
166 EXPECT_EQ(test.PerformRequests(metadata_size_above_hard_limit, 50), 0);
167 }
168
169 // Set hard limit * 0.8 higher than default soft limit and do not set soft
170 // limit. Hard limit * 0.8 should be used as soft limit.
CORE_END2END_TEST(Http2SingleHopTest,RequestWithLargeMetadataHardLimitOverridsDefaultSoft)171 CORE_END2END_TEST(Http2SingleHopTest,
172 RequestWithLargeMetadataHardLimitOverridsDefaultSoft) {
173 const size_t hard_limit = 45 * 1024;
174 const size_t metadata_size_below_soft_limit = hard_limit * 0.5;
175 const size_t metadata_size_above_hard_limit = hard_limit * 1.5;
176 const size_t metadata_size_between_limits =
177 (hard_limit * 0.8 + hard_limit) / 2;
178 LargeMetadataTest test(*this,
179 ChannelArgs().Set(GRPC_ARG_ABSOLUTE_MAX_METADATA_SIZE,
180 hard_limit + 1024));
181 // Send 50 requests below soft limit. Should be accepted.
182 EXPECT_EQ(test.PerformRequests(metadata_size_below_soft_limit, 50), 50);
183 // Send 100 requests between soft and hard limits. Some should be rejected.
184 EXPECT_THAT(test.PerformRequests(metadata_size_between_limits, 100),
185 ::testing::AllOf(::testing::Ge(5), ::testing::Le(95)));
186 // Send 50 requests above hard limit. Should be rejected.
187 EXPECT_EQ(test.PerformRequests(metadata_size_above_hard_limit, 50), 0);
188 }
189
190 // Set hard limit lower than default hard limit and ensure new limit is
191 // respected. Default soft limit is not respected since hard limit is lower than
192 // soft limit.
CORE_END2END_TEST(Http2SingleHopTest,RequestWithLargeMetadataHardLimitBelowDefaultHard)193 CORE_END2END_TEST(Http2SingleHopTest,
194 RequestWithLargeMetadataHardLimitBelowDefaultHard) {
195 const size_t hard_limit = 4 * 1024;
196 const size_t metadata_size_below_hard_limit = hard_limit;
197 const size_t metadata_size_above_hard_limit = hard_limit * 2;
198 LargeMetadataTest test(*this,
199 ChannelArgs().Set(GRPC_ARG_ABSOLUTE_MAX_METADATA_SIZE,
200 hard_limit + 1024));
201 // Send 50 requests below hard limit. Should be accepted.
202 EXPECT_EQ(test.PerformRequests(metadata_size_below_hard_limit, 50), 50);
203 // Send 50 requests above hard limit. Should be rejected.
204 EXPECT_EQ(test.PerformRequests(metadata_size_above_hard_limit, 50), 0);
205 }
206
207 // Set soft limit lower than default soft limit and ensure new limit is
208 // respected. Hard limit should be default hard since this is greater than 2 *
209 // soft limit.
CORE_END2END_TEST(Http2SingleHopTest,RequestWithLargeMetadataSoftLimitBelowDefaultSoft)210 CORE_END2END_TEST(Http2SingleHopTest,
211 RequestWithLargeMetadataSoftLimitBelowDefaultSoft) {
212 const size_t soft_limit = 1 * 1024;
213 const size_t metadata_size_below_soft_limit = soft_limit;
214 // greater than 2 * soft, less than default hard
215 const size_t metadata_size_between_limits = 10 * 1024;
216 const size_t metadata_size_above_hard_limit = 75 * 1024;
217 LargeMetadataTest test(
218 *this, ChannelArgs().Set(GRPC_ARG_MAX_METADATA_SIZE, soft_limit + 1024));
219 // Send 50 requests below soft limit. Should be accepted.
220 EXPECT_EQ(test.PerformRequests(metadata_size_below_soft_limit, 50), 50);
221 // Send 100 requests between soft and hard limits. Some should be rejected.
222 EXPECT_THAT(test.PerformRequests(metadata_size_between_limits, 100),
223 ::testing::AllOf(::testing::Ge(1), ::testing::Le(99)));
224 // Send 50 requests above hard limit. Should be rejected.
225 EXPECT_EQ(test.PerformRequests(metadata_size_above_hard_limit, 50), 0);
226 }
227
228 } // namespace
229 } // namespace grpc_core
230