| // 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 "net/third_party/quiche/src/quic/core/http/http_encoder.h" | 
 |  | 
 | #include "net/third_party/quiche/src/quic/core/quic_data_writer.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; | 
 |   } | 
 | } | 
 |  | 
 | bool WriteFrameHeader(QuicByteCount length, | 
 |                       HttpFrameType type, | 
 |                       QuicDataWriter* writer) { | 
 |   return writer->WriteVarInt62(static_cast<uint64_t>(type)) && | 
 |          writer->WriteVarInt62(length); | 
 | } | 
 |  | 
 | QuicByteCount GetTotalLength(QuicByteCount payload_length, HttpFrameType type) { | 
 |   return QuicDataWriter::GetVarInt62Len(payload_length) + | 
 |          QuicDataWriter::GetVarInt62Len(static_cast<uint64_t>(type)) + | 
 |          payload_length; | 
 | } | 
 |  | 
 | // Write prioritized element id and element dependency id if needed. | 
 | bool MaybeWriteIds(const PriorityFrame& priority, QuicDataWriter* writer) { | 
 |   if (priority.prioritized_type != ROOT_OF_TREE) { | 
 |     if (!writer->WriteVarInt62(priority.prioritized_element_id)) { | 
 |       return false; | 
 |     } | 
 |   } else { | 
 |     DCHECK_EQ(0u, priority.prioritized_element_id) | 
 |         << "Prioritized element id should be 0 when prioritized type is " | 
 |            "ROOT_OF_TREE"; | 
 |   } | 
 |   if (priority.dependency_type != ROOT_OF_TREE) { | 
 |     if (!writer->WriteVarInt62(priority.element_dependency_id)) { | 
 |       return false; | 
 |     } | 
 |   } else { | 
 |     DCHECK_EQ(0u, priority.element_dependency_id) | 
 |         << "Element dependency id should be 0 when dependency type is " | 
 |            "ROOT_OF_TREE"; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | // static | 
 | QuicByteCount HttpEncoder::SerializeDataFrameHeader( | 
 |     QuicByteCount payload_length, | 
 |     std::unique_ptr<char[]>* output) { | 
 |   DCHECK_NE(0u, payload_length); | 
 |   QuicByteCount header_length = QuicDataWriter::GetVarInt62Len(payload_length) + | 
 |                                 QuicDataWriter::GetVarInt62Len( | 
 |                                     static_cast<uint64_t>(HttpFrameType::DATA)); | 
 |  | 
 |   output->reset(new char[header_length]); | 
 |   QuicDataWriter writer(header_length, output->get()); | 
 |  | 
 |   if (WriteFrameHeader(payload_length, HttpFrameType::DATA, &writer)) { | 
 |     return header_length; | 
 |   } | 
 |   QUIC_DLOG(ERROR) | 
 |       << "Http encoder failed when attempting to serialize data frame header."; | 
 |   return 0; | 
 | } | 
 |  | 
 | // static | 
 | QuicByteCount HttpEncoder::SerializeHeadersFrameHeader( | 
 |     QuicByteCount payload_length, | 
 |     std::unique_ptr<char[]>* output) { | 
 |   DCHECK_NE(0u, payload_length); | 
 |   QuicByteCount header_length = | 
 |       QuicDataWriter::GetVarInt62Len(payload_length) + | 
 |       QuicDataWriter::GetVarInt62Len( | 
 |           static_cast<uint64_t>(HttpFrameType::HEADERS)); | 
 |  | 
 |   output->reset(new char[header_length]); | 
 |   QuicDataWriter writer(header_length, output->get()); | 
 |  | 
 |   if (WriteFrameHeader(payload_length, HttpFrameType::HEADERS, &writer)) { | 
 |     return header_length; | 
 |   } | 
 |   QUIC_DLOG(ERROR) | 
 |       << "Http encoder failed when attempting to serialize headers " | 
 |          "frame header."; | 
 |   return 0; | 
 | } | 
 |  | 
 | // static | 
 | QuicByteCount HttpEncoder::SerializePriorityFrame( | 
 |     const PriorityFrame& priority, | 
 |     std::unique_ptr<char[]>* output) { | 
 |   QuicByteCount payload_length = | 
 |       kPriorityFirstByteLength + | 
 |       (priority.prioritized_type == ROOT_OF_TREE | 
 |            ? 0 | 
 |            : QuicDataWriter::GetVarInt62Len(priority.prioritized_element_id)) + | 
 |       (priority.dependency_type == ROOT_OF_TREE | 
 |            ? 0 | 
 |            : QuicDataWriter::GetVarInt62Len(priority.element_dependency_id)) + | 
 |       kPriorityWeightLength; | 
 |   QuicByteCount total_length = | 
 |       GetTotalLength(payload_length, HttpFrameType::PRIORITY); | 
 |  | 
 |   output->reset(new char[total_length]); | 
 |   QuicDataWriter writer(total_length, output->get()); | 
 |  | 
 |   if (!WriteFrameHeader(payload_length, HttpFrameType::PRIORITY, &writer)) { | 
 |     QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize " | 
 |                         "priority frame header."; | 
 |     return 0; | 
 |   } | 
 |  | 
 |   // Set the first byte of the payload. | 
 |   uint8_t firstByte = 0; | 
 |   firstByte = SetPriorityFields(firstByte, priority.prioritized_type, true); | 
 |   firstByte = SetPriorityFields(firstByte, priority.dependency_type, false); | 
 |   if (priority.exclusive) { | 
 |     firstByte |= kPriorityExclusiveBit; | 
 |   } | 
 |  | 
 |   if (writer.WriteUInt8(firstByte) && MaybeWriteIds(priority, &writer) && | 
 |       writer.WriteUInt8(priority.weight)) { | 
 |     return total_length; | 
 |   } | 
 |   QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize " | 
 |                       "priority frame payload."; | 
 |   return 0; | 
 | } | 
 |  | 
 | // static | 
 | 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, HttpFrameType::CANCEL_PUSH); | 
 |  | 
 |   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; | 
 |   } | 
 |   QUIC_DLOG(ERROR) | 
 |       << "Http encoder failed when attempting to serialize cancel push frame."; | 
 |   return 0; | 
 | } | 
 |  | 
 | // static | 
 | QuicByteCount HttpEncoder::SerializeSettingsFrame( | 
 |     const SettingsFrame& settings, | 
 |     std::unique_ptr<char[]>* output) { | 
 |   QuicByteCount payload_length = 0; | 
 |   // Calculate the payload length. | 
 |   for (auto it = settings.values.begin(); it != settings.values.end(); ++it) { | 
 |     payload_length += QuicDataWriter::GetVarInt62Len(it->first); | 
 |     payload_length += QuicDataWriter::GetVarInt62Len(it->second); | 
 |   } | 
 |  | 
 |   QuicByteCount total_length = | 
 |       GetTotalLength(payload_length, HttpFrameType::SETTINGS); | 
 |  | 
 |   output->reset(new char[total_length]); | 
 |   QuicDataWriter writer(total_length, output->get()); | 
 |  | 
 |   if (!WriteFrameHeader(payload_length, HttpFrameType::SETTINGS, &writer)) { | 
 |     QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize " | 
 |                         "settings frame header."; | 
 |     return 0; | 
 |   } | 
 |  | 
 |   for (auto it = settings.values.begin(); it != settings.values.end(); ++it) { | 
 |     if (!writer.WriteVarInt62(it->first) || !writer.WriteVarInt62(it->second)) { | 
 |       QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize " | 
 |                           "settings frame payload."; | 
 |       return 0; | 
 |     } | 
 |   } | 
 |  | 
 |   return total_length; | 
 | } | 
 |  | 
 | // static | 
 | 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) + | 
 |       QuicDataWriter::GetVarInt62Len( | 
 |           static_cast<uint64_t>(HttpFrameType::PUSH_PROMISE)) + | 
 |       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; | 
 |   } | 
 |   QUIC_DLOG(ERROR) | 
 |       << "Http encoder failed when attempting to serialize push promise frame."; | 
 |   return 0; | 
 | } | 
 |  | 
 | // static | 
 | 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, HttpFrameType::GOAWAY); | 
 |  | 
 |   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; | 
 |   } | 
 |   QUIC_DLOG(ERROR) | 
 |       << "Http encoder failed when attempting to serialize goaway frame."; | 
 |   return 0; | 
 | } | 
 |  | 
 | // static | 
 | 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, HttpFrameType::MAX_PUSH_ID); | 
 |  | 
 |   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; | 
 |   } | 
 |   QUIC_DLOG(ERROR) | 
 |       << "Http encoder failed when attempting to serialize max push id frame."; | 
 |   return 0; | 
 | } | 
 |  | 
 | // static | 
 | 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, HttpFrameType::DUPLICATE_PUSH); | 
 |  | 
 |   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; | 
 |   } | 
 |   QUIC_DLOG(ERROR) << "Http encoder failed when attempting to serialize " | 
 |                       "duplicate push frame."; | 
 |   return 0; | 
 | } | 
 |  | 
 | }  // namespace quic |