mirror of https://github.com/grpc/grpc.git
This reverts commit 8185a56322
.
pull/31631/head
parent
dfb50dbab8
commit
e8ac147311
57 changed files with 380 additions and 2875 deletions
File diff suppressed because it is too large
Load Diff
@ -1,307 +0,0 @@ |
|||||||
// Copyright 2022 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 <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include "src/core/ext/transport/chaotic_good/frame.h" |
|
||||||
|
|
||||||
#include <string.h> |
|
||||||
|
|
||||||
#include <limits> |
|
||||||
#include <utility> |
|
||||||
|
|
||||||
#include "absl/status/status.h" |
|
||||||
#include "absl/status/statusor.h" |
|
||||||
|
|
||||||
#include <grpc/slice.h> |
|
||||||
#include <grpc/support/log.h> |
|
||||||
|
|
||||||
#include "src/core/lib/gprpp/bitset.h" |
|
||||||
#include "src/core/lib/gprpp/no_destruct.h" |
|
||||||
#include "src/core/lib/gprpp/status_helper.h" |
|
||||||
#include "src/core/lib/promise/context.h" |
|
||||||
#include "src/core/lib/slice/slice.h" |
|
||||||
#include "src/core/lib/slice/slice_buffer.h" |
|
||||||
|
|
||||||
namespace grpc_core { |
|
||||||
namespace chaotic_good { |
|
||||||
|
|
||||||
namespace { |
|
||||||
const NoDestruct<Slice> kZeroSlice{[] { |
|
||||||
auto slice = GRPC_SLICE_MALLOC(64); |
|
||||||
memset(GRPC_SLICE_START_PTR(slice), 0, 64); |
|
||||||
return slice; |
|
||||||
}()}; |
|
||||||
|
|
||||||
class FrameSerializer { |
|
||||||
public: |
|
||||||
explicit FrameSerializer(FrameType type, uint32_t stream_id) |
|
||||||
: header_{type, {}, stream_id, 0, 0, 0} { |
|
||||||
output_.AppendIndexed(kZeroSlice->Copy()); |
|
||||||
} |
|
||||||
// If called, must be called before AddMessage, AddTrailers, Finish
|
|
||||||
SliceBuffer& AddHeaders() { |
|
||||||
GPR_ASSERT(last_added_ == nullptr); |
|
||||||
header_.flags.set(0); |
|
||||||
return Start(&header_.header_length); |
|
||||||
} |
|
||||||
// If called, must be called before AddTrailers, Finish
|
|
||||||
SliceBuffer& AddMessage() { |
|
||||||
MaybeCommitLast(); |
|
||||||
header_.flags.set(1); |
|
||||||
return Start(&header_.message_length); |
|
||||||
} |
|
||||||
// If called, must be called before Finish
|
|
||||||
SliceBuffer& AddTrailers() { |
|
||||||
MaybeCommitLast(); |
|
||||||
header_.flags.set(2); |
|
||||||
return Start(&header_.trailer_length); |
|
||||||
} |
|
||||||
|
|
||||||
SliceBuffer Finish() { |
|
||||||
MaybeCommitLast(); |
|
||||||
header_.Serialize( |
|
||||||
GRPC_SLICE_START_PTR(output_.c_slice_buffer()->slices[0])); |
|
||||||
return std::move(output_); |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
SliceBuffer& Start(uint32_t* length_field) { |
|
||||||
last_added_ = length_field; |
|
||||||
length_at_last_added_ = output_.Length(); |
|
||||||
return output_; |
|
||||||
} |
|
||||||
|
|
||||||
void MaybeCommitLast() { |
|
||||||
if (last_added_ == nullptr) return; |
|
||||||
*last_added_ = output_.Length() - length_at_last_added_; |
|
||||||
if (output_.Length() % 64 != 0) { |
|
||||||
output_.Append(kZeroSlice->RefSubSlice(0, 64 - output_.Length() % 64)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
FrameHeader header_; |
|
||||||
|
|
||||||
uint32_t* last_added_ = nullptr; |
|
||||||
size_t length_at_last_added_; |
|
||||||
SliceBuffer output_; |
|
||||||
}; |
|
||||||
|
|
||||||
class FrameDeserializer { |
|
||||||
public: |
|
||||||
FrameDeserializer(const FrameHeader& header, SliceBuffer& input) |
|
||||||
: header_(header), input_(input) {} |
|
||||||
const FrameHeader& header() const { return header_; } |
|
||||||
// If called, must be called before ReceiveMessage, ReceiveTrailers
|
|
||||||
absl::StatusOr<SliceBuffer> ReceiveHeaders() { |
|
||||||
return Take(header_.header_length); |
|
||||||
} |
|
||||||
// If called, must be called before ReceiveTrailers
|
|
||||||
absl::StatusOr<SliceBuffer> ReceiveMessage() { |
|
||||||
return Take(header_.message_length); |
|
||||||
} |
|
||||||
// If called, must be called before Finish
|
|
||||||
absl::StatusOr<SliceBuffer> ReceiveTrailers() { |
|
||||||
return Take(header_.trailer_length); |
|
||||||
} |
|
||||||
|
|
||||||
absl::Status Finish() { return absl::OkStatus(); } |
|
||||||
|
|
||||||
private: |
|
||||||
absl::StatusOr<SliceBuffer> Take(uint32_t length) { |
|
||||||
if (length == 0) return SliceBuffer{}; |
|
||||||
if (input_.Length() < length) { |
|
||||||
return absl::InvalidArgumentError( |
|
||||||
"Frame too short (insufficient payload)"); |
|
||||||
} |
|
||||||
SliceBuffer out; |
|
||||||
input_.MoveFirstNBytesIntoSliceBuffer(length, out); |
|
||||||
if (length % 64 != 0) { |
|
||||||
const uint32_t padding_length = 64 - length % 64; |
|
||||||
if (input_.Length() < padding_length) { |
|
||||||
return absl::InvalidArgumentError( |
|
||||||
"Frame too short (insufficient padding)"); |
|
||||||
} |
|
||||||
uint8_t padding[64]; |
|
||||||
input_.MoveFirstNBytesIntoBuffer(padding_length, padding); |
|
||||||
for (uint32_t i = 0; i < padding_length; i++) { |
|
||||||
if (padding[i] != 0) { |
|
||||||
return absl::InvalidArgumentError("Frame padding not zero"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return std::move(out); |
|
||||||
} |
|
||||||
FrameHeader header_; |
|
||||||
SliceBuffer& input_; |
|
||||||
}; |
|
||||||
|
|
||||||
template <typename Metadata> |
|
||||||
absl::StatusOr<Arena::PoolPtr<Metadata>> ReadMetadata( |
|
||||||
HPackParser* parser, absl::StatusOr<SliceBuffer> maybe_slices, |
|
||||||
uint32_t stream_id, bool is_header, bool is_client) { |
|
||||||
if (!maybe_slices.ok()) return maybe_slices.status(); |
|
||||||
auto& slices = *maybe_slices; |
|
||||||
Arena::PoolPtr<Metadata> metadata; |
|
||||||
parser->BeginFrame( |
|
||||||
metadata.get(), std::numeric_limits<uint32_t>::max(), |
|
||||||
is_header ? HPackParser::Boundary::EndOfHeaders |
|
||||||
: HPackParser::Boundary::EndOfStream, |
|
||||||
HPackParser::Priority::None, |
|
||||||
HPackParser::LogInfo{stream_id, |
|
||||||
is_header ? HPackParser::LogInfo::Type::kHeaders |
|
||||||
: HPackParser::LogInfo::Type::kTrailers, |
|
||||||
is_client}); |
|
||||||
for (size_t i = 0; i < slices.Count(); i++) { |
|
||||||
GRPC_RETURN_IF_ERROR( |
|
||||||
parser->Parse(slices.c_slice_at(i), i == slices.Count() - 1)); |
|
||||||
} |
|
||||||
parser->FinishFrame(); |
|
||||||
return std::move(metadata); |
|
||||||
} |
|
||||||
} // namespace
|
|
||||||
|
|
||||||
absl::Status SettingsFrame::Deserialize(HPackParser*, const FrameHeader& header, |
|
||||||
SliceBuffer& slice_buffer) { |
|
||||||
if (header.type != FrameType::kSettings) { |
|
||||||
return absl::InvalidArgumentError("Expected settings frame"); |
|
||||||
} |
|
||||||
if (header.flags.any()) { |
|
||||||
return absl::InvalidArgumentError("Unexpected flags"); |
|
||||||
} |
|
||||||
FrameDeserializer deserializer(header, slice_buffer); |
|
||||||
return deserializer.Finish(); |
|
||||||
} |
|
||||||
|
|
||||||
SliceBuffer SettingsFrame::Serialize(HPackCompressor*) const { |
|
||||||
FrameSerializer serializer(FrameType::kSettings, 0); |
|
||||||
return serializer.Finish(); |
|
||||||
} |
|
||||||
|
|
||||||
absl::Status ClientFragmentFrame::Deserialize(HPackParser* parser, |
|
||||||
const FrameHeader& header, |
|
||||||
SliceBuffer& slice_buffer) { |
|
||||||
if (header.stream_id == 0) { |
|
||||||
return absl::InvalidArgumentError("Expected non-zero stream id"); |
|
||||||
} |
|
||||||
stream_id = header.stream_id; |
|
||||||
if (header.type != FrameType::kFragment) { |
|
||||||
return absl::InvalidArgumentError("Expected fragment frame"); |
|
||||||
} |
|
||||||
FrameDeserializer deserializer(header, slice_buffer); |
|
||||||
if (header.flags.is_set(0)) { |
|
||||||
auto r = ReadMetadata<ClientMetadata>(parser, deserializer.ReceiveHeaders(), |
|
||||||
header.stream_id, true, true); |
|
||||||
if (!r.ok()) return r.status(); |
|
||||||
} |
|
||||||
if (header.flags.is_set(1)) { |
|
||||||
message = GetContext<Arena>()->MakePooled<Message>(); |
|
||||||
auto r = deserializer.ReceiveMessage(); |
|
||||||
if (!r.ok()) return r.status(); |
|
||||||
r->Swap(message->payload()); |
|
||||||
} |
|
||||||
if (header.flags.is_set(2)) { |
|
||||||
if (header.trailer_length != 0) { |
|
||||||
return absl::InvalidArgumentError("Unexpected trailer length"); |
|
||||||
} |
|
||||||
end_of_stream = true; |
|
||||||
} else { |
|
||||||
end_of_stream = false; |
|
||||||
} |
|
||||||
return deserializer.Finish(); |
|
||||||
} |
|
||||||
|
|
||||||
SliceBuffer ClientFragmentFrame::Serialize(HPackCompressor* encoder) const { |
|
||||||
GPR_ASSERT(stream_id != 0); |
|
||||||
FrameSerializer serializer(FrameType::kFragment, stream_id); |
|
||||||
if (headers.get() != nullptr) { |
|
||||||
encoder->EncodeRawHeaders(*headers.get(), serializer.AddHeaders()); |
|
||||||
} |
|
||||||
if (message.get() != nullptr) { |
|
||||||
serializer.AddMessage().Append(*message->payload()); |
|
||||||
} |
|
||||||
if (end_of_stream) { |
|
||||||
serializer.AddTrailers(); |
|
||||||
} |
|
||||||
return serializer.Finish(); |
|
||||||
} |
|
||||||
|
|
||||||
absl::Status ServerFragmentFrame::Deserialize(HPackParser* parser, |
|
||||||
const FrameHeader& header, |
|
||||||
SliceBuffer& slice_buffer) { |
|
||||||
if (header.stream_id == 0) { |
|
||||||
return absl::InvalidArgumentError("Expected non-zero stream id"); |
|
||||||
} |
|
||||||
stream_id = header.stream_id; |
|
||||||
if (header.type != FrameType::kFragment) { |
|
||||||
return absl::InvalidArgumentError("Expected fragment frame"); |
|
||||||
} |
|
||||||
FrameDeserializer deserializer(header, slice_buffer); |
|
||||||
if (header.flags.is_set(0)) { |
|
||||||
auto r = ReadMetadata<ServerMetadata>(parser, deserializer.ReceiveHeaders(), |
|
||||||
header.stream_id, true, false); |
|
||||||
if (!r.ok()) return r.status(); |
|
||||||
} |
|
||||||
if (header.flags.is_set(1)) { |
|
||||||
message = GetContext<Arena>()->MakePooled<Message>(); |
|
||||||
auto r = deserializer.ReceiveMessage(); |
|
||||||
if (!r.ok()) return r.status(); |
|
||||||
r->Swap(message->payload()); |
|
||||||
} |
|
||||||
if (header.flags.is_set(2)) { |
|
||||||
auto r = ReadMetadata<ServerMetadata>( |
|
||||||
parser, deserializer.ReceiveTrailers(), header.stream_id, false, false); |
|
||||||
} |
|
||||||
return deserializer.Finish(); |
|
||||||
} |
|
||||||
|
|
||||||
SliceBuffer ServerFragmentFrame::Serialize(HPackCompressor* encoder) const { |
|
||||||
GPR_ASSERT(stream_id != 0); |
|
||||||
FrameSerializer serializer(FrameType::kFragment, stream_id); |
|
||||||
if (headers.get() != nullptr) { |
|
||||||
encoder->EncodeRawHeaders(*headers.get(), serializer.AddHeaders()); |
|
||||||
} |
|
||||||
if (message.get() != nullptr) { |
|
||||||
serializer.AddMessage().Append(*message->payload()); |
|
||||||
} |
|
||||||
if (trailers.get() != nullptr) { |
|
||||||
encoder->EncodeRawHeaders(*trailers.get(), serializer.AddTrailers()); |
|
||||||
} |
|
||||||
return serializer.Finish(); |
|
||||||
} |
|
||||||
|
|
||||||
absl::Status CancelFrame::Deserialize(HPackParser*, const FrameHeader& header, |
|
||||||
SliceBuffer& slice_buffer) { |
|
||||||
if (header.type != FrameType::kCancel) { |
|
||||||
return absl::InvalidArgumentError("Expected cancel frame"); |
|
||||||
} |
|
||||||
if (header.flags.any()) { |
|
||||||
return absl::InvalidArgumentError("Unexpected flags"); |
|
||||||
} |
|
||||||
if (header.stream_id == 0) { |
|
||||||
return absl::InvalidArgumentError("Expected non-zero stream id"); |
|
||||||
} |
|
||||||
FrameDeserializer deserializer(header, slice_buffer); |
|
||||||
stream_id = header.stream_id; |
|
||||||
return deserializer.Finish(); |
|
||||||
} |
|
||||||
|
|
||||||
SliceBuffer CancelFrame::Serialize(HPackCompressor*) const { |
|
||||||
GPR_ASSERT(stream_id != 0); |
|
||||||
FrameSerializer serializer(FrameType::kCancel, stream_id); |
|
||||||
return serializer.Finish(); |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace chaotic_good
|
|
||||||
} // namespace grpc_core
|
|
@ -1,122 +0,0 @@ |
|||||||
// Copyright 2022 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.
|
|
||||||
|
|
||||||
#ifndef GRPC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_FRAME_H |
|
||||||
#define GRPC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_FRAME_H |
|
||||||
|
|
||||||
#include <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include <cstdint> |
|
||||||
#include <memory> |
|
||||||
#include <string> |
|
||||||
|
|
||||||
#include "absl/status/status.h" |
|
||||||
#include "absl/types/variant.h" |
|
||||||
|
|
||||||
#include "src/core/ext/transport/chaotic_good/frame_header.h" |
|
||||||
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h" |
|
||||||
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h" |
|
||||||
#include "src/core/lib/resource_quota/arena.h" |
|
||||||
#include "src/core/lib/slice/slice_buffer.h" |
|
||||||
#include "src/core/lib/transport/metadata_batch.h" |
|
||||||
#include "src/core/lib/transport/transport.h" |
|
||||||
|
|
||||||
namespace grpc_core { |
|
||||||
namespace chaotic_good { |
|
||||||
|
|
||||||
class FrameInterface { |
|
||||||
public: |
|
||||||
virtual absl::Status Deserialize(HPackParser* parser, |
|
||||||
const FrameHeader& header, |
|
||||||
SliceBuffer& slice_buffer) = 0; |
|
||||||
virtual SliceBuffer Serialize(HPackCompressor* encoder) const = 0; |
|
||||||
|
|
||||||
protected: |
|
||||||
static bool EqVal(const Message& a, const Message& b) { |
|
||||||
return a.payload()->JoinIntoString() == b.payload()->JoinIntoString() && |
|
||||||
a.flags() == b.flags(); |
|
||||||
} |
|
||||||
static bool EqVal(const grpc_metadata_batch& a, |
|
||||||
const grpc_metadata_batch& b) { |
|
||||||
return a.DebugString() == b.DebugString(); |
|
||||||
} |
|
||||||
template <typename T> |
|
||||||
static bool EqHdl(const Arena::PoolPtr<T>& a, const Arena::PoolPtr<T>& b) { |
|
||||||
if (a == nullptr && b == nullptr) return true; |
|
||||||
if (a == nullptr || b == nullptr) return false; |
|
||||||
return EqVal(*a, *b); |
|
||||||
} |
|
||||||
~FrameInterface() = default; |
|
||||||
}; |
|
||||||
|
|
||||||
struct SettingsFrame final : public FrameInterface { |
|
||||||
absl::Status Deserialize(HPackParser* parser, const FrameHeader& header, |
|
||||||
SliceBuffer& slice_buffer) override; |
|
||||||
SliceBuffer Serialize(HPackCompressor* encoder) const override; |
|
||||||
|
|
||||||
bool operator==(const SettingsFrame&) const { return true; } |
|
||||||
}; |
|
||||||
|
|
||||||
struct ClientFragmentFrame final : public FrameInterface { |
|
||||||
absl::Status Deserialize(HPackParser* parser, const FrameHeader& header, |
|
||||||
SliceBuffer& slice_buffer) override; |
|
||||||
SliceBuffer Serialize(HPackCompressor* encoder) const override; |
|
||||||
|
|
||||||
uint32_t stream_id; |
|
||||||
ClientMetadataHandle headers; |
|
||||||
MessageHandle message; |
|
||||||
bool end_of_stream = false; |
|
||||||
|
|
||||||
bool operator==(const ClientFragmentFrame& other) const { |
|
||||||
return stream_id == other.stream_id && EqHdl(headers, other.headers) && |
|
||||||
EqHdl(message, other.message) && |
|
||||||
end_of_stream == other.end_of_stream; |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
struct ServerFragmentFrame final : public FrameInterface { |
|
||||||
absl::Status Deserialize(HPackParser* parser, const FrameHeader& header, |
|
||||||
SliceBuffer& slice_buffer) override; |
|
||||||
SliceBuffer Serialize(HPackCompressor* encoder) const override; |
|
||||||
|
|
||||||
uint32_t stream_id; |
|
||||||
ServerMetadataHandle headers; |
|
||||||
MessageHandle message; |
|
||||||
ServerMetadataHandle trailers; |
|
||||||
|
|
||||||
bool operator==(const ServerFragmentFrame& other) const { |
|
||||||
return stream_id == other.stream_id && EqHdl(headers, other.headers) && |
|
||||||
EqHdl(message, other.message) && EqHdl(trailers, other.trailers); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
struct CancelFrame final : public FrameInterface { |
|
||||||
absl::Status Deserialize(HPackParser* parser, const FrameHeader& header, |
|
||||||
SliceBuffer& slice_buffer) override; |
|
||||||
SliceBuffer Serialize(HPackCompressor* encoder) const override; |
|
||||||
|
|
||||||
uint32_t stream_id; |
|
||||||
|
|
||||||
bool operator==(const CancelFrame& other) const { |
|
||||||
return stream_id == other.stream_id; |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
using ClientFrame = absl::variant<ClientFragmentFrame, CancelFrame>; |
|
||||||
using ServerFrame = absl::variant<ServerFragmentFrame>; |
|
||||||
|
|
||||||
} // namespace chaotic_good
|
|
||||||
} // namespace grpc_core
|
|
||||||
|
|
||||||
#endif // GRPC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_FRAME_H
|
|
@ -1,87 +0,0 @@ |
|||||||
// Copyright 2022 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 <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include "src/core/ext/transport/chaotic_good/frame_header.h" |
|
||||||
|
|
||||||
#include <string.h> |
|
||||||
|
|
||||||
#include <cstdint> |
|
||||||
|
|
||||||
#include "absl/status/status.h" |
|
||||||
|
|
||||||
namespace grpc_core { |
|
||||||
namespace chaotic_good { |
|
||||||
|
|
||||||
namespace { |
|
||||||
void WriteLittleEndianUint32(uint32_t value, uint8_t* data) { |
|
||||||
data[0] = static_cast<uint8_t>(value); |
|
||||||
data[1] = static_cast<uint8_t>(value >> 8); |
|
||||||
data[2] = static_cast<uint8_t>(value >> 16); |
|
||||||
data[3] = static_cast<uint8_t>(value >> 24); |
|
||||||
} |
|
||||||
|
|
||||||
uint32_t ReadLittleEndianUint32(const uint8_t* data) { |
|
||||||
return static_cast<uint32_t>(data[0]) | |
|
||||||
(static_cast<uint32_t>(data[1]) << 8) | |
|
||||||
(static_cast<uint32_t>(data[2]) << 16) | |
|
||||||
(static_cast<uint32_t>(data[3]) << 24); |
|
||||||
} |
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void FrameHeader::Serialize(uint8_t* data) const { |
|
||||||
WriteLittleEndianUint32( |
|
||||||
static_cast<uint32_t>(type) | (flags.ToInt<uint32_t>() << 8), data); |
|
||||||
WriteLittleEndianUint32(stream_id, data + 4); |
|
||||||
WriteLittleEndianUint32(header_length, data + 8); |
|
||||||
WriteLittleEndianUint32(message_length, data + 12); |
|
||||||
WriteLittleEndianUint32(trailer_length, data + 16); |
|
||||||
memset(data + 20, 0, 44); |
|
||||||
} |
|
||||||
|
|
||||||
absl::StatusOr<FrameHeader> FrameHeader::Parse(const uint8_t* data) { |
|
||||||
FrameHeader header; |
|
||||||
const uint32_t type_and_flags = ReadLittleEndianUint32(data); |
|
||||||
header.type = static_cast<FrameType>(type_and_flags & 0xff); |
|
||||||
const uint32_t flags = type_and_flags >> 8; |
|
||||||
if (flags > 7) return absl::InvalidArgumentError("Invalid flags"); |
|
||||||
header.flags = BitSet<3>::FromInt(flags); |
|
||||||
header.stream_id = ReadLittleEndianUint32(data + 4); |
|
||||||
header.header_length = ReadLittleEndianUint32(data + 8); |
|
||||||
header.message_length = ReadLittleEndianUint32(data + 12); |
|
||||||
header.trailer_length = ReadLittleEndianUint32(data + 16); |
|
||||||
for (int i = 0; i < 44; i++) { |
|
||||||
if (data[20 + i] != 0) return absl::InvalidArgumentError("Invalid padding"); |
|
||||||
} |
|
||||||
return header; |
|
||||||
} |
|
||||||
|
|
||||||
namespace { |
|
||||||
uint64_t RoundUp(uint64_t x) { |
|
||||||
if (x % 64 == 0) return x; |
|
||||||
return x + 64 - (x % 64); |
|
||||||
} |
|
||||||
} // namespace
|
|
||||||
|
|
||||||
FrameSizes FrameHeader::ComputeFrameSizes() const { |
|
||||||
FrameSizes sizes; |
|
||||||
sizes.message_offset = RoundUp(header_length); |
|
||||||
sizes.trailer_offset = sizes.message_offset + RoundUp(message_length); |
|
||||||
sizes.frame_length = sizes.trailer_offset + RoundUp(trailer_length); |
|
||||||
return sizes; |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace chaotic_good
|
|
||||||
} // namespace grpc_core
|
|
@ -1,73 +0,0 @@ |
|||||||
// Copyright 2022 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.
|
|
||||||
|
|
||||||
#ifndef GRPC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_FRAME_HEADER_H |
|
||||||
#define GRPC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_FRAME_HEADER_H |
|
||||||
|
|
||||||
#include <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include <cstdint> |
|
||||||
|
|
||||||
#include "absl/status/statusor.h" |
|
||||||
|
|
||||||
#include "src/core/lib/gprpp/bitset.h" |
|
||||||
|
|
||||||
namespace grpc_core { |
|
||||||
namespace chaotic_good { |
|
||||||
|
|
||||||
enum class FrameType : uint8_t { |
|
||||||
kSettings = 0x00, |
|
||||||
kFragment = 0x80, |
|
||||||
kCancel = 0x81, |
|
||||||
}; |
|
||||||
|
|
||||||
struct FrameSizes { |
|
||||||
uint64_t message_offset; |
|
||||||
uint64_t trailer_offset; |
|
||||||
uint64_t frame_length; |
|
||||||
|
|
||||||
bool operator==(const FrameSizes& other) const { |
|
||||||
return message_offset == other.message_offset && |
|
||||||
trailer_offset == other.trailer_offset && |
|
||||||
frame_length == other.frame_length; |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
struct FrameHeader { |
|
||||||
FrameType type; |
|
||||||
BitSet<3> flags; |
|
||||||
uint32_t stream_id; |
|
||||||
uint32_t header_length; |
|
||||||
uint32_t message_length; |
|
||||||
uint32_t trailer_length; |
|
||||||
|
|
||||||
// Parses a frame header from a buffer of 64 bytes. All 64 bytes are consumed.
|
|
||||||
static absl::StatusOr<FrameHeader> Parse(const uint8_t* data); |
|
||||||
// Serializes a frame header into a buffer of 64 bytes.
|
|
||||||
void Serialize(uint8_t* data) const; |
|
||||||
// Compute frame sizes from the header.
|
|
||||||
FrameSizes ComputeFrameSizes() const; |
|
||||||
|
|
||||||
bool operator==(const FrameHeader& h) const { |
|
||||||
return type == h.type && flags == h.flags && stream_id == h.stream_id && |
|
||||||
header_length == h.header_length && |
|
||||||
message_length == h.message_length && |
|
||||||
trailer_length == h.trailer_length; |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
} // namespace chaotic_good
|
|
||||||
} // namespace grpc_core
|
|
||||||
|
|
||||||
#endif // GRPC_CORE_EXT_TRANSPORT_CHAOTIC_GOOD_FRAME_HEADER_H
|
|
@ -1,19 +0,0 @@ |
|||||||
// Copyright 2022 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 <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include "src/core/ext/transport/chttp2/transport/http_trace.h" |
|
||||||
|
|
||||||
grpc_core::TraceFlag grpc_http_trace(false, "http"); |
|
@ -1,24 +0,0 @@ |
|||||||
// Copyright 2022 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.
|
|
||||||
|
|
||||||
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP_TRACE_H |
|
||||||
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP_TRACE_H |
|
||||||
|
|
||||||
#include <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include "src/core/lib/debug/trace.h" |
|
||||||
|
|
||||||
extern grpc_core::TraceFlag grpc_http_trace; |
|
||||||
|
|
||||||
#endif // GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP_TRACE_H
|
|
@ -1,78 +0,0 @@ |
|||||||
# Copyright 2021 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. |
|
||||||
|
|
||||||
load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package") |
|
||||||
load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") |
|
||||||
|
|
||||||
licenses(["notice"]) |
|
||||||
|
|
||||||
grpc_package( |
|
||||||
name = "test/core/transport/chaotic_good", |
|
||||||
visibility = "tests", |
|
||||||
) |
|
||||||
|
|
||||||
grpc_cc_test( |
|
||||||
name = "frame_header_test", |
|
||||||
srcs = ["frame_header_test.cc"], |
|
||||||
external_deps = [ |
|
||||||
"absl/status", |
|
||||||
"gtest", |
|
||||||
], |
|
||||||
deps = ["//src/core:chaotic_good_frame_header"], |
|
||||||
) |
|
||||||
|
|
||||||
grpc_fuzzer( |
|
||||||
name = "frame_header_fuzzer", |
|
||||||
srcs = ["frame_header_fuzzer.cc"], |
|
||||||
corpus = "frame_header_fuzzer_corpus", |
|
||||||
external_deps = ["absl/status:statusor"], |
|
||||||
language = "C++", |
|
||||||
tags = ["no_windows"], |
|
||||||
deps = ["//src/core:chaotic_good_frame_header"], |
|
||||||
) |
|
||||||
|
|
||||||
grpc_cc_test( |
|
||||||
name = "frame_test", |
|
||||||
srcs = ["frame_test.cc"], |
|
||||||
external_deps = [ |
|
||||||
"absl/status", |
|
||||||
"absl/status:statusor", |
|
||||||
"gtest", |
|
||||||
], |
|
||||||
deps = ["//src/core:chaotic_good_frame"], |
|
||||||
) |
|
||||||
|
|
||||||
grpc_fuzzer( |
|
||||||
name = "frame_fuzzer", |
|
||||||
srcs = ["frame_fuzzer.cc"], |
|
||||||
corpus = "frame_fuzzer_corpus", |
|
||||||
external_deps = ["absl/status:statusor"], |
|
||||||
language = "C++", |
|
||||||
tags = ["no_windows"], |
|
||||||
deps = [ |
|
||||||
"//:gpr", |
|
||||||
"//:hpack_encoder", |
|
||||||
"//:hpack_parser", |
|
||||||
"//:ref_counted_ptr", |
|
||||||
"//src/core:arena", |
|
||||||
"//src/core:chaotic_good_frame", |
|
||||||
"//src/core:chaotic_good_frame_header", |
|
||||||
"//src/core:event_engine_memory_allocator", |
|
||||||
"//src/core:memory_quota", |
|
||||||
"//src/core:resource_quota", |
|
||||||
"//src/core:slice", |
|
||||||
"//src/core:slice_buffer", |
|
||||||
"//test/core/promise:test_context", |
|
||||||
], |
|
||||||
) |
|
@ -1,112 +0,0 @@ |
|||||||
// Copyright 2022 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 <stddef.h> |
|
||||||
#include <stdint.h> |
|
||||||
|
|
||||||
#include <memory> |
|
||||||
|
|
||||||
#include "absl/status/statusor.h" |
|
||||||
|
|
||||||
#include <grpc/event_engine/memory_allocator.h> |
|
||||||
#include <grpc/support/log.h> |
|
||||||
|
|
||||||
#include "src/core/ext/transport/chaotic_good/frame.h" |
|
||||||
#include "src/core/ext/transport/chaotic_good/frame_header.h" |
|
||||||
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h" |
|
||||||
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h" |
|
||||||
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
|
||||||
#include "src/core/lib/resource_quota/arena.h" |
|
||||||
#include "src/core/lib/resource_quota/memory_quota.h" |
|
||||||
#include "src/core/lib/resource_quota/resource_quota.h" |
|
||||||
#include "src/core/lib/slice/slice.h" |
|
||||||
#include "src/core/lib/slice/slice_buffer.h" |
|
||||||
#include "test/core/promise/test_context.h" |
|
||||||
|
|
||||||
bool squelch = false; |
|
||||||
|
|
||||||
namespace grpc_core { |
|
||||||
namespace chaotic_good { |
|
||||||
|
|
||||||
static auto* g_memory_allocator = new MemoryAllocator( |
|
||||||
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator("test")); |
|
||||||
|
|
||||||
template <typename T> |
|
||||||
void AssertRoundTrips(const T& input, FrameType expected_frame_type) { |
|
||||||
HPackCompressor hpack_compressor; |
|
||||||
auto serialized = input.Serialize(&hpack_compressor); |
|
||||||
GPR_ASSERT(serialized.Length() >= 64); |
|
||||||
GPR_ASSERT(serialized.Length() % 64 == 0); |
|
||||||
uint8_t header_bytes[64]; |
|
||||||
serialized.MoveFirstNBytesIntoBuffer(64, header_bytes); |
|
||||||
auto header = FrameHeader::Parse(header_bytes); |
|
||||||
GPR_ASSERT(header.ok()); |
|
||||||
GPR_ASSERT(header->type == expected_frame_type); |
|
||||||
T output; |
|
||||||
HPackParser hpack_parser; |
|
||||||
auto deser = output.Deserialize(&hpack_parser, header.value(), serialized); |
|
||||||
GPR_ASSERT(deser.ok()); |
|
||||||
GPR_ASSERT(output == input); |
|
||||||
} |
|
||||||
|
|
||||||
template <typename T> |
|
||||||
void FinishParseAndChecks(const FrameHeader& header, const uint8_t* data, |
|
||||||
size_t size) { |
|
||||||
T parsed; |
|
||||||
HPackParser hpack_parser; |
|
||||||
SliceBuffer serialized; |
|
||||||
serialized.Append(Slice::FromCopiedBuffer(data, size)); |
|
||||||
auto deser = parsed.Deserialize(&hpack_parser, header, serialized); |
|
||||||
if (!deser.ok()) return; |
|
||||||
AssertRoundTrips(parsed, header.type); |
|
||||||
} |
|
||||||
|
|
||||||
int Run(const uint8_t* data, size_t size) { |
|
||||||
if (size < 1) return 0; |
|
||||||
const bool is_server = (data[0] & 1) != 0; |
|
||||||
size--; |
|
||||||
data++; |
|
||||||
if (size < 64) return 0; |
|
||||||
auto r = FrameHeader::Parse(data); |
|
||||||
if (!r.ok()) return 0; |
|
||||||
size -= 64; |
|
||||||
data += 64; |
|
||||||
auto arena = MakeScopedArena(1024, g_memory_allocator); |
|
||||||
TestContext<Arena> ctx(arena.get()); |
|
||||||
switch (r->type) { |
|
||||||
default: |
|
||||||
return 0; // We don't know how to parse this frame type.
|
|
||||||
case FrameType::kSettings: |
|
||||||
FinishParseAndChecks<SettingsFrame>(*r, data, size); |
|
||||||
break; |
|
||||||
case FrameType::kFragment: |
|
||||||
if (is_server) { |
|
||||||
FinishParseAndChecks<ServerFragmentFrame>(*r, data, size); |
|
||||||
} else { |
|
||||||
FinishParseAndChecks<ClientFragmentFrame>(*r, data, size); |
|
||||||
} |
|
||||||
break; |
|
||||||
case FrameType::kCancel: |
|
||||||
FinishParseAndChecks<CancelFrame>(*r, data, size); |
|
||||||
break; |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace chaotic_good
|
|
||||||
} // namespace grpc_core
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
|
||||||
return grpc_core::chaotic_good::Run(data, size); |
|
||||||
} |
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,34 +0,0 @@ |
|||||||
// Copyright 2022 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 <stdint.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <string.h> |
|
||||||
|
|
||||||
#include "absl/status/statusor.h" |
|
||||||
|
|
||||||
#include "src/core/ext/transport/chaotic_good/frame_header.h" |
|
||||||
|
|
||||||
bool squelch = false; |
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
|
||||||
if (size != 64) return 0; |
|
||||||
auto r = grpc_core::chaotic_good::FrameHeader::Parse(data); |
|
||||||
if (!r.ok()) return 0; |
|
||||||
uint8_t reserialized[64]; |
|
||||||
r->Serialize(reserialized); |
|
||||||
// If it parses, we insist that the bytes reserialize to the same thing.
|
|
||||||
if (memcmp(data, reserialized, 64) != 0) abort(); |
|
||||||
return 0; |
|
||||||
} |
|
@ -1,120 +0,0 @@ |
|||||||
// Copyright 2022 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/chaotic_good/frame_header.h" |
|
||||||
|
|
||||||
#include <algorithm> |
|
||||||
#include <cstdint> |
|
||||||
#include <vector> |
|
||||||
|
|
||||||
#include "absl/status/status.h" |
|
||||||
#include "gtest/gtest.h" |
|
||||||
|
|
||||||
namespace grpc_core { |
|
||||||
namespace chaotic_good { |
|
||||||
namespace { |
|
||||||
|
|
||||||
std::vector<uint8_t> Serialize(FrameHeader h) { |
|
||||||
uint8_t buffer[64]; |
|
||||||
h.Serialize(buffer); |
|
||||||
return std::vector<uint8_t>(buffer, buffer + 64); |
|
||||||
} |
|
||||||
|
|
||||||
absl::StatusOr<FrameHeader> Deserialize(std::vector<uint8_t> data) { |
|
||||||
if (data.size() != 64) return absl::InvalidArgumentError("bad length"); |
|
||||||
return FrameHeader::Parse(data.data()); |
|
||||||
} |
|
||||||
|
|
||||||
TEST(FrameHeaderTest, SimpleSerialize) { |
|
||||||
EXPECT_EQ( |
|
||||||
Serialize(FrameHeader{FrameType::kCancel, BitSet<3>::FromInt(0), |
|
||||||
0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f10}), |
|
||||||
std::vector<uint8_t>({0x81, 0, 0, 0, // type, flags
|
|
||||||
0x04, 0x03, 0x02, 0x01, // stream_id
|
|
||||||
0x08, 0x07, 0x06, 0x05, // header_length
|
|
||||||
0x0c, 0x0b, 0x0a, 0x09, // message_length
|
|
||||||
0x10, 0x0f, 0x0e, 0x0d, // trailer_length
|
|
||||||
// padding
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); |
|
||||||
} |
|
||||||
|
|
||||||
TEST(FrameHeaderTest, SimpleDeserialize) { |
|
||||||
EXPECT_EQ( |
|
||||||
Deserialize(std::vector<uint8_t>( |
|
||||||
{0x81, 0, 0, 0, // type, flags
|
|
||||||
0x04, 0x03, 0x02, 0x01, // stream_id
|
|
||||||
0x08, 0x07, 0x06, 0x05, // header_length
|
|
||||||
0x0c, 0x0b, 0x0a, 0x09, // message_length
|
|
||||||
0x10, 0x0f, 0x0e, 0x0d, // trailer_length
|
|
||||||
// padding
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})), |
|
||||||
absl::StatusOr<FrameHeader>( |
|
||||||
FrameHeader{FrameType::kCancel, BitSet<3>::FromInt(0), 0x01020304, |
|
||||||
0x05060708, 0x090a0b0c, 0x0d0e0f10})); |
|
||||||
EXPECT_EQ(Deserialize(std::vector<uint8_t>( |
|
||||||
{0x81, 88, 88, 88, // type, flags
|
|
||||||
0x04, 0x03, 0x02, 0x01, // stream_id
|
|
||||||
0x08, 0x07, 0x06, 0x05, // header_length
|
|
||||||
0x0c, 0x0b, 0x0a, 0x09, // message_length
|
|
||||||
0x10, 0x0f, 0x0e, 0x0d, // trailer_length
|
|
||||||
// garbage padding
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0})) |
|
||||||
.status(), |
|
||||||
absl::InvalidArgumentError("Invalid flags")); |
|
||||||
EXPECT_EQ(Deserialize(std::vector<uint8_t>( |
|
||||||
{0x81, 0, 0, 0, // type, flags
|
|
||||||
0x04, 0x03, 0x02, 0x01, // stream_id
|
|
||||||
0x08, 0x07, 0x06, 0x05, // header_length
|
|
||||||
0x0c, 0x0b, 0x0a, 0x09, // message_length
|
|
||||||
0x10, 0x0f, 0x0e, 0x0d, // trailer_length
|
|
||||||
// garbage padding
|
|
||||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0})) |
|
||||||
.status(), |
|
||||||
absl::InvalidArgumentError("Invalid padding")); |
|
||||||
} |
|
||||||
|
|
||||||
TEST(FrameHeaderTest, ComputeFrameSizes) { |
|
||||||
EXPECT_EQ( |
|
||||||
(FrameHeader{FrameType::kFragment, BitSet<3>::FromInt(7), 1, 0, 0, 0}) |
|
||||||
.ComputeFrameSizes(), |
|
||||||
(FrameSizes{0, 0, 0})); |
|
||||||
EXPECT_EQ( |
|
||||||
(FrameHeader{FrameType::kFragment, BitSet<3>::FromInt(7), 1, 14, 0, 0}) |
|
||||||
.ComputeFrameSizes(), |
|
||||||
(FrameSizes{64, 64, 64})); |
|
||||||
EXPECT_EQ( |
|
||||||
(FrameHeader{FrameType::kFragment, BitSet<3>::FromInt(7), 1, 0, 14, 0}) |
|
||||||
.ComputeFrameSizes(), |
|
||||||
(FrameSizes{0, 64, 64})); |
|
||||||
EXPECT_EQ( |
|
||||||
(FrameHeader{FrameType::kFragment, BitSet<3>::FromInt(7), 1, 0, 0, 14}) |
|
||||||
.ComputeFrameSizes(), |
|
||||||
(FrameSizes{0, 0, 64})); |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace chaotic_good
|
|
||||||
} // namespace grpc_core
|
|
||||||
|
|
||||||
int main(int argc, char** argv) { |
|
||||||
::testing::InitGoogleTest(&argc, argv); |
|
||||||
return RUN_ALL_TESTS(); |
|
||||||
} |
|
@ -1,57 +0,0 @@ |
|||||||
// Copyright 2022 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/chaotic_good/frame.h" |
|
||||||
|
|
||||||
#include <cstdint> |
|
||||||
|
|
||||||
#include "absl/status/status.h" |
|
||||||
#include "absl/status/statusor.h" |
|
||||||
#include "gtest/gtest.h" |
|
||||||
|
|
||||||
namespace grpc_core { |
|
||||||
namespace chaotic_good { |
|
||||||
namespace { |
|
||||||
|
|
||||||
template <typename T> |
|
||||||
void AssertRoundTrips(const T input, FrameType expected_frame_type) { |
|
||||||
HPackCompressor hpack_compressor; |
|
||||||
auto serialized = input.Serialize(&hpack_compressor); |
|
||||||
EXPECT_GE(serialized.Length(), 64); |
|
||||||
EXPECT_EQ(serialized.Length() % 64, 0); |
|
||||||
uint8_t header_bytes[64]; |
|
||||||
serialized.MoveFirstNBytesIntoBuffer(64, header_bytes); |
|
||||||
auto header = FrameHeader::Parse(header_bytes); |
|
||||||
EXPECT_TRUE(header.ok()) << header.status(); |
|
||||||
EXPECT_EQ(header->type, expected_frame_type); |
|
||||||
T output; |
|
||||||
HPackParser hpack_parser; |
|
||||||
auto deser = output.Deserialize(&hpack_parser, header.value(), serialized); |
|
||||||
EXPECT_TRUE(deser.ok()) << deser; |
|
||||||
EXPECT_EQ(output, input); |
|
||||||
} |
|
||||||
|
|
||||||
TEST(FrameTest, SettingsFrameRoundTrips) { |
|
||||||
AssertRoundTrips(SettingsFrame{}, FrameType::kSettings); |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace chaotic_good
|
|
||||||
} // namespace grpc_core
|
|
||||||
|
|
||||||
int main(int argc, char** argv) { |
|
||||||
::testing::InitGoogleTest(&argc, argv); |
|
||||||
int r = RUN_ALL_TESTS(); |
|
||||||
return r; |
|
||||||
} |
|
Loading…
Reference in new issue