mirror of https://github.com/grpc/grpc.git
[chttp2] Rework settings management to be a c++ type (#35449)
Closes #35449
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35449 from ctiller:h2-settings f67e542a8b
PiperOrigin-RevId: 597970333
pull/35530/head
parent
650bb21abd
commit
9f6789e2b2
31 changed files with 1062 additions and 681 deletions
@ -0,0 +1,514 @@ |
||||
// Copyright 2024 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/core/ext/transport/chttp2/transport/http2_settings.h" |
||||
|
||||
#include "gmock/gmock.h" |
||||
#include "gtest/gtest.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
TEST(Http2SettingsTest, CanSetAndRetrieveSettings) { |
||||
Http2Settings settings; |
||||
settings.SetHeaderTableSize(1); |
||||
settings.SetEnablePush(true); |
||||
settings.SetMaxConcurrentStreams(3); |
||||
settings.SetInitialWindowSize(4); |
||||
settings.SetMaxFrameSize(50000); |
||||
settings.SetMaxHeaderListSize(6); |
||||
settings.SetAllowTrueBinaryMetadata(true); |
||||
settings.SetPreferredReceiveCryptoMessageSize(77777); |
||||
EXPECT_EQ(settings.header_table_size(), 1u); |
||||
EXPECT_EQ(settings.enable_push(), true); |
||||
EXPECT_EQ(settings.max_concurrent_streams(), 3u); |
||||
EXPECT_EQ(settings.initial_window_size(), 4u); |
||||
EXPECT_EQ(settings.max_frame_size(), 50000u); |
||||
EXPECT_EQ(settings.max_header_list_size(), 6u); |
||||
EXPECT_EQ(settings.allow_true_binary_metadata(), true); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 77777u); |
||||
settings.SetHeaderTableSize(10); |
||||
settings.SetEnablePush(false); |
||||
settings.SetMaxConcurrentStreams(30); |
||||
settings.SetInitialWindowSize(40); |
||||
settings.SetMaxFrameSize(5000000); |
||||
settings.SetMaxHeaderListSize(60); |
||||
settings.SetAllowTrueBinaryMetadata(false); |
||||
settings.SetPreferredReceiveCryptoMessageSize(70000); |
||||
EXPECT_EQ(settings.header_table_size(), 10u); |
||||
EXPECT_EQ(settings.enable_push(), false); |
||||
EXPECT_EQ(settings.max_concurrent_streams(), 30u); |
||||
EXPECT_EQ(settings.initial_window_size(), 40u); |
||||
EXPECT_EQ(settings.max_frame_size(), 5000000u); |
||||
EXPECT_EQ(settings.max_header_list_size(), 60u); |
||||
EXPECT_EQ(settings.allow_true_binary_metadata(), false); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 70000u); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, InitialWindowSizeLimits) { |
||||
Http2Settings settings; |
||||
settings.SetInitialWindowSize(0); |
||||
EXPECT_EQ(settings.initial_window_size(), 0u); |
||||
settings.SetInitialWindowSize(0x7fffffff); |
||||
EXPECT_EQ(settings.initial_window_size(), 0x7fffffffu); |
||||
settings.SetInitialWindowSize(0x80000000); |
||||
EXPECT_EQ(settings.initial_window_size(), 0x7fffffffu); |
||||
settings.SetInitialWindowSize(0xffffffff); |
||||
EXPECT_EQ(settings.initial_window_size(), 0x7fffffffu); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, MaxFrameSizeLimits) { |
||||
Http2Settings settings; |
||||
settings.SetMaxFrameSize(0); |
||||
EXPECT_EQ(settings.max_frame_size(), 16384u); |
||||
settings.SetMaxFrameSize(16384); |
||||
EXPECT_EQ(settings.max_frame_size(), 16384u); |
||||
settings.SetMaxFrameSize(16385); |
||||
EXPECT_EQ(settings.max_frame_size(), 16385u); |
||||
settings.SetMaxFrameSize(16777215); |
||||
EXPECT_EQ(settings.max_frame_size(), 16777215u); |
||||
settings.SetMaxFrameSize(16777216); |
||||
EXPECT_EQ(settings.max_frame_size(), 16777215u); |
||||
settings.SetMaxFrameSize(16777217); |
||||
EXPECT_EQ(settings.max_frame_size(), 16777215u); |
||||
settings.SetMaxFrameSize(0xffffffff); |
||||
EXPECT_EQ(settings.max_frame_size(), 16777215u); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, PreferredReceiveCryptoMessageSize) { |
||||
Http2Settings settings; |
||||
settings.SetPreferredReceiveCryptoMessageSize(0); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16384u); |
||||
settings.SetPreferredReceiveCryptoMessageSize(16384); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16384u); |
||||
settings.SetPreferredReceiveCryptoMessageSize(16385); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16385u); |
||||
settings.SetPreferredReceiveCryptoMessageSize(16777215); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16777215u); |
||||
settings.SetPreferredReceiveCryptoMessageSize(16777216); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16777216u); |
||||
settings.SetPreferredReceiveCryptoMessageSize(16777217); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16777217u); |
||||
settings.SetPreferredReceiveCryptoMessageSize(0x7fffffff); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu); |
||||
settings.SetPreferredReceiveCryptoMessageSize(0x80000000); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu); |
||||
settings.SetPreferredReceiveCryptoMessageSize(0xffffffff); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu); |
||||
} |
||||
|
||||
namespace { |
||||
using KeyValue = std::pair<uint16_t, uint32_t>; |
||||
using KeyValueVec = std::vector<KeyValue>; |
||||
|
||||
KeyValueVec Diff(const Http2Settings& a, const Http2Settings& b, |
||||
bool is_first_send) { |
||||
KeyValueVec diffs; |
||||
a.Diff(is_first_send, b, [&diffs](uint16_t key, uint32_t value) { |
||||
diffs.emplace_back(key, value); |
||||
}); |
||||
return diffs; |
||||
} |
||||
|
||||
bool operator==(const KeyValue& a, const Http2SettingsFrame::Setting& b) { |
||||
return a.first == b.id && a.second == b.value; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Http2SettingsTest, DiffOnFreshlyInitializedSettings) { |
||||
const Http2Settings settings1; |
||||
const Http2Settings settings2; |
||||
EXPECT_THAT(Diff(settings1, settings2, false), ::testing::IsEmpty()); |
||||
EXPECT_THAT(Diff(settings1, settings2, true), |
||||
::testing::UnorderedElementsAre(KeyValue{4, 65535})); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, DiffOnSettingsWithOneValueSet) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetHeaderTableSize(1); |
||||
EXPECT_THAT(Diff(settings1, settings2, false), |
||||
::testing::UnorderedElementsAre(KeyValue{1, 1})); |
||||
EXPECT_THAT( |
||||
Diff(settings1, settings2, true), |
||||
::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{4, 65535})); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, DiffOnSettingsWithTwoValuesSet) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetHeaderTableSize(1); |
||||
settings1.SetEnablePush(false); |
||||
EXPECT_THAT(Diff(settings1, settings2, false), |
||||
::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0})); |
||||
EXPECT_THAT(Diff(settings1, settings2, true), |
||||
::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0}, |
||||
KeyValue{4, 65535})); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, DiffOnSettingsWithThreeValuesSet) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetHeaderTableSize(1); |
||||
settings1.SetEnablePush(false); |
||||
settings1.SetMaxConcurrentStreams(3); |
||||
EXPECT_THAT(Diff(settings1, settings2, false), |
||||
::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0}, |
||||
KeyValue{3, 3})); |
||||
EXPECT_THAT( |
||||
Diff(settings1, settings2, true), |
||||
::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0}, |
||||
KeyValue{3, 3}, KeyValue{4, 65535})); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, DiffOnSettingsWithFourValuesSet) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetHeaderTableSize(1); |
||||
settings1.SetEnablePush(false); |
||||
settings1.SetMaxConcurrentStreams(3); |
||||
settings1.SetInitialWindowSize(4); |
||||
EXPECT_THAT(Diff(settings1, settings2, false), |
||||
::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0}, |
||||
KeyValue{3, 3}, KeyValue{4, 4})); |
||||
EXPECT_THAT(Diff(settings1, settings2, true), |
||||
::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0}, |
||||
KeyValue{3, 3}, KeyValue{4, 4})); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, DiffOnSettingsWithFiveValuesSet) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetHeaderTableSize(1); |
||||
settings1.SetEnablePush(false); |
||||
settings1.SetMaxConcurrentStreams(3); |
||||
settings1.SetInitialWindowSize(4); |
||||
settings1.SetMaxFrameSize(50000); |
||||
EXPECT_THAT(Diff(settings1, settings2, false), |
||||
::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0}, |
||||
KeyValue{3, 3}, KeyValue{4, 4}, |
||||
KeyValue{5, 50000})); |
||||
EXPECT_THAT(Diff(settings1, settings2, true), |
||||
::testing::UnorderedElementsAre(KeyValue{1, 1}, KeyValue{2, 0}, |
||||
KeyValue{3, 3}, KeyValue{4, 4}, |
||||
KeyValue{5, 50000})); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, DiffOnSettingsWithSixValuesSet) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetHeaderTableSize(1); |
||||
settings1.SetEnablePush(false); |
||||
settings1.SetMaxConcurrentStreams(3); |
||||
settings1.SetInitialWindowSize(4); |
||||
settings1.SetMaxFrameSize(50000); |
||||
settings1.SetMaxHeaderListSize(6); |
||||
EXPECT_THAT(Diff(settings1, settings2, false), |
||||
::testing::UnorderedElementsAre( |
||||
KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3}, |
||||
KeyValue{4, 4}, KeyValue{5, 50000}, KeyValue{6, 6})); |
||||
EXPECT_THAT(Diff(settings1, settings2, true), |
||||
::testing::UnorderedElementsAre( |
||||
KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3}, |
||||
KeyValue{4, 4}, KeyValue{5, 50000}, KeyValue{6, 6})); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, DiffOnSettingsWithSevenValuesSet) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetHeaderTableSize(1); |
||||
settings1.SetEnablePush(false); |
||||
settings1.SetMaxConcurrentStreams(3); |
||||
settings1.SetInitialWindowSize(4); |
||||
settings1.SetMaxFrameSize(50000); |
||||
settings1.SetMaxHeaderListSize(6); |
||||
settings1.SetAllowTrueBinaryMetadata(true); |
||||
EXPECT_THAT( |
||||
Diff(settings1, settings2, false), |
||||
::testing::UnorderedElementsAre( |
||||
KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3}, KeyValue{4, 4}, |
||||
KeyValue{5, 50000}, KeyValue{6, 6}, KeyValue{65027, 1})); |
||||
EXPECT_THAT( |
||||
Diff(settings1, settings2, true), |
||||
::testing::UnorderedElementsAre( |
||||
KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3}, KeyValue{4, 4}, |
||||
KeyValue{5, 50000}, KeyValue{6, 6}, KeyValue{65027, 1})); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, DiffOnSettingsWithEightValuesSet) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetHeaderTableSize(1); |
||||
settings1.SetEnablePush(false); |
||||
settings1.SetMaxConcurrentStreams(3); |
||||
settings1.SetInitialWindowSize(4); |
||||
settings1.SetMaxFrameSize(50000); |
||||
settings1.SetMaxHeaderListSize(6); |
||||
settings1.SetAllowTrueBinaryMetadata(true); |
||||
settings1.SetPreferredReceiveCryptoMessageSize(77777); |
||||
EXPECT_THAT(Diff(settings1, settings2, false), |
||||
::testing::UnorderedElementsAre( |
||||
KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3}, |
||||
KeyValue{4, 4}, KeyValue{5, 50000}, KeyValue{6, 6}, |
||||
KeyValue{65027, 1}, KeyValue{65028, 77777})); |
||||
EXPECT_THAT(Diff(settings1, settings2, true), |
||||
::testing::UnorderedElementsAre( |
||||
KeyValue{1, 1}, KeyValue{2, 0}, KeyValue{3, 3}, |
||||
KeyValue{4, 4}, KeyValue{5, 50000}, KeyValue{6, 6}, |
||||
KeyValue{65027, 1}, KeyValue{65028, 77777})); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ChangingHeaderTableSizeChangesEquality) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetHeaderTableSize(1); |
||||
EXPECT_NE(settings1, settings2); |
||||
settings2.SetHeaderTableSize(1); |
||||
EXPECT_EQ(settings1, settings2); |
||||
settings2.SetHeaderTableSize(2); |
||||
EXPECT_NE(settings1, settings2); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ChangingEnablePushChangesEquality) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetEnablePush(false); |
||||
EXPECT_NE(settings1, settings2); |
||||
settings2.SetEnablePush(false); |
||||
EXPECT_EQ(settings1, settings2); |
||||
settings2.SetEnablePush(true); |
||||
EXPECT_NE(settings1, settings2); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ChangingMaxConcurrentStreamsChangesEquality) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetMaxConcurrentStreams(1); |
||||
EXPECT_NE(settings1, settings2); |
||||
settings2.SetMaxConcurrentStreams(1); |
||||
EXPECT_EQ(settings1, settings2); |
||||
settings2.SetMaxConcurrentStreams(2); |
||||
EXPECT_NE(settings1, settings2); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ChangingInitialWindowSizeChangesEquality) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetInitialWindowSize(1); |
||||
EXPECT_NE(settings1, settings2); |
||||
settings2.SetInitialWindowSize(1); |
||||
EXPECT_EQ(settings1, settings2); |
||||
settings2.SetInitialWindowSize(2); |
||||
EXPECT_NE(settings1, settings2); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ChangingMaxFrameSizeChangesEquality) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetMaxFrameSize(100000); |
||||
EXPECT_NE(settings1, settings2); |
||||
settings2.SetMaxFrameSize(100000); |
||||
EXPECT_EQ(settings1, settings2); |
||||
settings2.SetMaxFrameSize(200000); |
||||
EXPECT_NE(settings1, settings2); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ChangingMaxHeaderListSizeChangesEquality) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetMaxHeaderListSize(1); |
||||
EXPECT_NE(settings1, settings2); |
||||
settings2.SetMaxHeaderListSize(1); |
||||
EXPECT_EQ(settings1, settings2); |
||||
settings2.SetMaxHeaderListSize(2); |
||||
EXPECT_NE(settings1, settings2); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ChangingAllowTrueBinaryMetadataChangesEquality) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetAllowTrueBinaryMetadata(true); |
||||
EXPECT_NE(settings1, settings2); |
||||
settings2.SetAllowTrueBinaryMetadata(true); |
||||
EXPECT_EQ(settings1, settings2); |
||||
settings2.SetAllowTrueBinaryMetadata(false); |
||||
EXPECT_NE(settings1, settings2); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, |
||||
ChangingPreferredReceiveCryptoMessageSizeChangesEquality) { |
||||
Http2Settings settings1; |
||||
Http2Settings settings2; |
||||
settings1.SetPreferredReceiveCryptoMessageSize(100000); |
||||
EXPECT_NE(settings1, settings2); |
||||
settings2.SetPreferredReceiveCryptoMessageSize(100000); |
||||
EXPECT_EQ(settings1, settings2); |
||||
settings2.SetPreferredReceiveCryptoMessageSize(200000); |
||||
EXPECT_NE(settings1, settings2); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, WireIdToNameWorks) { |
||||
EXPECT_EQ(Http2Settings::WireIdToName(1), "HEADER_TABLE_SIZE"); |
||||
EXPECT_EQ(Http2Settings::WireIdToName(2), "ENABLE_PUSH"); |
||||
EXPECT_EQ(Http2Settings::WireIdToName(3), "MAX_CONCURRENT_STREAMS"); |
||||
EXPECT_EQ(Http2Settings::WireIdToName(4), "INITIAL_WINDOW_SIZE"); |
||||
EXPECT_EQ(Http2Settings::WireIdToName(5), "MAX_FRAME_SIZE"); |
||||
EXPECT_EQ(Http2Settings::WireIdToName(6), "MAX_HEADER_LIST_SIZE"); |
||||
EXPECT_EQ(Http2Settings::WireIdToName(65027), |
||||
"GRPC_ALLOW_TRUE_BINARY_METADATA"); |
||||
EXPECT_EQ(Http2Settings::WireIdToName(65028), |
||||
"GRPC_PREFERRED_RECEIVE_MESSAGE_SIZE"); |
||||
EXPECT_EQ(Http2Settings::WireIdToName(65029), "UNKNOWN (65029)"); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ApplyHeaderTableSizeWorks) { |
||||
Http2Settings settings; |
||||
EXPECT_EQ(settings.Apply(1, 1), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.header_table_size(), 1u); |
||||
EXPECT_EQ(settings.Apply(1, 0x7fffffff), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.header_table_size(), 0x7fffffffu); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ApplyEnablePushWorks) { |
||||
Http2Settings settings; |
||||
EXPECT_EQ(settings.Apply(2, 0), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.enable_push(), false); |
||||
EXPECT_EQ(settings.Apply(2, 1), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.enable_push(), true); |
||||
EXPECT_EQ(settings.Apply(2, 2), GRPC_HTTP2_PROTOCOL_ERROR); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ApplyMaxConcurrentStreamsWorks) { |
||||
Http2Settings settings; |
||||
EXPECT_EQ(settings.Apply(3, 1), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.max_concurrent_streams(), 1u); |
||||
EXPECT_EQ(settings.Apply(3, 0x7fffffff), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.max_concurrent_streams(), 0x7fffffffu); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ApplyInitialWindowSizeWorks) { |
||||
Http2Settings settings; |
||||
EXPECT_EQ(settings.Apply(4, 1), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.initial_window_size(), 1u); |
||||
EXPECT_EQ(settings.Apply(4, 0x7fffffff), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.initial_window_size(), 0x7fffffffu); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ApplyMaxFrameSizeWorks) { |
||||
Http2Settings settings; |
||||
EXPECT_EQ(settings.Apply(5, 16384), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.max_frame_size(), 16384u); |
||||
EXPECT_EQ(settings.Apply(5, 16777215), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.max_frame_size(), 16777215); |
||||
EXPECT_EQ(settings.Apply(5, 16383), GRPC_HTTP2_PROTOCOL_ERROR); |
||||
EXPECT_EQ(settings.Apply(5, 16777216), GRPC_HTTP2_PROTOCOL_ERROR); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ApplyMaxHeaderListSizeWorks) { |
||||
Http2Settings settings; |
||||
EXPECT_EQ(settings.Apply(6, 1), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.max_header_list_size(), 1u); |
||||
EXPECT_EQ(settings.Apply(6, 0x7fffffff), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.max_header_list_size(), 16777216); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ApplyAllowTrueBinaryMetadataWorks) { |
||||
Http2Settings settings; |
||||
EXPECT_EQ(settings.Apply(65027, 0), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.allow_true_binary_metadata(), false); |
||||
EXPECT_EQ(settings.Apply(65027, 1), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.allow_true_binary_metadata(), true); |
||||
EXPECT_EQ(settings.Apply(65027, 2), GRPC_HTTP2_PROTOCOL_ERROR); |
||||
} |
||||
|
||||
TEST(Http2SettingsTest, ApplyPreferredReceiveCryptoMessageSizeWorks) { |
||||
Http2Settings settings; |
||||
EXPECT_EQ(settings.Apply(65028, 1), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 16384u); |
||||
EXPECT_EQ(settings.Apply(65028, 0x7fffffff), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu); |
||||
EXPECT_EQ(settings.Apply(65028, 0x80000000), GRPC_HTTP2_NO_ERROR); |
||||
EXPECT_EQ(settings.preferred_receive_crypto_message_size(), 0x7fffffffu); |
||||
} |
||||
|
||||
namespace { |
||||
MATCHER_P(SettingsFrame, settings, "") { |
||||
if (!arg.has_value()) { |
||||
*result_listener << "Expected a settings frame, got nothing"; |
||||
return false; |
||||
} |
||||
if (arg->ack) { |
||||
*result_listener << "Expected a settings frame, got an ack"; |
||||
return false; |
||||
} |
||||
if (arg->settings.size() != settings.size()) { |
||||
*result_listener << "Expected settings frame with " << settings.size() |
||||
<< " settings, got " << arg->settings.size(); |
||||
return false; |
||||
} |
||||
for (size_t i = 0; i < settings.size(); i++) { |
||||
bool found = false; |
||||
for (size_t j = 0; j < arg->settings.size(); j++) { |
||||
if (settings[i] == arg->settings[j]) { |
||||
found = true; |
||||
break; |
||||
} |
||||
} |
||||
if (!found) { |
||||
*result_listener << "Expected settings frame with setting " |
||||
<< settings[i].first << " = " << settings[i].second |
||||
<< ", but it was not found"; |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
} // namespace
|
||||
|
||||
TEST(Http2SettingsManagerTest, ImmediatelyNeedsToSend) { |
||||
Http2SettingsManager settings_manager; |
||||
EXPECT_THAT(settings_manager.MaybeSendUpdate(), |
||||
SettingsFrame(KeyValueVec{{4, 65535}})); |
||||
} |
||||
|
||||
TEST(Http2SettingsManagerTest, SendAckWorks) { |
||||
Http2SettingsManager settings_manager; |
||||
settings_manager.mutable_local().SetInitialWindowSize(100000); |
||||
EXPECT_EQ(settings_manager.acked().initial_window_size(), 65535u); |
||||
EXPECT_THAT(settings_manager.MaybeSendUpdate(), |
||||
SettingsFrame(KeyValueVec{{4, 100000}})); |
||||
EXPECT_TRUE(settings_manager.AckLastSend()); |
||||
EXPECT_EQ(settings_manager.acked().initial_window_size(), 100000u); |
||||
} |
||||
|
||||
TEST(Http2SettingsManagerTest, AckWithoutSendFails) { |
||||
Http2SettingsManager settings_manager; |
||||
EXPECT_FALSE(settings_manager.AckLastSend()); |
||||
} |
||||
|
||||
TEST(Http2SettingsManagerTest, AckAfterAckFails) { |
||||
Http2SettingsManager settings_manager; |
||||
settings_manager.mutable_local().SetInitialWindowSize(100000); |
||||
EXPECT_THAT(settings_manager.MaybeSendUpdate(), |
||||
SettingsFrame(KeyValueVec{{4, 100000}})); |
||||
EXPECT_TRUE(settings_manager.AckLastSend()); |
||||
EXPECT_FALSE(settings_manager.AckLastSend()); |
||||
} |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) { |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
return RUN_ALL_TESTS(); |
||||
} |
@ -1,270 +0,0 @@ |
||||
#!/usr/bin/env python3 |
||||
|
||||
# Copyright 2017 gRPC authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
from __future__ import print_function |
||||
|
||||
import collections |
||||
import sys |
||||
|
||||
import perfection |
||||
|
||||
_MAX_HEADER_LIST_SIZE = 16 * 1024 * 1024 |
||||
|
||||
Setting = collections.namedtuple("Setting", "id default min max on_error") |
||||
OnError = collections.namedtuple("OnError", "behavior code") |
||||
clamp_invalid_value = OnError("CLAMP_INVALID_VALUE", "PROTOCOL_ERROR") |
||||
disconnect_on_invalid_value = lambda e: OnError( |
||||
"DISCONNECT_ON_INVALID_VALUE", e |
||||
) |
||||
DecoratedSetting = collections.namedtuple( |
||||
"DecoratedSetting", "enum name setting" |
||||
) |
||||
|
||||
_SETTINGS = { |
||||
"HEADER_TABLE_SIZE": Setting(1, 4096, 0, 0xFFFFFFFF, clamp_invalid_value), |
||||
"ENABLE_PUSH": Setting( |
||||
2, 1, 0, 1, disconnect_on_invalid_value("PROTOCOL_ERROR") |
||||
), |
||||
"MAX_CONCURRENT_STREAMS": Setting( |
||||
3, |
||||
0xFFFFFFFF, |
||||
0, |
||||
0xFFFFFFFF, |
||||
disconnect_on_invalid_value("PROTOCOL_ERROR"), |
||||
), |
||||
"INITIAL_WINDOW_SIZE": Setting( |
||||
4, |
||||
65535, |
||||
0, |
||||
0x7FFFFFFF, |
||||
disconnect_on_invalid_value("FLOW_CONTROL_ERROR"), |
||||
), |
||||
"MAX_FRAME_SIZE": Setting( |
||||
5, 16384, 16384, 16777215, disconnect_on_invalid_value("PROTOCOL_ERROR") |
||||
), |
||||
"MAX_HEADER_LIST_SIZE": Setting( |
||||
6, _MAX_HEADER_LIST_SIZE, 0, _MAX_HEADER_LIST_SIZE, clamp_invalid_value |
||||
), |
||||
"GRPC_ALLOW_TRUE_BINARY_METADATA": Setting( |
||||
0xFE03, 0, 0, 1, clamp_invalid_value |
||||
), |
||||
"GRPC_PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE": Setting( |
||||
0xFE04, 0, 16384, 0x7FFFFFFF, clamp_invalid_value |
||||
), |
||||
} |
||||
|
||||
H = open("src/core/ext/transport/chttp2/transport/http2_settings.h", "w") |
||||
C = open("src/core/ext/transport/chttp2/transport/http2_settings.cc", "w") |
||||
|
||||
|
||||
# utility: print a big comment block into a set of files |
||||
def put_banner(files, banner): |
||||
for f in files: |
||||
print("/*", file=f) |
||||
for line in banner: |
||||
print(" * %s" % line, file=f) |
||||
print(" */", file=f) |
||||
print(file=f) |
||||
|
||||
|
||||
# copy-paste copyright notice from this file |
||||
with open(sys.argv[0]) as my_source: |
||||
copyright = [] |
||||
for line in my_source: |
||||
if line[0] != "#": |
||||
break |
||||
for line in my_source: |
||||
if line[0] == "#": |
||||
copyright.append(line) |
||||
break |
||||
for line in my_source: |
||||
if line[0] != "#": |
||||
break |
||||
copyright.append(line) |
||||
put_banner([H, C], [line[2:].rstrip() for line in copyright]) |
||||
|
||||
put_banner( |
||||
[H, C], |
||||
["Automatically generated by tools/codegen/core/gen_settings_ids.py"], |
||||
) |
||||
|
||||
print( |
||||
"#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H", file=H |
||||
) |
||||
print( |
||||
"#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H", file=H |
||||
) |
||||
print(file=H) |
||||
print("#include <grpc/support/port_platform.h>", file=H) |
||||
print("#include <stdint.h>", file=H) |
||||
print(file=H) |
||||
|
||||
print("#include <grpc/support/port_platform.h>", file=C) |
||||
print( |
||||
'#include "src/core/ext/transport/chttp2/transport/http2_settings.h"', |
||||
file=C, |
||||
) |
||||
print(file=C) |
||||
print('#include "src/core/lib/gpr/useful.h"', file=C) |
||||
print('#include "src/core/lib/transport/http2_errors.h"', file=C) |
||||
print(file=C) |
||||
|
||||
p = perfection.hash_parameters(sorted(x.id for x in list(_SETTINGS.values()))) |
||||
print(p) |
||||
|
||||
|
||||
def hash(i): |
||||
i += p.offset |
||||
x = i % p.t |
||||
y = i // p.t |
||||
return x + p.r[y] |
||||
|
||||
|
||||
decorated_settings = [ |
||||
DecoratedSetting(hash(setting.id), name, setting) |
||||
for name, setting in _SETTINGS.items() |
||||
] |
||||
|
||||
print("typedef enum {", file=H) |
||||
for decorated_setting in sorted(decorated_settings): |
||||
print( |
||||
" GRPC_CHTTP2_SETTINGS_%s = %d, /* wire id %d */" |
||||
% ( |
||||
decorated_setting.name, |
||||
decorated_setting.enum, |
||||
decorated_setting.setting.id, |
||||
), |
||||
file=H, |
||||
) |
||||
print("} grpc_chttp2_setting_id;", file=H) |
||||
print(file=H) |
||||
print( |
||||
"#define GRPC_CHTTP2_NUM_SETTINGS %d" |
||||
% (max(x.enum for x in decorated_settings) + 1), |
||||
file=H, |
||||
) |
||||
|
||||
print("extern const uint16_t grpc_setting_id_to_wire_id[];", file=H) |
||||
print( |
||||
"const uint16_t grpc_setting_id_to_wire_id[] = {%s};" |
||||
% ",".join("%d" % s for s in p.slots), |
||||
file=C, |
||||
) |
||||
print(file=H) |
||||
print( |
||||
( |
||||
"bool grpc_wire_id_to_setting_id(uint32_t wire_id," |
||||
" grpc_chttp2_setting_id *out);" |
||||
), |
||||
file=H, |
||||
) |
||||
cgargs = { |
||||
"r": ",".join("%d" % (r if r is not None else 0) for r in p.r), |
||||
"t": p.t, |
||||
"offset": abs(p.offset), |
||||
"offset_sign": "+" if p.offset > 0 else "-", |
||||
} |
||||
print( |
||||
""" |
||||
bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id *out) { |
||||
uint32_t i = wire_id %(offset_sign)s %(offset)d; |
||||
uint32_t x = i %% %(t)d; |
||||
uint32_t y = i / %(t)d; |
||||
uint32_t h = x; |
||||
switch (y) { |
||||
""" |
||||
% cgargs, |
||||
file=C, |
||||
) |
||||
for i, r in enumerate(p.r): |
||||
if not r: |
||||
continue |
||||
if r < 0: |
||||
print("case %d: h -= %d; break;" % (i, -r), file=C) |
||||
else: |
||||
print("case %d: h += %d; break;" % (i, r), file=C) |
||||
print( |
||||
""" |
||||
} |
||||
*out = static_cast<grpc_chttp2_setting_id>(h); |
||||
return h < GPR_ARRAY_SIZE(grpc_setting_id_to_wire_id) && grpc_setting_id_to_wire_id[h] == wire_id; |
||||
} |
||||
""" |
||||
% cgargs, |
||||
file=C, |
||||
) |
||||
|
||||
print( |
||||
""" |
||||
typedef enum { |
||||
GRPC_CHTTP2_CLAMP_INVALID_VALUE, |
||||
GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE |
||||
} grpc_chttp2_invalid_value_behavior; |
||||
|
||||
typedef struct { |
||||
const char *name; |
||||
uint32_t default_value; |
||||
uint32_t min_value; |
||||
uint32_t max_value; |
||||
grpc_chttp2_invalid_value_behavior invalid_value_behavior; |
||||
uint32_t error_value; |
||||
} grpc_chttp2_setting_parameters; |
||||
|
||||
extern const grpc_chttp2_setting_parameters grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS]; |
||||
""", |
||||
file=H, |
||||
) |
||||
print( |
||||
( |
||||
"const grpc_chttp2_setting_parameters" |
||||
" grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {" |
||||
), |
||||
file=C, |
||||
) |
||||
i = 0 |
||||
for decorated_setting in sorted(decorated_settings): |
||||
while i < decorated_setting.enum: |
||||
print( |
||||
( |
||||
"{NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE," |
||||
" GRPC_HTTP2_PROTOCOL_ERROR}," |
||||
), |
||||
file=C, |
||||
) |
||||
i += 1 |
||||
print( |
||||
'{"%s", %du, %du, %du, GRPC_CHTTP2_%s, GRPC_HTTP2_%s},' |
||||
% ( |
||||
decorated_setting.name, |
||||
decorated_setting.setting.default, |
||||
decorated_setting.setting.min, |
||||
decorated_setting.setting.max, |
||||
decorated_setting.setting.on_error.behavior, |
||||
decorated_setting.setting.on_error.code, |
||||
), |
||||
file=C, |
||||
) |
||||
i += 1 |
||||
print("};", file=C) |
||||
|
||||
print(file=H) |
||||
print( |
||||
"#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H */", |
||||
file=H, |
||||
) |
||||
|
||||
H.close() |
||||
C.close() |
Loading…
Reference in new issue