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