diff options
Diffstat (limited to 'chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc')
-rw-r--r-- | chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc new file mode 100644 index 00000000000..beeef9b6abb --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_encoder.cc @@ -0,0 +1,258 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> + +#include "net/third_party/quiche/src/quic/core/http/http_encoder.h" +#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +namespace { + +// Set the first byte of a PRIORITY frame according to its fields. +uint8_t SetPriorityFields(uint8_t num, + PriorityElementType type, + bool prioritized) { + switch (type) { + case REQUEST_STREAM: + return num; + case PUSH_STREAM: + if (prioritized) { + return num | (1 << 6); + } + return num | (1 << 4); + case PLACEHOLDER: + if (prioritized) { + return num | (1 << 7); + } + return num | (1 << 5); + case ROOT_OF_TREE: + if (prioritized) { + num = num | (1 << 6); + return num | (1 << 7); + } + num = num | (1 << 4); + return num | (1 << 5); + default: + QUIC_NOTREACHED(); + return num; + } +} + +// Length of the type field of a frame. +static const size_t kFrameTypeLength = 1; +// Length of the weight field of a priority frame. +static const size_t kPriorityWeightLength = 1; +// Length of a priority frame's first byte. +static const size_t kPriorityFirstByteLength = 1; +// Length of a key in the map of a settings frame. +static const size_t kSettingsMapKeyLength = 2; + +} // namespace + +HttpEncoder::HttpEncoder() {} + +HttpEncoder::~HttpEncoder() {} + +QuicByteCount HttpEncoder::SerializeDataFrameHeader( + QuicByteCount payload_length, + std::unique_ptr<char[]>* output) { + DCHECK_NE(0u, payload_length); + QuicByteCount header_length = + QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength; + + output->reset(new char[header_length]); + QuicDataWriter writer(header_length, output->get()); + + if (WriteFrameHeader(payload_length, HttpFrameType::DATA, &writer)) { + return header_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeHeadersFrameHeader( + QuicByteCount payload_length, + std::unique_ptr<char[]>* output) { + DCHECK_NE(0u, payload_length); + QuicByteCount header_length = + QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength; + + output->reset(new char[header_length]); + QuicDataWriter writer(header_length, output->get()); + + if (WriteFrameHeader(payload_length, HttpFrameType::HEADERS, &writer)) { + return header_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializePriorityFrame( + const PriorityFrame& priority, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + kPriorityFirstByteLength + + QuicDataWriter::GetVarInt62Len(priority.prioritized_element_id) + + QuicDataWriter::GetVarInt62Len(priority.element_dependency_id) + + kPriorityWeightLength; + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get()); + + if (!WriteFrameHeader(payload_length, HttpFrameType::PRIORITY, &writer)) { + return 0; + } + + // Set the first byte of the payload. + uint8_t bits = 0; + bits = SetPriorityFields(bits, priority.prioritized_type, true); + bits = SetPriorityFields(bits, priority.dependency_type, false); + if (priority.exclusive) { + bits |= 1; + } + + if (writer.WriteUInt8(bits) && + writer.WriteVarInt62(priority.prioritized_element_id) && + writer.WriteVarInt62(priority.element_dependency_id) && + writer.WriteUInt8(priority.weight)) { + return total_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeCancelPushFrame( + const CancelPushFrame& cancel_push, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + QuicDataWriter::GetVarInt62Len(cancel_push.push_id); + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get()); + + if (WriteFrameHeader(payload_length, HttpFrameType::CANCEL_PUSH, &writer) && + writer.WriteVarInt62(cancel_push.push_id)) { + return total_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeSettingsFrame( + const SettingsFrame& settings, + std::unique_ptr<char[]>* output) { + // Calculate the key sizes. + QuicByteCount payload_length = settings.values.size() * kSettingsMapKeyLength; + // Calculate the value sizes. + for (auto it = settings.values.begin(); it != settings.values.end(); ++it) { + payload_length += QuicDataWriter::GetVarInt62Len(it->second); + } + + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get()); + + if (!WriteFrameHeader(payload_length, HttpFrameType::SETTINGS, &writer)) { + return 0; + } + + for (auto it = settings.values.begin(); it != settings.values.end(); ++it) { + if (!writer.WriteUInt16(it->first) || !writer.WriteVarInt62(it->second)) { + return 0; + } + } + + return total_length; +} + +QuicByteCount HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( + const PushPromiseFrame& push_promise, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + QuicDataWriter::GetVarInt62Len(push_promise.push_id) + + push_promise.headers.length(); + // GetTotalLength() is not used because headers will not be serialized. + QuicByteCount total_length = + QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength + + QuicDataWriter::GetVarInt62Len(push_promise.push_id); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get()); + + if (WriteFrameHeader(payload_length, HttpFrameType::PUSH_PROMISE, &writer) && + writer.WriteVarInt62(push_promise.push_id)) { + return total_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeGoAwayFrame( + const GoAwayFrame& goaway, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + QuicDataWriter::GetVarInt62Len(goaway.stream_id); + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get()); + + if (WriteFrameHeader(payload_length, HttpFrameType::GOAWAY, &writer) && + writer.WriteVarInt62(goaway.stream_id)) { + return total_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeMaxPushIdFrame( + const MaxPushIdFrame& max_push_id, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + QuicDataWriter::GetVarInt62Len(max_push_id.push_id); + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get()); + + if (WriteFrameHeader(payload_length, HttpFrameType::MAX_PUSH_ID, &writer) && + writer.WriteVarInt62(max_push_id.push_id)) { + return total_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeDuplicatePushFrame( + const DuplicatePushFrame& duplicate_push, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + QuicDataWriter::GetVarInt62Len(duplicate_push.push_id); + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get()); + + if (WriteFrameHeader(payload_length, HttpFrameType::DUPLICATE_PUSH, + &writer) && + writer.WriteVarInt62(duplicate_push.push_id)) { + return total_length; + } + return 0; +} + +bool HttpEncoder::WriteFrameHeader(QuicByteCount length, + HttpFrameType type, + QuicDataWriter* writer) { + return writer->WriteVarInt62(length) && + writer->WriteUInt8(static_cast<uint8_t>(type)); +} + +QuicByteCount HttpEncoder::GetTotalLength(QuicByteCount payload_length) { + return QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength + + payload_length; +} + +} // namespace quic |