mirror of https://github.com/grpc/grpc.git
Move metadata setting into HPackParser (#27545)
* forward work to get append, limit check into parser * further cleanup * Remove chttp2_incoming_metadata_buffer * Automated change: Fix sanity tests * test fixes * fix cronet * wip * first pass mementofication of parsing - libgrpc compiles * further progress * fixes * fixes * fix leak * Automated change: Fix sanity tests * fix leak * fixes * x * improve fuzzer * init ordering fix * Update hpack_parser_table.h * Update hpack_parser.cc * Update hpack_parser_test.cc * Automated change: Fix sanity tests * Automated change: Fix sanity tests * i mustache myself why * fix use after free * Automated change: Fix sanity tests * fixes * eliminate second pass metadata - this is an illegal frame and fails the new parser * handle mementos with size > sizeof(intptr_t) * fix * add parsed metadata header, test * Automated change: Fix sanity tests * fix includes * phase1 * phase2 * Update parsed_metadata.h * fix Co-authored-by: ctiller <ctiller@users.noreply.github.com>pull/27686/head
parent
2f56cb3d87
commit
f57a1f7d8c
732 changed files with 3215 additions and 1699 deletions
@ -1,65 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 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/incoming_metadata.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/ext/transport/chttp2/transport/internal.h" |
||||
|
||||
grpc_error_handle grpc_chttp2_incoming_metadata_buffer_add( |
||||
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_mdelem elem) { |
||||
buffer->size += GRPC_MDELEM_LENGTH(elem); |
||||
grpc_linked_mdelem* storage; |
||||
if (buffer->count < buffer->kPreallocatedMDElem) { |
||||
storage = &buffer->preallocated_mdelems[buffer->count]; |
||||
buffer->count++; |
||||
} else { |
||||
storage = static_cast<grpc_linked_mdelem*>( |
||||
buffer->arena->Alloc(sizeof(grpc_linked_mdelem))); |
||||
} |
||||
storage->md = elem; |
||||
return buffer->batch.LinkTail(storage); |
||||
} |
||||
|
||||
grpc_error_handle grpc_chttp2_incoming_metadata_buffer_replace_or_add( |
||||
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_slice key, |
||||
grpc_slice value) { |
||||
if (buffer->batch.ReplaceIfExists(key, value)) return GRPC_ERROR_NONE; |
||||
return grpc_chttp2_incoming_metadata_buffer_add( |
||||
buffer, grpc_mdelem_from_slices(key, value)); |
||||
} |
||||
|
||||
void grpc_chttp2_incoming_metadata_buffer_set_deadline( |
||||
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_millis deadline) { |
||||
if (deadline != GRPC_MILLIS_INF_FUTURE) { |
||||
buffer->batch.Set(grpc_core::GrpcTimeoutMetadata(), deadline); |
||||
} else { |
||||
buffer->batch.Remove(grpc_core::GrpcTimeoutMetadata()); |
||||
} |
||||
} |
||||
|
||||
void grpc_chttp2_incoming_metadata_buffer_publish( |
||||
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_metadata_batch* batch) { |
||||
*batch = std::move(buffer->batch); |
||||
} |
@ -1,54 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 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_INCOMING_METADATA_H |
||||
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/transport/transport.h" |
||||
|
||||
struct grpc_chttp2_incoming_metadata_buffer { |
||||
explicit grpc_chttp2_incoming_metadata_buffer(grpc_core::Arena* arena) |
||||
: arena(arena) {} |
||||
~grpc_chttp2_incoming_metadata_buffer() = default; |
||||
|
||||
static constexpr size_t kPreallocatedMDElem = 10; |
||||
|
||||
grpc_core::Arena* arena; |
||||
size_t size = 0; // total size of metadata.
|
||||
size_t count = 0; // minimum of count of metadata and kPreallocatedMDElem.
|
||||
// These preallocated mdelems are used while count < kPreallocatedMDElem.
|
||||
grpc_linked_mdelem preallocated_mdelems[kPreallocatedMDElem]; |
||||
grpc_metadata_batch batch; |
||||
}; |
||||
|
||||
void grpc_chttp2_incoming_metadata_buffer_publish( |
||||
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_metadata_batch* batch); |
||||
|
||||
grpc_error_handle grpc_chttp2_incoming_metadata_buffer_add( |
||||
grpc_chttp2_incoming_metadata_buffer* buffer, |
||||
grpc_mdelem elem) GRPC_MUST_USE_RESULT; |
||||
// key & value ownership are transferred to this function.
|
||||
grpc_error_handle grpc_chttp2_incoming_metadata_buffer_replace_or_add( |
||||
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_slice key, |
||||
grpc_slice value) GRPC_MUST_USE_RESULT; |
||||
void grpc_chttp2_incoming_metadata_buffer_set_deadline( |
||||
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_millis deadline); |
||||
|
||||
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H */ |
@ -0,0 +1,260 @@ |
||||
// 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.
|
||||
|
||||
#ifndef GRPC_CORE_LIB_TRANSPORT_PARSED_METADATA_H |
||||
#define GRPC_CORE_LIB_TRANSPORT_PARSED_METADATA_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <cstdint> |
||||
#include <type_traits> |
||||
|
||||
#include "absl/meta/type_traits.h" |
||||
#include "absl/strings/match.h" |
||||
|
||||
#include "src/core/lib/iomgr/error.h" |
||||
#include "src/core/lib/surface/validate_metadata.h" |
||||
#include "src/core/lib/transport/metadata.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
namespace metadata_detail { |
||||
|
||||
// Helper to determine whether a traits metadata is inlinable inside a memento,
|
||||
// or (if not) we'll need to take the memory allocation path.
|
||||
template <typename Which> |
||||
struct HasSimpleMemento { |
||||
static constexpr bool value = |
||||
std::is_trivial<typename Which::MementoType>::value && |
||||
sizeof(typename Which::MementoType) <= sizeof(intptr_t); |
||||
}; |
||||
|
||||
} // namespace metadata_detail
|
||||
|
||||
// A parsed metadata value.
|
||||
// This type captures a type erased MementoType from one trait of
|
||||
// MetadataContainer, and provides utilities to manipulate that and to set it on
|
||||
// a MetadataContainer.
|
||||
template <typename MetadataContainer> |
||||
class ParsedMetadata { |
||||
public: |
||||
// Construct metadata from a trait Which of MetadataContainer.
|
||||
// Two versions: the first is for simple inlinable mementos, and the second
|
||||
// forces an allocation.
|
||||
template <typename Which> |
||||
ParsedMetadata( |
||||
Which, |
||||
absl::enable_if_t<metadata_detail::HasSimpleMemento<Which>::value, |
||||
typename Which::MementoType> |
||||
value, |
||||
uint32_t transport_size) |
||||
: vtable_(ParsedMetadata::template TrivialTraitVTable<Which>()), |
||||
value_(static_cast<intptr_t>(value)), |
||||
transport_size_(transport_size) {} |
||||
template <typename Which> |
||||
ParsedMetadata( |
||||
Which, |
||||
absl::enable_if_t<!metadata_detail::HasSimpleMemento<Which>::value, |
||||
typename Which::MementoType> |
||||
value, |
||||
uint32_t transport_size) |
||||
: vtable_(ParsedMetadata::template NonTrivialTraitVTable<Which>()), |
||||
value_( |
||||
reinterpret_cast<intptr_t>(new typename Which::MementoType(value))), |
||||
transport_size_(transport_size) {} |
||||
// Takes ownership of elem
|
||||
explicit ParsedMetadata(grpc_mdelem elem) |
||||
: vtable_(grpc_is_binary_header_internal(GRPC_MDKEY(elem)) |
||||
? MdelemVtable<true>() |
||||
: MdelemVtable<false>()), |
||||
value_(static_cast<intptr_t>(elem.payload)), |
||||
transport_size_(GRPC_MDELEM_LENGTH(elem)) {} |
||||
ParsedMetadata() : vtable_(EmptyVTable()) {} |
||||
~ParsedMetadata() { vtable_->destroy(value_); } |
||||
|
||||
// Non copyable, but movable.
|
||||
ParsedMetadata(const ParsedMetadata&) = delete; |
||||
ParsedMetadata& operator=(const ParsedMetadata&) = delete; |
||||
ParsedMetadata(ParsedMetadata&& other) noexcept |
||||
: vtable_(other.vtable_), |
||||
value_(other.value_), |
||||
transport_size_(other.transport_size_) { |
||||
other.vtable_ = EmptyVTable(); |
||||
} |
||||
ParsedMetadata& operator=(ParsedMetadata&& other) noexcept { |
||||
vtable_ = other.vtable_; |
||||
value_ = other.value_; |
||||
transport_size_ = other.transport_size_; |
||||
other.vtable_ = EmptyVTable(); |
||||
return *this; |
||||
} |
||||
|
||||
// Set this parsed value on a container.
|
||||
GRPC_MUST_USE_RESULT grpc_error_handle |
||||
SetOnContainer(MetadataContainer* container) const { |
||||
return vtable_->set(value_, container); |
||||
} |
||||
|
||||
// Is this a binary header or not?
|
||||
bool is_binary_header() const { return vtable_->is_binary_header; } |
||||
// HTTP2 defined storage size of this metadatum.
|
||||
uint32_t transport_size() const { return transport_size_; } |
||||
// Create a new parsed metadata with the same key but a different value.
|
||||
ParsedMetadata WithNewValue(const grpc_slice& value) const { |
||||
return vtable_->with_new_value(value_, value); |
||||
} |
||||
std::string DebugString() const { return vtable_->debug_string(value_); } |
||||
|
||||
// TODO(ctiller): move to transport
|
||||
static uint32_t TransportSize(uint32_t key_size, uint32_t value_size) { |
||||
// TODO(ctiller): use hpack constant?
|
||||
return key_size + value_size + 32; |
||||
} |
||||
|
||||
private: |
||||
struct VTable { |
||||
const bool is_binary_header; |
||||
void (*const destroy)(intptr_t value); |
||||
grpc_error_handle (*const set)(intptr_t value, |
||||
MetadataContainer* container); |
||||
ParsedMetadata (*const with_new_value)(intptr_t value, |
||||
const grpc_slice& new_value); |
||||
std::string (*debug_string)(intptr_t value); |
||||
}; |
||||
|
||||
static const VTable* EmptyVTable(); |
||||
template <typename Which> |
||||
static const VTable* TrivialTraitVTable(); |
||||
template <typename Which> |
||||
static const VTable* NonTrivialTraitVTable(); |
||||
template <bool kIsBinaryHeader> |
||||
static const VTable* MdelemVtable(); |
||||
|
||||
const VTable* vtable_; |
||||
intptr_t value_; |
||||
uint32_t transport_size_; |
||||
}; |
||||
|
||||
template <typename MetadataContainer> |
||||
const typename ParsedMetadata<MetadataContainer>::VTable* |
||||
ParsedMetadata<MetadataContainer>::EmptyVTable() { |
||||
static const VTable vtable = { |
||||
false, |
||||
// destroy
|
||||
[](intptr_t) {}, |
||||
// set
|
||||
[](intptr_t, MetadataContainer*) { return GRPC_ERROR_NONE; }, |
||||
// with_new_value
|
||||
[](intptr_t, const grpc_slice&) { return ParsedMetadata(); }, |
||||
// debug_string
|
||||
[](intptr_t) -> std::string { return "empty"; }}; |
||||
return &vtable; |
||||
} |
||||
|
||||
template <typename MetadataContainer> |
||||
template <typename Which> |
||||
const typename ParsedMetadata<MetadataContainer>::VTable* |
||||
ParsedMetadata<MetadataContainer>::TrivialTraitVTable() { |
||||
static const VTable vtable = { |
||||
absl::EndsWith(Which::key(), "-bin"), |
||||
// destroy
|
||||
[](intptr_t) {}, |
||||
// set
|
||||
[](intptr_t value, MetadataContainer* map) { |
||||
map->Set(Which(), Which::MementoToValue( |
||||
static_cast<typename Which::MementoType>(value))); |
||||
return GRPC_ERROR_NONE; |
||||
}, |
||||
// with_new_value
|
||||
[](intptr_t, const grpc_slice& value) { |
||||
return ParsedMetadata( |
||||
Which(), Which::ParseMemento(value), |
||||
TransportSize(strlen(Which::key()), GRPC_SLICE_LENGTH(value))); |
||||
}, |
||||
// debug_string
|
||||
[](intptr_t value) { |
||||
return absl::StrCat(Which::key(), ": ", Which::DisplayValue(value)); |
||||
}}; |
||||
return &vtable; |
||||
} |
||||
|
||||
template <typename MetadataContainer> |
||||
template <typename Which> |
||||
const typename ParsedMetadata<MetadataContainer>::VTable* |
||||
ParsedMetadata<MetadataContainer>::NonTrivialTraitVTable() { |
||||
static const VTable vtable = { |
||||
absl::EndsWith(Which::key(), "-bin"), |
||||
// destroy
|
||||
[](intptr_t value) { |
||||
delete reinterpret_cast<typename Which::MementoType*>(value); |
||||
}, |
||||
// set
|
||||
[](intptr_t value, MetadataContainer* map) { |
||||
auto* p = reinterpret_cast<typename Which::MementoType*>(value); |
||||
map->Set(Which(), Which::MementoToValue(*p)); |
||||
return GRPC_ERROR_NONE; |
||||
}, |
||||
// with_new_value
|
||||
[](intptr_t, const grpc_slice& value) { |
||||
return ParsedMetadata( |
||||
Which(), Which::ParseMemento(value), |
||||
TransportSize(strlen(Which::key()), GRPC_SLICE_LENGTH(value))); |
||||
}, |
||||
// debug_string
|
||||
[](intptr_t value) { |
||||
auto* p = reinterpret_cast<typename Which::MementoType*>(value); |
||||
return absl::StrCat(Which::key(), ": ", Which::DisplayValue(*p)); |
||||
}}; |
||||
return &vtable; |
||||
} |
||||
|
||||
template <typename MetadataContainer> |
||||
template <bool kIsBinaryHeader> |
||||
const typename ParsedMetadata<MetadataContainer>::VTable* |
||||
ParsedMetadata<MetadataContainer>::MdelemVtable() { |
||||
static const VTable vtable = { |
||||
kIsBinaryHeader, |
||||
// destroy
|
||||
[](intptr_t value) { GRPC_MDELEM_UNREF(grpc_mdelem{uintptr_t(value)}); }, |
||||
// set
|
||||
[](intptr_t value, MetadataContainer* map) { |
||||
auto md = GRPC_MDELEM_REF(grpc_mdelem{uintptr_t(value)}); |
||||
auto err = map->Append(md); |
||||
// If an error occurs, md is not consumed and we need to.
|
||||
// This is an awful API, but that's why we're replacing it.
|
||||
if (err != GRPC_ERROR_NONE) { |
||||
GRPC_MDELEM_UNREF(md); |
||||
} |
||||
return err; |
||||
}, |
||||
// with_new_value
|
||||
[](intptr_t value, const grpc_slice& value_slice) { |
||||
grpc_mdelem elem{uintptr_t(value)}; |
||||
return ParsedMetadata(grpc_mdelem_from_slices( |
||||
static_cast<const ManagedMemorySlice&>( |
||||
grpc_slice_ref_internal(GRPC_MDKEY(elem))), |
||||
value_slice)); |
||||
}, |
||||
// debug_string
|
||||
[](intptr_t value) { |
||||
grpc_mdelem elem{uintptr_t(value)}; |
||||
return absl::StrCat(StringViewFromSlice(GRPC_MDKEY(elem)), ": ", |
||||
StringViewFromSlice(GRPC_MDVALUE(elem))); |
||||
}}; |
||||
return &vtable; |
||||
} |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif // GRPC_CORE_LIB_TRANSPORT_PARSED_METADATA_H
|
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.
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.
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.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue